From 7da1e51bc8e0505c9bfa3db957116d688df25780 Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 27 May 2024 11:57:13 +0200 Subject: [PATCH 01/31] Update TS to support heatmap series type in the config --- packages/x-charts-pro/src/index.ts | 2 + .../src/models/seriesType/heatmap.ts | 40 +++++++++++++++++ .../x-charts-pro/src/typeOverloads/modules.ts | 18 ++++++++ packages/x-charts/src/ChartsLegend/utils.ts | 8 ++-- .../x-charts/src/models/seriesType/config.ts | 39 +++++++++++++--- .../x-charts/src/models/seriesType/index.ts | 44 +++++++++---------- 6 files changed, 121 insertions(+), 30 deletions(-) create mode 100644 packages/x-charts-pro/src/models/seriesType/heatmap.ts create mode 100644 packages/x-charts-pro/src/typeOverloads/modules.ts diff --git a/packages/x-charts-pro/src/index.ts b/packages/x-charts-pro/src/index.ts index 4fec074aff7a6..6e5ab2d71b97d 100644 --- a/packages/x-charts-pro/src/index.ts +++ b/packages/x-charts-pro/src/index.ts @@ -1 +1,3 @@ +import {} from './typeOverloads/modules'; + export * from '@mui/x-charts'; diff --git a/packages/x-charts-pro/src/models/seriesType/heatmap.ts b/packages/x-charts-pro/src/models/seriesType/heatmap.ts new file mode 100644 index 0000000000000..f4310a80c176e --- /dev/null +++ b/packages/x-charts-pro/src/models/seriesType/heatmap.ts @@ -0,0 +1,40 @@ +import { + DefaultizedProps, + CommonDefaultizedProps, + CommonSeriesType, + CartesianSeriesType, +} from '@mui/x-charts/internals'; + +// TODO: discuss if it's the best data format. +export type HeatmapValueType = [number, number, number]; + +export interface HeatmapSeriesType + extends Omit, 'color'>, + CartesianSeriesType { + type: 'heatmap'; + /** + * Data associated to each bar. + */ + data?: HeatmapValueType[]; + /** + * The key used to retrieve data from the dataset. + */ + dataKey?: string; + /** + * The label to display on the tooltip or the legend. It can be a string or a function. + */ + label?: string | ((location: 'tooltip' | 'legend') => string); +} + +/** + * An object that allows to identify a single bar. + * Used for item interaction + */ +export type HeatmapItemIdentifier = { + type: 'heatmap'; + seriesId: DefaultizedHeatmapSeriesType['id']; + dataIndex: number; +}; + +export interface DefaultizedHeatmapSeriesType + extends DefaultizedProps {} diff --git a/packages/x-charts-pro/src/typeOverloads/modules.ts b/packages/x-charts-pro/src/typeOverloads/modules.ts new file mode 100644 index 0000000000000..f9a2db62ac1a5 --- /dev/null +++ b/packages/x-charts-pro/src/typeOverloads/modules.ts @@ -0,0 +1,18 @@ +import { DefaultizedProps } from '@mui/x-charts/internals'; +import { + HeatmapItemIdentifier, + HeatmapSeriesType, + DefaultizedHeatmapSeriesType, +} from '../models/seriesType/heatmap'; + +declare module '@mui/x-charts/internals' { + interface ChartsSeriesConfig { + heatmap: { + seriesInput: DefaultizedProps; + series: DefaultizedHeatmapSeriesType; + seriesProp: HeatmapSeriesType; + itemIdentifier: HeatmapItemIdentifier; + cartesian: true; + }; + } +} diff --git a/packages/x-charts/src/ChartsLegend/utils.ts b/packages/x-charts/src/ChartsLegend/utils.ts index a5da75c6985b7..8f57e1077219e 100644 --- a/packages/x-charts/src/ChartsLegend/utils.ts +++ b/packages/x-charts/src/ChartsLegend/utils.ts @@ -12,7 +12,7 @@ export type AnchorPosition = { horizontal: AnchorX; vertical: AnchorY }; export type Direction = 'row' | 'column'; -const legendGetter: { [T in ChartSeriesType]: LegendGetter } = { +const legendGetter: { [T in ChartSeriesType]?: LegendGetter } = { bar: getBarLegend, scatter: getScatterLegend, line: getLineLegend, @@ -21,7 +21,9 @@ const legendGetter: { [T in ChartSeriesType]: LegendGetter } = { export function getSeriesToDisplay(series: FormattedSeries) { return (Object.keys(series) as ChartSeriesType[]).flatMap( - (seriesType: T) => - legendGetter[seriesType as T](series[seriesType as T]!), + (seriesType: T) => { + const getter = legendGetter[seriesType as T]; + return getter === undefined ? [] : getter(series[seriesType as T]!); + }, ); } diff --git a/packages/x-charts/src/models/seriesType/config.ts b/packages/x-charts/src/models/seriesType/config.ts index 608962f6af702..952afd3ee2087 100644 --- a/packages/x-charts/src/models/seriesType/config.ts +++ b/packages/x-charts/src/models/seriesType/config.ts @@ -7,35 +7,64 @@ import { DefaultizedProps, MakeOptional } from '../helpers'; import { StackingGroupsType } from '../../internals/stackSeries'; import { SeriesId } from './common'; -interface ChartsSeriesConfig { +export interface ChartsSeriesConfig { bar: { + /** + * Series type when passed to the formatter (some ids are defaultised to simplify the DX) + */ seriesInput: DefaultizedProps & { color: string }; + /** + * Series type when stored in the context (with all the preprocessing added)) + */ series: DefaultizedBarSeriesType; - canBeStacked: true; + /** + * Series typing such that the one user need to provide + */ + seriesProp: BarSeriesType; itemIdentifier: BarItemIdentifier; + canBeStacked: true; + cartesian: true; }; line: { seriesInput: DefaultizedProps & { color: string }; series: DefaultizedLineSeriesType; - canBeStacked: true; + seriesProp: LineSeriesType; itemIdentifier: LineItemIdentifier; + canBeStacked: true; + cartesian: true; }; scatter: { seriesInput: DefaultizedProps & { color: string }; series: DefaultizedScatterSeriesType; + seriesProp: ScatterSeriesType; itemIdentifier: ScatterItemIdentifier; + cartesian: true; }; pie: { seriesInput: Omit, 'data'> & { data: (MakeOptional & { color: string })[]; }; series: DefaultizedPieSeriesType; + seriesProp: PieSeriesType>; itemIdentifier: PieItemIdentifier; }; } -export type CartesianChartSeriesType = 'bar' | 'line' | 'scatter'; -export type ChartSeriesType = 'bar' | 'line' | 'scatter' | 'pie'; +export type ChartSeriesType = keyof ChartsSeriesConfig; + +export type CartesianChartSeriesType = keyof Pick< + ChartsSeriesConfig, + { + [Key in ChartSeriesType]: ChartsSeriesConfig[Key] extends { cartesian: true } ? Key : never; + }[ChartSeriesType] +>; + +export type StackableChartSeriesType = keyof Pick< + ChartsSeriesConfig, + { + [Key in ChartSeriesType]: ChartsSeriesConfig[Key] extends { canBeStacked: true } ? Key : never; + }[ChartSeriesType] +>; export type ChartSeries = ChartsSeriesConfig[T] extends { canBeStacked: true; diff --git a/packages/x-charts/src/models/seriesType/index.ts b/packages/x-charts/src/models/seriesType/index.ts index c6c848eb91656..70dbfedf195aa 100644 --- a/packages/x-charts/src/models/seriesType/index.ts +++ b/packages/x-charts/src/models/seriesType/index.ts @@ -1,31 +1,29 @@ -import { BarItemIdentifier, BarSeriesType, DefaultizedBarSeriesType } from './bar'; -import { DefaultizedLineSeriesType, LineItemIdentifier, LineSeriesType } from './line'; -import { DefaultizedScatterSeriesType, ScatterItemIdentifier, ScatterSeriesType } from './scatter'; -import { DefaultizedPieSeriesType, PieSeriesType, PieItemIdentifier, PieValueType } from './pie'; -import { MakeOptional } from '../helpers'; +import { BarSeriesType, DefaultizedBarSeriesType } from './bar'; +import { + CartesianChartSeriesType, + ChartSeriesType, + ChartsSeriesConfig, + StackableChartSeriesType, +} from './config'; -type AllSeriesType = - | BarSeriesType - | LineSeriesType - | ScatterSeriesType - | PieSeriesType>; +// Series definition -type CartesianSeriesType = BarSeriesType | LineSeriesType | ScatterSeriesType; +type AllSeriesType = + ChartsSeriesConfig[T]['seriesProp']; -type DefaultizedCartesianSeriesType = - | DefaultizedBarSeriesType - | DefaultizedLineSeriesType - | DefaultizedScatterSeriesType; +type CartesianSeriesType = AllSeriesType; -type DefaultizedSeriesType = DefaultizedCartesianSeriesType | DefaultizedPieSeriesType; +type DefaultizedSeriesType = + ChartsSeriesConfig[T]['series']; -type StackableSeriesType = DefaultizedBarSeriesType | DefaultizedLineSeriesType; +type DefaultizedCartesianSeriesType = DefaultizedSeriesType; -export type SeriesItemIdentifier = - | BarItemIdentifier - | LineItemIdentifier - | ScatterItemIdentifier - | PieItemIdentifier; +type StackableSeriesType = DefaultizedSeriesType; + +// item identifier + +export type SeriesItemIdentifier = + ChartsSeriesConfig[T]['itemIdentifier']; export * from './line'; export * from './bar'; @@ -39,6 +37,8 @@ export type { StackableSeriesType, }; +// Helpers + export function isDefaultizedBarSeries( series: DefaultizedSeriesType, ): series is DefaultizedBarSeriesType { From 767279b0312f712bd64bc8aaf87a9d82d169398d Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 27 May 2024 11:59:22 +0200 Subject: [PATCH 02/31] Allow to extend formatter and extremum getter --- .../src/ChartContainer/ChartContainer.tsx | 21 ++++++- .../ChartContainer/defaultExtremumGetters.ts | 25 +++++++++ packages/x-charts/src/ChartsTooltip/utils.tsx | 2 +- .../src/context/CartesianContextProvider.tsx | 56 +++++++++---------- .../src/context/SeriesContextProvider.tsx | 32 +++++++++-- 5 files changed, 96 insertions(+), 40 deletions(-) create mode 100644 packages/x-charts/src/ChartContainer/defaultExtremumGetters.ts diff --git a/packages/x-charts/src/ChartContainer/ChartContainer.tsx b/packages/x-charts/src/ChartContainer/ChartContainer.tsx index 79fdeb77b04d1..b0cd664dd5bb7 100644 --- a/packages/x-charts/src/ChartContainer/ChartContainer.tsx +++ b/packages/x-charts/src/ChartContainer/ChartContainer.tsx @@ -15,12 +15,13 @@ import { } from '../context/CartesianContextProvider'; import { HighlightProvider } from '../context/HighlightProvider'; import { ChartsAxesGradients } from '../internals/components/ChartsAxesGradients'; +import { xExtremumGetters, yExtremumGetters } from './defaultExtremumGetters'; export type ChartContainerProps = Omit< ChartsSurfaceProps & - SeriesContextProviderProps & + Omit & Omit & - CartesianContextProviderProps, + Omit, 'children' > & { children?: React.ReactNode; @@ -50,7 +51,13 @@ const ChartContainer = React.forwardRef(function ChartContainer(props: ChartCont return ( - + ; +}; + export type CartesianContextProviderProps = { /** * The configuration of the x-axes. @@ -46,25 +38,20 @@ export type CartesianContextProviderProps = { * An array of objects that can be used to populate series and axes data using their `dataKey` property. */ dataset?: DatasetType; + /** + * An object with x-axis extremum getters per series type. + */ + xExtremumGetters: ExtremumGettersConfig; + /** + * An object with y-axis extremum getters per series type. + */ + yExtremumGetters: ExtremumGettersConfig; children: React.ReactNode; }; const DEFAULT_CATEGORY_GAP_RATIO = 0.2; const DEFAULT_BAR_GAP_RATIO = 0.1; -// TODO: those might be better placed in a distinct file -const xExtremumGetters: { [T in CartesianChartSeriesType]: ExtremumGetter } = { - bar: getBarExtremumX, - scatter: getScatterExtremumX, - line: getLineExtremumX, -}; - -const yExtremumGetters: { [T in CartesianChartSeriesType]: ExtremumGetter } = { - bar: getBarExtremumY, - scatter: getScatterExtremumY, - line: getLineExtremumY, -}; - type DefaultizedAxisConfig = { [axisKey: string]: AxisDefaultized; }; @@ -98,7 +85,14 @@ if (process.env.NODE_ENV !== 'production') { } function CartesianContextProvider(props: CartesianContextProviderProps) { - const { xAxis: inXAxis, yAxis: inYAxis, dataset, children } = props; + const { + xAxis: inXAxis, + yAxis: inYAxis, + dataset, + xExtremumGetters, + yExtremumGetters, + children, + } = props; const formattedSeries = React.useContext(SeriesContext); const drawingArea = useDrawingArea(); @@ -143,17 +137,17 @@ function CartesianContextProvider(props: CartesianContextProviderProps) { acc: ExtremumGetterResult, chartType: T, axis: AxisConfig, - getters: { [T2 in CartesianChartSeriesType]: ExtremumGetter }, + getters: { [T2 in CartesianChartSeriesType]?: ExtremumGetter }, isDefaultAxis: boolean, ): ExtremumGetterResult => { const getter = getters[chartType]; const series = (formattedSeries[chartType]?.series as Record>) ?? {}; - const [minChartTypeData, maxChartTypeData] = getter({ + const [minChartTypeData, maxChartTypeData] = getter?.({ series, axis, isDefaultAxis, - }); + }) ?? [null, null]; const [minData, maxData] = acc; @@ -170,7 +164,7 @@ function CartesianContextProvider(props: CartesianContextProviderProps) { const getAxisExtremum = ( axis: AxisConfig, - getters: { [T in CartesianChartSeriesType]: ExtremumGetter }, + getters: { [T in CartesianChartSeriesType]?: ExtremumGetter }, isDefaultAxis: boolean, ) => { const charTypes = Object.keys(getters) as CartesianChartSeriesType[]; @@ -331,7 +325,9 @@ function CartesianContextProvider(props: CartesianContextProviderProps) { drawingArea.width, formattedSeries, xAxis, + xExtremumGetters, yAxis, + yExtremumGetters, ]); // @ts-ignore diff --git a/packages/x-charts/src/context/SeriesContextProvider.tsx b/packages/x-charts/src/context/SeriesContextProvider.tsx index e39746611bd4f..27d572bf8bc1f 100644 --- a/packages/x-charts/src/context/SeriesContextProvider.tsx +++ b/packages/x-charts/src/context/SeriesContextProvider.tsx @@ -14,19 +14,33 @@ import { } from '../models/seriesType/config'; import { ChartsColorPalette, blueberryTwilightPalette } from '../colorPalettes'; -export type SeriesContextProviderProps = { +export type SeriesFormatterType = ( + series: AllSeriesType[], + colors: string[], + dataset?: DatasetType, +) => { [type in T]?: FormatterResult }; + +export type SeriesContextProviderProps = { dataset?: DatasetType; /** * The array of series to display. * Each type of series has its own specificity. * Please refer to the appropriate docs page to learn more about it. */ - series: AllSeriesType[]; + series: AllSeriesType[]; /** * Color palette used to colorize multiple series. * @default blueberryTwilightPalette */ colors?: ChartsColorPalette; + /** + * Preprocess series before saving them in the context. + * @param series + * @param colors + * @param dataset + * @returns + */ + formatSeries?: SeriesFormatterType; children: React.ReactNode; }; @@ -55,7 +69,7 @@ const seriesTypeFormatter: { * @param colors The color palette used to defaultize series colors * @returns An object structuring all the series by type. */ -const formatSeries = (series: AllSeriesType[], colors: string[], dataset?: DatasetType) => { +const defaultFormatSeries = (series: AllSeriesType[], colors: string[], dataset?: DatasetType) => { // Group series by type const seriesGroups: { [type in ChartSeriesType]?: FormatterParams } = {}; series.forEach((seriesData, seriesIndex: number) => { @@ -87,8 +101,14 @@ const formatSeries = (series: AllSeriesType[], colors: string[], dataset?: Datas return formattedSeries; }; -function SeriesContextProvider(props: SeriesContextProviderProps) { - const { series, dataset, colors = blueberryTwilightPalette, children } = props; +function SeriesContextProvider(props: SeriesContextProviderProps) { + const { + series, + dataset, + colors = blueberryTwilightPalette, + formatSeries = defaultFormatSeries, + children, + } = props; const theme = useTheme(); @@ -99,7 +119,7 @@ function SeriesContextProvider(props: SeriesContextProviderProps) { typeof colors === 'function' ? colors(theme.palette.mode) : colors, dataset as DatasetType, ), - [series, colors, theme.palette.mode, dataset], + [series, colors, theme.palette.mode, formatSeries, dataset], ); return {children}; From 1646b2789e8d8612159c7b5f5b0405d376feeb1b Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 27 May 2024 12:01:53 +0200 Subject: [PATCH 03/31] Rework color management --- .../ChartsAxisTooltipContent.tsx | 5 ++- .../ChartsItemTooltipContent.tsx | 5 ++- .../DefaultChartsItemTooltipContent.tsx | 2 +- packages/x-charts/src/hooks/index.ts | 1 + packages/x-charts/src/hooks/useColorScale.ts | 34 ++++++++++++++++ .../x-charts/src/internals/colorGetter.ts | 40 ++++++++++++------- packages/x-charts/src/models/axis.ts | 2 +- 7 files changed, 69 insertions(+), 20 deletions(-) create mode 100644 packages/x-charts/src/hooks/useColorScale.ts diff --git a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx index c65b9e1e17866..8f4ca252a020c 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx @@ -78,12 +78,12 @@ function ChartsAxisTooltipContent(props: { let getColor: (index: number) => string; switch (seriesToAdd.type) { - case 'scatter': + case 'line': + case 'bar': getColor = colorGetter( seriesToAdd, xAxis[seriesToAdd.xAxisKey ?? xAxisIds[0]], yAxis[seriesToAdd.yAxisKey ?? yAxisIds[0]], - zAxis[seriesToAdd.zAxisKey ?? zAxisIds[0]], ); break; default: @@ -91,6 +91,7 @@ function ChartsAxisTooltipContent(props: { seriesToAdd, xAxis[seriesToAdd.xAxisKey ?? xAxisIds[0]], yAxis[seriesToAdd.yAxisKey ?? yAxisIds[0]], + zAxis[seriesToAdd.zAxisKey ?? zAxisIds[0]], ); break; } diff --git a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx index 2f7183a6fd938..1fda6a1bd32dd 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx @@ -58,12 +58,12 @@ function ChartsItemTooltipContent(props: { case 'pie': getColor = colorGetter(series); break; - case 'scatter': + case 'line': + case 'bar': getColor = colorGetter( series, xAxis[series.xAxisKey ?? defaultXAxisId], yAxis[series.yAxisKey ?? defaultYAxisId], - zAxis[series.zAxisKey ?? defaultZAxisId], ); break; default: @@ -71,6 +71,7 @@ function ChartsItemTooltipContent(props: { series, xAxis[series.xAxisKey ?? defaultXAxisId], yAxis[series.yAxisKey ?? defaultYAxisId], + zAxis[series.zAxisKey ?? defaultZAxisId], ); break; } diff --git a/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx index 72bba158688b4..29fb6f74338b1 100644 --- a/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx @@ -28,7 +28,7 @@ function DefaultChartsItemTooltipContent( + identifier?: number | string, +): AxisScaleComputedConfig[S]['colorScale'] { + const { xAxis, xAxisIds } = React.useContext(CartesianContext); + + const id = typeof identifier === 'string' ? identifier : xAxisIds[identifier ?? 0]; + + return xAxis[id].colorScale; +} + +export function useYColorScale( + identifier?: number | string, +): AxisScaleComputedConfig[S]['colorScale'] { + const { yAxis, yAxisIds } = React.useContext(CartesianContext); + + const id = typeof identifier === 'string' ? identifier : yAxisIds[identifier ?? 0]; + + return yAxis[id].colorScale; +} + +export function useZColorScale( + identifier?: number | string, +): AxisScaleComputedConfig[S]['colorScale'] { + const { zAxis, zAxisIds } = React.useContext(ZAxisContext); + + const id = typeof identifier === 'string' ? identifier : zAxisIds[identifier ?? 0]; + + return zAxis[id].colorScale; +} diff --git a/packages/x-charts/src/internals/colorGetter.ts b/packages/x-charts/src/internals/colorGetter.ts index 0b022ff91e258..928c0a762281e 100644 --- a/packages/x-charts/src/internals/colorGetter.ts +++ b/packages/x-charts/src/internals/colorGetter.ts @@ -2,33 +2,31 @@ import getBarColor from '../BarChart/getColor'; import getLineColor from '../LineChart/getColor'; import getScatterColor from '../ScatterChart/getColor'; import getPieColor from '../PieChart/getColor'; -import { - DefaultizedBarSeriesType, - DefaultizedLineSeriesType, - DefaultizedPieSeriesType, - DefaultizedScatterSeriesType, -} from '../models'; +import { DefaultizedSeriesType } from '../models'; import { AxisDefaultized } from '../models/axis'; import { ZAxisDefaultized } from '../models/z-axis'; -function getColor(series: DefaultizedPieSeriesType): (dataIndex: number) => string; +export type ColorGetterType = ( + series: DefaultizedSeriesType, + xAxis?: AxisDefaultized, + yAxis?: AxisDefaultized, + zAxis?: ZAxisDefaultized, +) => string; + +function getColor(series: DefaultizedSeriesType<'pie'>): (dataIndex: number) => string; function getColor( - series: DefaultizedBarSeriesType | DefaultizedLineSeriesType, + series: DefaultizedSeriesType<'line' | 'bar'>, xAxis: AxisDefaultized, yAxis: AxisDefaultized, ): (dataIndex: number) => string; function getColor( - series: DefaultizedScatterSeriesType, + series: DefaultizedSeriesType<'scatter'>, xAxis: AxisDefaultized, yAxis: AxisDefaultized, zAxis?: ZAxisDefaultized, ): (dataIndex: number) => string; function getColor( - series: - | DefaultizedBarSeriesType - | DefaultizedLineSeriesType - | DefaultizedScatterSeriesType - | DefaultizedPieSeriesType, + series: DefaultizedSeriesType, xAxis?: AxisDefaultized, yAxis?: AxisDefaultized, zAxis?: ZAxisDefaultized, @@ -50,6 +48,20 @@ function getColor( return getPieColor(series); } + if (series.type === 'heatmap') { + const colorScale = zAxis?.colorScale; + + if (colorScale) { + return (dataIndex: number) => { + const value = series.data[dataIndex][2]; + if (value !== undefined) { + return colorScale(value) ?? ''; + } + return ''; + }; + } + } + throw Error( `MUI X Charts: getColor called with unexpected arguments for series with id "${series.id}"`, ); diff --git a/packages/x-charts/src/models/axis.ts b/packages/x-charts/src/models/axis.ts index cb6b11300956b..9eeb2779f56a6 100644 --- a/packages/x-charts/src/models/axis.ts +++ b/packages/x-charts/src/models/axis.ts @@ -214,7 +214,7 @@ export interface AxisScaleConfig { }; } -interface AxisScaleComputedConfig { +export interface AxisScaleComputedConfig { band: { colorScale?: | ScaleOrdinal From 477d2b2a1ffbfc997fe882c74560875da14591df Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 27 May 2024 12:02:46 +0200 Subject: [PATCH 04/31] Creat heatmap atoms --- .../src/Heatmap/HeatmapContainer.tsx | 154 ++++++++++++++++++ .../x-charts-pro/src/Heatmap/HeatmapPlot.tsx | 36 ++++ packages/x-charts-pro/src/Heatmap/index.ts | 2 + packages/x-charts-pro/src/hooks/index.ts | 1 + packages/x-charts-pro/src/hooks/useSeries.ts | 15 ++ packages/x-charts/src/internals/index.ts | 21 +++ 6 files changed, 229 insertions(+) create mode 100644 packages/x-charts-pro/src/Heatmap/HeatmapContainer.tsx create mode 100644 packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx create mode 100644 packages/x-charts-pro/src/Heatmap/index.ts create mode 100644 packages/x-charts-pro/src/hooks/index.ts create mode 100644 packages/x-charts-pro/src/hooks/useSeries.ts create mode 100644 packages/x-charts/src/internals/index.ts diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapContainer.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapContainer.tsx new file mode 100644 index 0000000000000..82cc536c5988f --- /dev/null +++ b/packages/x-charts-pro/src/Heatmap/HeatmapContainer.tsx @@ -0,0 +1,154 @@ +import * as React from 'react'; +import useForkRef from '@mui/utils/useForkRef'; +import { ChartsSurface, ChartsSurfaceProps } from '@mui/x-charts/ChartsSurface'; +import { + ChartsAxesGradients, + DrawingProvider, + DrawingProviderProps, + SeriesContextProvider, + SeriesContextProviderProps, + InteractionProvider, + CartesianContextProvider, + CartesianContextProviderProps, + HighlightProvider, + ExtremumGetter, + FormatterParams, + SeriesFormatterType, + FormatterResult, + ZAxisContextProvider, +} from '@mui/x-charts/internals'; +import { AllSeriesType } from '@mui/x-charts/models'; +import { ZAxisContextProviderProps } from '@mui/x-charts/context'; + +export type HeatmapContainerProps = Omit< + ChartsSurfaceProps & + Omit, 'formatSeries'> & + Omit & + ZAxisContextProviderProps & + Omit, + 'children' +> & { + children?: React.ReactNode; +}; + +const getBaseExtremum: ExtremumGetter<'heatmap'> = (params) => { + const { axis } = params; + + const minX = Math.min(...(axis.data ?? [])); + const maxX = Math.max(...(axis.data ?? [])); + return [minX, maxX]; +}; + +const xExtremumGetters = { + heatmap: getBaseExtremum, +}; +const yExtremumGetters = { + heatmap: getBaseExtremum, +}; + +const formatSeries: SeriesFormatterType<'heatmap'> = (series: AllSeriesType[]) => { + // Group series by type + const seriesGroups: { heatmap?: FormatterParams<'heatmap'> } = {}; + + series.forEach((seriesData, seriesIndex: number) => { + const { id = `auto-generated-id-${seriesIndex}`, type } = seriesData; + + if (type !== 'heatmap') { + throw new Error('Heatmap does nto suport other series type that "heatmap"'); + } + + if (seriesGroups[type] === undefined) { + seriesGroups[type] = { series: {}, seriesOrder: [] }; + } + if (seriesGroups[type]?.series[id] !== undefined) { + throw new Error(`MUI X Charts: series' id "${id}" is not unique.`); + } + + seriesGroups[type]!.series[id] = { + id, + ...seriesData, + }; + seriesGroups[type]!.seriesOrder.push(id); + }); + + const formattedSeries: { heatmap: FormatterResult<'heatmap'> } = { + heatmap: { + series: {}, + seriesOrder: seriesGroups.heatmap?.seriesOrder ?? [], + }, + }; + + seriesGroups.heatmap?.seriesOrder.forEach((id) => { + formattedSeries.heatmap!.series[id] = { + valueFormatter: (value) => (value === undefined ? '' : value.toString()), + data: [], + ...seriesGroups.heatmap!.series[id], + }; + }); + + return formattedSeries; +}; + +export const HeatmapContainer = React.forwardRef(function HeatmapContainer( + props: HeatmapContainerProps, + ref, +) { + const { + width, + height, + series, + margin, + xAxis, + yAxis, + zAxis, + colors, + dataset, + sx, + title, + desc, + disableAxisListener, + children, + } = props; + const svgRef = React.useRef(null); + const handleRef = useForkRef(ref, svgRef); + + // useReducedMotion(); // a11y reduce motion (see: https://react-spring.dev/docs/utilities/use-reduced-motion) + + return ( + + + + + + + + + {children} + + + + + + + + ); +}); diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx new file mode 100644 index 0000000000000..a0357869d1cc2 --- /dev/null +++ b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx @@ -0,0 +1,36 @@ +import * as React from 'react'; + +import { useXScale, useYScale, useZColorScale } from '@mui/x-charts'; +import { useHeatmapSeries } from '../hooks/useSeries'; + +export function HeatmapPlot() { + const xScale = useXScale<'band'>(); + const yScale = useYScale<'band'>(); + const colorScale = useZColorScale()!; + const series = useHeatmapSeries(); + + const xDomain = xScale.domain(); + const yDomain = yScale.domain(); + + if (!series || series.seriesOrder.length === 0) { + return null; + } + const seriesToDisplay = series.series[series.seriesOrder[0]]; + + return ( + + {seriesToDisplay.data.map(([xIndex, yIndex, value]) => { + return ( + + ); + })} + + ); +} diff --git a/packages/x-charts-pro/src/Heatmap/index.ts b/packages/x-charts-pro/src/Heatmap/index.ts new file mode 100644 index 0000000000000..c0b609ea6426c --- /dev/null +++ b/packages/x-charts-pro/src/Heatmap/index.ts @@ -0,0 +1,2 @@ +export { HeatmapContainer } from './HeatmapContainer'; +export { HeatmapPlot } from './HeatmapPlot'; diff --git a/packages/x-charts-pro/src/hooks/index.ts b/packages/x-charts-pro/src/hooks/index.ts new file mode 100644 index 0000000000000..efe4654a2e1f8 --- /dev/null +++ b/packages/x-charts-pro/src/hooks/index.ts @@ -0,0 +1 @@ +export { useHeatmapSeries as unstable_useHeatmapSeries } from './useSeries'; diff --git a/packages/x-charts-pro/src/hooks/useSeries.ts b/packages/x-charts-pro/src/hooks/useSeries.ts new file mode 100644 index 0000000000000..81ff3ebc30cb3 --- /dev/null +++ b/packages/x-charts-pro/src/hooks/useSeries.ts @@ -0,0 +1,15 @@ +import * as React from 'react'; +import { useSeries } 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() { + const series = useSeries(); + + return React.useMemo(() => series.heatmap, [series.heatmap]); +} diff --git a/packages/x-charts/src/internals/index.ts b/packages/x-charts/src/internals/index.ts new file mode 100644 index 0000000000000..915f68ee38b39 --- /dev/null +++ b/packages/x-charts/src/internals/index.ts @@ -0,0 +1,21 @@ +// Components +export * from './components/ChartsAxesGradients'; + +// hooks +export { useReducedMotion } from '../hooks/useReducedMotion'; +export { useSeries } from '../hooks/useSeries'; + +// contexts + +export * from '../context/CartesianContextProvider'; +export * from '../context/DrawingProvider'; +export * from '../context/HighlightProvider'; +export * from '../context/InteractionProvider'; +export * from '../context/SeriesContextProvider'; +export * from '../context/ZAxisContextProvider'; + +// series configuration +export * from '../models/seriesType/config'; +export * from '../models/seriesType/common'; + +export * from '../models/helpers'; From 431d5af86eb9af5a88642cdd66e524fd9ad77773 Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 27 May 2024 12:03:08 +0200 Subject: [PATCH 05/31] Demonstrate first heatmap --- docs/data/charts/heat-map/BasicHeatmap.js | 72 ++++++++++++++++++++ docs/data/charts/heat-map/BasicHeatmap.tsx | 78 ++++++++++++++++++++++ docs/data/charts/heat-map/heat-map.md | 2 + 3 files changed, 152 insertions(+) create mode 100644 docs/data/charts/heat-map/BasicHeatmap.js create mode 100644 docs/data/charts/heat-map/BasicHeatmap.tsx diff --git a/docs/data/charts/heat-map/BasicHeatmap.js b/docs/data/charts/heat-map/BasicHeatmap.js new file mode 100644 index 0000000000000..2eccd7516a3ae --- /dev/null +++ b/docs/data/charts/heat-map/BasicHeatmap.js @@ -0,0 +1,72 @@ +import * as React from 'react'; +import '@mui/x-charts-pro/typeOverloads'; +import { ChartsAxis } from '@mui/x-charts/ChartsAxis'; +import { HeatmapContainer, HeatmapPlot } from '@mui/x-charts-pro/Heatmap'; + +export default function BasicHeatmap() { + return ( + + + + + ); +} diff --git a/docs/data/charts/heat-map/BasicHeatmap.tsx b/docs/data/charts/heat-map/BasicHeatmap.tsx new file mode 100644 index 0000000000000..867f16ae9392f --- /dev/null +++ b/docs/data/charts/heat-map/BasicHeatmap.tsx @@ -0,0 +1,78 @@ +import * as React from 'react'; +import '@mui/x-charts-pro/typeOverloads'; +import { ChartsAxis } from '@mui/x-charts/ChartsAxis'; +import { ChartsTooltip } from '@mui/x-charts/ChartsTooltip'; +import { HeatmapContainer, HeatmapPlot } from '@mui/x-charts-pro/Heatmap'; + +export default function BasicHeatmap() { + return ( + + + + + + ); +} diff --git a/docs/data/charts/heat-map/heat-map.md b/docs/data/charts/heat-map/heat-map.md index 6d6413b064b8e..d81cc95e4ad4a 100644 --- a/docs/data/charts/heat-map/heat-map.md +++ b/docs/data/charts/heat-map/heat-map.md @@ -13,3 +13,5 @@ The Heatmap Chart component isn't available yet, but you can upvote [**this GitH Don't hesitate to leave a comment there to influence what gets built. Especially if you already have a use case for this component, or if you're facing a pain point with your current solution. ::: + +{{"demo": "BasicHeatmap.js"}} From 67cd276d9614a087176ba8d333468381408a061d Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 27 May 2024 12:05:42 +0200 Subject: [PATCH 06/31] Mark heatmap as unstable --- docs/data/charts/heat-map/BasicHeatmap.js | 17 +++++++++++++---- docs/data/charts/heat-map/BasicHeatmap.tsx | 11 +++++++---- packages/x-charts-pro/src/Heatmap/index.ts | 4 ++-- packages/x-charts-pro/src/index.ts | 1 + .../src/ChartContainer/ChartContainer.tsx | 8 -------- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/docs/data/charts/heat-map/BasicHeatmap.js b/docs/data/charts/heat-map/BasicHeatmap.js index 2eccd7516a3ae..9525f9b798c91 100644 --- a/docs/data/charts/heat-map/BasicHeatmap.js +++ b/docs/data/charts/heat-map/BasicHeatmap.js @@ -1,11 +1,15 @@ import * as React from 'react'; import '@mui/x-charts-pro/typeOverloads'; import { ChartsAxis } from '@mui/x-charts/ChartsAxis'; -import { HeatmapContainer, HeatmapPlot } from '@mui/x-charts-pro/Heatmap'; +import { ChartsTooltip } from '@mui/x-charts/ChartsTooltip'; +import { + UnstableHeatmapContainer, + UnstableHeatmapPlot, +} from '@mui/x-charts-pro/Heatmap'; export default function BasicHeatmap() { return ( - - - + + + ); } diff --git a/docs/data/charts/heat-map/BasicHeatmap.tsx b/docs/data/charts/heat-map/BasicHeatmap.tsx index 867f16ae9392f..9525f9b798c91 100644 --- a/docs/data/charts/heat-map/BasicHeatmap.tsx +++ b/docs/data/charts/heat-map/BasicHeatmap.tsx @@ -2,11 +2,14 @@ import * as React from 'react'; import '@mui/x-charts-pro/typeOverloads'; import { ChartsAxis } from '@mui/x-charts/ChartsAxis'; import { ChartsTooltip } from '@mui/x-charts/ChartsTooltip'; -import { HeatmapContainer, HeatmapPlot } from '@mui/x-charts-pro/Heatmap'; +import { + UnstableHeatmapContainer, + UnstableHeatmapPlot, +} from '@mui/x-charts-pro/Heatmap'; export default function BasicHeatmap() { return ( - - + - + ); } diff --git a/packages/x-charts-pro/src/Heatmap/index.ts b/packages/x-charts-pro/src/Heatmap/index.ts index c0b609ea6426c..4e5eb08d2e262 100644 --- a/packages/x-charts-pro/src/Heatmap/index.ts +++ b/packages/x-charts-pro/src/Heatmap/index.ts @@ -1,2 +1,2 @@ -export { HeatmapContainer } from './HeatmapContainer'; -export { HeatmapPlot } from './HeatmapPlot'; +export { HeatmapContainer as UnstableHeatmapContainer } from './HeatmapContainer'; +export { HeatmapPlot as UnstableHeatmapPlot } from './HeatmapPlot'; diff --git a/packages/x-charts-pro/src/index.ts b/packages/x-charts-pro/src/index.ts index 6e5ab2d71b97d..9508f7e3ab46f 100644 --- a/packages/x-charts-pro/src/index.ts +++ b/packages/x-charts-pro/src/index.ts @@ -1,3 +1,4 @@ import {} from './typeOverloads/modules'; export * from '@mui/x-charts'; +export * from './Heatmap'; diff --git a/packages/x-charts/src/ChartContainer/ChartContainer.tsx b/packages/x-charts/src/ChartContainer/ChartContainer.tsx index b0cd664dd5bb7..443d374d87de9 100644 --- a/packages/x-charts/src/ChartContainer/ChartContainer.tsx +++ b/packages/x-charts/src/ChartContainer/ChartContainer.tsx @@ -103,14 +103,6 @@ ChartContainer.propTypes = { * @default false */ disableAxisListener: PropTypes.bool, - /** - * Preprocess series before saving them in the context. - * @param series - * @param colors - * @param dataset - * @returns - */ - formatSeries: PropTypes.func, /** * The height of the chart in px. */ From 76c2566f4aa434237e9511c166f7c48fac371650 Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 27 May 2024 14:38:36 +0200 Subject: [PATCH 07/31] fix missing export --- packages/x-charts-pro/src/typeOverloads/index.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/x-charts-pro/src/typeOverloads/index.ts diff --git a/packages/x-charts-pro/src/typeOverloads/index.ts b/packages/x-charts-pro/src/typeOverloads/index.ts new file mode 100644 index 0000000000000..4f6953ed9a942 --- /dev/null +++ b/packages/x-charts-pro/src/typeOverloads/index.ts @@ -0,0 +1 @@ +export {} from './modules'; From 3fde5c14dfd984d88a5dfd8e711625a6fec8fd8e Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 30 May 2024 17:45:59 +0200 Subject: [PATCH 08/31] WIP --- docs/data/charts/heat-map/BasicHeatmap.js | 4 +- docs/data/charts/heat-map/BasicHeatmap.tsx | 4 +- docs/pages/x/api/charts/chart-container.json | 6 + docs/pages/x/api/charts/pie-chart.json | 6 + .../charts/responsive-chart-container.json | 6 + .../chart-container/chart-container.json | 3 + .../api-docs/charts/pie-chart/pie-chart.json | 3 + .../responsive-chart-container.json | 3 + packages/x-charts-pro/src/Heatmap/Heatmap.tsx | 0 .../src/Heatmap/HeatmapContainer.tsx | 152 +----------------- .../x-charts-pro/src/Heatmap/HeatmapPlot.tsx | 2 +- .../x-charts-pro/src/Heatmap/extremums.ts | 9 ++ .../x-charts-pro/src/Heatmap/formatter.ts | 10 ++ packages/x-charts-pro/src/Heatmap/getColor.ts | 24 +++ packages/x-charts-pro/src/Heatmap/plugin.ts | 12 ++ .../src/models/seriesType/heatmap.ts | 2 +- packages/x-charts/src/BarChart/BarChart.tsx | 2 +- packages/x-charts/src/BarChart/formatter.ts | 2 +- packages/x-charts/src/BarChart/getColor.ts | 12 +- packages/x-charts/src/BarChart/plugin.ts | 12 ++ .../src/ChartContainer/ChartContainer.tsx | 58 ++++++- .../ChartContainer/defaultExtremumGetters.ts | 25 --- .../src/ChartContainer/defaultPlugins.ts | 6 + .../src/ChartContainer/usePluginsMerge.ts | 41 +++++ .../ChartsAxisTooltipContent.tsx | 51 +++--- .../ChartsItemTooltipContent.tsx | 38 ++--- packages/x-charts/src/ChartsTooltip/utils.tsx | 5 +- packages/x-charts/src/LineChart/LineChart.tsx | 2 +- packages/x-charts/src/LineChart/formatter.ts | 2 +- packages/x-charts/src/LineChart/getColor.ts | 8 +- packages/x-charts/src/LineChart/plugin.ts | 12 ++ packages/x-charts/src/PieChart/PieChart.tsx | 2 +- packages/x-charts/src/PieChart/plugin.ts | 9 ++ .../ResponsiveChartContainer.tsx | 36 +++++ .../src/ScatterChart/ScatterChart.tsx | 2 +- .../x-charts/src/ScatterChart/formatter.ts | 2 +- .../x-charts/src/ScatterChart/getColor.ts | 8 +- packages/x-charts/src/ScatterChart/plugin.ts | 12 ++ .../src/SparkLineChart/SparkLineChart.tsx | 2 +- .../src/context/CartesianContextProvider.tsx | 5 +- .../x-charts/src/context/ColorProvider.tsx | 22 +++ .../src/context/SeriesContextProvider.tsx | 50 +++--- packages/x-charts/src/hooks/useColor.ts | 18 +++ packages/x-charts/src/hooks/useColorScale.ts | 8 +- .../x-charts/src/internals/colorGetter.ts | 70 -------- .../src/internals/defaultizeValueFormatter.ts | 4 +- packages/x-charts/src/internals/index.ts | 6 +- packages/x-charts/src/models/index.ts | 1 + packages/x-charts/src/models/plugin.ts | 27 ++++ .../x-charts/src/models/seriesType/config.ts | 4 + scripts/x-charts.exports.json | 6 + 51 files changed, 451 insertions(+), 365 deletions(-) create mode 100644 packages/x-charts-pro/src/Heatmap/Heatmap.tsx create mode 100644 packages/x-charts-pro/src/Heatmap/extremums.ts create mode 100644 packages/x-charts-pro/src/Heatmap/formatter.ts create mode 100644 packages/x-charts-pro/src/Heatmap/getColor.ts create mode 100644 packages/x-charts-pro/src/Heatmap/plugin.ts create mode 100644 packages/x-charts/src/BarChart/plugin.ts delete mode 100644 packages/x-charts/src/ChartContainer/defaultExtremumGetters.ts create mode 100644 packages/x-charts/src/ChartContainer/defaultPlugins.ts create mode 100644 packages/x-charts/src/ChartContainer/usePluginsMerge.ts create mode 100644 packages/x-charts/src/LineChart/plugin.ts create mode 100644 packages/x-charts/src/PieChart/plugin.ts create mode 100644 packages/x-charts/src/ScatterChart/plugin.ts create mode 100644 packages/x-charts/src/context/ColorProvider.tsx create mode 100644 packages/x-charts/src/hooks/useColor.ts delete mode 100644 packages/x-charts/src/internals/colorGetter.ts create mode 100644 packages/x-charts/src/models/plugin.ts diff --git a/docs/data/charts/heat-map/BasicHeatmap.js b/docs/data/charts/heat-map/BasicHeatmap.js index 9525f9b798c91..b69b2fc398149 100644 --- a/docs/data/charts/heat-map/BasicHeatmap.js +++ b/docs/data/charts/heat-map/BasicHeatmap.js @@ -73,8 +73,8 @@ export default function BasicHeatmap() { ); diff --git a/docs/data/charts/heat-map/BasicHeatmap.tsx b/docs/data/charts/heat-map/BasicHeatmap.tsx index 9525f9b798c91..b69b2fc398149 100644 --- a/docs/data/charts/heat-map/BasicHeatmap.tsx +++ b/docs/data/charts/heat-map/BasicHeatmap.tsx @@ -73,8 +73,8 @@ export default function BasicHeatmap() { ); diff --git a/docs/pages/x/api/charts/chart-container.json b/docs/pages/x/api/charts/chart-container.json index a4fd61c1cc3d3..249706de72d93 100644 --- a/docs/pages/x/api/charts/chart-container.json +++ b/docs/pages/x/api/charts/chart-container.json @@ -32,6 +32,12 @@ "describedArgs": ["highlightedItem"] } }, + "plugins": { + "type": { + "name": "arrayOf", + "description": "Array<{ colorProcessor: func, seriesFormatter: func, seriesType: 'bar', xExtremumGetter?: func, yExtremumGetter?: func }
| { colorProcessor: func, seriesFormatter: func, seriesType: 'line', xExtremumGetter?: func, yExtremumGetter?: func }
| { colorProcessor: func, seriesFormatter: func, seriesType: 'scatter', xExtremumGetter?: func, yExtremumGetter?: func }
| { colorProcessor: func, seriesFormatter: func, seriesType: 'pie', xExtremumGetter?: func, yExtremumGetter?: func }>" + } + }, "xAxis": { "type": { "name": "arrayOf", diff --git a/docs/pages/x/api/charts/pie-chart.json b/docs/pages/x/api/charts/pie-chart.json index 4dc1041445f3d..bac61b53de152 100644 --- a/docs/pages/x/api/charts/pie-chart.json +++ b/docs/pages/x/api/charts/pie-chart.json @@ -61,6 +61,12 @@ } }, "onItemClick": { "type": { "name": "func" } }, + "plugins": { + "type": { + "name": "arrayOf", + "description": "Array<{ colorProcessor: func, seriesFormatter: func, seriesType: 'bar', xExtremumGetter?: func, yExtremumGetter?: func }
| { colorProcessor: func, seriesFormatter: func, seriesType: 'line', xExtremumGetter?: func, yExtremumGetter?: func }
| { colorProcessor: func, seriesFormatter: func, seriesType: 'scatter', xExtremumGetter?: func, yExtremumGetter?: func }
| { colorProcessor: func, seriesFormatter: func, seriesType: 'pie', xExtremumGetter?: func, yExtremumGetter?: func }>" + } + }, "rightAxis": { "type": { "name": "union", "description": "object
| string" }, "default": "null" diff --git a/docs/pages/x/api/charts/responsive-chart-container.json b/docs/pages/x/api/charts/responsive-chart-container.json index fb64c42ff23da..d3b1b63830ea7 100644 --- a/docs/pages/x/api/charts/responsive-chart-container.json +++ b/docs/pages/x/api/charts/responsive-chart-container.json @@ -31,6 +31,12 @@ "describedArgs": ["highlightedItem"] } }, + "plugins": { + "type": { + "name": "arrayOf", + "description": "Array<{ colorProcessor: func, seriesFormatter: func, seriesType: 'bar', xExtremumGetter?: func, yExtremumGetter?: func }
| { colorProcessor: func, seriesFormatter: func, seriesType: 'line', xExtremumGetter?: func, yExtremumGetter?: func }
| { colorProcessor: func, seriesFormatter: func, seriesType: 'scatter', xExtremumGetter?: func, yExtremumGetter?: func }
| { colorProcessor: func, seriesFormatter: func, seriesType: 'pie', xExtremumGetter?: func, yExtremumGetter?: func }>" + } + }, "width": { "type": { "name": "number" } }, "xAxis": { "type": { diff --git a/docs/translations/api-docs/charts/chart-container/chart-container.json b/docs/translations/api-docs/charts/chart-container/chart-container.json index 9e58aa2904d70..625af15ee0311 100644 --- a/docs/translations/api-docs/charts/chart-container/chart-container.json +++ b/docs/translations/api-docs/charts/chart-container/chart-container.json @@ -19,6 +19,9 @@ "description": "The callback fired when the highlighted item changes.", "typeDescriptions": { "highlightedItem": "The newly highlighted item." } }, + "plugins": { + "description": "An array of plugins defining how to preprocess data. If not provided, the container supports line, bar, scatter and pie charts." + }, "series": { "description": "The array of series to display. Each type of series has its own specificity. Please refer to the appropriate docs page to learn more about it." }, diff --git a/docs/translations/api-docs/charts/pie-chart/pie-chart.json b/docs/translations/api-docs/charts/pie-chart/pie-chart.json index 7f1be4fa44ccf..8a53115fa8a9b 100644 --- a/docs/translations/api-docs/charts/pie-chart/pie-chart.json +++ b/docs/translations/api-docs/charts/pie-chart/pie-chart.json @@ -34,6 +34,9 @@ "typeDescriptions": { "highlightedItem": "The newly highlighted item." } }, "onItemClick": { "description": "Callback fired when a pie arc is clicked." }, + "plugins": { + "description": "An array of plugins defining how to preprocess data. If not provided, the container supports line, bar, scatter and pie charts." + }, "rightAxis": { "description": "Indicate which axis to display the right of the charts. Can be a string (the id of the axis) or an object ChartsYAxisProps." }, diff --git a/docs/translations/api-docs/charts/responsive-chart-container/responsive-chart-container.json b/docs/translations/api-docs/charts/responsive-chart-container/responsive-chart-container.json index 66c192844541a..812a9391959a6 100644 --- a/docs/translations/api-docs/charts/responsive-chart-container/responsive-chart-container.json +++ b/docs/translations/api-docs/charts/responsive-chart-container/responsive-chart-container.json @@ -21,6 +21,9 @@ "description": "The callback fired when the highlighted item changes.", "typeDescriptions": { "highlightedItem": "The newly highlighted item." } }, + "plugins": { + "description": "An array of plugins defining how to preprocess data. If not provided, the container supports line, bar, scatter and pie charts." + }, "series": { "description": "The array of series to display. Each type of series has its own specificity. Please refer to the appropriate docs page to learn more about it." }, diff --git a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapContainer.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapContainer.tsx index 82cc536c5988f..c5258494a69d4 100644 --- a/packages/x-charts-pro/src/Heatmap/HeatmapContainer.tsx +++ b/packages/x-charts-pro/src/Heatmap/HeatmapContainer.tsx @@ -1,154 +1,18 @@ import * as React from 'react'; -import useForkRef from '@mui/utils/useForkRef'; -import { ChartsSurface, ChartsSurfaceProps } from '@mui/x-charts/ChartsSurface'; -import { - ChartsAxesGradients, - DrawingProvider, - DrawingProviderProps, - SeriesContextProvider, - SeriesContextProviderProps, - InteractionProvider, - CartesianContextProvider, - CartesianContextProviderProps, - HighlightProvider, - ExtremumGetter, - FormatterParams, - SeriesFormatterType, - FormatterResult, - ZAxisContextProvider, -} from '@mui/x-charts/internals'; -import { AllSeriesType } from '@mui/x-charts/models'; -import { ZAxisContextProviderProps } from '@mui/x-charts/context'; -export type HeatmapContainerProps = Omit< - ChartsSurfaceProps & - Omit, 'formatSeries'> & - Omit & - ZAxisContextProviderProps & - Omit, - 'children' -> & { - children?: React.ReactNode; -}; - -const getBaseExtremum: ExtremumGetter<'heatmap'> = (params) => { - const { axis } = params; - - const minX = Math.min(...(axis.data ?? [])); - const maxX = Math.max(...(axis.data ?? [])); - return [minX, maxX]; -}; - -const xExtremumGetters = { - heatmap: getBaseExtremum, -}; -const yExtremumGetters = { - heatmap: getBaseExtremum, -}; - -const formatSeries: SeriesFormatterType<'heatmap'> = (series: AllSeriesType[]) => { - // Group series by type - const seriesGroups: { heatmap?: FormatterParams<'heatmap'> } = {}; - - series.forEach((seriesData, seriesIndex: number) => { - const { id = `auto-generated-id-${seriesIndex}`, type } = seriesData; - - if (type !== 'heatmap') { - throw new Error('Heatmap does nto suport other series type that "heatmap"'); - } - - if (seriesGroups[type] === undefined) { - seriesGroups[type] = { series: {}, seriesOrder: [] }; - } - if (seriesGroups[type]?.series[id] !== undefined) { - throw new Error(`MUI X Charts: series' id "${id}" is not unique.`); - } - - seriesGroups[type]!.series[id] = { - id, - ...seriesData, - }; - seriesGroups[type]!.seriesOrder.push(id); - }); - - const formattedSeries: { heatmap: FormatterResult<'heatmap'> } = { - heatmap: { - series: {}, - seriesOrder: seriesGroups.heatmap?.seriesOrder ?? [], - }, - }; - - seriesGroups.heatmap?.seriesOrder.forEach((id) => { - formattedSeries.heatmap!.series[id] = { - valueFormatter: (value) => (value === undefined ? '' : value.toString()), - data: [], - ...seriesGroups.heatmap!.series[id], - }; - }); - - return formattedSeries; -}; +import { ZAxisContextProvider, ZAxisContextProviderProps } from '@mui/x-charts/context'; +import { ChartContainer, ChartContainerProps } from '@mui/x-charts/ChartContainer'; +import { plugin } from './plugin'; export const HeatmapContainer = React.forwardRef(function HeatmapContainer( - props: HeatmapContainerProps, + props: ChartContainerProps & Pick, ref, ) { - const { - width, - height, - series, - margin, - xAxis, - yAxis, - zAxis, - colors, - dataset, - sx, - title, - desc, - disableAxisListener, - children, - } = props; - const svgRef = React.useRef(null); - const handleRef = useForkRef(ref, svgRef); - - // useReducedMotion(); // a11y reduce motion (see: https://react-spring.dev/docs/utilities/use-reduced-motion) + const { children, zAxis, ...other } = props; return ( - - - - - - - - - {children} - - - - - - - + + {children} + ); }); diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx index a0357869d1cc2..fc065304100e4 100644 --- a/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx +++ b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx @@ -27,7 +27,7 @@ export function HeatmapPlot() { height={yScale.bandwidth()} x={xScale(xDomain[xIndex])} y={yScale(yDomain[yIndex])} - fill={colorScale(value) ?? undefined} + fill={colorScale?.(value) ?? undefined} /> ); })} diff --git a/packages/x-charts-pro/src/Heatmap/extremums.ts b/packages/x-charts-pro/src/Heatmap/extremums.ts new file mode 100644 index 0000000000000..a0bdab36b7262 --- /dev/null +++ b/packages/x-charts-pro/src/Heatmap/extremums.ts @@ -0,0 +1,9 @@ +import { ExtremumGetter } from '@mui/x-charts/internals'; + +export const getBaseExtremum: ExtremumGetter<'heatmap'> = (params) => { + const { axis } = params; + + const minX = Math.min(...(axis.data ?? [])); + const maxX = Math.max(...(axis.data ?? [])); + return [minX, maxX]; +}; diff --git a/packages/x-charts-pro/src/Heatmap/formatter.ts b/packages/x-charts-pro/src/Heatmap/formatter.ts new file mode 100644 index 0000000000000..fa7133db4d8ac --- /dev/null +++ b/packages/x-charts-pro/src/Heatmap/formatter.ts @@ -0,0 +1,10 @@ +import { defaultizeValueFormatter, Formatter } from '@mui/x-charts/internals'; + +const formatter: Formatter<'heatmap'> = ({ series, seriesOrder }) => { + return { + series: defaultizeValueFormatter(series, (v) => v[2].toString()), + seriesOrder, + }; +}; + +export default formatter; diff --git a/packages/x-charts-pro/src/Heatmap/getColor.ts b/packages/x-charts-pro/src/Heatmap/getColor.ts new file mode 100644 index 0000000000000..f51d382250233 --- /dev/null +++ b/packages/x-charts-pro/src/Heatmap/getColor.ts @@ -0,0 +1,24 @@ +import { DefaultizedSeriesType } from '@mui/x-charts'; +import { AxisDefaultized, ZAxisDefaultized } from '@mui/x-charts/internals'; + +export default function getColor( + series: DefaultizedSeriesType<'heatmap'>, + xAxis?: AxisDefaultized, + yAxis?: AxisDefaultized, + zAxis?: ZAxisDefaultized, +) { + const zColorScale = zAxis?.colorScale; + + if (zColorScale) { + return (dataIndex: number) => { + const value = series.data[dataIndex]; + const color = zColorScale(value[2]); + if (color === null) { + return ''; + } + return color; + }; + } + + return () => ''; +} diff --git a/packages/x-charts-pro/src/Heatmap/plugin.ts b/packages/x-charts-pro/src/Heatmap/plugin.ts new file mode 100644 index 0000000000000..c6d7b42077af2 --- /dev/null +++ b/packages/x-charts-pro/src/Heatmap/plugin.ts @@ -0,0 +1,12 @@ +import { ChartsPluginType } from '@mui/x-charts/models'; +import { getBaseExtremum } from './extremums'; +import formatter from './formatter'; +import getColor from './getColor'; + +export const plugin: ChartsPluginType<'heatmap'> = { + seriesType: 'heatmap', + seriesFormatter: formatter, + colorProcessor: getColor, + xExtremumGetter: getBaseExtremum, + yExtremumGetter: getBaseExtremum, +}; diff --git a/packages/x-charts-pro/src/models/seriesType/heatmap.ts b/packages/x-charts-pro/src/models/seriesType/heatmap.ts index f4310a80c176e..a43805d1fee87 100644 --- a/packages/x-charts-pro/src/models/seriesType/heatmap.ts +++ b/packages/x-charts-pro/src/models/seriesType/heatmap.ts @@ -9,7 +9,7 @@ import { export type HeatmapValueType = [number, number, number]; export interface HeatmapSeriesType - extends Omit, 'color'>, + extends Omit, 'color'>, CartesianSeriesType { type: 'heatmap'; /** diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index 677812fd3a678..a213ea1869834 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -51,7 +51,7 @@ export interface BarChartSlotProps ChartsOverlaySlotProps {} export interface BarChartProps - extends Omit, + extends Omit, Omit, Omit, Omit, diff --git a/packages/x-charts/src/BarChart/formatter.ts b/packages/x-charts/src/BarChart/formatter.ts index 548f363c30106..808268e3e130d 100644 --- a/packages/x-charts/src/BarChart/formatter.ts +++ b/packages/x-charts/src/BarChart/formatter.ts @@ -6,7 +6,7 @@ import { DatasetType, Formatter, } from '../models/seriesType/config'; -import defaultizeValueFormatter from '../internals/defaultizeValueFormatter'; +import { defaultizeValueFormatter } from '../internals/defaultizeValueFormatter'; import { DefaultizedProps } from '../models/helpers'; import { SeriesId } from '../models/seriesType/common'; diff --git a/packages/x-charts/src/BarChart/getColor.ts b/packages/x-charts/src/BarChart/getColor.ts index 31a06feac93b3..ccb8beb2ea232 100644 --- a/packages/x-charts/src/BarChart/getColor.ts +++ b/packages/x-charts/src/BarChart/getColor.ts @@ -3,14 +3,14 @@ import { DefaultizedBarSeriesType } from '../models/seriesType/bar'; export default function getColor( series: DefaultizedBarSeriesType, - xAxis: AxisDefaultized, - yAxis: AxisDefaultized, + xAxis?: AxisDefaultized, + yAxis?: AxisDefaultized, ) { const verticalLayout = series.layout === 'vertical'; - const bandColorScale = verticalLayout ? xAxis.colorScale : yAxis.colorScale; - const valueColorScale = verticalLayout ? yAxis.colorScale : xAxis.colorScale; - const bandValues = verticalLayout ? xAxis.data! : yAxis.data!; + const bandColorScale = verticalLayout ? xAxis?.colorScale : yAxis?.colorScale; + const valueColorScale = verticalLayout ? yAxis?.colorScale : xAxis?.colorScale; + const bandValues = verticalLayout ? xAxis?.data : yAxis?.data; if (valueColorScale) { return (dataIndex: number) => { @@ -22,7 +22,7 @@ export default function getColor( return color; }; } - if (bandColorScale) { + if (bandColorScale && bandValues) { return (dataIndex: number) => { const value = bandValues[dataIndex]; const color = value === null ? series.color : bandColorScale(value); diff --git a/packages/x-charts/src/BarChart/plugin.ts b/packages/x-charts/src/BarChart/plugin.ts new file mode 100644 index 0000000000000..1527621c8026e --- /dev/null +++ b/packages/x-charts/src/BarChart/plugin.ts @@ -0,0 +1,12 @@ +import { ChartsPluginType } from '../models/plugin'; +import { getExtremumX, getExtremumY } from './extremums'; +import formatter from './formatter'; +import getColor from './getColor'; + +export const plugin: ChartsPluginType<'bar'> = { + seriesType: 'bar', + seriesFormatter: formatter, + colorProcessor: getColor, + xExtremumGetter: getExtremumX, + yExtremumGetter: getExtremumY, +}; diff --git a/packages/x-charts/src/ChartContainer/ChartContainer.tsx b/packages/x-charts/src/ChartContainer/ChartContainer.tsx index d86604d0a0a5c..2b5ffb66ef0e6 100644 --- a/packages/x-charts/src/ChartContainer/ChartContainer.tsx +++ b/packages/x-charts/src/ChartContainer/ChartContainer.tsx @@ -14,18 +14,25 @@ import { CartesianContextProviderProps, } from '../context/CartesianContextProvider'; import { ChartsAxesGradients } from '../internals/components/ChartsAxesGradients'; -import { xExtremumGetters, yExtremumGetters } from './defaultExtremumGetters'; import { HighlightedProvider, HighlightedProviderProps } from '../context'; +import { ChartsPluginTypes } from '../models/plugin'; +import { ChartSeriesType } from '../models/seriesType/config'; +import { usePluginsMerge } from './usePluginsMerge'; -export type ChartContainerProps = Omit< +export type ChartContainerProps = Omit< ChartsSurfaceProps & - Omit & + Omit & Omit & Omit & HighlightedProviderProps, 'children' > & { children?: React.ReactNode; + /** + * An array of plugins defining how to preprocess data. + * If not provided, the container supports line, bar, scatter and pie charts. + */ + plugins?: ChartsPluginTypes[]; }; const ChartContainer = React.forwardRef(function ChartContainer(props: ChartContainerProps, ref) { @@ -44,16 +51,23 @@ const ChartContainer = React.forwardRef(function ChartContainer(props: ChartCont disableAxisListener, highlightedItem, onHighlightChange, + plugins, children, } = props; const svgRef = React.useRef(null); const handleRef = useForkRef(ref, svgRef); + const { xExtremumGetters, yExtremumGetters, seriesFormatters } = usePluginsMerge(plugins); useReducedMotion(); // a11y reduce motion (see: https://react-spring.dev/docs/utilities/use-reduced-motion) return ( - + (plugins?: ChartsPluginTypes[]) { + const defaultizedPlugins = plugins ?? defaultPlugins; + + return React.useMemo(() => { + const seriesFormatters: SeriesFormatterConfig = {}; + const colorProcessors: ColorProcessorsConfig = {}; + const xExtremumGetters: ExtremumGettersConfig = {}; + const yExtremumGetters: ExtremumGettersConfig = {}; + + for (let i = 0; i < defaultizedPlugins.length; i += 1) { + const plugin = defaultizedPlugins[i]; + + // To remove those any we will need to solve this union discrimination issue: + // https://www.typescriptlang.org/play/?#code/FDAuE8AcFMAIDkCuBbARtATgYQPYDsAzASwHNYBeWAb2FlgGsi8ATALlgHI8V0MOBuWrBwwMAQ1A4M7ABQAPdtzSYAlBQB8sJb0EBfEBBiwAyqAxMSuQqQrUhjFuw4BnMxYFCRmCVNkLYruZ4JGrkmoEWeiAAxviuWqhWxCTsSMrY+Mm2VAxMbLAARNqYBQA0wqI+0rByGrAATLAAVDWw+rF48YFJpOymQZaZNpQ5DvkFEcFlFd6S1bVhsAAG9S0AJFRyukttMXGgsB3JzrYA2niJQyTl3VcAugZQcADylXPOALJikJAW2ULFDAAflSPEwPRIpw4XnEcw4d1KQkmJBBJjcwQhUJhVXhiN0gmAHXi2LmXx+FnYr1mUk+31+wWy+JABCksBkABtoAcjjYcARDldnGoaCA6AB6MWwADqUnoJxw9FgRH5AHc4L9ooroGJogALQ5iZxwPJEABuRGYiDE7PASJVRFAerZPJIADoxsKhHRooa4FwwXxWF66DNYVIyfTIS73Xk7rZoySpIIQyHUBhtfRkyGfUbOMiOEGU3RExgIxZTtGxnHKAm3kng8xoAQxIh2aBC0W0xms-pvftqLkWOUS2141chBLYABJDimuB4HBKxtiWBiVA4RAHXU4FWwSSwTkHAAqxlgiBYmFcYhYAusbrGq5vtepGFX6YPTHo0GYnjrpbp5ZVrYJZ6EAA + seriesFormatters[plugin.seriesType] = plugin.seriesFormatter as any; + + colorProcessors[plugin.seriesType] = plugin.colorProcessor as any; + + if (plugin.xExtremumGetter) { + xExtremumGetters[plugin.seriesType] = plugin.xExtremumGetter as any; + } + + if (plugin.yExtremumGetter) { + yExtremumGetters[plugin.seriesType] = plugin.yExtremumGetter as any; + } + } + return { + seriesFormatters, + colorProcessors, + xExtremumGetters, + yExtremumGetters, + }; + }, [defaultizedPlugins]); +} diff --git a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx index 8f4ca252a020c..b1e1a10b9af18 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx @@ -5,13 +5,16 @@ import { useSlotProps } from '@mui/base/utils'; import { AxisInteractionData } from '../context/InteractionProvider'; import { SeriesContext } from '../context/SeriesContextProvider'; import { CartesianContext } from '../context/CartesianContextProvider'; -import { ChartSeriesDefaultized, ChartSeriesType } from '../models/seriesType/config'; +import { + ChartSeriesDefaultized, + ChartSeriesType, + isCartesianSeriesType, +} from '../models/seriesType/config'; import { AxisDefaultized } from '../models/axis'; import { ChartsTooltipClasses } from './chartsTooltipClasses'; import { DefaultChartsAxisTooltipContent } from './DefaultChartsAxisTooltipContent'; -import { isCartesianSeriesType } from './utils'; -import colorGetter from '../internals/colorGetter'; import { ZAxisContext } from '../context/ZAxisContextProvider'; +import { useColorProcessor } from '../hooks/useColor'; type ChartSeriesDefaultizedWithColorGetter = ChartSeriesDefaultized & { getColor: (dataIndex: number) => string; @@ -62,6 +65,7 @@ function ChartsAxisTooltipContent(props: { const { xAxisIds, xAxis, yAxisIds, yAxis } = React.useContext(CartesianContext); const { zAxisIds, zAxis } = React.useContext(ZAxisContext); const series = React.useContext(SeriesContext); + const colorProcessors = useColorProcessor(); const USED_AXIS_ID = isXaxis ? xAxisIds[0] : yAxisIds[0]; @@ -76,32 +80,33 @@ function ChartsAxisTooltipContent(props: { if (axisKey === undefined || axisKey === USED_AXIS_ID) { const seriesToAdd = series[seriesType]!.series[seriesId]; - let getColor: (index: number) => string; - switch (seriesToAdd.type) { - case 'line': - case 'bar': - getColor = colorGetter( - seriesToAdd, - xAxis[seriesToAdd.xAxisKey ?? xAxisIds[0]], - yAxis[seriesToAdd.yAxisKey ?? yAxisIds[0]], - ); - break; - default: - getColor = colorGetter( - seriesToAdd, - xAxis[seriesToAdd.xAxisKey ?? xAxisIds[0]], - yAxis[seriesToAdd.yAxisKey ?? yAxisIds[0]], - zAxis[seriesToAdd.zAxisKey ?? zAxisIds[0]], - ); - break; - } + const zAxisKey = (seriesToAdd as any).zAxisKey ?? zAxisIds[0]; + + const getColor = + colorProcessors[seriesType]?.( + seriesToAdd as any, + xAxis[seriesToAdd.xAxisKey ?? xAxisIds[0]], + yAxis[seriesToAdd.yAxisKey ?? yAxisIds[0]], + zAxisKey && zAxis[zAxisKey], + ) ?? (() => ''); rep.push({ ...seriesToAdd, getColor }); } }); }); return rep; - }, [USED_AXIS_ID, isXaxis, series, xAxis, xAxisIds, yAxis, yAxisIds, zAxis, zAxisIds]); + }, [ + USED_AXIS_ID, + colorProcessors, + isXaxis, + series, + xAxis, + xAxisIds, + yAxis, + yAxisIds, + zAxis, + zAxisIds, + ]); const relevantAxis = React.useMemo(() => { return isXaxis ? xAxis[USED_AXIS_ID] : yAxis[USED_AXIS_ID]; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx index 1fda6a1bd32dd..5970f5f3bcea8 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx @@ -8,8 +8,8 @@ import { ChartSeriesDefaultized, ChartSeriesType } from '../models/seriesType/co import { ChartsTooltipClasses } from './chartsTooltipClasses'; import { DefaultChartsItemTooltipContent } from './DefaultChartsItemTooltipContent'; import { CartesianContext } from '../context/CartesianContextProvider'; -import colorGetter from '../internals/colorGetter'; import { ZAxisContext } from '../context/ZAxisContextProvider'; +import { useColorProcessor } from '../hooks/useColor'; export type ChartsItemContentProps = { /** @@ -48,33 +48,19 @@ function ChartsItemTooltipContent(props: { const { xAxis, yAxis, xAxisIds, yAxisIds } = React.useContext(CartesianContext); const { zAxis, zAxisIds } = React.useContext(ZAxisContext); + const colorProcessors = useColorProcessor(); - const defaultXAxisId = xAxisIds[0]; - const defaultYAxisId = yAxisIds[0]; - const defaultZAxisId = zAxisIds[0]; + const xAxisKey = (series as any).xAxisKey ?? xAxisIds[0]; + const yAxisKey = (series as any).yAxisKey ?? yAxisIds[0]; + const zAxisKey = (series as any).zAxisKey ?? zAxisIds[0]; - let getColor: (index: number) => string; - switch (series.type) { - case 'pie': - getColor = colorGetter(series); - break; - case 'line': - case 'bar': - getColor = colorGetter( - series, - xAxis[series.xAxisKey ?? defaultXAxisId], - yAxis[series.yAxisKey ?? defaultYAxisId], - ); - break; - default: - getColor = colorGetter( - series, - xAxis[series.xAxisKey ?? defaultXAxisId], - yAxis[series.yAxisKey ?? defaultYAxisId], - zAxis[series.zAxisKey ?? defaultZAxisId], - ); - break; - } + const getColor = + colorProcessors[series.type]?.( + series as any, + xAxisKey && xAxis[xAxisKey], + yAxisKey && yAxis[yAxisKey], + zAxisKey && zAxis[zAxisKey], + ) ?? (() => ''); const Content = content ?? DefaultChartsItemTooltipContent; const chartTooltipContentProps = useSlotProps({ diff --git a/packages/x-charts/src/ChartsTooltip/utils.tsx b/packages/x-charts/src/ChartsTooltip/utils.tsx index 24deb6f38607b..6e177b9ab5ee1 100644 --- a/packages/x-charts/src/ChartsTooltip/utils.tsx +++ b/packages/x-charts/src/ChartsTooltip/utils.tsx @@ -5,6 +5,7 @@ import { CartesianChartSeriesType, ChartSeriesDefaultized, ChartSeriesType, + isCartesianSeriesType, } from '../models/seriesType/config'; export function generateVirtualElement(mousePosition: { x: number; y: number } | null) { @@ -95,10 +96,6 @@ export function getTooltipHasData( return hasAxisXData || hasAxisYData; } -export function isCartesianSeriesType(seriesType: string): seriesType is CartesianChartSeriesType { - return ['bar', 'line', 'scatter', 'heatmap'].includes(seriesType); -} - export function isCartesianSeries( series: ChartSeriesDefaultized & { getColor: (dataIndex: number) => string }, ): series is ChartSeriesDefaultized & { diff --git a/packages/x-charts/src/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index dc8b7d5fe0f4a..3459111e8311f 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -64,7 +64,7 @@ export interface LineChartSlotProps ChartsOverlaySlotProps {} export interface LineChartProps - extends Omit, + extends Omit, Omit, Omit, ChartsOnAxisClickHandlerProps { diff --git a/packages/x-charts/src/LineChart/formatter.ts b/packages/x-charts/src/LineChart/formatter.ts index 8a7cb0f645894..95a2af39db278 100644 --- a/packages/x-charts/src/LineChart/formatter.ts +++ b/packages/x-charts/src/LineChart/formatter.ts @@ -6,7 +6,7 @@ import { DatasetType, Formatter, } from '../models/seriesType/config'; -import defaultizeValueFormatter from '../internals/defaultizeValueFormatter'; +import { defaultizeValueFormatter } from '../internals/defaultizeValueFormatter'; import { DefaultizedProps } from '../models/helpers'; import { SeriesId } from '../models/seriesType/common'; diff --git a/packages/x-charts/src/LineChart/getColor.ts b/packages/x-charts/src/LineChart/getColor.ts index af924c4fc574c..07207a177cf9d 100644 --- a/packages/x-charts/src/LineChart/getColor.ts +++ b/packages/x-charts/src/LineChart/getColor.ts @@ -3,11 +3,11 @@ import { DefaultizedLineSeriesType } from '../models/seriesType/line'; export default function getColor( series: DefaultizedLineSeriesType, - xAxis: AxisDefaultized, - yAxis: AxisDefaultized, + xAxis?: AxisDefaultized, + yAxis?: AxisDefaultized, ) { - const yColorScale = yAxis.colorScale; - const xColorScale = xAxis.colorScale; + const yColorScale = yAxis?.colorScale; + const xColorScale = xAxis?.colorScale; if (yColorScale) { return (dataIndex: number) => { diff --git a/packages/x-charts/src/LineChart/plugin.ts b/packages/x-charts/src/LineChart/plugin.ts new file mode 100644 index 0000000000000..bc799c54b1ec7 --- /dev/null +++ b/packages/x-charts/src/LineChart/plugin.ts @@ -0,0 +1,12 @@ +import { ChartsPluginType } from '../models/plugin'; +import { getExtremumX, getExtremumY } from './extremums'; +import formatter from './formatter'; +import getColor from './getColor'; + +export const plugin: ChartsPluginType<'line'> = { + seriesType: 'line', + colorProcessor: getColor, + seriesFormatter: formatter, + xExtremumGetter: getExtremumX, + yExtremumGetter: getExtremumY, +}; diff --git a/packages/x-charts/src/PieChart/PieChart.tsx b/packages/x-charts/src/PieChart/PieChart.tsx index 1cc829f48f0c4..95a05af37c6ed 100644 --- a/packages/x-charts/src/PieChart/PieChart.tsx +++ b/packages/x-charts/src/PieChart/PieChart.tsx @@ -52,7 +52,7 @@ export interface PieChartSlotProps ChartsOverlaySlotProps {} export interface PieChartProps - extends Omit, + extends Omit, Omit, Omit, Pick { diff --git a/packages/x-charts/src/PieChart/plugin.ts b/packages/x-charts/src/PieChart/plugin.ts new file mode 100644 index 0000000000000..53962ded67649 --- /dev/null +++ b/packages/x-charts/src/PieChart/plugin.ts @@ -0,0 +1,9 @@ +import { ChartsPluginType } from '../models/plugin'; +import formatter from './formatter'; +import getColor from './getColor'; + +export const plugin: ChartsPluginType<'pie'> = { + seriesType: 'pie', + colorProcessor: getColor, + seriesFormatter: formatter, +}; diff --git a/packages/x-charts/src/ResponsiveChartContainer/ResponsiveChartContainer.tsx b/packages/x-charts/src/ResponsiveChartContainer/ResponsiveChartContainer.tsx index 3714d73b6040a..962a3dcafd727 100644 --- a/packages/x-charts/src/ResponsiveChartContainer/ResponsiveChartContainer.tsx +++ b/packages/x-charts/src/ResponsiveChartContainer/ResponsiveChartContainer.tsx @@ -103,6 +103,42 @@ ResponsiveChartContainer.propTypes = { * @param {HighlightItemData | null} highlightedItem The newly highlighted item. */ onHighlightChange: PropTypes.func, + /** + * An array of plugins defining how to preprocess data. + * If not provided, the container supports line, bar, scatter and pie charts. + */ + plugins: PropTypes.arrayOf( + PropTypes.oneOfType([ + PropTypes.shape({ + colorProcessor: PropTypes.func.isRequired, + seriesFormatter: PropTypes.func.isRequired, + seriesType: PropTypes.oneOf(['bar']).isRequired, + xExtremumGetter: PropTypes.func, + yExtremumGetter: PropTypes.func, + }), + PropTypes.shape({ + colorProcessor: PropTypes.func.isRequired, + seriesFormatter: PropTypes.func.isRequired, + seriesType: PropTypes.oneOf(['line']).isRequired, + xExtremumGetter: PropTypes.func, + yExtremumGetter: PropTypes.func, + }), + PropTypes.shape({ + colorProcessor: PropTypes.func.isRequired, + seriesFormatter: PropTypes.func.isRequired, + seriesType: PropTypes.oneOf(['scatter']).isRequired, + xExtremumGetter: PropTypes.func, + yExtremumGetter: PropTypes.func, + }), + PropTypes.shape({ + colorProcessor: PropTypes.func.isRequired, + seriesFormatter: PropTypes.func.isRequired, + seriesType: PropTypes.oneOf(['pie']).isRequired, + xExtremumGetter: PropTypes.func, + yExtremumGetter: PropTypes.func, + }), + ]).isRequired, + ), /** * The array of series to display. * Each type of series has its own specificity. diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index ab66f226fd038..f05493ed857c5 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -54,7 +54,7 @@ export interface ScatterChartSlotProps ChartsOverlaySlotProps {} export interface ScatterChartProps - extends Omit, + extends Omit, Omit, Omit, Omit, diff --git a/packages/x-charts/src/ScatterChart/formatter.ts b/packages/x-charts/src/ScatterChart/formatter.ts index d0db1a6ad0a5a..4f212f9afa8ef 100644 --- a/packages/x-charts/src/ScatterChart/formatter.ts +++ b/packages/x-charts/src/ScatterChart/formatter.ts @@ -1,4 +1,4 @@ -import defaultizeValueFormatter from '../internals/defaultizeValueFormatter'; +import { defaultizeValueFormatter } from '../internals/defaultizeValueFormatter'; import { Formatter } from '../models/seriesType/config'; const formatter: Formatter<'scatter'> = ({ series, seriesOrder }) => { diff --git a/packages/x-charts/src/ScatterChart/getColor.ts b/packages/x-charts/src/ScatterChart/getColor.ts index 79166556b1437..273a8b37c7042 100644 --- a/packages/x-charts/src/ScatterChart/getColor.ts +++ b/packages/x-charts/src/ScatterChart/getColor.ts @@ -4,13 +4,13 @@ import { DefaultizedScatterSeriesType } from '../models/seriesType/scatter'; export default function getColor( series: DefaultizedScatterSeriesType, - xAxis: AxisDefaultized, - yAxis: AxisDefaultized, + xAxis?: AxisDefaultized, + yAxis?: AxisDefaultized, zAxis?: ZAxisDefaultized, ) { const zColorScale = zAxis?.colorScale; - const yColorScale = yAxis.colorScale; - const xColorScale = xAxis.colorScale; + const yColorScale = yAxis?.colorScale; + const xColorScale = xAxis?.colorScale; if (zColorScale) { return (dataIndex: number) => { diff --git a/packages/x-charts/src/ScatterChart/plugin.ts b/packages/x-charts/src/ScatterChart/plugin.ts new file mode 100644 index 0000000000000..ca77573981a1b --- /dev/null +++ b/packages/x-charts/src/ScatterChart/plugin.ts @@ -0,0 +1,12 @@ +import { ChartsPluginType } from '../models/plugin'; +import { getExtremumX, getExtremumY } from './extremums'; +import formatter from './formatter'; +import getColor from './getColor'; + +export const plugin: ChartsPluginType<'scatter'> = { + seriesType: 'scatter', + seriesFormatter: formatter, + colorProcessor: getColor, + xExtremumGetter: getExtremumX, + yExtremumGetter: getExtremumY, +}; diff --git a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx index 0e1431d1de4a7..7867bb862bccc 100644 --- a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx +++ b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx @@ -40,7 +40,7 @@ export interface SparkLineChartSlotProps ChartsTooltipSlotProps {} export interface SparkLineChartProps - extends Omit { + extends Omit { /** * The xAxis configuration. * Notice it is a single configuration object, not an array of configuration. diff --git a/packages/x-charts/src/context/CartesianContextProvider.tsx b/packages/x-charts/src/context/CartesianContextProvider.tsx index 3435fd835d6b1..9040db402ffd8 100644 --- a/packages/x-charts/src/context/CartesianContextProvider.tsx +++ b/packages/x-charts/src/context/CartesianContextProvider.tsx @@ -6,6 +6,7 @@ import { SeriesContext } from './SeriesContextProvider'; import { DEFAULT_X_AXIS_KEY, DEFAULT_Y_AXIS_KEY } from '../constants'; import { CartesianChartSeriesType, + ChartSeriesType, ChartSeries, DatasetType, ExtremumGetter, @@ -17,8 +18,8 @@ import { useDrawingArea } from '../hooks/useDrawingArea'; import { SeriesId } from '../models/seriesType/common'; import { getColorScale, getOrdinalColorScale } from '../internals/colorScale'; -export type ExtremumGettersConfig = { - [T in CartesianChartSeriesType]?: ExtremumGetter; +export type ExtremumGettersConfig = { + [K in T]?: ExtremumGetter; }; export type CartesianContextProviderProps = { diff --git a/packages/x-charts/src/context/ColorProvider.tsx b/packages/x-charts/src/context/ColorProvider.tsx new file mode 100644 index 0000000000000..46faebddded34 --- /dev/null +++ b/packages/x-charts/src/context/ColorProvider.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; +import { ColorProcessorsConfig } from '../models'; +import { ChartSeriesType } from '../internals'; + +export interface ColorProviderProps { + children: React.ReactNode; + /** + * A mapping defining for each series type how to get item colors. + */ + colorProcessors: ColorProcessorsConfig; +} +export const ColorContext = React.createContext({}); + +if (process.env.NODE_ENV !== 'production') { + ColorContext.displayName = 'ColorContext'; +} + +export function ColorProvider(props: ColorProviderProps) { + const { colorProcessors, children } = props; + + return {children}; +} diff --git a/packages/x-charts/src/context/SeriesContextProvider.tsx b/packages/x-charts/src/context/SeriesContextProvider.tsx index 27d572bf8bc1f..4a40379a81b7c 100644 --- a/packages/x-charts/src/context/SeriesContextProvider.tsx +++ b/packages/x-charts/src/context/SeriesContextProvider.tsx @@ -1,9 +1,5 @@ import * as React from 'react'; import { useTheme } from '@mui/material/styles'; -import barSeriesFormatter from '../BarChart/formatter'; -import scatterSeriesFormatter from '../ScatterChart/formatter'; -import lineSeriesFormatter from '../LineChart/formatter'; -import pieSeriesFormatter from '../PieChart/formatter'; import { AllSeriesType } from '../models/seriesType'; import { defaultizeColor } from '../internals/defaultizeColor'; import { @@ -34,13 +30,9 @@ export type SeriesContextProviderProps; + seriesFormatters: SeriesFormatterConfig; children: React.ReactNode; }; @@ -52,13 +44,9 @@ if (process.env.NODE_ENV !== 'production') { SeriesContext.displayName = 'SeriesContext'; } -const seriesTypeFormatter: { - [type in ChartSeriesType]?: (series: any, dataset?: DatasetType) => any; -} = { - bar: barSeriesFormatter, - scatter: scatterSeriesFormatter, - line: lineSeriesFormatter, - pie: pieSeriesFormatter, +export type SeriesFormatterConfig = { + // TODO replace the function type by Formatter + [K in T]?: (series: FormatterParams, dataset?: DatasetType) => any; }; /** @@ -69,7 +57,12 @@ const seriesTypeFormatter: { * @param colors The color palette used to defaultize series colors * @returns An object structuring all the series by type. */ -const defaultFormatSeries = (series: AllSeriesType[], colors: string[], dataset?: DatasetType) => { +const preprocessSeries = ( + series: AllSeriesType[], + colors: string[], + seriesFormatters: SeriesFormatterConfig, + dataset?: DatasetType, +) => { // Group series by type const seriesGroups: { [type in ChartSeriesType]?: FormatterParams } = {}; series.forEach((seriesData, seriesIndex: number) => { @@ -91,10 +84,10 @@ const defaultFormatSeries = (series: AllSeriesType[], colors: string[], dataset? const formattedSeries: FormattedSeries = {}; // Apply formatter on a type group - (Object.keys(seriesTypeFormatter) as ChartSeriesType[]).forEach((type) => { - if (seriesGroups[type] !== undefined) { - formattedSeries[type] = - seriesTypeFormatter[type]?.(seriesGroups[type], dataset) ?? seriesGroups[type]; + (Object.keys(seriesFormatters) as T[]).forEach((type) => { + const group = seriesGroups[type]; + if (group !== undefined) { + formattedSeries[type] = seriesFormatters[type]?.(group, dataset) ?? seriesGroups[type]; } }); @@ -102,24 +95,19 @@ const defaultFormatSeries = (series: AllSeriesType[], colors: string[], dataset? }; function SeriesContextProvider(props: SeriesContextProviderProps) { - const { - series, - dataset, - colors = blueberryTwilightPalette, - formatSeries = defaultFormatSeries, - children, - } = props; + const { series, dataset, colors = blueberryTwilightPalette, seriesFormatters, children } = props; const theme = useTheme(); const formattedSeries = React.useMemo( () => - formatSeries( + preprocessSeries( series, typeof colors === 'function' ? colors(theme.palette.mode) : colors, + seriesFormatters, dataset as DatasetType, ), - [series, colors, theme.palette.mode, formatSeries, dataset], + [series, colors, theme.palette.mode, seriesFormatters, dataset], ); return {children}; diff --git a/packages/x-charts/src/hooks/useColor.ts b/packages/x-charts/src/hooks/useColor.ts new file mode 100644 index 0000000000000..9ff93418ffa7b --- /dev/null +++ b/packages/x-charts/src/hooks/useColor.ts @@ -0,0 +1,18 @@ +import * as React from 'react'; +import { ChartSeriesType } from '../internals'; +import { ColorContext } from '../context/ColorProvider'; +import { ColorProcessorsConfig } from '../models/plugin'; + +export function useColorProcessor( + seriesType: T, +): ColorProcessorsConfig[T]; +export function useColorProcessor(): ColorProcessorsConfig; +export function useColorProcessor(seriesType?: ChartSeriesType) { + const colorProcessors = React.useContext(ColorContext); + + if (!seriesType) { + return colorProcessors; + } + + return colorProcessors[seriesType]; +} diff --git a/packages/x-charts/src/hooks/useColorScale.ts b/packages/x-charts/src/hooks/useColorScale.ts index 05511349107af..947d2acbd6ded 100644 --- a/packages/x-charts/src/hooks/useColorScale.ts +++ b/packages/x-charts/src/hooks/useColorScale.ts @@ -5,7 +5,7 @@ import { ZAxisContext } from '../context/ZAxisContextProvider'; export function useXColorScale( identifier?: number | string, -): AxisScaleComputedConfig[S]['colorScale'] { +): AxisScaleComputedConfig[S]['colorScale'] | undefined { const { xAxis, xAxisIds } = React.useContext(CartesianContext); const id = typeof identifier === 'string' ? identifier : xAxisIds[identifier ?? 0]; @@ -15,7 +15,7 @@ export function useXColorScale( export function useYColorScale( identifier?: number | string, -): AxisScaleComputedConfig[S]['colorScale'] { +): AxisScaleComputedConfig[S]['colorScale'] | undefined { const { yAxis, yAxisIds } = React.useContext(CartesianContext); const id = typeof identifier === 'string' ? identifier : yAxisIds[identifier ?? 0]; @@ -25,10 +25,10 @@ export function useYColorScale( export function useZColorScale( identifier?: number | string, -): AxisScaleComputedConfig[S]['colorScale'] { +): AxisScaleComputedConfig[S]['colorScale'] | undefined { const { zAxis, zAxisIds } = React.useContext(ZAxisContext); const id = typeof identifier === 'string' ? identifier : zAxisIds[identifier ?? 0]; - return zAxis[id].colorScale; + return zAxis[id]?.colorScale; } diff --git a/packages/x-charts/src/internals/colorGetter.ts b/packages/x-charts/src/internals/colorGetter.ts deleted file mode 100644 index 928c0a762281e..0000000000000 --- a/packages/x-charts/src/internals/colorGetter.ts +++ /dev/null @@ -1,70 +0,0 @@ -import getBarColor from '../BarChart/getColor'; -import getLineColor from '../LineChart/getColor'; -import getScatterColor from '../ScatterChart/getColor'; -import getPieColor from '../PieChart/getColor'; -import { DefaultizedSeriesType } from '../models'; -import { AxisDefaultized } from '../models/axis'; -import { ZAxisDefaultized } from '../models/z-axis'; - -export type ColorGetterType = ( - series: DefaultizedSeriesType, - xAxis?: AxisDefaultized, - yAxis?: AxisDefaultized, - zAxis?: ZAxisDefaultized, -) => string; - -function getColor(series: DefaultizedSeriesType<'pie'>): (dataIndex: number) => string; -function getColor( - series: DefaultizedSeriesType<'line' | 'bar'>, - xAxis: AxisDefaultized, - yAxis: AxisDefaultized, -): (dataIndex: number) => string; -function getColor( - series: DefaultizedSeriesType<'scatter'>, - xAxis: AxisDefaultized, - yAxis: AxisDefaultized, - zAxis?: ZAxisDefaultized, -): (dataIndex: number) => string; -function getColor( - series: DefaultizedSeriesType, - xAxis?: AxisDefaultized, - yAxis?: AxisDefaultized, - zAxis?: ZAxisDefaultized, -): (dataIndex: number) => string { - if (xAxis !== undefined && yAxis !== undefined) { - if (series.type === 'bar') { - return getBarColor(series, xAxis, yAxis); - } - - if (series.type === 'line') { - return getLineColor(series, xAxis, yAxis); - } - - if (series.type === 'scatter') { - return getScatterColor(series, xAxis, yAxis, zAxis); - } - } - if (series.type === 'pie') { - return getPieColor(series); - } - - if (series.type === 'heatmap') { - const colorScale = zAxis?.colorScale; - - if (colorScale) { - return (dataIndex: number) => { - const value = series.data[dataIndex][2]; - if (value !== undefined) { - return colorScale(value) ?? ''; - } - return ''; - }; - } - } - - throw Error( - `MUI X Charts: getColor called with unexpected arguments for series with id "${series.id}"`, - ); -} - -export default getColor; diff --git a/packages/x-charts/src/internals/defaultizeValueFormatter.ts b/packages/x-charts/src/internals/defaultizeValueFormatter.ts index b9fa91ba88103..22b7040e0f1cb 100644 --- a/packages/x-charts/src/internals/defaultizeValueFormatter.ts +++ b/packages/x-charts/src/internals/defaultizeValueFormatter.ts @@ -1,6 +1,6 @@ import { SeriesId, SeriesValueFormatter } from '../models/seriesType/common'; -function defaultizeValueFormatter< +export function defaultizeValueFormatter< TValue, ISeries extends { valueFormatter?: SeriesValueFormatter }, >( @@ -19,5 +19,3 @@ function defaultizeValueFormatter< }); return defaultizedSeries; } - -export default defaultizeValueFormatter; diff --git a/packages/x-charts/src/internals/index.ts b/packages/x-charts/src/internals/index.ts index 915f68ee38b39..725b97ad997c7 100644 --- a/packages/x-charts/src/internals/index.ts +++ b/packages/x-charts/src/internals/index.ts @@ -5,11 +5,13 @@ export * from './components/ChartsAxesGradients'; export { useReducedMotion } from '../hooks/useReducedMotion'; export { useSeries } from '../hooks/useSeries'; +// utils +export * from './defaultizeValueFormatter'; + // contexts export * from '../context/CartesianContextProvider'; export * from '../context/DrawingProvider'; -export * from '../context/HighlightProvider'; export * from '../context/InteractionProvider'; export * from '../context/SeriesContextProvider'; export * from '../context/ZAxisContextProvider'; @@ -19,3 +21,5 @@ export * from '../models/seriesType/config'; export * from '../models/seriesType/common'; export * from '../models/helpers'; +export * from '../models/z-axis'; +export * from '../models/axis'; diff --git a/packages/x-charts/src/models/index.ts b/packages/x-charts/src/models/index.ts index abb5d36002f65..9f82bffa3f6ad 100644 --- a/packages/x-charts/src/models/index.ts +++ b/packages/x-charts/src/models/index.ts @@ -1,6 +1,7 @@ export * from './seriesType'; export * from './layout'; export * from './stacking'; +export * from './plugin'; export type { AxisConfig, ChartsYAxisProps, diff --git a/packages/x-charts/src/models/plugin.ts b/packages/x-charts/src/models/plugin.ts new file mode 100644 index 0000000000000..50a351690bb24 --- /dev/null +++ b/packages/x-charts/src/models/plugin.ts @@ -0,0 +1,27 @@ +import { ChartSeriesType, ExtremumGetter, Formatter } from '../internals'; +import { AxisDefaultized } from './axis'; +import { DefaultizedSeriesType } from './seriesType'; +import { ZAxisDefaultized } from './z-axis'; + +type ColorProcessor = ( + series: DefaultizedSeriesType, + xAxis?: AxisDefaultized, + yAxis?: AxisDefaultized, + zAxis?: ZAxisDefaultized, +) => (dataIndex: number) => string; + +export type ColorProcessorsConfig = { + [Key in T]?: ColorProcessor; +}; + +export type ChartsPluginType = { + seriesType: T; + seriesFormatter: Formatter; + colorProcessor: ColorProcessor; + xExtremumGetter?: ExtremumGetter; + yExtremumGetter?: ExtremumGetter; +}; + +export type ChartsPluginTypes = { + [Key in T]: ChartsPluginType; +}[T]; diff --git a/packages/x-charts/src/models/seriesType/config.ts b/packages/x-charts/src/models/seriesType/config.ts index 952afd3ee2087..04ca91143c089 100644 --- a/packages/x-charts/src/models/seriesType/config.ts +++ b/packages/x-charts/src/models/seriesType/config.ts @@ -59,6 +59,10 @@ export type CartesianChartSeriesType = keyof Pick< }[ChartSeriesType] >; +export function isCartesianSeriesType(seriesType: string): seriesType is CartesianChartSeriesType { + return ['bar', 'line', 'scatter', 'heatmap'].includes(seriesType); +} + export type StackableChartSeriesType = keyof Pick< ChartsSeriesConfig, { diff --git a/scripts/x-charts.exports.json b/scripts/x-charts.exports.json index b474cb1075ef4..621e027e4dd0b 100644 --- a/scripts/x-charts.exports.json +++ b/scripts/x-charts.exports.json @@ -92,6 +92,8 @@ { "name": "ChartsOnAxisClickHandler", "kind": "Function" }, { "name": "ChartsOnAxisClickHandlerProps", "kind": "Interface" }, { "name": "ChartsPieSorting", "kind": "TypeAlias" }, + { "name": "ChartsPluginType", "kind": "TypeAlias" }, + { "name": "ChartsPluginTypes", "kind": "TypeAlias" }, { "name": "ChartsReferenceLine", "kind": "Function" }, { "name": "ChartsReferenceLineClasses", "kind": "Interface" }, { "name": "ChartsReferenceLineClassKey", "kind": "TypeAlias" }, @@ -116,6 +118,7 @@ { "name": "cheerfulFiestaPalette", "kind": "Variable" }, { "name": "cheerfulFiestaPaletteDark", "kind": "Variable" }, { "name": "cheerfulFiestaPaletteLight", "kind": "Variable" }, + { "name": "ColorProcessorsConfig", "kind": "TypeAlias" }, { "name": "ComputedPieRadius", "kind": "Interface" }, { "name": "ContinuousScaleName", "kind": "TypeAlias" }, { "name": "CurveType", "kind": "TypeAlias" }, @@ -285,8 +288,11 @@ { "name": "useHighlighted", "kind": "Function" }, { "name": "useItemHighlighted", "kind": "Function" }, { "name": "useSvgRef", "kind": "Function" }, + { "name": "useXColorScale", "kind": "Function" }, { "name": "useXScale", "kind": "Function" }, + { "name": "useYColorScale", "kind": "Function" }, { "name": "useYScale", "kind": "Function" }, + { "name": "useZColorScale", "kind": "Function" }, { "name": "ZAxisContextProvider", "kind": "Function" }, { "name": "ZAxisContextProviderProps", "kind": "TypeAlias" } ] From ea9175c33a3ac1c2df300abfc95ca0df2563a429 Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 31 May 2024 10:15:36 +0200 Subject: [PATCH 09/31] ts fix --- .../x-charts-pro/src/Heatmap/formatter.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/x-charts-pro/src/Heatmap/formatter.ts b/packages/x-charts-pro/src/Heatmap/formatter.ts index fa7133db4d8ac..17e0b2a68ae38 100644 --- a/packages/x-charts-pro/src/Heatmap/formatter.ts +++ b/packages/x-charts-pro/src/Heatmap/formatter.ts @@ -1,8 +1,21 @@ -import { defaultizeValueFormatter, Formatter } from '@mui/x-charts/internals'; +import { Formatter, SeriesId } from '@mui/x-charts/internals'; +import { DefaultizedHeatmapSeriesType } from '../models/seriesType/heatmap'; + +const formatter: Formatter<'heatmap'> = (params) => { + const { series, seriesOrder } = params; + + const defaultizedSeries: Record = {}; + Object.keys(series).forEach((seriesId) => { + defaultizedSeries[seriesId] = { + // Defaultize the data and the value formatter. + valueFormatter: (v) => v[2].toString(), + data: [], + ...series[seriesId], + }; + }); -const formatter: Formatter<'heatmap'> = ({ series, seriesOrder }) => { return { - series: defaultizeValueFormatter(series, (v) => v[2].toString()), + series: defaultizedSeries, seriesOrder, }; }; From ed30368e124d0032f60da3ce1a8ee36019d72249 Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 31 May 2024 10:24:48 +0200 Subject: [PATCH 10/31] proptypes --- docs/pages/x/api/charts/pie-chart.json | 6 ------ docs/translations/api-docs/charts/pie-chart/pie-chart.json | 3 --- 2 files changed, 9 deletions(-) diff --git a/docs/pages/x/api/charts/pie-chart.json b/docs/pages/x/api/charts/pie-chart.json index bac61b53de152..4dc1041445f3d 100644 --- a/docs/pages/x/api/charts/pie-chart.json +++ b/docs/pages/x/api/charts/pie-chart.json @@ -61,12 +61,6 @@ } }, "onItemClick": { "type": { "name": "func" } }, - "plugins": { - "type": { - "name": "arrayOf", - "description": "Array<{ colorProcessor: func, seriesFormatter: func, seriesType: 'bar', xExtremumGetter?: func, yExtremumGetter?: func }
| { colorProcessor: func, seriesFormatter: func, seriesType: 'line', xExtremumGetter?: func, yExtremumGetter?: func }
| { colorProcessor: func, seriesFormatter: func, seriesType: 'scatter', xExtremumGetter?: func, yExtremumGetter?: func }
| { colorProcessor: func, seriesFormatter: func, seriesType: 'pie', xExtremumGetter?: func, yExtremumGetter?: func }>" - } - }, "rightAxis": { "type": { "name": "union", "description": "object
| string" }, "default": "null" diff --git a/docs/translations/api-docs/charts/pie-chart/pie-chart.json b/docs/translations/api-docs/charts/pie-chart/pie-chart.json index 8a53115fa8a9b..7f1be4fa44ccf 100644 --- a/docs/translations/api-docs/charts/pie-chart/pie-chart.json +++ b/docs/translations/api-docs/charts/pie-chart/pie-chart.json @@ -34,9 +34,6 @@ "typeDescriptions": { "highlightedItem": "The newly highlighted item." } }, "onItemClick": { "description": "Callback fired when a pie arc is clicked." }, - "plugins": { - "description": "An array of plugins defining how to preprocess data. If not provided, the container supports line, bar, scatter and pie charts." - }, "rightAxis": { "description": "Indicate which axis to display the right of the charts. Can be a string (the id of the axis) or an object ChartsYAxisProps." }, From 195019904700c1031a6bad70fa1797225a68d873 Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 31 May 2024 10:35:52 +0200 Subject: [PATCH 11/31] prettier --- .../DefaultChartsAxisTooltipContent.tsx | 48 +++++++++---------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx index 5cbc62f59c86e..9fcc5da3886de 100644 --- a/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx @@ -39,32 +39,28 @@ function DefaultChartsAxisTooltipContent(props: ChartsAxisContentProps) { )} - {series - .filter(isCartesianSeries) - .map(({ color, id, label, valueFormatter, data, getColor }) => { - // @ts-ignore - const formattedValue = valueFormatter(data[dataIndex] ?? null, { dataIndex }); - if (formattedValue == null) { - return null; - } - const formattedLabel = getLabel(label, 'tooltip'); - return ( - - - - - - {formattedLabel ? {formattedLabel} : null} - - - {formattedValue} - - - ); - })} + {series.filter(isCartesianSeries).map(({ id, label, valueFormatter, data, getColor }) => { + // @ts-ignore + const formattedValue = valueFormatter(data[dataIndex] ?? null, { dataIndex }); + if (formattedValue == null) { + return null; + } + const formattedLabel = getLabel(label, 'tooltip'); + const color = getColor(dataIndex); + return ( + + + {color && } + + + {formattedLabel ? {formattedLabel} : null} + + + {formattedValue} + + + ); + })} From b43b8f4a1747ec60dd11d8311a2ebfd06c6d8b9f Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 12 Jun 2024 10:06:39 +0200 Subject: [PATCH 12/31] Add zAxis by default to the container --- .../src/ChartContainer/ChartContainer.tsx | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/packages/x-charts/src/ChartContainer/ChartContainer.tsx b/packages/x-charts/src/ChartContainer/ChartContainer.tsx index 31770a088e55f..d3f954744d7f6 100644 --- a/packages/x-charts/src/ChartContainer/ChartContainer.tsx +++ b/packages/x-charts/src/ChartContainer/ChartContainer.tsx @@ -15,7 +15,12 @@ import { CartesianContextProviderProps, } from '../context/CartesianContextProvider'; import { ChartsAxesGradients } from '../internals/components/ChartsAxesGradients'; -import { HighlightedProvider, HighlightedProviderProps } from '../context'; +import { + HighlightedProvider, + HighlightedProviderProps, + ZAxisContextProvider, + ZAxisContextProviderProps, +} from '../context'; import { ChartsPluginType } from '../models/plugin'; import { ChartSeriesType } from '../models/seriesType/config'; import { usePluginsMerge } from './usePluginsMerge'; @@ -25,6 +30,7 @@ export type ChartContainerProps = Omit< Omit & Omit & Omit & + ZAxisContextProviderProps & HighlightedProviderProps, 'children' > & { @@ -44,6 +50,7 @@ const ChartContainer = React.forwardRef(function ChartContainer(props: ChartCont margin, xAxis, yAxis, + zAxis, colors, dataset, sx, @@ -78,25 +85,27 @@ const ChartContainer = React.forwardRef(function ChartContainer(props: ChartCont xExtremumGetters={xExtremumGetters} yExtremumGetters={yExtremumGetters} > - - - + + - - {children} - - - + + + {children} + + +
+
From b6ecd2ad303cccd9fc5d6c73c3f3c6fe3778767e Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 12 Jun 2024 10:10:25 +0200 Subject: [PATCH 13/31] clean TS depending on which charts use z axis --- packages/x-charts/src/BarChart/BarChart.tsx | 37 +++++++++++++++++++ .../src/ChartContainer/ChartContainer.tsx | 37 +++++++++++++++++++ packages/x-charts/src/LineChart/LineChart.tsx | 37 +++++++++++++++++++ packages/x-charts/src/PieChart/PieChart.tsx | 5 ++- .../ResponsiveChartContainer.tsx | 37 +++++++++++++++++++ .../src/SparkLineChart/SparkLineChart.tsx | 5 ++- 6 files changed, 156 insertions(+), 2 deletions(-) diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index d35db5a296e1a..ac998cdea4977 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -555,6 +555,43 @@ BarChart.propTypes = { valueFormatter: PropTypes.func, }), ), + /** + * The configuration of the z-axes. + */ + zAxis: PropTypes.arrayOf( + PropTypes.shape({ + colorMap: PropTypes.oneOfType([ + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + type: PropTypes.oneOf(['ordinal']).isRequired, + unknownColor: PropTypes.string, + values: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) + .isRequired, + ), + }), + PropTypes.shape({ + color: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.string.isRequired), + PropTypes.func, + ]).isRequired, + max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + type: PropTypes.oneOf(['continuous']).isRequired, + }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + thresholds: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]).isRequired, + ).isRequired, + type: PropTypes.oneOf(['piecewise']).isRequired, + }), + ]), + data: PropTypes.array, + dataKey: PropTypes.string, + id: PropTypes.string, + }), + ), } as any; export { BarChart }; diff --git a/packages/x-charts/src/ChartContainer/ChartContainer.tsx b/packages/x-charts/src/ChartContainer/ChartContainer.tsx index d3f954744d7f6..7ebdd67c0e32f 100644 --- a/packages/x-charts/src/ChartContainer/ChartContainer.tsx +++ b/packages/x-charts/src/ChartContainer/ChartContainer.tsx @@ -334,6 +334,43 @@ ChartContainer.propTypes = { valueFormatter: PropTypes.func, }), ), + /** + * The configuration of the z-axes. + */ + zAxis: PropTypes.arrayOf( + PropTypes.shape({ + colorMap: PropTypes.oneOfType([ + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + type: PropTypes.oneOf(['ordinal']).isRequired, + unknownColor: PropTypes.string, + values: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) + .isRequired, + ), + }), + PropTypes.shape({ + color: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.string.isRequired), + PropTypes.func, + ]).isRequired, + max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + type: PropTypes.oneOf(['continuous']).isRequired, + }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + thresholds: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]).isRequired, + ).isRequired, + type: PropTypes.oneOf(['piecewise']).isRequired, + }), + ]), + data: PropTypes.array, + dataKey: PropTypes.string, + id: PropTypes.string, + }), + ), } as any; export { ChartContainer }; diff --git a/packages/x-charts/src/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index 98a15f16debd5..682c456cc8f3e 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -574,6 +574,43 @@ LineChart.propTypes = { valueFormatter: PropTypes.func, }), ), + /** + * The configuration of the z-axes. + */ + zAxis: PropTypes.arrayOf( + PropTypes.shape({ + colorMap: PropTypes.oneOfType([ + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + type: PropTypes.oneOf(['ordinal']).isRequired, + unknownColor: PropTypes.string, + values: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) + .isRequired, + ), + }), + PropTypes.shape({ + color: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.string.isRequired), + PropTypes.func, + ]).isRequired, + max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + type: PropTypes.oneOf(['continuous']).isRequired, + }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + thresholds: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]).isRequired, + ).isRequired, + type: PropTypes.oneOf(['piecewise']).isRequired, + }), + ]), + data: PropTypes.array, + dataKey: PropTypes.string, + id: PropTypes.string, + }), + ), } as any; export { LineChart }; diff --git a/packages/x-charts/src/PieChart/PieChart.tsx b/packages/x-charts/src/PieChart/PieChart.tsx index 9c3e1b7769723..61df9e82c3e79 100644 --- a/packages/x-charts/src/PieChart/PieChart.tsx +++ b/packages/x-charts/src/PieChart/PieChart.tsx @@ -52,7 +52,10 @@ export interface PieChartSlotProps ChartsOverlaySlotProps {} export interface PieChartProps - extends Omit, + extends Omit< + ResponsiveChartContainerProps, + 'series' | 'leftAxis' | 'bottomAxis' | 'plugins' | 'zAxis' + >, Omit, Omit, Pick { diff --git a/packages/x-charts/src/ResponsiveChartContainer/ResponsiveChartContainer.tsx b/packages/x-charts/src/ResponsiveChartContainer/ResponsiveChartContainer.tsx index 52616f191ce22..d33fbcf1590e3 100644 --- a/packages/x-charts/src/ResponsiveChartContainer/ResponsiveChartContainer.tsx +++ b/packages/x-charts/src/ResponsiveChartContainer/ResponsiveChartContainer.tsx @@ -253,6 +253,43 @@ ResponsiveChartContainer.propTypes = { valueFormatter: PropTypes.func, }), ), + /** + * The configuration of the z-axes. + */ + zAxis: PropTypes.arrayOf( + PropTypes.shape({ + colorMap: PropTypes.oneOfType([ + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + type: PropTypes.oneOf(['ordinal']).isRequired, + unknownColor: PropTypes.string, + values: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) + .isRequired, + ), + }), + PropTypes.shape({ + color: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.string.isRequired), + PropTypes.func, + ]).isRequired, + max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + type: PropTypes.oneOf(['continuous']).isRequired, + }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + thresholds: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]).isRequired, + ).isRequired, + type: PropTypes.oneOf(['piecewise']).isRequired, + }), + ]), + data: PropTypes.array, + dataKey: PropTypes.string, + id: PropTypes.string, + }), + ), } as any; export { ResponsiveChartContainer }; diff --git a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx index 0456631bd7e55..028db19f4acf1 100644 --- a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx +++ b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx @@ -40,7 +40,10 @@ export interface SparkLineChartSlotProps ChartsTooltipSlotProps {} export interface SparkLineChartProps - extends Omit { + extends Omit< + ResponsiveChartContainerProps, + 'series' | 'xAxis' | 'yAxis' | 'zAxis' | 'margin' | 'plugins' + > { /** * The xAxis configuration. * Notice it is a single [[AxisConfig]] object, not an array of configuration. From 5aed6762d1c1566c60dec76a781686a3fbf0649d Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 12 Jun 2024 11:54:15 +0200 Subject: [PATCH 14/31] fixes --- docs/data/charts/heat-map/BasicHeatmap.js | 19 +- docs/data/charts/heat-map/BasicHeatmap.tsx | 40 ++-- docs/data/charts/scatter/scatter.md | 2 +- docs/pages/x/api/charts/chart-container.json | 6 + .../charts/responsive-chart-container.json | 6 + .../chart-container/chart-container.json | 3 +- .../responsive-chart-container.json | 3 +- packages/x-charts-pro/src/Heatmap/Heatmap.tsx | 181 ++++++++++++++++++ .../src/Heatmap/HeatmapContainer.tsx | 18 -- .../x-charts-pro/src/Heatmap/HeatmapPlot.tsx | 3 +- packages/x-charts-pro/src/Heatmap/index.ts | 2 +- packages/x-charts/src/BarChart/BarChart.tsx | 39 +--- packages/x-charts/src/ChartsOverlay/index.ts | 5 + packages/x-charts/src/LineChart/LineChart.tsx | 41 +--- packages/x-charts/src/PieChart/PieChart.tsx | 2 +- .../src/ScatterChart/ScatterChart.tsx | 2 +- packages/x-charts/src/models/colorMapping.ts | 2 +- 17 files changed, 228 insertions(+), 146 deletions(-) delete mode 100644 packages/x-charts-pro/src/Heatmap/HeatmapContainer.tsx diff --git a/docs/data/charts/heat-map/BasicHeatmap.js b/docs/data/charts/heat-map/BasicHeatmap.js index b69b2fc398149..b5798ac970780 100644 --- a/docs/data/charts/heat-map/BasicHeatmap.js +++ b/docs/data/charts/heat-map/BasicHeatmap.js @@ -1,15 +1,9 @@ import * as React from 'react'; -import '@mui/x-charts-pro/typeOverloads'; -import { ChartsAxis } from '@mui/x-charts/ChartsAxis'; -import { ChartsTooltip } from '@mui/x-charts/ChartsTooltip'; -import { - UnstableHeatmapContainer, - UnstableHeatmapPlot, -} from '@mui/x-charts-pro/Heatmap'; +import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; export default function BasicHeatmap() { return ( - - - - - + /> ); } diff --git a/docs/data/charts/heat-map/BasicHeatmap.tsx b/docs/data/charts/heat-map/BasicHeatmap.tsx index b69b2fc398149..860a8c9d16922 100644 --- a/docs/data/charts/heat-map/BasicHeatmap.tsx +++ b/docs/data/charts/heat-map/BasicHeatmap.tsx @@ -1,32 +1,27 @@ import * as React from 'react'; import '@mui/x-charts-pro/typeOverloads'; -import { ChartsAxis } from '@mui/x-charts/ChartsAxis'; -import { ChartsTooltip } from '@mui/x-charts/ChartsTooltip'; -import { - UnstableHeatmapContainer, - UnstableHeatmapPlot, -} from '@mui/x-charts-pro/Heatmap'; +import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; export default function BasicHeatmap() { return ( - - - - - + /> ); } diff --git a/docs/data/charts/scatter/scatter.md b/docs/data/charts/scatter/scatter.md index 188c91bdd01b4..6aefc4f003a26 100644 --- a/docs/data/charts/scatter/scatter.md +++ b/docs/data/charts/scatter/scatter.md @@ -67,7 +67,7 @@ The scatter charts use by priority: :::info The z-axis is a third axis that allows to customize scatter points independently from their position. -It can be provided with `zAxis` props, or with `ZAxisContextProvider` when using composition. +It can be provided with `zAxis` props. The value to map can either come from the `z` property of series data, or from the zAxis data. Here are three ways to set z value to 5. diff --git a/docs/pages/x/api/charts/chart-container.json b/docs/pages/x/api/charts/chart-container.json index bd978a54494a9..b92a05628f0da 100644 --- a/docs/pages/x/api/charts/chart-container.json +++ b/docs/pages/x/api/charts/chart-container.json @@ -44,6 +44,12 @@ "name": "arrayOf", "description": "Array<{ axisId?: number
| string, classes?: object, colorMap?: { colors: Array<string>, type: 'ordinal', unknownColor?: string, values?: Array<Date
| number
| string> }
| { color: Array<string>
| func, max?: Date
| number, min?: Date
| number, type: 'continuous' }
| { colors: Array<string>, thresholds: Array<Date
| number>, type: 'piecewise' }, data?: array, dataKey?: string, disableLine?: bool, disableTicks?: bool, fill?: string, hideTooltip?: bool, id?: number
| string, label?: string, labelFontSize?: number, labelStyle?: object, max?: Date
| number, min?: Date
| number, position?: 'left'
| 'right', reverse?: bool, scaleType?: 'band'
| 'linear'
| 'log'
| 'point'
| 'pow'
| 'sqrt'
| 'time'
| 'utc', slotProps?: object, slots?: object, stroke?: string, tickFontSize?: number, tickInterval?: 'auto'
| array
| func, tickLabelInterval?: 'auto'
| func, tickLabelPlacement?: 'middle'
| 'tick', tickLabelStyle?: object, tickMaxStep?: number, tickMinStep?: number, tickNumber?: number, tickPlacement?: 'end'
| 'extremities'
| 'middle'
| 'start', tickSize?: number, valueFormatter?: func }>" } + }, + "zAxis": { + "type": { + "name": "arrayOf", + "description": "Array<{ colorMap?: { colors: Array<string>, type: 'ordinal', unknownColor?: string, values?: Array<Date
| number
| string> }
| { color: Array<string>
| func, max?: Date
| number, min?: Date
| number, type: 'continuous' }
| { colors: Array<string>, thresholds: Array<Date
| number>, type: 'piecewise' }, data?: array, dataKey?: string, id?: string }>" + } } }, "name": "ChartContainer", diff --git a/docs/pages/x/api/charts/responsive-chart-container.json b/docs/pages/x/api/charts/responsive-chart-container.json index cc76f819d0271..f758a3c363d96 100644 --- a/docs/pages/x/api/charts/responsive-chart-container.json +++ b/docs/pages/x/api/charts/responsive-chart-container.json @@ -44,6 +44,12 @@ "name": "arrayOf", "description": "Array<{ axisId?: number
| string, classes?: object, colorMap?: { colors: Array<string>, type: 'ordinal', unknownColor?: string, values?: Array<Date
| number
| string> }
| { color: Array<string>
| func, max?: Date
| number, min?: Date
| number, type: 'continuous' }
| { colors: Array<string>, thresholds: Array<Date
| number>, type: 'piecewise' }, data?: array, dataKey?: string, disableLine?: bool, disableTicks?: bool, fill?: string, hideTooltip?: bool, id?: number
| string, label?: string, labelFontSize?: number, labelStyle?: object, max?: Date
| number, min?: Date
| number, position?: 'left'
| 'right', reverse?: bool, scaleType?: 'band'
| 'linear'
| 'log'
| 'point'
| 'pow'
| 'sqrt'
| 'time'
| 'utc', slotProps?: object, slots?: object, stroke?: string, tickFontSize?: number, tickInterval?: 'auto'
| array
| func, tickLabelInterval?: 'auto'
| func, tickLabelPlacement?: 'middle'
| 'tick', tickLabelStyle?: object, tickMaxStep?: number, tickMinStep?: number, tickNumber?: number, tickPlacement?: 'end'
| 'extremities'
| 'middle'
| 'start', tickSize?: number, valueFormatter?: func }>" } + }, + "zAxis": { + "type": { + "name": "arrayOf", + "description": "Array<{ colorMap?: { colors: Array<string>, type: 'ordinal', unknownColor?: string, values?: Array<Date
| number
| string> }
| { color: Array<string>
| func, max?: Date
| number, min?: Date
| number, type: 'continuous' }
| { colors: Array<string>, thresholds: Array<Date
| number>, type: 'piecewise' }, data?: array, dataKey?: string, id?: string }>" + } } }, "name": "ResponsiveChartContainer", diff --git a/docs/translations/api-docs/charts/chart-container/chart-container.json b/docs/translations/api-docs/charts/chart-container/chart-container.json index 625af15ee0311..5a13d2067ae7c 100644 --- a/docs/translations/api-docs/charts/chart-container/chart-container.json +++ b/docs/translations/api-docs/charts/chart-container/chart-container.json @@ -31,7 +31,8 @@ }, "yAxis": { "description": "The configuration of the y-axes. If not provided, a default axis config is used. An array of AxisConfig objects." - } + }, + "zAxis": { "description": "The configuration of the z-axes." } }, "classDescriptions": {} } diff --git a/docs/translations/api-docs/charts/responsive-chart-container/responsive-chart-container.json b/docs/translations/api-docs/charts/responsive-chart-container/responsive-chart-container.json index 812a9391959a6..1623c12c44cda 100644 --- a/docs/translations/api-docs/charts/responsive-chart-container/responsive-chart-container.json +++ b/docs/translations/api-docs/charts/responsive-chart-container/responsive-chart-container.json @@ -35,7 +35,8 @@ }, "yAxis": { "description": "The configuration of the y-axes. If not provided, a default axis config is used. An array of AxisConfig objects." - } + }, + "zAxis": { "description": "The configuration of the z-axes." } }, "classDescriptions": {} } diff --git a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx index e69de29bb2d1d..4a93ac8cf4094 100644 --- a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx +++ b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx @@ -0,0 +1,181 @@ +import * as React from 'react'; +import useId from '@mui/utils/useId'; +import { ChartsAxis, ChartsAxisProps } from '@mui/x-charts/ChartsAxis'; +import { + ChartsTooltip, + ChartsTooltipProps, + ChartsTooltipSlotProps, + ChartsTooltipSlots, +} from '@mui/x-charts/ChartsTooltip'; +import { + MakeOptional, + ChartsAxisSlots, + ChartsAxisSlotProps, + ChartsXAxisProps, + ChartsYAxisProps, + AxisConfig, +} from '@mui/x-charts/internals'; +import { ChartsClipPath } from '@mui/x-charts/ChartsClipPath'; +import { + ChartsOnAxisClickHandler, + ChartsOnAxisClickHandlerProps, +} from '@mui/x-charts/ChartsOnAxisClickHandler'; +import { + ChartsOverlay, + ChartsOverlayProps, + ChartsOverlaySlotProps, + ChartsOverlaySlots, +} from '@mui/x-charts/ChartsOverlay'; +import { + ResponsiveChartContainerPro, + ResponsiveChartContainerProProps, +} from '../ResponsiveChartContainerPro'; +import { HeatmapSeriesType } from '../models/seriesType/heatmap'; +import { HeatmapPlot } from './HeatmapPlot'; +import { plugin as heatmapPlugin } from './plugin'; + +export interface HeatmapSlots extends ChartsAxisSlots, ChartsTooltipSlots, ChartsOverlaySlots {} +export interface HeatmapSlotProps + extends ChartsAxisSlotProps, + ChartsTooltipSlotProps, + ChartsOverlaySlotProps {} + +export interface HeatmapProps + extends Omit, + Omit, + Omit, + ChartsOnAxisClickHandlerProps { + /** + * The configuration of the x-axes. + * If not provided, a default axis config is used. + * An array of [[AxisConfig]] objects. + */ + xAxis: MakeOptional, 'id' | 'scaleType'>[]; + /** + * The configuration of the y-axes. + * If not provided, a default axis config is used. + * An array of [[AxisConfig]] objects. + */ + yAxis: MakeOptional, 'id' | 'scaleType'>[]; + /** + * The series to display in the bar chart. + * An array of [[HeatmapSeriesType]] objects. + */ + series: MakeOptional[]; + /** + * The configuration of the tooltip. + * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. + */ + tooltip?: ChartsTooltipProps; + /** + * Overridable component slots. + * @default {} + */ + slots?: HeatmapSlots; + /** + * The props used for each component slot. + * @default {} + */ + slotProps?: HeatmapSlotProps; +} + +export const Heatmap = React.forwardRef(function Heatmap(props: HeatmapProps, ref) { + const { + xAxis, + yAxis, + zAxis, + series, + width, + height, + margin, + colors, + dataset, + sx, + tooltip, + topAxis, + leftAxis, + rightAxis, + bottomAxis, + onAxisClick, + children, + slots, + slotProps, + loading, + highlightedItem, + onHighlightChange, + } = props; + + const id = useId(); + const clipPathId = `${id}-clip-path`; + + const defaultizedXAxis = React.useMemo( + () => xAxis.map((axis) => ({ scaleType: 'band' as const, ...axis })), + [xAxis], + ); + + const defaultizedYAxis = React.useMemo( + () => yAxis.map((axis) => ({ scaleType: 'band' as const, ...axis })), + [yAxis], + ); + + const defaultizedZAxis = React.useMemo( + () => + zAxis ?? [ + { + colorMap: { + type: 'continuous', + min: 0, + max: 10, + color: ['blue', 'red'], + }, + } as const, + ], + [zAxis], + ); + + return ( + ({ + type: 'heatmap', + ...s, + }))} + width={width} + height={height} + margin={margin} + xAxis={defaultizedXAxis} + yAxis={defaultizedYAxis} + zAxis={defaultizedZAxis} + colors={colors} + dataset={dataset} + sx={sx} + disableAxisListener={ + // tooltip?.trigger !== 'axis' && + // axisHighlight?.x === 'none' && + // axisHighlight?.y === 'none' && + !onAxisClick + } + highlightedItem={highlightedItem} + onHighlightChange={onHighlightChange} + > + {onAxisClick && } + + + + + + + {!loading && } + + {children} + + ); +}); diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapContainer.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapContainer.tsx deleted file mode 100644 index c5258494a69d4..0000000000000 --- a/packages/x-charts-pro/src/Heatmap/HeatmapContainer.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import * as React from 'react'; - -import { ZAxisContextProvider, ZAxisContextProviderProps } from '@mui/x-charts/context'; -import { ChartContainer, ChartContainerProps } from '@mui/x-charts/ChartContainer'; -import { plugin } from './plugin'; - -export const HeatmapContainer = React.forwardRef(function HeatmapContainer( - props: ChartContainerProps & Pick, - ref, -) { - const { children, zAxis, ...other } = props; - - return ( - - {children} - - ); -}); diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx index fc065304100e4..2fa2733d4c70e 100644 --- a/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx +++ b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; - -import { useXScale, useYScale, useZColorScale } from '@mui/x-charts'; +import { useXScale, useYScale, useZColorScale } from '@mui/x-charts/hooks'; import { useHeatmapSeries } from '../hooks/useSeries'; export function HeatmapPlot() { diff --git a/packages/x-charts-pro/src/Heatmap/index.ts b/packages/x-charts-pro/src/Heatmap/index.ts index 4e5eb08d2e262..4e0867c2ddf7e 100644 --- a/packages/x-charts-pro/src/Heatmap/index.ts +++ b/packages/x-charts-pro/src/Heatmap/index.ts @@ -1,2 +1,2 @@ -export { HeatmapContainer as UnstableHeatmapContainer } from './HeatmapContainer'; +export { Heatmap as UnstableHeatmap } from './Heatmap'; export { HeatmapPlot as UnstableHeatmapPlot } from './HeatmapPlot'; diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index ac998cdea4977..b36d1fdaac1ae 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -51,7 +51,7 @@ export interface BarChartSlotProps ChartsOverlaySlotProps {} export interface BarChartProps - extends Omit, + extends Omit, Omit, Omit, Omit, @@ -555,43 +555,6 @@ BarChart.propTypes = { valueFormatter: PropTypes.func, }), ), - /** - * The configuration of the z-axes. - */ - zAxis: PropTypes.arrayOf( - PropTypes.shape({ - colorMap: PropTypes.oneOfType([ - PropTypes.shape({ - colors: PropTypes.arrayOf(PropTypes.string).isRequired, - type: PropTypes.oneOf(['ordinal']).isRequired, - unknownColor: PropTypes.string, - values: PropTypes.arrayOf( - PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) - .isRequired, - ), - }), - PropTypes.shape({ - color: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.string.isRequired), - PropTypes.func, - ]).isRequired, - max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), - min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), - type: PropTypes.oneOf(['continuous']).isRequired, - }), - PropTypes.shape({ - colors: PropTypes.arrayOf(PropTypes.string).isRequired, - thresholds: PropTypes.arrayOf( - PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]).isRequired, - ).isRequired, - type: PropTypes.oneOf(['piecewise']).isRequired, - }), - ]), - data: PropTypes.array, - dataKey: PropTypes.string, - id: PropTypes.string, - }), - ), } as any; export { BarChart }; diff --git a/packages/x-charts/src/ChartsOverlay/index.ts b/packages/x-charts/src/ChartsOverlay/index.ts index 200c86e4c6073..0ca99b20ab32c 100644 --- a/packages/x-charts/src/ChartsOverlay/index.ts +++ b/packages/x-charts/src/ChartsOverlay/index.ts @@ -1,3 +1,8 @@ export { ChartsOverlay } from './ChartsOverlay'; +export type { + ChartsOverlayProps, + ChartsOverlaySlotProps, + ChartsOverlaySlots, +} from './ChartsOverlay'; export { ChartsLoadingOverlay } from './ChartsLoadingOverlay'; export { ChartsNoDataOverlay } from './ChartsNoDataOverlay'; diff --git a/packages/x-charts/src/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index 682c456cc8f3e..33015b56d69ec 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -42,7 +42,7 @@ import { ChartsOverlayProps, ChartsOverlaySlotProps, ChartsOverlaySlots, -} from '../ChartsOverlay/ChartsOverlay'; +} from '../ChartsOverlay'; export interface LineChartSlots extends ChartsAxisSlots, @@ -64,7 +64,7 @@ export interface LineChartSlotProps ChartsOverlaySlotProps {} export interface LineChartProps - extends Omit, + extends Omit, Omit, Omit, ChartsOnAxisClickHandlerProps { @@ -574,43 +574,6 @@ LineChart.propTypes = { valueFormatter: PropTypes.func, }), ), - /** - * The configuration of the z-axes. - */ - zAxis: PropTypes.arrayOf( - PropTypes.shape({ - colorMap: PropTypes.oneOfType([ - PropTypes.shape({ - colors: PropTypes.arrayOf(PropTypes.string).isRequired, - type: PropTypes.oneOf(['ordinal']).isRequired, - unknownColor: PropTypes.string, - values: PropTypes.arrayOf( - PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) - .isRequired, - ), - }), - PropTypes.shape({ - color: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.string.isRequired), - PropTypes.func, - ]).isRequired, - max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), - min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), - type: PropTypes.oneOf(['continuous']).isRequired, - }), - PropTypes.shape({ - colors: PropTypes.arrayOf(PropTypes.string).isRequired, - thresholds: PropTypes.arrayOf( - PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]).isRequired, - ).isRequired, - type: PropTypes.oneOf(['piecewise']).isRequired, - }), - ]), - data: PropTypes.array, - dataKey: PropTypes.string, - id: PropTypes.string, - }), - ), } as any; export { LineChart }; diff --git a/packages/x-charts/src/PieChart/PieChart.tsx b/packages/x-charts/src/PieChart/PieChart.tsx index 61df9e82c3e79..bf00ee9effaa3 100644 --- a/packages/x-charts/src/PieChart/PieChart.tsx +++ b/packages/x-charts/src/PieChart/PieChart.tsx @@ -35,7 +35,7 @@ import { ChartsOverlayProps, ChartsOverlaySlotProps, ChartsOverlaySlots, -} from '../ChartsOverlay/ChartsOverlay'; +} from '../ChartsOverlay'; export interface PieChartSlots extends ChartsAxisSlots, diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index 3548f83c99774..7afb59255eb3d 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -30,7 +30,7 @@ import { ChartsOverlayProps, ChartsOverlaySlotProps, ChartsOverlaySlots, -} from '../ChartsOverlay/ChartsOverlay'; +} from '../ChartsOverlay'; import { ChartsAxisHighlight, ChartsAxisHighlightProps } from '../ChartsAxisHighlight'; import { ChartsAxisSlots, ChartsAxisSlotProps } from '../models/axis'; import { diff --git a/packages/x-charts/src/models/colorMapping.ts b/packages/x-charts/src/models/colorMapping.ts index ba5dd13ecd5a6..f14cf41cf89af 100644 --- a/packages/x-charts/src/models/colorMapping.ts +++ b/packages/x-charts/src/models/colorMapping.ts @@ -13,7 +13,7 @@ export interface ContinuousColorConfig { /** * The colors to render. It can be an array with the extremum colors, or an interpolation function. */ - color: [string, string] | ((t: number) => string); + color: readonly [string, string] | ((t: number) => string); } export interface PiecewiseColorConfig { From 1ddb6fbcfc5d3769353d7f10a8b58d757f07013b Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 14 Jun 2024 11:18:23 +0200 Subject: [PATCH 15/31] PoC Highlight --- docs/data/charts/heat-map/BasicHeatmap.js | 27 ++++++++------ docs/data/charts/heat-map/BasicHeatmap.tsx | 4 ++ packages/x-charts-pro/src/Heatmap/Heatmap.tsx | 4 +- .../x-charts-pro/src/Heatmap/HeatmapItem.tsx | 37 +++++++++++++++++++ .../x-charts-pro/src/Heatmap/HeatmapPlot.tsx | 19 +++++++--- packages/x-charts/src/internals/index.ts | 1 + 6 files changed, 74 insertions(+), 18 deletions(-) create mode 100644 packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx diff --git a/docs/data/charts/heat-map/BasicHeatmap.js b/docs/data/charts/heat-map/BasicHeatmap.js index b5798ac970780..18924be4b49cb 100644 --- a/docs/data/charts/heat-map/BasicHeatmap.js +++ b/docs/data/charts/heat-map/BasicHeatmap.js @@ -1,4 +1,5 @@ import * as React from 'react'; +import '@mui/x-charts-pro/typeOverloads'; import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; export default function BasicHeatmap() { @@ -10,20 +11,24 @@ export default function BasicHeatmap() { yAxis={[ { scaleType: 'band', data: ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'] }, ]} - zAxis={[ - { - id: 'color-map-id', - colorMap: { - type: 'continuous', - min: -2, - max: 4, - color: ['green', 'orange'], - }, - }, - ]} + // zAxis={[ + // { + // id: 'color-map-id', + // colorMap: { + // type: 'continuous', + // min: -2, + // max: 4, + // color: ['green', 'orange'], + // }, + // }, + // ]} series={[ { type: 'heatmap', + highlightScope: { + highlight: 'item', + fade: 'global', + }, data: [ [0, 0, 1], [0, 1, 2], diff --git a/docs/data/charts/heat-map/BasicHeatmap.tsx b/docs/data/charts/heat-map/BasicHeatmap.tsx index 860a8c9d16922..18924be4b49cb 100644 --- a/docs/data/charts/heat-map/BasicHeatmap.tsx +++ b/docs/data/charts/heat-map/BasicHeatmap.tsx @@ -25,6 +25,10 @@ export default function BasicHeatmap() { series={[ { type: 'heatmap', + highlightScope: { + highlight: 'item', + fade: 'global', + }, data: [ [0, 0, 1], [0, 1, 2], diff --git a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx index 4a93ac8cf4094..98bea885dbf99 100644 --- a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx +++ b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx @@ -109,12 +109,12 @@ export const Heatmap = React.forwardRef(function Heatmap(props: HeatmapProps, re const clipPathId = `${id}-clip-path`; const defaultizedXAxis = React.useMemo( - () => xAxis.map((axis) => ({ scaleType: 'band' as const, ...axis })), + () => xAxis.map((axis) => ({ scaleType: 'band' as const, categoryGapRatio: 0, ...axis })), [xAxis], ); const defaultizedYAxis = React.useMemo( - () => yAxis.map((axis) => ({ scaleType: 'band' as const, ...axis })), + () => yAxis.map((axis) => ({ scaleType: 'band' as const, categoryGapRatio: 0, ...axis })), [yAxis], ); diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx new file mode 100644 index 0000000000000..88aacf54ce746 --- /dev/null +++ b/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx @@ -0,0 +1,37 @@ +import * as React from 'react'; +import { useItemHighlighted } from '@mui/x-charts/context'; +import { useInteractionItemProps, SeriesId } from '@mui/x-charts/internals'; + +interface HeatmapItemProps { + dataIndex: number; + seriesId: SeriesId; + width: number; + height: number; + x: number; + y: number; + color: string; +} + +export function HeatmapItem(props: HeatmapItemProps) { + const { dataIndex, seriesId, width, height, x, y, color } = props; + + const getInteractionItemProps = useInteractionItemProps(); + const { isFaded, isHighlighted } = useItemHighlighted({ + seriesId, + dataIndex, + }); + + return ( + + ); +} diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx index 2fa2733d4c70e..775531188da02 100644 --- a/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx +++ b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { useXScale, useYScale, useZColorScale } from '@mui/x-charts/hooks'; import { useHeatmapSeries } from '../hooks/useSeries'; +import { HeatmapItem } from './HeatmapItem'; export function HeatmapPlot() { const xScale = useXScale<'band'>(); @@ -18,15 +19,23 @@ export function HeatmapPlot() { return ( - {seriesToDisplay.data.map(([xIndex, yIndex, value]) => { + {seriesToDisplay.data.map(([xIndex, yIndex, value], dataIndex) => { + const x = xScale(xDomain[xIndex]); + const y = yScale(yDomain[yIndex]); + const color = colorScale?.(value); + if (x === undefined || y === undefined || !color) { + return null; + } return ( - ); })} diff --git a/packages/x-charts/src/internals/index.ts b/packages/x-charts/src/internals/index.ts index 6e6bafd231d47..653283d4fff3c 100644 --- a/packages/x-charts/src/internals/index.ts +++ b/packages/x-charts/src/internals/index.ts @@ -7,6 +7,7 @@ export * from '../ResponsiveChartContainer/ResizableContainer'; // hooks export { useReducedMotion } from '../hooks/useReducedMotion'; export { useSeries } from '../hooks/useSeries'; +export { useInteractionItemProps } from '../hooks/useInteractionItemProps'; // utils export * from './defaultizeValueFormatter'; From 655d4e2d342379a5460596e38e01034a197b6747 Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 14 Jun 2024 11:28:14 +0200 Subject: [PATCH 16/31] Modify url from "heat-map" to "heatmap" for consistency --- docs/data/charts/{heat-map => heatmap}/BasicHeatmap.js | 0 docs/data/charts/{heat-map => heatmap}/BasicHeatmap.tsx | 0 docs/data/charts/{heat-map/heat-map.md => heatmap/heatmap.md} | 0 docs/data/pages.ts | 2 +- docs/pages/x/react-charts/{heat-map.js => heatmap.js} | 2 +- docs/public/_redirects | 1 + docs/src/modules/components/ChartComponentsGrid.js | 2 +- 7 files changed, 4 insertions(+), 3 deletions(-) rename docs/data/charts/{heat-map => heatmap}/BasicHeatmap.js (100%) rename docs/data/charts/{heat-map => heatmap}/BasicHeatmap.tsx (100%) rename docs/data/charts/{heat-map/heat-map.md => heatmap/heatmap.md} (100%) rename docs/pages/x/react-charts/{heat-map.js => heatmap.js} (68%) diff --git a/docs/data/charts/heat-map/BasicHeatmap.js b/docs/data/charts/heatmap/BasicHeatmap.js similarity index 100% rename from docs/data/charts/heat-map/BasicHeatmap.js rename to docs/data/charts/heatmap/BasicHeatmap.js diff --git a/docs/data/charts/heat-map/BasicHeatmap.tsx b/docs/data/charts/heatmap/BasicHeatmap.tsx similarity index 100% rename from docs/data/charts/heat-map/BasicHeatmap.tsx rename to docs/data/charts/heatmap/BasicHeatmap.tsx diff --git a/docs/data/charts/heat-map/heat-map.md b/docs/data/charts/heatmap/heatmap.md similarity index 100% rename from docs/data/charts/heat-map/heat-map.md rename to docs/data/charts/heatmap/heatmap.md diff --git a/docs/data/pages.ts b/docs/data/pages.ts index b9b9e91b240e9..c0ea851c91fdc 100644 --- a/docs/data/pages.ts +++ b/docs/data/pages.ts @@ -462,7 +462,7 @@ const pages: MuiPage[] = [ { pathname: '/x/react-charts/radar', planned: true }, { pathname: '/x/react-charts/tree-map', title: 'Treemap', planned: true }, { - pathname: '/x/react-charts/heat-map', + pathname: '/x/react-charts/heatmap', title: 'Heatmap', plan: 'pro', planned: true, diff --git a/docs/pages/x/react-charts/heat-map.js b/docs/pages/x/react-charts/heatmap.js similarity index 68% rename from docs/pages/x/react-charts/heat-map.js rename to docs/pages/x/react-charts/heatmap.js index 1ca391b5fe221..64f12f23f6eaa 100644 --- a/docs/pages/x/react-charts/heat-map.js +++ b/docs/pages/x/react-charts/heatmap.js @@ -1,6 +1,6 @@ import * as React from 'react'; import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; -import * as pageProps from 'docsx/data/charts/heat-map/heat-map.md?muiMarkdown'; +import * as pageProps from 'docsx/data/charts/heatmap/heatmap.md?muiMarkdown'; export default function Page() { return ; diff --git a/docs/public/_redirects b/docs/public/_redirects index e2f314a49a5bc..e91623d735379 100644 --- a/docs/public/_redirects +++ b/docs/public/_redirects @@ -59,5 +59,6 @@ /x/react-date-pickers/calendar/ /x/react-date-pickers/date-calendar/ 301 /x/react-date-pickers/legacy-date-time-picker/ /x/react-date-pickers/date-time-picker/ 301 # 2024 +/x/react-charts/heat-map/ /x/react-charts/heatmap/ 301 # Proxies diff --git a/docs/src/modules/components/ChartComponentsGrid.js b/docs/src/modules/components/ChartComponentsGrid.js index c981309f64ca7..50968e765682b 100644 --- a/docs/src/modules/components/ChartComponentsGrid.js +++ b/docs/src/modules/components/ChartComponentsGrid.js @@ -64,7 +64,7 @@ function getComponents() { title: 'Heatmap', srcLight: '/static/x/component-illustrations/heatmap-light.png', srcDark: '/static/x/component-illustrations/heatmap-dark.png', - href: '/x/react-charts/heat-map/', + href: '/x/react-charts/heatmap/', planned: true, pro: true, }, From 97b2317f8847d16db093c6dbecc9942f739bb4e0 Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 14 Jun 2024 15:00:24 +0200 Subject: [PATCH 17/31] WIP tooltip --- .../src/Heatmap/DefaultHeatmapTooltip.tsx | 67 +++++++++++++++++++ packages/x-charts-pro/src/Heatmap/Heatmap.tsx | 25 ++++--- packages/x-charts-pro/src/Heatmap/index.ts | 1 + .../ChartsItemTooltipContent.tsx | 14 ++-- .../src/ChartsTooltip/ChartsTooltip.tsx | 24 ++++--- .../src/ChartsTooltip/ChartsTooltipTable.ts | 15 +++++ packages/x-charts/src/ChartsTooltip/index.ts | 2 + packages/x-charts/src/hooks/index.ts | 1 + packages/x-charts/src/hooks/useAxis.ts | 18 +++++ packages/x-charts/src/hooks/useScale.ts | 15 ++--- packages/x-charts/src/internals/index.ts | 1 + scripts/x-charts.exports.json | 7 ++ 12 files changed, 154 insertions(+), 36 deletions(-) create mode 100644 packages/x-charts-pro/src/Heatmap/DefaultHeatmapTooltip.tsx create mode 100644 packages/x-charts/src/hooks/useAxis.ts diff --git a/packages/x-charts-pro/src/Heatmap/DefaultHeatmapTooltip.tsx b/packages/x-charts-pro/src/Heatmap/DefaultHeatmapTooltip.tsx new file mode 100644 index 0000000000000..084ded296a671 --- /dev/null +++ b/packages/x-charts-pro/src/Heatmap/DefaultHeatmapTooltip.tsx @@ -0,0 +1,67 @@ +import * as React from 'react'; +import clsx from 'clsx'; +import { + ChartsItemContentProps, + ChartsTooltipPaper, + ChartsTooltipTable, + ChartsTooltipRow, + ChartsTooltipCell, + ChartsTooltipMark, +} from '@mui/x-charts/ChartsTooltip'; +import { useXAxis, useYAxis } from '@mui/x-charts/hooks'; +import { getLabel } from '@mui/x-charts/internals'; + +/** + * @ignore - do not document. + */ +export function DefaultHeatmapTooltip(props: ChartsItemContentProps<'heatmap'>) { + const { series, itemData, sx, classes, getColor } = props; + + const xAxis = useXAxis(); + const yAxis = useYAxis(); + + if (itemData.dataIndex === undefined || !series.data[itemData.dataIndex]) { + return null; + } + + const color = getColor(itemData.dataIndex); + + const valueItem = series.data[itemData.dataIndex]; + const [xIndex, yIndex] = valueItem; + + const formattedX = + xAxis.valueFormatter?.(xAxis.data![xIndex], { location: 'tooltip' }) ?? + xAxis.data![xIndex].toLocaleString(); + const formattedY = + yAxis.valueFormatter?.(yAxis.data![yIndex], { location: 'tooltip' }) ?? + yAxis.data![yIndex].toLocaleString(); + const formattedValue = series.valueFormatter(valueItem, { dataIndex: itemData.dataIndex }); + + const seriesLabel = getLabel(series.label, 'tooltip'); + + return ( + + + + + {formattedX} + {formattedY} + + + + + + + + + {seriesLabel} + + + {formattedValue} + + + + + + ); +} diff --git a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx index 98bea885dbf99..1bda6b8653098 100644 --- a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx +++ b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx @@ -33,11 +33,15 @@ import { import { HeatmapSeriesType } from '../models/seriesType/heatmap'; import { HeatmapPlot } from './HeatmapPlot'; import { plugin as heatmapPlugin } from './plugin'; +import { DefaultHeatmapTooltip } from './DefaultHeatmapTooltip'; -export interface HeatmapSlots extends ChartsAxisSlots, ChartsTooltipSlots, ChartsOverlaySlots {} +export interface HeatmapSlots + extends ChartsAxisSlots, + Omit, 'axisContent'>, + ChartsOverlaySlots {} export interface HeatmapSlotProps extends ChartsAxisSlotProps, - ChartsTooltipSlotProps, + Omit, ChartsOverlaySlotProps {} export interface HeatmapProps @@ -66,7 +70,7 @@ export interface HeatmapProps * The configuration of the tooltip. * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. */ - tooltip?: ChartsTooltipProps; + tooltip?: ChartsTooltipProps<'heatmap'>; /** * Overridable component slots. * @default {} @@ -150,12 +154,7 @@ export const Heatmap = React.forwardRef(function Heatmap(props: HeatmapProps, re colors={colors} dataset={dataset} sx={sx} - disableAxisListener={ - // tooltip?.trigger !== 'axis' && - // axisHighlight?.x === 'none' && - // axisHighlight?.y === 'none' && - !onAxisClick - } + disableAxisListener highlightedItem={highlightedItem} onHighlightChange={onHighlightChange} > @@ -173,7 +172,13 @@ export const Heatmap = React.forwardRef(function Heatmap(props: HeatmapProps, re slotProps={slotProps} /> - {!loading && } + {!loading && ( + + )} {children} diff --git a/packages/x-charts-pro/src/Heatmap/index.ts b/packages/x-charts-pro/src/Heatmap/index.ts index 4e0867c2ddf7e..a69d106f47551 100644 --- a/packages/x-charts-pro/src/Heatmap/index.ts +++ b/packages/x-charts-pro/src/Heatmap/index.ts @@ -1,2 +1,3 @@ export { Heatmap as UnstableHeatmap } from './Heatmap'; export { HeatmapPlot as UnstableHeatmapPlot } from './HeatmapPlot'; +export * from './DefaultHeatmapTooltip'; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx index ea0951a2d1a49..4a9a6a4f3abe7 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx @@ -11,7 +11,7 @@ import { ZAxisContext } from '../context/ZAxisContextProvider'; import { useColorProcessor } from '../hooks/useColor'; import { useSeries } from '../hooks/useSeries'; -export type ChartsItemContentProps = { +export interface ChartsItemContentProps { /** * The data used to identify the triggered item. */ @@ -31,15 +31,19 @@ export type ChartsItemContentProps */ getColor: (dataIndex: number) => string; sx?: SxProps; -}; +} -function ChartsItemTooltipContent(props: { +interface ChartsItemTooltipContentProps { itemData: ItemInteractionData; content?: React.ElementType>; contentProps?: Partial>; sx?: SxProps; - classes: ChartsItemContentProps['classes']; -}) { + classes: ChartsItemContentProps['classes']; +} + +function ChartsItemTooltipContent( + props: ChartsItemTooltipContentProps, +) { const { content, itemData, sx, classes, contentProps } = props; const series = useSeries()[itemData.type]!.series[itemData.seriesId] as ChartSeriesDefaultized; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx index 1b321df5522d2..0fdf829f48a89 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx @@ -28,7 +28,7 @@ export type PopperProps = BasePopperProps & { sx?: SxProps; }; -export interface ChartsTooltipSlots { +export interface ChartsTooltipSlots { /** * Custom component for the tooltip popper. * @default ChartsTooltipRoot @@ -43,16 +43,16 @@ export interface ChartsTooltipSlots { * Custom component for displaying tooltip content when triggered by item event. * @default DefaultChartsItemTooltipContent */ - itemContent?: React.ElementType; + itemContent?: React.ElementType>; } -export interface ChartsTooltipSlotProps { +export interface ChartsTooltipSlotProps { popper?: Partial; axisContent?: Partial; - itemContent?: Partial; + itemContent?: Partial>; } -export type ChartsTooltipProps = { +export type ChartsTooltipProps = { /** * Select the kind of tooltip to display * - 'item': Shows data about the item below the mouse. @@ -79,15 +79,17 @@ export type ChartsTooltipProps = { * Overridable component slots. * @default {} */ - slots?: ChartsTooltipSlots; + slots?: ChartsTooltipSlots; /** * The props used for each component slot. * @default {} */ - slotProps?: ChartsTooltipSlotProps; + slotProps?: ChartsTooltipSlotProps; }; -const useUtilityClasses = (ownerState: { classes: ChartsTooltipProps['classes'] }) => { +const useUtilityClasses = (ownerState: { + classes: ChartsTooltipProps['classes']; +}) => { const { classes } = ownerState; const slots = { @@ -122,7 +124,7 @@ const ChartsTooltipRoot = styled(Popper, { * * - [ChartsTooltip API](https://mui.com/x/api/charts/charts-tool-tip/) */ -function ChartsTooltip(props: ChartsTooltipProps) { +function ChartsTooltip(props: ChartsTooltipProps) { const themeProps = useThemeProps({ props, name: 'MuiChartsTooltip', @@ -162,9 +164,9 @@ function ChartsTooltip(props: ChartsTooltipProps) { {trigger === 'item' ? ( } + itemData={displayedData as ItemInteractionData} content={slots?.itemContent ?? itemContent} - contentProps={slotProps?.itemContent} + contentProps={slotProps?.itemContent as Partial>} sx={{ mx: 2 }} classes={classes} /> diff --git a/packages/x-charts/src/ChartsTooltip/ChartsTooltipTable.ts b/packages/x-charts/src/ChartsTooltip/ChartsTooltipTable.ts index 1e1073914c63f..a83a70ae9e5be 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsTooltipTable.ts +++ b/packages/x-charts/src/ChartsTooltip/ChartsTooltipTable.ts @@ -2,6 +2,9 @@ import { styled } from '@mui/material/styles'; import { shouldForwardProp } from '@mui/system'; import { chartsTooltipClasses } from './chartsTooltipClasses'; +/** + * @ignore - internal component. + */ export const ChartsTooltipPaper = styled('div', { name: 'MuiChartsTooltip', slot: 'Container', @@ -13,6 +16,9 @@ export const ChartsTooltipPaper = styled('div', { borderRadius: theme.shape.borderRadius, })); +/** + * @ignore - internal component. + */ export const ChartsTooltipTable = styled('table', { name: 'MuiChartsTooltip', slot: 'Table', @@ -23,6 +29,9 @@ export const ChartsTooltipTable = styled('table', { }, })); +/** + * @ignore - internal component. + */ export const ChartsTooltipRow = styled('tr', { name: 'MuiChartsTooltip', slot: 'Row', @@ -35,6 +44,9 @@ export const ChartsTooltipRow = styled('tr', { }, })); +/** + * @ignore - internal component. + */ export const ChartsTooltipCell = styled('td', { name: 'MuiChartsTooltip', slot: 'Cell', @@ -56,6 +68,9 @@ export const ChartsTooltipCell = styled('td', { }, })); +/** + * @ignore - internal component. + */ export const ChartsTooltipMark = styled('div', { name: 'MuiChartsTooltip', slot: 'Mark', diff --git a/packages/x-charts/src/ChartsTooltip/index.ts b/packages/x-charts/src/ChartsTooltip/index.ts index f1ec9209697d0..dc13976d1d750 100644 --- a/packages/x-charts/src/ChartsTooltip/index.ts +++ b/packages/x-charts/src/ChartsTooltip/index.ts @@ -6,3 +6,5 @@ export * from './ChartsItemTooltipContent'; export * from './DefaultChartsAxisTooltipContent'; export * from './DefaultChartsItemTooltipContent'; + +export * from './ChartsTooltipTable'; diff --git a/packages/x-charts/src/hooks/index.ts b/packages/x-charts/src/hooks/index.ts index 148bf66d030b1..7f6e5dcdbdafe 100644 --- a/packages/x-charts/src/hooks/index.ts +++ b/packages/x-charts/src/hooks/index.ts @@ -1,6 +1,7 @@ export * from './useDrawingArea'; export * from './useChartId'; export * from './useScale'; +export * from './useAxis'; export * from './useColorScale'; export * from './useSvgRef'; export { diff --git a/packages/x-charts/src/hooks/useAxis.ts b/packages/x-charts/src/hooks/useAxis.ts new file mode 100644 index 0000000000000..2e095a131bd6b --- /dev/null +++ b/packages/x-charts/src/hooks/useAxis.ts @@ -0,0 +1,18 @@ +import * as React from 'react'; +import { CartesianContext } from '../context/CartesianContextProvider'; + +export function useXAxis(identifier?: number | string) { + const { xAxis, xAxisIds } = React.useContext(CartesianContext); + + const id = typeof identifier === 'string' ? identifier : xAxisIds[identifier ?? 0]; + + return xAxis[id]; +} + +export function useYAxis(identifier?: number | string) { + const { yAxis, yAxisIds } = React.useContext(CartesianContext); + + const id = typeof identifier === 'string' ? identifier : yAxisIds[identifier ?? 0]; + + return yAxis[id]; +} diff --git a/packages/x-charts/src/hooks/useScale.ts b/packages/x-charts/src/hooks/useScale.ts index 648249f21c75e..ccb01cbf20db6 100644 --- a/packages/x-charts/src/hooks/useScale.ts +++ b/packages/x-charts/src/hooks/useScale.ts @@ -1,7 +1,6 @@ -import * as React from 'react'; -import { CartesianContext } from '../context/CartesianContextProvider'; import { isBandScale } from '../internals/isBandScale'; import { AxisScaleConfig, D3Scale, ScaleName } from '../models/axis'; +import { useXAxis, useYAxis } from './useAxis'; /** * For a given scale return a function that map value to their position. @@ -19,19 +18,15 @@ export function getValueToPositionMapper(scale: D3Scale) { export function useXScale( identifier?: number | string, ): AxisScaleConfig[S]['scale'] { - const { xAxis, xAxisIds } = React.useContext(CartesianContext); + const axis = useXAxis(identifier); - const id = typeof identifier === 'string' ? identifier : xAxisIds[identifier ?? 0]; - - return xAxis[id].scale; + return axis.scale; } export function useYScale( identifier?: number | string, ): AxisScaleConfig[S]['scale'] { - const { yAxis, yAxisIds } = React.useContext(CartesianContext); - - const id = typeof identifier === 'string' ? identifier : yAxisIds[identifier ?? 0]; + const axis = useYAxis(identifier); - return yAxis[id].scale; + return axis.scale; } diff --git a/packages/x-charts/src/internals/index.ts b/packages/x-charts/src/internals/index.ts index 653283d4fff3c..95681c174ccec 100644 --- a/packages/x-charts/src/internals/index.ts +++ b/packages/x-charts/src/internals/index.ts @@ -12,6 +12,7 @@ export { useInteractionItemProps } from '../hooks/useInteractionItemProps'; // utils export * from './defaultizeValueFormatter'; export * from './configInit'; +export * from './getLabel'; // contexts diff --git a/scripts/x-charts.exports.json b/scripts/x-charts.exports.json index 4863552e605e8..130ba9b6914a8 100644 --- a/scripts/x-charts.exports.json +++ b/scripts/x-charts.exports.json @@ -102,12 +102,17 @@ { "name": "ChartsTextProps", "kind": "Interface" }, { "name": "ChartsTextStyle", "kind": "Interface" }, { "name": "ChartsTooltip", "kind": "Function" }, + { "name": "ChartsTooltipCell", "kind": "Variable" }, { "name": "chartsTooltipClasses", "kind": "Variable" }, { "name": "ChartsTooltipClasses", "kind": "Interface" }, { "name": "ChartsTooltipClassKey", "kind": "TypeAlias" }, + { "name": "ChartsTooltipMark", "kind": "Variable" }, + { "name": "ChartsTooltipPaper", "kind": "Variable" }, { "name": "ChartsTooltipProps", "kind": "TypeAlias" }, + { "name": "ChartsTooltipRow", "kind": "Variable" }, { "name": "ChartsTooltipSlotProps", "kind": "Interface" }, { "name": "ChartsTooltipSlots", "kind": "Interface" }, + { "name": "ChartsTooltipTable", "kind": "Variable" }, { "name": "ChartsVoronoiHandler", "kind": "Function" }, { "name": "ChartsVoronoiHandlerProps", "kind": "TypeAlias" }, { "name": "ChartsXAxis", "kind": "Function" }, @@ -287,8 +292,10 @@ { "name": "useHighlighted", "kind": "Function" }, { "name": "useItemHighlighted", "kind": "Function" }, { "name": "useSvgRef", "kind": "Function" }, + { "name": "useXAxis", "kind": "Function" }, { "name": "useXColorScale", "kind": "Function" }, { "name": "useXScale", "kind": "Function" }, + { "name": "useYAxis", "kind": "Function" }, { "name": "useYColorScale", "kind": "Function" }, { "name": "useYScale", "kind": "Function" }, { "name": "useZColorScale", "kind": "Function" }, From 36ece8527f091d7cca00209132cd9df401ec193e Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 14 Jun 2024 16:22:09 +0200 Subject: [PATCH 18/31] Fix TS --- packages/x-charts-pro/src/Heatmap/Heatmap.tsx | 3 ++- packages/x-charts/src/BarChart/BarChart.tsx | 6 +++--- .../src/ChartsTooltip/ChartsItemTooltipContent.tsx | 6 +++--- .../x-charts/src/ChartsTooltip/ChartsTooltip.tsx | 12 ++++++------ packages/x-charts/src/LineChart/LineChart.tsx | 6 +++--- packages/x-charts/src/PieChart/PieChart.tsx | 6 +++--- packages/x-charts/src/ScatterChart/ScatterChart.tsx | 6 +++--- .../x-charts/src/SparkLineChart/SparkLineChart.tsx | 6 +++--- packages/x-charts/src/themeAugmentation/props.d.ts | 4 +++- 9 files changed, 29 insertions(+), 26 deletions(-) diff --git a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx index 1bda6b8653098..14431b9e1e5e8 100644 --- a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx +++ b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx @@ -41,7 +41,7 @@ export interface HeatmapSlots ChartsOverlaySlots {} export interface HeatmapSlotProps extends ChartsAxisSlotProps, - Omit, + Omit, 'axisContent'>, ChartsOverlaySlotProps {} export interface HeatmapProps @@ -175,6 +175,7 @@ export const Heatmap = React.forwardRef(function Heatmap(props: HeatmapProps, re {!loading && ( diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index b36d1fdaac1ae..ced200758e9d9 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -41,13 +41,13 @@ export interface BarChartSlots extends ChartsAxisSlots, BarPlotSlots, ChartsLegendSlots, - ChartsTooltipSlots, + ChartsTooltipSlots<'bar'>, ChartsOverlaySlots {} export interface BarChartSlotProps extends ChartsAxisSlotProps, BarPlotSlotProps, ChartsLegendSlotProps, - ChartsTooltipSlotProps, + ChartsTooltipSlotProps<'bar'>, ChartsOverlaySlotProps {} export interface BarChartProps @@ -65,7 +65,7 @@ export interface BarChartProps * The configuration of the tooltip. * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. */ - tooltip?: ChartsTooltipProps; + tooltip?: ChartsTooltipProps<'bar'>; /** * Option to display a cartesian grid in the background. */ diff --git a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx index 4a9a6a4f3abe7..e758a1cce4419 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx @@ -11,7 +11,7 @@ import { ZAxisContext } from '../context/ZAxisContextProvider'; import { useColorProcessor } from '../hooks/useColor'; import { useSeries } from '../hooks/useSeries'; -export interface ChartsItemContentProps { +export interface ChartsItemContentProps { /** * The data used to identify the triggered item. */ @@ -33,12 +33,12 @@ export interface ChartsItemContentProps; } -interface ChartsItemTooltipContentProps { +export interface ChartsItemTooltipContentProps { itemData: ItemInteractionData; content?: React.ElementType>; contentProps?: Partial>; sx?: SxProps; - classes: ChartsItemContentProps['classes']; + classes: ChartsItemContentProps['classes']; } function ChartsItemTooltipContent( diff --git a/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx index 0fdf829f48a89..d2e218c25227f 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx @@ -28,7 +28,7 @@ export type PopperProps = BasePopperProps & { sx?: SxProps; }; -export interface ChartsTooltipSlots { +export interface ChartsTooltipSlots { /** * Custom component for the tooltip popper. * @default ChartsTooltipRoot @@ -46,13 +46,13 @@ export interface ChartsTooltipSlots itemContent?: React.ElementType>; } -export interface ChartsTooltipSlotProps { +export interface ChartsTooltipSlotProps { popper?: Partial; axisContent?: Partial; itemContent?: Partial>; } -export type ChartsTooltipProps = { +export interface ChartsTooltipProps { /** * Select the kind of tooltip to display * - 'item': Shows data about the item below the mouse. @@ -85,7 +85,7 @@ export type ChartsTooltipProps = { * @default {} */ slotProps?: ChartsTooltipSlotProps; -}; +} const useUtilityClasses = (ownerState: { classes: ChartsTooltipProps['classes']; @@ -124,7 +124,7 @@ const ChartsTooltipRoot = styled(Popper, { * * - [ChartsTooltip API](https://mui.com/x/api/charts/charts-tool-tip/) */ -function ChartsTooltip(props: ChartsTooltipProps) { +function ChartsTooltip(props: ChartsTooltipProps) { const themeProps = useThemeProps({ props, name: 'MuiChartsTooltip', @@ -165,7 +165,7 @@ function ChartsTooltip(props: Chart {trigger === 'item' ? ( } - content={slots?.itemContent ?? itemContent} + content={(slots?.itemContent ?? itemContent) as any} contentProps={slotProps?.itemContent as Partial>} sx={{ mx: 2 }} classes={classes} diff --git a/packages/x-charts/src/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index 33015b56d69ec..0240ef978cbee 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -51,7 +51,7 @@ export interface LineChartSlots MarkPlotSlots, LineHighlightPlotSlots, ChartsLegendSlots, - ChartsTooltipSlots, + ChartsTooltipSlots<'line'>, ChartsOverlaySlots {} export interface LineChartSlotProps extends ChartsAxisSlotProps, @@ -60,7 +60,7 @@ export interface LineChartSlotProps MarkPlotSlotProps, LineHighlightPlotSlotProps, ChartsLegendSlotProps, - ChartsTooltipSlotProps, + ChartsTooltipSlotProps<'line'>, ChartsOverlaySlotProps {} export interface LineChartProps @@ -78,7 +78,7 @@ export interface LineChartProps * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. * @default { trigger: 'item' } */ - tooltip?: ChartsTooltipProps; + tooltip?: ChartsTooltipProps<'line'>; /** * Option to display a cartesian grid in the background. */ diff --git a/packages/x-charts/src/PieChart/PieChart.tsx b/packages/x-charts/src/PieChart/PieChart.tsx index bf00ee9effaa3..856052afdc282 100644 --- a/packages/x-charts/src/PieChart/PieChart.tsx +++ b/packages/x-charts/src/PieChart/PieChart.tsx @@ -41,14 +41,14 @@ export interface PieChartSlots extends ChartsAxisSlots, PiePlotSlots, ChartsLegendSlots, - ChartsTooltipSlots, + ChartsTooltipSlots<'pie'>, ChartsOverlaySlots {} export interface PieChartSlotProps extends ChartsAxisSlotProps, PiePlotSlotProps, ChartsLegendSlotProps, - ChartsTooltipSlotProps, + ChartsTooltipSlotProps<'pie'>, ChartsOverlaySlotProps {} export interface PieChartProps @@ -81,7 +81,7 @@ export interface PieChartProps * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. * @default { trigger: 'item' } */ - tooltip?: ChartsTooltipProps; + tooltip?: ChartsTooltipProps<'pie'>; /** * The configuration of axes highlight. * @see See {@link https://mui.com/x/react-charts/tooltip/#highlights highlight docs} for more details. diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index 7afb59255eb3d..fa9530b40a630 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -44,13 +44,13 @@ export interface ScatterChartSlots extends ChartsAxisSlots, ScatterPlotSlots, ChartsLegendSlots, - ChartsTooltipSlots, + ChartsTooltipSlots<'scatter'>, ChartsOverlaySlots {} export interface ScatterChartSlotProps extends ChartsAxisSlotProps, ScatterPlotSlotProps, ChartsLegendSlotProps, - ChartsTooltipSlotProps, + ChartsTooltipSlotProps<'scatter'>, ChartsOverlaySlotProps {} export interface ScatterChartProps @@ -69,7 +69,7 @@ export interface ScatterChartProps * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. * @default { trigger: 'item' } */ - tooltip?: ChartsTooltipProps; + tooltip?: ChartsTooltipProps<'scatter'>; /** * The configuration of axes highlight. * @see See {@link https://mui.com/x/react-charts/tooltip/#highlights highlight docs} for more details. diff --git a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx index 028db19f4acf1..d46ac24e85bd2 100644 --- a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx +++ b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx @@ -30,14 +30,14 @@ export interface SparkLineChartSlots MarkPlotSlots, LineHighlightPlotSlots, Omit, - ChartsTooltipSlots {} + ChartsTooltipSlots<'line' | 'bar'> {} export interface SparkLineChartSlotProps extends AreaPlotSlotProps, LinePlotSlotProps, MarkPlotSlotProps, LineHighlightPlotSlotProps, BarPlotSlotProps, - ChartsTooltipSlotProps {} + ChartsTooltipSlotProps<'line' | 'bar'> {} export interface SparkLineChartProps extends Omit< @@ -54,7 +54,7 @@ export interface SparkLineChartProps * Notice it is a single [[AxisConfig]] object, not an array of configuration. */ yAxis?: MakeOptional, 'id'>; - tooltip?: ChartsTooltipProps; + tooltip?: ChartsTooltipProps<'line' | 'bar'>; axisHighlight?: ChartsAxisHighlightProps; /** * Type of plot used. diff --git a/packages/x-charts/src/themeAugmentation/props.d.ts b/packages/x-charts/src/themeAugmentation/props.d.ts index 0189a5b19e679..76ef6581f1c81 100644 --- a/packages/x-charts/src/themeAugmentation/props.d.ts +++ b/packages/x-charts/src/themeAugmentation/props.d.ts @@ -13,6 +13,8 @@ import { LineChartProps } from '../LineChart/LineChart'; import { ScatterProps } from '../ScatterChart/Scatter'; import { ScatterChartProps } from '../ScatterChart/ScatterChart'; import { ChartsXAxisProps, ChartsYAxisProps } from '../models/axis'; +import { ChartSeriesType } from '../models/seriesType/config'; + export interface ChartsComponentsPropsList { MuiChartsAxis: ChartsAxisProps; @@ -22,7 +24,7 @@ export interface ChartsComponentsPropsList { MuiChartsClipPath: ChartsClipPathProps; MuiChartsGrid: ChartsGridProps; MuiChartsLegend: ChartsLegendProps; - MuiChartsTooltip: ChartsTooltipProps; + MuiChartsTooltip: ChartsTooltipProps; MuiChartsSurface: ChartsSurfaceProps; // BarChart components From fe501570334ac9c52786ba5ad85ea2b1ac327df5 Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 17 Jun 2024 15:12:28 +0200 Subject: [PATCH 19/31] move heatmap in the docs --- docs/data/pages.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/data/pages.ts b/docs/data/pages.ts index c0ea851c91fdc..202fe2245342a 100644 --- a/docs/data/pages.ts +++ b/docs/data/pages.ts @@ -423,6 +423,12 @@ const pages: MuiPage[] = [ title: 'Sparkline', }, { pathname: '/x/react-charts/gauge' }, + { + pathname: '/x/react-charts/heatmap', + title: 'Heatmap', + plan: 'pro', + unstable: true, + }, { pathname: '/x/react-charts/common-features', subheader: 'Common features', @@ -461,12 +467,6 @@ const pages: MuiPage[] = [ children: [ { pathname: '/x/react-charts/radar', planned: true }, { pathname: '/x/react-charts/tree-map', title: 'Treemap', planned: true }, - { - pathname: '/x/react-charts/heatmap', - title: 'Heatmap', - plan: 'pro', - planned: true, - }, { pathname: '/x/react-charts/funnel', plan: 'pro', planned: true }, { pathname: '/x/react-charts/sankey', plan: 'pro', planned: true }, { pathname: '/x/react-charts/gantt', plan: 'pro', planned: true }, From e6d4f8685180f52184b9f07e7640ca25cc2dc3b9 Mon Sep 17 00:00:00 2001 From: alexandre Date: Tue, 18 Jun 2024 11:02:17 +0200 Subject: [PATCH 20/31] docs --- docs/data/charts/heatmap/BasicHeatmap.js | 98 +++++--------- docs/data/charts/heatmap/BasicHeatmap.tsx | 99 +++++--------- .../charts/heatmap/BasicHeatmap.tsx.preview | 7 + docs/data/charts/heatmap/ColorConfig.js | 123 +++++++++++++++++ docs/data/charts/heatmap/ColorConfig.tsx | 126 ++++++++++++++++++ docs/data/charts/heatmap/HighlightHeatmap.js | 41 ++++++ docs/data/charts/heatmap/HighlightHeatmap.tsx | 42 ++++++ .../heatmap/HighlightHeatmap.tsx.preview | 7 + docs/data/charts/heatmap/heatmap.md | 45 ++++++- docs/package.json | 2 + .../src/Heatmap/DefaultHeatmapTooltip.tsx | 3 +- .../x-charts-pro/src/Heatmap/HeatmapItem.tsx | 1 + packages/x-charts-pro/src/models/index.ts | 1 + .../src/models/seriesType/heatmap.ts | 1 - .../src/models/seriesType/index.ts | 1 + .../src/context/ZAxisContextProvider.tsx | 6 +- packages/x-charts/src/models/z-axis.ts | 8 ++ .../x-charts/src/themeAugmentation/props.d.ts | 1 - pnpm-lock.yaml | 20 +++ 19 files changed, 494 insertions(+), 138 deletions(-) create mode 100644 docs/data/charts/heatmap/BasicHeatmap.tsx.preview create mode 100644 docs/data/charts/heatmap/ColorConfig.js create mode 100644 docs/data/charts/heatmap/ColorConfig.tsx create mode 100644 docs/data/charts/heatmap/HighlightHeatmap.js create mode 100644 docs/data/charts/heatmap/HighlightHeatmap.tsx create mode 100644 docs/data/charts/heatmap/HighlightHeatmap.tsx.preview create mode 100644 packages/x-charts-pro/src/models/index.ts create mode 100644 packages/x-charts-pro/src/models/seriesType/index.ts diff --git a/docs/data/charts/heatmap/BasicHeatmap.js b/docs/data/charts/heatmap/BasicHeatmap.js index 18924be4b49cb..2f334d1aa000c 100644 --- a/docs/data/charts/heatmap/BasicHeatmap.js +++ b/docs/data/charts/heatmap/BasicHeatmap.js @@ -1,73 +1,41 @@ import * as React from 'react'; +import Box from '@mui/material/Box'; import '@mui/x-charts-pro/typeOverloads'; import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; +const data = [ + [0, 0, 1], + [0, 1, 2], + [0, 2, 4], + [0, 3, 5], + [0, 4, 2], + [1, 0, 3], + [1, 1, 5], + [1, 2, 1], + [1, 3, 2], + [1, 4, 4], + [2, 0, 5], + [2, 1, 2], + [2, 2, 3], + [2, 3, 1], + [2, 4, 2], + [3, 0, 4], + [3, 1, 5], + [3, 2, 2], + [3, 3, 3], + [3, 4, 5], +]; + export default function BasicHeatmap() { return ( - + + + ); } diff --git a/docs/data/charts/heatmap/BasicHeatmap.tsx b/docs/data/charts/heatmap/BasicHeatmap.tsx index 18924be4b49cb..851d318b1989e 100644 --- a/docs/data/charts/heatmap/BasicHeatmap.tsx +++ b/docs/data/charts/heatmap/BasicHeatmap.tsx @@ -1,73 +1,42 @@ import * as React from 'react'; +import Box from '@mui/material/Box'; import '@mui/x-charts-pro/typeOverloads'; import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; +import { HeatmapValueType } from '@mui/x-charts-pro/models'; + +const data: HeatmapValueType[] = [ + [0, 0, 1], + [0, 1, 2], + [0, 2, 4], + [0, 3, 5], + [0, 4, 2], + [1, 0, 3], + [1, 1, 5], + [1, 2, 1], + [1, 3, 2], + [1, 4, 4], + [2, 0, 5], + [2, 1, 2], + [2, 2, 3], + [2, 3, 1], + [2, 4, 2], + [3, 0, 4], + [3, 1, 5], + [3, 2, 2], + [3, 3, 3], + [3, 4, 5], +]; export default function BasicHeatmap() { return ( - + + + ); } diff --git a/docs/data/charts/heatmap/BasicHeatmap.tsx.preview b/docs/data/charts/heatmap/BasicHeatmap.tsx.preview new file mode 100644 index 0000000000000..bfe0e2212184a --- /dev/null +++ b/docs/data/charts/heatmap/BasicHeatmap.tsx.preview @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/docs/data/charts/heatmap/ColorConfig.js b/docs/data/charts/heatmap/ColorConfig.js new file mode 100644 index 0000000000000..f99083ed87650 --- /dev/null +++ b/docs/data/charts/heatmap/ColorConfig.js @@ -0,0 +1,123 @@ +import * as React from 'react'; +import { interpolateBlues } from 'd3-scale-chromatic'; +import '@mui/x-charts-pro/typeOverloads'; +import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; + +const dataset = [ + { + london: 59, + paris: 57, + newYork: 86, + seoul: 21, + month: 'January', + }, + { + london: 50, + paris: 52, + newYork: 78, + seoul: 28, + month: 'February', + }, + { + london: 47, + paris: 53, + newYork: 106, + seoul: 41, + month: 'March', + }, + { + london: 54, + paris: 56, + newYork: 92, + seoul: 73, + month: 'April', + }, + { + london: 57, + paris: 69, + newYork: 92, + seoul: 99, + month: 'May', + }, + { + london: 60, + paris: 63, + newYork: 103, + seoul: 144, + month: 'June', + }, + { + london: 59, + paris: 60, + newYork: 105, + seoul: 319, + month: 'July', + }, + { + london: 65, + paris: 60, + newYork: 106, + seoul: 249, + month: 'August', + }, + { + london: 51, + paris: 51, + newYork: 95, + seoul: 131, + month: 'September', + }, + { + london: 60, + paris: 65, + newYork: 97, + seoul: 55, + month: 'October', + }, + { + london: 67, + paris: 64, + newYork: 76, + seoul: 48, + month: 'November', + }, + { + london: 61, + paris: 70, + newYork: 103, + seoul: 25, + month: 'December', + }, +]; + +const data = dataset.flatMap(({ london, paris, newYork, seoul }, monthIndex) => [ + [0, monthIndex, london], + [1, monthIndex, paris], + [2, monthIndex, newYork], + [3, monthIndex, seoul], +]); + +const xData = ['London', 'Paris', 'NewYork', 'Seoul']; +const yData = dataset.flatMap(({ month }) => month); + +export default function ColorConfig() { + return ( + + ); +} diff --git a/docs/data/charts/heatmap/ColorConfig.tsx b/docs/data/charts/heatmap/ColorConfig.tsx new file mode 100644 index 0000000000000..88957b1db0abf --- /dev/null +++ b/docs/data/charts/heatmap/ColorConfig.tsx @@ -0,0 +1,126 @@ +import * as React from 'react'; +import { interpolateBlues } from 'd3-scale-chromatic'; +import '@mui/x-charts-pro/typeOverloads'; +import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; +import { HeatmapValueType } from '@mui/x-charts-pro/models'; + +const dataset = [ + { + london: 59, + paris: 57, + newYork: 86, + seoul: 21, + month: 'January', + }, + { + london: 50, + paris: 52, + newYork: 78, + seoul: 28, + month: 'February', + }, + { + london: 47, + paris: 53, + newYork: 106, + seoul: 41, + month: 'March', + }, + { + london: 54, + paris: 56, + newYork: 92, + seoul: 73, + month: 'April', + }, + { + london: 57, + paris: 69, + newYork: 92, + seoul: 99, + month: 'May', + }, + { + london: 60, + paris: 63, + newYork: 103, + seoul: 144, + month: 'June', + }, + { + london: 59, + paris: 60, + newYork: 105, + seoul: 319, + month: 'July', + }, + { + london: 65, + paris: 60, + newYork: 106, + seoul: 249, + month: 'August', + }, + { + london: 51, + paris: 51, + newYork: 95, + seoul: 131, + month: 'September', + }, + { + london: 60, + paris: 65, + newYork: 97, + seoul: 55, + month: 'October', + }, + { + london: 67, + paris: 64, + newYork: 76, + seoul: 48, + month: 'November', + }, + { + london: 61, + paris: 70, + newYork: 103, + seoul: 25, + month: 'December', + }, +]; + +const data = dataset.flatMap( + ({ london, paris, newYork, seoul }, monthIndex): HeatmapValueType[] => [ + [0, monthIndex, london], + [1, monthIndex, paris], + [2, monthIndex, newYork], + [3, monthIndex, seoul], + ], +); + +const xData = ['London', 'Paris', 'NewYork', 'Seoul']; +const yData = dataset.flatMap(({ month }) => month); + +export default function ColorConfig() { + return ( + + ); +} diff --git a/docs/data/charts/heatmap/HighlightHeatmap.js b/docs/data/charts/heatmap/HighlightHeatmap.js new file mode 100644 index 0000000000000..db7d1aad59483 --- /dev/null +++ b/docs/data/charts/heatmap/HighlightHeatmap.js @@ -0,0 +1,41 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import '@mui/x-charts-pro/typeOverloads'; +import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; + +const data = [ + [0, 0, 1], + [0, 1, 2], + [0, 2, 4], + [0, 3, 5], + [0, 4, 2], + [1, 0, 3], + [1, 1, 5], + [1, 2, 1], + [1, 3, 2], + [1, 4, 4], + [2, 0, 5], + [2, 1, 2], + [2, 2, 3], + [2, 3, 1], + [2, 4, 2], + [3, 0, 4], + [3, 1, 5], + [3, 2, 2], + [3, 3, 3], + [3, 4, 5], +]; + +export default function HighlightHeatmap() { + return ( + + + + ); +} diff --git a/docs/data/charts/heatmap/HighlightHeatmap.tsx b/docs/data/charts/heatmap/HighlightHeatmap.tsx new file mode 100644 index 0000000000000..67699dc7501e0 --- /dev/null +++ b/docs/data/charts/heatmap/HighlightHeatmap.tsx @@ -0,0 +1,42 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import '@mui/x-charts-pro/typeOverloads'; +import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; +import { HeatmapValueType } from '@mui/x-charts-pro/models'; + +const data: HeatmapValueType[] = [ + [0, 0, 1], + [0, 1, 2], + [0, 2, 4], + [0, 3, 5], + [0, 4, 2], + [1, 0, 3], + [1, 1, 5], + [1, 2, 1], + [1, 3, 2], + [1, 4, 4], + [2, 0, 5], + [2, 1, 2], + [2, 2, 3], + [2, 3, 1], + [2, 4, 2], + [3, 0, 4], + [3, 1, 5], + [3, 2, 2], + [3, 3, 3], + [3, 4, 5], +]; + +export default function HighlightHeatmap() { + return ( + + + + ); +} diff --git a/docs/data/charts/heatmap/HighlightHeatmap.tsx.preview b/docs/data/charts/heatmap/HighlightHeatmap.tsx.preview new file mode 100644 index 0000000000000..5d6588033cb77 --- /dev/null +++ b/docs/data/charts/heatmap/HighlightHeatmap.tsx.preview @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/docs/data/charts/heatmap/heatmap.md b/docs/data/charts/heatmap/heatmap.md index d81cc95e4ad4a..9fbef8bde815f 100644 --- a/docs/data/charts/heatmap/heatmap.md +++ b/docs/data/charts/heatmap/heatmap.md @@ -8,10 +8,47 @@ productId: x-charts

Heatmap charts allow to highlight correlation between categories.

:::warning -The Heatmap Chart component isn't available yet, but you can upvote [**this GitHub issue**](https://github.com/mui/mui-x/issues/7926) to see it arrive sooner. - -Don't hesitate to leave a comment there to influence what gets built. -Especially if you already have a use case for this component, or if you're facing a pain point with your current solution. +The Heatmap Chart component isn't stable. Don't hesitate to open issues to give feedback. ::: +## Basics + +The Heatmap requires two axes with `data` properties. +Those data defined the x and y categories. + +The series `data` is an array of 3-tuples. +The 2 first numbers are respectively the x and y indexes of the cell. +And the third is its value. + {{"demo": "BasicHeatmap.js"}} + +## Customization + +### Color mapping + +To customize the color mapping, use the `zAxis` configuration. +You can either use the piecewise or continuous [color mapping](https://mui.com/x/react-charts/styling/#values-color). + +{{"demo": "ColorConfig.js"}} + +### Highlight 🚧 + +Is this a disco dancefloor? πŸ•ΊπŸͺ© + +Planned work: + +- Add a way to override the styling. I woudl be in favor of adding a CSS classes instead of using styled component with ownerState, to let user apply filters on top of the current color, but they could not do crazy thing like complete color modification. They would need to use slots for that +- Adding an other highlight scopes: `x-axis`, `y-axis`, and `xy-axis` + +{{"demo": "HighlightHeatmap.js"}} + +### Axes + +The Heatmap axes can be customized like any other chart axis. +The available options are available in the [dedicated page](/x/react-charts/axis/#axis-customization). + +### Tooltip 🚧 + +## Legend 🚧 + +## Labels 🚧 diff --git a/docs/package.json b/docs/package.json index ee47da0c27e39..cc882be406cf7 100644 --- a/docs/package.json +++ b/docs/package.json @@ -62,6 +62,7 @@ "date-fns-jalali": "^2.30.0-0", "dayjs": "^1.11.11", "doctrine": "^3.0.0", + "d3-scale-chromatic": "^3.1.0", "exceljs": "^4.4.0", "fg-loadcss": "^3.1.0", "jscodeshift": "0.13.1", @@ -102,6 +103,7 @@ "@mui/internal-scripts": "^1.0.10", "@types/chance": "^1.1.6", "@types/d3-scale": "^4.0.8", + "@types/d3-scale-chromatic": "^3.0.3", "@types/doctrine": "^0.0.9", "@types/lodash": "^4.17.5", "@types/luxon": "^3.4.2", diff --git a/packages/x-charts-pro/src/Heatmap/DefaultHeatmapTooltip.tsx b/packages/x-charts-pro/src/Heatmap/DefaultHeatmapTooltip.tsx index 084ded296a671..7fc3974a8a8f1 100644 --- a/packages/x-charts-pro/src/Heatmap/DefaultHeatmapTooltip.tsx +++ b/packages/x-charts-pro/src/Heatmap/DefaultHeatmapTooltip.tsx @@ -45,7 +45,8 @@ export function DefaultHeatmapTooltip(props: ChartsItemContentProps<'heatmap'>) {formattedX} - {formattedY} + {formattedX && formattedY && } + {formattedY} diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx index 88aacf54ce746..53b3120dadc43 100644 --- a/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx +++ b/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx @@ -31,6 +31,7 @@ export function HeatmapItem(props: HeatmapItemProps) { {...getInteractionItemProps({ type: 'heatmap', seriesId, dataIndex })} style={{ filter: (isHighlighted && 'saturate(120%)') || (isFaded && 'saturate(80%)') || undefined, + shapeRendering: 'crispEdges', }} /> ); diff --git a/packages/x-charts-pro/src/models/index.ts b/packages/x-charts-pro/src/models/index.ts new file mode 100644 index 0000000000000..d06c5e1be13a0 --- /dev/null +++ b/packages/x-charts-pro/src/models/index.ts @@ -0,0 +1 @@ +export * from './seriesType'; diff --git a/packages/x-charts-pro/src/models/seriesType/heatmap.ts b/packages/x-charts-pro/src/models/seriesType/heatmap.ts index a43805d1fee87..9444f4af60a20 100644 --- a/packages/x-charts-pro/src/models/seriesType/heatmap.ts +++ b/packages/x-charts-pro/src/models/seriesType/heatmap.ts @@ -5,7 +5,6 @@ import { CartesianSeriesType, } from '@mui/x-charts/internals'; -// TODO: discuss if it's the best data format. export type HeatmapValueType = [number, number, number]; export interface HeatmapSeriesType diff --git a/packages/x-charts-pro/src/models/seriesType/index.ts b/packages/x-charts-pro/src/models/seriesType/index.ts new file mode 100644 index 0000000000000..8b355086c2087 --- /dev/null +++ b/packages/x-charts-pro/src/models/seriesType/index.ts @@ -0,0 +1 @@ +export * from './heatmap'; diff --git a/packages/x-charts/src/context/ZAxisContextProvider.tsx b/packages/x-charts/src/context/ZAxisContextProvider.tsx index fa24fd59a9793..cc0b15776e08e 100644 --- a/packages/x-charts/src/context/ZAxisContextProvider.tsx +++ b/packages/x-charts/src/context/ZAxisContextProvider.tsx @@ -69,7 +69,11 @@ function ZAxisContextProvider(props: ZAxisContextProviderProps) { axis.colorMap && (axis.colorMap.type === 'ordinal' && axis.data ? getOrdinalColorScale({ values: axis.data, ...axis.colorMap }) - : getColorScale(axis.colorMap)), + : getColorScale( + axis.colorMap.type === 'continuous' + ? { min: axis.min, max: axis.max, ...axis.colorMap } + : axis.colorMap, + )), }; }); diff --git a/packages/x-charts/src/models/z-axis.ts b/packages/x-charts/src/models/z-axis.ts index 0a493f5d8f680..1946220495347 100644 --- a/packages/x-charts/src/models/z-axis.ts +++ b/packages/x-charts/src/models/z-axis.ts @@ -8,6 +8,14 @@ export interface ZAxisConfig { * The key used to retrieve `data` from the `dataset` prop. */ dataKey?: string; + /** + * The minimal value of the scale. + */ + min?: number; + /** + * The maximal value of the scale. + */ + max?: number; colorMap?: OrdinalColorConfig | ContinuousColorConfig | PiecewiseColorConfig; } diff --git a/packages/x-charts/src/themeAugmentation/props.d.ts b/packages/x-charts/src/themeAugmentation/props.d.ts index 76ef6581f1c81..7dc62f3974005 100644 --- a/packages/x-charts/src/themeAugmentation/props.d.ts +++ b/packages/x-charts/src/themeAugmentation/props.d.ts @@ -15,7 +15,6 @@ import { ScatterChartProps } from '../ScatterChart/ScatterChart'; import { ChartsXAxisProps, ChartsYAxisProps } from '../models/axis'; import { ChartSeriesType } from '../models/seriesType/config'; - export interface ChartsComponentsPropsList { MuiChartsAxis: ChartsAxisProps; MuiChartsXAxis: ChartsXAxisProps; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b6a77e37e7372..1da6c4abad192 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -518,6 +518,9 @@ importers: cross-env: specifier: ^7.0.3 version: 7.0.3 + d3-scale-chromatic: + specifier: ^3.1.0 + version: 3.1.0 date-fns: specifier: ^2.30.0 version: 2.30.0 @@ -645,6 +648,9 @@ importers: '@types/d3-scale': specifier: ^4.0.8 version: 4.0.8 + '@types/d3-scale-chromatic': + specifier: ^3.0.3 + version: 3.0.3 '@types/doctrine': specifier: ^0.0.9 version: 0.0.9 @@ -3599,6 +3605,9 @@ packages: '@types/d3-path@3.1.0': resolution: {integrity: sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==} + '@types/d3-scale-chromatic@3.0.3': + resolution: {integrity: sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==} + '@types/d3-scale@4.0.8': resolution: {integrity: sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==} @@ -4987,6 +4996,10 @@ packages: resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} engines: {node: '>=12'} + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + d3-scale@4.0.2: resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} engines: {node: '>=12'} @@ -12476,6 +12489,8 @@ snapshots: '@types/d3-path@3.1.0': {} + '@types/d3-scale-chromatic@3.0.3': {} + '@types/d3-scale@4.0.8': dependencies: '@types/d3-time': 3.0.3 @@ -14130,6 +14145,11 @@ snapshots: d3-path@3.1.0: {} + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + d3-scale@4.0.2: dependencies: d3-array: 3.2.4 From 0bc6ff94715e7891101c2fe51914bedfca58eb22 Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 19 Jun 2024 11:32:04 +0200 Subject: [PATCH 21/31] fix proptypes --- docs/scripts/createXTypeScriptProjects.ts | 1 + docs/scripts/generateProptypes.ts | 24 +++++--- .../src/ChartContainer/ChartContainer.tsx | 2 + .../ChartsAxisTooltipContent.tsx | 58 +------------------ .../ChartsItemTooltipContent.tsx | 38 +----------- .../ResponsiveChartContainer.tsx | 2 + .../src/ScatterChart/ScatterChart.tsx | 2 + .../src/context/ZAxisContextProvider.tsx | 2 + 8 files changed, 31 insertions(+), 98 deletions(-) diff --git a/docs/scripts/createXTypeScriptProjects.ts b/docs/scripts/createXTypeScriptProjects.ts index 3b859b06427a3..8d339b2b97c21 100644 --- a/docs/scripts/createXTypeScriptProjects.ts +++ b/docs/scripts/createXTypeScriptProjects.ts @@ -37,6 +37,7 @@ export type XProjectNames = | 'x-date-pickers' | 'x-date-pickers-pro' | 'x-charts' + | 'x-charts-pro' | 'x-tree-view' | 'x-tree-view-pro'; diff --git a/docs/scripts/generateProptypes.ts b/docs/scripts/generateProptypes.ts index 5d7f3c8ec5537..c68602a94873f 100644 --- a/docs/scripts/generateProptypes.ts +++ b/docs/scripts/generateProptypes.ts @@ -10,6 +10,8 @@ import { import { fixBabelGeneratorIssues, fixLineEndings } from '@mui/internal-docs-utils'; import { createXTypeScriptProjects, XTypeScriptProject } from './createXTypeScriptProjects'; +const COMPONENTS_WITHOUT_PROPTYPES = ['ChartsAxisTooltipContent', 'ChartsItemTooltipContent']; + async function generateProptypes(project: XTypeScriptProject, sourceFile: string) { const isTDate = (name: string) => { if (['x-date-pickers', 'x-date-pickers-pro'].includes(project.name)) { @@ -176,14 +178,20 @@ async function run() { } const componentsWithPropTypes = project.getComponentsWithPropTypes(project); - return componentsWithPropTypes.map>(async (filename) => { - try { - await generateProptypes(project, filename); - } catch (error: any) { - error.message = `${filename}: ${error.message}`; - throw error; - } - }); + return componentsWithPropTypes + .filter((filename) => + COMPONENTS_WITHOUT_PROPTYPES.every( + (ignoredComponent) => !filename.includes(ignoredComponent), + ), + ) + .map>(async (filename) => { + try { + await generateProptypes(project, filename); + } catch (error: any) { + error.message = `${filename}: ${error.message}`; + throw error; + } + }); }); const results = await Promise.allSettled(promises); diff --git a/packages/x-charts/src/ChartContainer/ChartContainer.tsx b/packages/x-charts/src/ChartContainer/ChartContainer.tsx index 7ebdd67c0e32f..9026e292f5601 100644 --- a/packages/x-charts/src/ChartContainer/ChartContainer.tsx +++ b/packages/x-charts/src/ChartContainer/ChartContainer.tsx @@ -369,6 +369,8 @@ ChartContainer.propTypes = { data: PropTypes.array, dataKey: PropTypes.string, id: PropTypes.string, + max: PropTypes.number, + min: PropTypes.number, }), ), } as any; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx index 262bb36880297..8c34671584f9b 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import PropTypes from 'prop-types'; import { SxProps, Theme } from '@mui/material/styles'; import { useSlotProps } from '@mui/base/utils'; import { AxisInteractionData } from '../context/InteractionProvider'; @@ -45,6 +44,9 @@ export type ChartsAxisContentProps = { sx?: SxProps; }; +/** + * @ignore - internal component. + */ function ChartsAxisTooltipContent(props: { axisData: AxisInteractionData; content?: React.ElementType; @@ -128,58 +130,4 @@ function ChartsAxisTooltipContent(props: { return ; } -ChartsAxisTooltipContent.propTypes = { - // ----------------------------- Warning -------------------------------- - // | These PropTypes are generated from the TypeScript type definitions | - // | To update them edit the TypeScript types and run "pnpm proptypes" | - // ---------------------------------------------------------------------- - axisData: PropTypes.shape({ - x: PropTypes.shape({ - index: PropTypes.number, - value: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) - .isRequired, - }), - y: PropTypes.shape({ - index: PropTypes.number, - value: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) - .isRequired, - }), - }).isRequired, - classes: PropTypes.object.isRequired, - content: PropTypes.elementType, - contentProps: PropTypes.shape({ - axis: PropTypes.object, - axisData: PropTypes.shape({ - x: PropTypes.shape({ - index: PropTypes.number, - value: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) - .isRequired, - }), - y: PropTypes.shape({ - index: PropTypes.number, - value: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) - .isRequired, - }), - }), - axisValue: PropTypes.oneOfType([ - PropTypes.instanceOf(Date), - PropTypes.number, - PropTypes.string, - ]), - classes: PropTypes.object, - dataIndex: PropTypes.number, - series: PropTypes.arrayOf(PropTypes.object), - sx: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), - PropTypes.func, - PropTypes.object, - ]), - }), - sx: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), - PropTypes.func, - PropTypes.object, - ]), -} as any; - export { ChartsAxisTooltipContent }; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx index e758a1cce4419..8c2fa7c8e6bef 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import PropTypes from 'prop-types'; import { SxProps, Theme } from '@mui/material/styles'; import { useSlotProps } from '@mui/base/utils'; import { ItemInteractionData } from '../context/InteractionProvider'; @@ -41,6 +40,9 @@ export interface ChartsItemTooltipContentProps { classes: ChartsItemContentProps['classes']; } +/** + * @ignore - internal component. + */ function ChartsItemTooltipContent( props: ChartsItemTooltipContentProps, ) { @@ -80,38 +82,4 @@ function ChartsItemTooltipContent( return ; } -ChartsItemTooltipContent.propTypes = { - // ----------------------------- Warning -------------------------------- - // | These PropTypes are generated from the TypeScript type definitions | - // | To update them edit the TypeScript types and run "pnpm proptypes" | - // ---------------------------------------------------------------------- - classes: PropTypes.object.isRequired, - content: PropTypes.elementType, - contentProps: PropTypes.shape({ - classes: PropTypes.object, - getColor: PropTypes.func, - itemData: PropTypes.shape({ - dataIndex: PropTypes.number, - seriesId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, - type: PropTypes.oneOf(['bar', 'line', 'pie', 'scatter']).isRequired, - }), - series: PropTypes.object, - sx: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), - PropTypes.func, - PropTypes.object, - ]), - }), - itemData: PropTypes.shape({ - dataIndex: PropTypes.number, - seriesId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, - type: PropTypes.oneOf(['bar', 'line', 'pie', 'scatter']).isRequired, - }).isRequired, - sx: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), - PropTypes.func, - PropTypes.object, - ]), -} as any; - export { ChartsItemTooltipContent }; diff --git a/packages/x-charts/src/ResponsiveChartContainer/ResponsiveChartContainer.tsx b/packages/x-charts/src/ResponsiveChartContainer/ResponsiveChartContainer.tsx index d33fbcf1590e3..8ea518934c3b3 100644 --- a/packages/x-charts/src/ResponsiveChartContainer/ResponsiveChartContainer.tsx +++ b/packages/x-charts/src/ResponsiveChartContainer/ResponsiveChartContainer.tsx @@ -288,6 +288,8 @@ ResponsiveChartContainer.propTypes = { data: PropTypes.array, dataKey: PropTypes.string, id: PropTypes.string, + max: PropTypes.number, + min: PropTypes.number, }), ), } as any; diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index fa9530b40a630..f8d97cd20b9ab 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -542,6 +542,8 @@ ScatterChart.propTypes = { data: PropTypes.array, dataKey: PropTypes.string, id: PropTypes.string, + max: PropTypes.number, + min: PropTypes.number, }), ), } as any; diff --git a/packages/x-charts/src/context/ZAxisContextProvider.tsx b/packages/x-charts/src/context/ZAxisContextProvider.tsx index cc0b15776e08e..413dc0fad32f4 100644 --- a/packages/x-charts/src/context/ZAxisContextProvider.tsx +++ b/packages/x-charts/src/context/ZAxisContextProvider.tsx @@ -131,6 +131,8 @@ ZAxisContextProvider.propTypes = { data: PropTypes.array, dataKey: PropTypes.string, id: PropTypes.string, + max: PropTypes.number, + min: PropTypes.number, }), ), } as any; From 3e3b50245997196558e003435ff4ffd17290c7bd Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 19 Jun 2024 15:53:39 +0200 Subject: [PATCH 22/31] add slots and classes --- docs/data/charts-component-api-pages.ts | 8 -- docs/pages/x/api/charts/chart-container.json | 2 +- .../api/charts/charts-axis-tooltip-content.js | 23 ---- .../charts/charts-axis-tooltip-content.json | 63 ----------- .../api/charts/charts-item-tooltip-content.js | 23 ---- .../charts/charts-item-tooltip-content.json | 63 ----------- .../charts/responsive-chart-container.json | 2 +- docs/pages/x/api/charts/scatter-chart.json | 2 +- .../charts-axis-tooltip-content.json | 23 ---- .../charts-item-tooltip-content.json | 23 ---- packages/x-charts-pro/src/Heatmap/Heatmap.tsx | 9 +- .../x-charts-pro/src/Heatmap/HeatmapItem.tsx | 100 +++++++++++++++--- .../x-charts-pro/src/Heatmap/HeatmapPlot.tsx | 8 +- .../src/Heatmap/heatmapClasses.ts | 24 +++++ scripts/x-charts.exports.json | 5 +- 15 files changed, 126 insertions(+), 252 deletions(-) delete mode 100644 docs/pages/x/api/charts/charts-axis-tooltip-content.js delete mode 100644 docs/pages/x/api/charts/charts-axis-tooltip-content.json delete mode 100644 docs/pages/x/api/charts/charts-item-tooltip-content.js delete mode 100644 docs/pages/x/api/charts/charts-item-tooltip-content.json delete mode 100644 docs/translations/api-docs/charts/charts-axis-tooltip-content/charts-axis-tooltip-content.json delete mode 100644 docs/translations/api-docs/charts/charts-item-tooltip-content/charts-item-tooltip-content.json create mode 100644 packages/x-charts-pro/src/Heatmap/heatmapClasses.ts diff --git a/docs/data/charts-component-api-pages.ts b/docs/data/charts-component-api-pages.ts index 3a0d808b2d06b..c1ed7174bf0e2 100644 --- a/docs/data/charts-component-api-pages.ts +++ b/docs/data/charts-component-api-pages.ts @@ -45,10 +45,6 @@ const apiPages: MuiPage[] = [ pathname: '/x/api/charts/charts-axis-highlight', title: 'ChartsAxisHighlight', }, - { - pathname: '/x/api/charts/charts-axis-tooltip-content', - title: 'ChartsAxisTooltipContent', - }, { pathname: '/x/api/charts/charts-clip-path', title: 'ChartsClipPath', @@ -57,10 +53,6 @@ const apiPages: MuiPage[] = [ pathname: '/x/api/charts/charts-grid', title: 'ChartsGrid', }, - { - pathname: '/x/api/charts/charts-item-tooltip-content', - title: 'ChartsItemTooltipContent', - }, { pathname: '/x/api/charts/charts-legend', title: 'ChartsLegend', diff --git a/docs/pages/x/api/charts/chart-container.json b/docs/pages/x/api/charts/chart-container.json index b92a05628f0da..823f299ffea2b 100644 --- a/docs/pages/x/api/charts/chart-container.json +++ b/docs/pages/x/api/charts/chart-container.json @@ -48,7 +48,7 @@ "zAxis": { "type": { "name": "arrayOf", - "description": "Array<{ colorMap?: { colors: Array<string>, type: 'ordinal', unknownColor?: string, values?: Array<Date
| number
| string> }
| { color: Array<string>
| func, max?: Date
| number, min?: Date
| number, type: 'continuous' }
| { colors: Array<string>, thresholds: Array<Date
| number>, type: 'piecewise' }, data?: array, dataKey?: string, id?: string }>" + "description": "Array<{ colorMap?: { colors: Array<string>, type: 'ordinal', unknownColor?: string, values?: Array<Date
| number
| string> }
| { color: Array<string>
| func, max?: Date
| number, min?: Date
| number, type: 'continuous' }
| { colors: Array<string>, thresholds: Array<Date
| number>, type: 'piecewise' }, data?: array, dataKey?: string, id?: string, max?: number, min?: number }>" } } }, diff --git a/docs/pages/x/api/charts/charts-axis-tooltip-content.js b/docs/pages/x/api/charts/charts-axis-tooltip-content.js deleted file mode 100644 index 9dc6feb6568cf..0000000000000 --- a/docs/pages/x/api/charts/charts-axis-tooltip-content.js +++ /dev/null @@ -1,23 +0,0 @@ -import * as React from 'react'; -import ApiPage from 'docs/src/modules/components/ApiPage'; -import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; -import jsonPageContent from './charts-axis-tooltip-content.json'; - -export default function Page(props) { - const { descriptions, pageContent } = props; - return ; -} - -Page.getInitialProps = () => { - const req = require.context( - 'docsx/translations/api-docs/charts/charts-axis-tooltip-content', - false, - /\.\/charts-axis-tooltip-content.*.json$/, - ); - const descriptions = mapApiPageTranslations(req); - - return { - descriptions, - pageContent: jsonPageContent, - }; -}; diff --git a/docs/pages/x/api/charts/charts-axis-tooltip-content.json b/docs/pages/x/api/charts/charts-axis-tooltip-content.json deleted file mode 100644 index 377c83930f32b..0000000000000 --- a/docs/pages/x/api/charts/charts-axis-tooltip-content.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "props": {}, - "name": "ChartsAxisTooltipContent", - "imports": [ - "import { ChartsAxisTooltipContent } from '@mui/x-charts/ChartsTooltip';", - "import { ChartsAxisTooltipContent } from '@mui/x-charts';" - ], - "classes": [ - { - "key": "cell", - "className": "MuiChartsAxisTooltipContent-cell", - "description": "Styles applied to the cell element.", - "isGlobal": false - }, - { - "key": "labelCell", - "className": "MuiChartsAxisTooltipContent-labelCell", - "description": "Styles applied to the labelCell element.", - "isGlobal": false - }, - { - "key": "mark", - "className": "MuiChartsAxisTooltipContent-mark", - "description": "Styles applied to the mark element.", - "isGlobal": false - }, - { - "key": "markCell", - "className": "MuiChartsAxisTooltipContent-markCell", - "description": "Styles applied to the markCell element.", - "isGlobal": false - }, - { - "key": "root", - "className": "MuiChartsAxisTooltipContent-root", - "description": "Styles applied to the root element.", - "isGlobal": false - }, - { - "key": "row", - "className": "MuiChartsAxisTooltipContent-row", - "description": "Styles applied to the row element.", - "isGlobal": false - }, - { - "key": "table", - "className": "MuiChartsAxisTooltipContent-table", - "description": "Styles applied to the table element.", - "isGlobal": false - }, - { - "key": "valueCell", - "className": "MuiChartsAxisTooltipContent-valueCell", - "description": "Styles applied to the valueCell element.", - "isGlobal": false - } - ], - "muiName": "MuiChartsAxisTooltipContent", - "filename": "/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx", - "inheritance": null, - "demos": "", - "cssComponent": false -} diff --git a/docs/pages/x/api/charts/charts-item-tooltip-content.js b/docs/pages/x/api/charts/charts-item-tooltip-content.js deleted file mode 100644 index 3eb3dbfb139a1..0000000000000 --- a/docs/pages/x/api/charts/charts-item-tooltip-content.js +++ /dev/null @@ -1,23 +0,0 @@ -import * as React from 'react'; -import ApiPage from 'docs/src/modules/components/ApiPage'; -import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; -import jsonPageContent from './charts-item-tooltip-content.json'; - -export default function Page(props) { - const { descriptions, pageContent } = props; - return ; -} - -Page.getInitialProps = () => { - const req = require.context( - 'docsx/translations/api-docs/charts/charts-item-tooltip-content', - false, - /\.\/charts-item-tooltip-content.*.json$/, - ); - const descriptions = mapApiPageTranslations(req); - - return { - descriptions, - pageContent: jsonPageContent, - }; -}; diff --git a/docs/pages/x/api/charts/charts-item-tooltip-content.json b/docs/pages/x/api/charts/charts-item-tooltip-content.json deleted file mode 100644 index e00782f429849..0000000000000 --- a/docs/pages/x/api/charts/charts-item-tooltip-content.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "props": {}, - "name": "ChartsItemTooltipContent", - "imports": [ - "import { ChartsItemTooltipContent } from '@mui/x-charts/ChartsTooltip';", - "import { ChartsItemTooltipContent } from '@mui/x-charts';" - ], - "classes": [ - { - "key": "cell", - "className": "MuiChartsItemTooltipContent-cell", - "description": "Styles applied to the cell element.", - "isGlobal": false - }, - { - "key": "labelCell", - "className": "MuiChartsItemTooltipContent-labelCell", - "description": "Styles applied to the labelCell element.", - "isGlobal": false - }, - { - "key": "mark", - "className": "MuiChartsItemTooltipContent-mark", - "description": "Styles applied to the mark element.", - "isGlobal": false - }, - { - "key": "markCell", - "className": "MuiChartsItemTooltipContent-markCell", - "description": "Styles applied to the markCell element.", - "isGlobal": false - }, - { - "key": "root", - "className": "MuiChartsItemTooltipContent-root", - "description": "Styles applied to the root element.", - "isGlobal": false - }, - { - "key": "row", - "className": "MuiChartsItemTooltipContent-row", - "description": "Styles applied to the row element.", - "isGlobal": false - }, - { - "key": "table", - "className": "MuiChartsItemTooltipContent-table", - "description": "Styles applied to the table element.", - "isGlobal": false - }, - { - "key": "valueCell", - "className": "MuiChartsItemTooltipContent-valueCell", - "description": "Styles applied to the valueCell element.", - "isGlobal": false - } - ], - "muiName": "MuiChartsItemTooltipContent", - "filename": "/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx", - "inheritance": null, - "demos": "", - "cssComponent": false -} diff --git a/docs/pages/x/api/charts/responsive-chart-container.json b/docs/pages/x/api/charts/responsive-chart-container.json index f758a3c363d96..b04b83407c931 100644 --- a/docs/pages/x/api/charts/responsive-chart-container.json +++ b/docs/pages/x/api/charts/responsive-chart-container.json @@ -48,7 +48,7 @@ "zAxis": { "type": { "name": "arrayOf", - "description": "Array<{ colorMap?: { colors: Array<string>, type: 'ordinal', unknownColor?: string, values?: Array<Date
| number
| string> }
| { color: Array<string>
| func, max?: Date
| number, min?: Date
| number, type: 'continuous' }
| { colors: Array<string>, thresholds: Array<Date
| number>, type: 'piecewise' }, data?: array, dataKey?: string, id?: string }>" + "description": "Array<{ colorMap?: { colors: Array<string>, type: 'ordinal', unknownColor?: string, values?: Array<Date
| number
| string> }
| { color: Array<string>
| func, max?: Date
| number, min?: Date
| number, type: 'continuous' }
| { colors: Array<string>, thresholds: Array<Date
| number>, type: 'piecewise' }, data?: array, dataKey?: string, id?: string, max?: number, min?: number }>" } } }, diff --git a/docs/pages/x/api/charts/scatter-chart.json b/docs/pages/x/api/charts/scatter-chart.json index 42263922241a2..96bb86d6ba1e9 100644 --- a/docs/pages/x/api/charts/scatter-chart.json +++ b/docs/pages/x/api/charts/scatter-chart.json @@ -101,7 +101,7 @@ "zAxis": { "type": { "name": "arrayOf", - "description": "Array<{ colorMap?: { colors: Array<string>, type: 'ordinal', unknownColor?: string, values?: Array<Date
| number
| string> }
| { color: Array<string>
| func, max?: Date
| number, min?: Date
| number, type: 'continuous' }
| { colors: Array<string>, thresholds: Array<Date
| number>, type: 'piecewise' }, data?: array, dataKey?: string, id?: string }>" + "description": "Array<{ colorMap?: { colors: Array<string>, type: 'ordinal', unknownColor?: string, values?: Array<Date
| number
| string> }
| { color: Array<string>
| func, max?: Date
| number, min?: Date
| number, type: 'continuous' }
| { colors: Array<string>, thresholds: Array<Date
| number>, type: 'piecewise' }, data?: array, dataKey?: string, id?: string, max?: number, min?: number }>" } } }, diff --git a/docs/translations/api-docs/charts/charts-axis-tooltip-content/charts-axis-tooltip-content.json b/docs/translations/api-docs/charts/charts-axis-tooltip-content/charts-axis-tooltip-content.json deleted file mode 100644 index e6bd069242ac0..0000000000000 --- a/docs/translations/api-docs/charts/charts-axis-tooltip-content/charts-axis-tooltip-content.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "componentDescription": "", - "propDescriptions": {}, - "classDescriptions": { - "cell": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the cell element" }, - "labelCell": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the labelCell element" - }, - "mark": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the mark element" }, - "markCell": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the markCell element" - }, - "root": { "description": "Styles applied to the root element." }, - "row": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the row element" }, - "table": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the table element" }, - "valueCell": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the valueCell element" - } - } -} diff --git a/docs/translations/api-docs/charts/charts-item-tooltip-content/charts-item-tooltip-content.json b/docs/translations/api-docs/charts/charts-item-tooltip-content/charts-item-tooltip-content.json deleted file mode 100644 index e6bd069242ac0..0000000000000 --- a/docs/translations/api-docs/charts/charts-item-tooltip-content/charts-item-tooltip-content.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "componentDescription": "", - "propDescriptions": {}, - "classDescriptions": { - "cell": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the cell element" }, - "labelCell": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the labelCell element" - }, - "mark": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the mark element" }, - "markCell": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the markCell element" - }, - "root": { "description": "Styles applied to the root element." }, - "row": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the row element" }, - "table": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the table element" }, - "valueCell": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the valueCell element" - } - } -} diff --git a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx index 14431b9e1e5e8..817c3eaad15e1 100644 --- a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx +++ b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx @@ -34,15 +34,18 @@ import { HeatmapSeriesType } from '../models/seriesType/heatmap'; import { HeatmapPlot } from './HeatmapPlot'; import { plugin as heatmapPlugin } from './plugin'; import { DefaultHeatmapTooltip } from './DefaultHeatmapTooltip'; +import { HeatmapItemSlotProps, HeatmapItemSlots } from './HeatmapItem'; export interface HeatmapSlots extends ChartsAxisSlots, Omit, 'axisContent'>, - ChartsOverlaySlots {} + ChartsOverlaySlots, + HeatmapItemSlots {} export interface HeatmapSlotProps extends ChartsAxisSlotProps, Omit, 'axisContent'>, - ChartsOverlaySlotProps {} + ChartsOverlaySlotProps, + HeatmapItemSlotProps {} export interface HeatmapProps extends Omit, @@ -160,7 +163,7 @@ export const Heatmap = React.forwardRef(function Heatmap(props: HeatmapProps, re > {onAxisClick && } - + >; +} + +export interface HeatmapItemProps { dataIndex: number; seriesId: SeriesId; width: number; @@ -10,10 +26,56 @@ interface HeatmapItemProps { x: number; y: number; color: string; + /** + * The props used for each component slot. + * @default {} + */ + slotProps?: HeatmapItemSlotProps; + /** + * Overridable component slots. + * @default {} + */ + slots?: HeatmapItemSlots; +} + +export interface HeatmapItemOwnerState { + seriesId: SeriesId; + dataIndex: number; + color: string; + isFaded: boolean; + isHighlighted: boolean; + classes?: Partial; } +const HeatmapCell = styled('rect', { + name: 'MuiHeatmap', + slot: 'Cell', + overridesResolver: (_, styles) => styles.arc, +})<{ ownerState: HeatmapItemOwnerState }>(({ ownerState }) => ({ + filter: + (ownerState.isHighlighted && 'saturate(120%)') || + (ownerState.isFaded && 'saturate(80%)') || + undefined, + fill: ownerState.color, + shapeRendering: 'crispEdges', +})); + +const useUtilityClasses = (ownerState: HeatmapItemOwnerState) => { + const { classes, seriesId, isFaded, isHighlighted } = ownerState; + const slots = { + cell: [ + 'root', + `series-${seriesId}`, + isFaded && heatmapClasses.faded, + isHighlighted && heatmapClasses.highlighted, + ], + }; + + return composeClasses(slots, getHeatmapUtilityClass, classes); +}; + export function HeatmapItem(props: HeatmapItemProps) { - const { dataIndex, seriesId, width, height, x, y, color } = props; + const { seriesId, dataIndex, color, slotProps = {}, slots = {}, ...other } = props; const getInteractionItemProps = useInteractionItemProps(); const { isFaded, isHighlighted } = useItemHighlighted({ @@ -21,18 +83,24 @@ export function HeatmapItem(props: HeatmapItemProps) { dataIndex, }); - return ( - - ); + const ownerState = { + seriesId, + dataIndex, + color, + isFaded, + isHighlighted, + }; + const classes = useUtilityClasses(ownerState); + + const Cell = slots?.cell ?? HeatmapCell; + const cellProps = useSlotProps({ + elementType: Cell, + additionalProps: getInteractionItemProps({ type: 'heatmap', seriesId, dataIndex }), + externalForwardedProps: { ...other }, + externalSlotProps: slotProps.cell, + ownerState, + className: classes.cell, + }); + + return ; } diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx index 775531188da02..01197919f42f7 100644 --- a/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx +++ b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx @@ -1,9 +1,11 @@ import * as React from 'react'; import { useXScale, useYScale, useZColorScale } from '@mui/x-charts/hooks'; import { useHeatmapSeries } from '../hooks/useSeries'; -import { HeatmapItem } from './HeatmapItem'; +import { HeatmapItem, HeatmapItemProps } from './HeatmapItem'; -export function HeatmapPlot() { +export interface HeatmapPlotProps extends Pick {} + +export function HeatmapPlot(props: HeatmapPlotProps) { const xScale = useXScale<'band'>(); const yScale = useYScale<'band'>(); const colorScale = useZColorScale()!; @@ -36,6 +38,8 @@ export function HeatmapPlot() { color={color} dataIndex={dataIndex} seriesId={series.seriesOrder[0]} + slots={props.slots} + slotProps={props.slotProps} /> ); })} diff --git a/packages/x-charts-pro/src/Heatmap/heatmapClasses.ts b/packages/x-charts-pro/src/Heatmap/heatmapClasses.ts new file mode 100644 index 0000000000000..f70a56c14d23a --- /dev/null +++ b/packages/x-charts-pro/src/Heatmap/heatmapClasses.ts @@ -0,0 +1,24 @@ +import { + unstable_generateUtilityClass as generateUtilityClass, + unstable_generateUtilityClasses as generateUtilityClasses, +} from '@mui/utils'; + +export interface HeatmapClasses { + /** Styles applied to the heatmap cells. */ + cell: string; + /** Styles applied to the cell element if highlighted. */ + highlighted: string; + /** Styles applied to the cell element if faded. */ + faded: string; +} + +export type HeatmapClassKey = keyof HeatmapClasses; + +export function getHeatmapUtilityClass(slot: string) { + return generateUtilityClass('MuiHeatmap', slot); +} +export const heatmapClasses: HeatmapClasses = { + ...generateUtilityClasses('MuiHeatmap', ['cell']), + highlighted: 'Charts-highlighted', + faded: 'Charts-faded', +}; diff --git a/scripts/x-charts.exports.json b/scripts/x-charts.exports.json index 130ba9b6914a8..11b63c1a501fb 100644 --- a/scripts/x-charts.exports.json +++ b/scripts/x-charts.exports.json @@ -79,8 +79,9 @@ { "name": "ChartsGridClasses", "kind": "Interface" }, { "name": "ChartsGridClassKey", "kind": "TypeAlias" }, { "name": "ChartsGridProps", "kind": "Interface" }, - { "name": "ChartsItemContentProps", "kind": "TypeAlias" }, + { "name": "ChartsItemContentProps", "kind": "Interface" }, { "name": "ChartsItemTooltipContent", "kind": "Function" }, + { "name": "ChartsItemTooltipContentProps", "kind": "Interface" }, { "name": "ChartsLegend", "kind": "Function" }, { "name": "ChartsLegendClasses", "kind": "Interface" }, { "name": "ChartsLegendClassKey", "kind": "TypeAlias" }, @@ -108,7 +109,7 @@ { "name": "ChartsTooltipClassKey", "kind": "TypeAlias" }, { "name": "ChartsTooltipMark", "kind": "Variable" }, { "name": "ChartsTooltipPaper", "kind": "Variable" }, - { "name": "ChartsTooltipProps", "kind": "TypeAlias" }, + { "name": "ChartsTooltipProps", "kind": "Interface" }, { "name": "ChartsTooltipRow", "kind": "Variable" }, { "name": "ChartsTooltipSlotProps", "kind": "Interface" }, { "name": "ChartsTooltipSlots", "kind": "Interface" }, From 007977d9059f64ba34f0859a48b81b6565a20152 Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 19 Jun 2024 16:37:37 +0200 Subject: [PATCH 23/31] Add slots demo --- docs/data/charts/heatmap/CustomItem.js | 68 ++++++++++++++++++ docs/data/charts/heatmap/CustomItem.tsx | 69 +++++++++++++++++++ .../charts/heatmap/CustomItem.tsx.preview | 8 +++ docs/data/charts/heatmap/heatmap.md | 4 ++ .../x-charts-pro/src/Heatmap/HeatmapItem.tsx | 6 +- .../x-charts-pro/src/Heatmap/HeatmapPlot.tsx | 1 + 6 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 docs/data/charts/heatmap/CustomItem.js create mode 100644 docs/data/charts/heatmap/CustomItem.tsx create mode 100644 docs/data/charts/heatmap/CustomItem.tsx.preview diff --git a/docs/data/charts/heatmap/CustomItem.js b/docs/data/charts/heatmap/CustomItem.js new file mode 100644 index 0000000000000..ba94c79d0212b --- /dev/null +++ b/docs/data/charts/heatmap/CustomItem.js @@ -0,0 +1,68 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import '@mui/x-charts-pro/typeOverloads'; +import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; + +const data = [ + [0, 0, 1], + [0, 1, 2], + [0, 2, 4], + [0, 3, 5], + [0, 4, 2], + [1, 0, 3], + [1, 1, 5], + [1, 2, 1], + [1, 3, 2], + [1, 4, 4], + [2, 0, 5], + [2, 1, 2], + [2, 2, 3], + [2, 3, 1], + [2, 4, 2], + [3, 0, 4], + [3, 1, 5], + [3, 2, 2], + [3, 3, 3], + [3, 4, 5], +]; + +function CustomCell(props) { + const { x, y, width, height, ownerState, ...other } = props; + + return ( + + + + {ownerState.value} + + + ); +} +export default function CustomItem() { + return ( + + + + ); +} diff --git a/docs/data/charts/heatmap/CustomItem.tsx b/docs/data/charts/heatmap/CustomItem.tsx new file mode 100644 index 0000000000000..6ee5ff94f19b3 --- /dev/null +++ b/docs/data/charts/heatmap/CustomItem.tsx @@ -0,0 +1,69 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import '@mui/x-charts-pro/typeOverloads'; +import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; +import { HeatmapValueType } from '@mui/x-charts-pro/models'; + +const data: HeatmapValueType[] = [ + [0, 0, 1], + [0, 1, 2], + [0, 2, 4], + [0, 3, 5], + [0, 4, 2], + [1, 0, 3], + [1, 1, 5], + [1, 2, 1], + [1, 3, 2], + [1, 4, 4], + [2, 0, 5], + [2, 1, 2], + [2, 2, 3], + [2, 3, 1], + [2, 4, 2], + [3, 0, 4], + [3, 1, 5], + [3, 2, 2], + [3, 3, 3], + [3, 4, 5], +]; + +function CustomCell(props: any) { + const { x, y, width, height, ownerState, ...other } = props; + + return ( + + + + {ownerState.value} + + + ); +} +export default function CustomItem() { + return ( + + + + ); +} diff --git a/docs/data/charts/heatmap/CustomItem.tsx.preview b/docs/data/charts/heatmap/CustomItem.tsx.preview new file mode 100644 index 0000000000000..cf90fc6243728 --- /dev/null +++ b/docs/data/charts/heatmap/CustomItem.tsx.preview @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/docs/data/charts/heatmap/heatmap.md b/docs/data/charts/heatmap/heatmap.md index 9fbef8bde815f..30f83d11c6d3d 100644 --- a/docs/data/charts/heatmap/heatmap.md +++ b/docs/data/charts/heatmap/heatmap.md @@ -52,3 +52,7 @@ The available options are available in the [dedicated page](/x/react-charts/axis ## Legend 🚧 ## Labels 🚧 + +## Custom item + +{{"demo": "CustomItem.js"}} diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx index 5456921257ad0..a5b96a7245974 100644 --- a/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx +++ b/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx @@ -21,6 +21,7 @@ export interface HeatmapItemSlotProps { export interface HeatmapItemProps { dataIndex: number; seriesId: SeriesId; + value: number; width: number; height: number; x: number; @@ -75,7 +76,7 @@ const useUtilityClasses = (ownerState: HeatmapItemOwnerState) => { }; export function HeatmapItem(props: HeatmapItemProps) { - const { seriesId, dataIndex, color, slotProps = {}, slots = {}, ...other } = props; + const { seriesId, dataIndex, color, value, slotProps = {}, slots = {}, ...other } = props; const getInteractionItemProps = useInteractionItemProps(); const { isFaded, isHighlighted } = useItemHighlighted({ @@ -87,6 +88,7 @@ export function HeatmapItem(props: HeatmapItemProps) { seriesId, dataIndex, color, + value, isFaded, isHighlighted, }; @@ -95,7 +97,7 @@ export function HeatmapItem(props: HeatmapItemProps) { const Cell = slots?.cell ?? HeatmapCell; const cellProps = useSlotProps({ elementType: Cell, - additionalProps: getInteractionItemProps({ type: 'heatmap', seriesId, dataIndex }), + additionalProps: { ...getInteractionItemProps({ type: 'heatmap', seriesId, dataIndex }) }, externalForwardedProps: { ...other }, externalSlotProps: slotProps.cell, ownerState, diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx index 01197919f42f7..42c9d8e0fe4a9 100644 --- a/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx +++ b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx @@ -38,6 +38,7 @@ export function HeatmapPlot(props: HeatmapPlotProps) { color={color} dataIndex={dataIndex} seriesId={series.seriesOrder[0]} + value={value} slots={props.slots} slotProps={props.slotProps} /> From ba7cfc1580126e89bb02baa5c6f349bb9ad5120d Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 19 Jun 2024 17:31:09 +0200 Subject: [PATCH 24/31] more demos --- docs/data/charts/heatmap/CustomItem.js | 4 +- .../charts/heatmap/CustomItem.tsx.preview | 2 +- docs/data/charts/heatmap/HighlightClasses.js | 61 ++++++++++++++++++ docs/data/charts/heatmap/HighlightClasses.tsx | 62 +++++++++++++++++++ docs/data/charts/heatmap/heatmap.md | 4 ++ .../x-charts-pro/src/Heatmap/HeatmapItem.tsx | 10 +-- .../src/Heatmap/heatmapClasses.ts | 4 ++ packages/x-charts-pro/src/Heatmap/index.ts | 1 + 8 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 docs/data/charts/heatmap/HighlightClasses.js create mode 100644 docs/data/charts/heatmap/HighlightClasses.tsx diff --git a/docs/data/charts/heatmap/CustomItem.js b/docs/data/charts/heatmap/CustomItem.js index ba94c79d0212b..a072126f209f4 100644 --- a/docs/data/charts/heatmap/CustomItem.js +++ b/docs/data/charts/heatmap/CustomItem.js @@ -38,7 +38,7 @@ function CustomCell(props) { width={width - 2 * 4} height={height - 2 * 4} fill={ownerState.color} - clipPath="inset(0px round 4px)" + clipPath={ownerState.isHighlighted ? undefined : 'inset(0px round 10px)'} /> diff --git a/docs/data/charts/heatmap/CustomItem.tsx.preview b/docs/data/charts/heatmap/CustomItem.tsx.preview index cf90fc6243728..9c1801cf7cd48 100644 --- a/docs/data/charts/heatmap/CustomItem.tsx.preview +++ b/docs/data/charts/heatmap/CustomItem.tsx.preview @@ -2,7 +2,7 @@ slots={{ cell: CustomCell }} xAxis={[{ data: [1, 2, 3, 4] }]} yAxis={[{ data: ['A', 'B', 'C', 'D', 'E'] }]} - series={[{ data }]} + series={[{ data, highlightScope: { highlight: 'item' } }]} margin={{ top: 5, right: 5, left: 20 }} height={300} /> \ No newline at end of file diff --git a/docs/data/charts/heatmap/HighlightClasses.js b/docs/data/charts/heatmap/HighlightClasses.js new file mode 100644 index 0000000000000..1443819f7f60c --- /dev/null +++ b/docs/data/charts/heatmap/HighlightClasses.js @@ -0,0 +1,61 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import '@mui/x-charts-pro/typeOverloads'; +import { UnstableHeatmap, heatmapClasses } from '@mui/x-charts-pro/Heatmap'; + +const data = [ + [0, 0, 1], + [0, 1, 2], + [0, 2, 4], + [0, 3, 5], + [0, 4, 2], + [1, 0, 3], + [1, 1, 5], + [1, 2, 1], + [1, 3, 2], + [1, 4, 4], + [2, 0, 5], + [2, 1, 2], + [2, 2, 3], + [2, 3, 1], + [2, 4, 2], + [3, 0, 4], + [3, 1, 5], + [3, 2, 2], + [3, 3, 3], + [3, 4, 5], +]; + +export default function HighlightClasses() { + console.log([`& .${heatmapClasses.cell}.${heatmapClasses.highlighted}`]); + return ( + + + + ); +} diff --git a/docs/data/charts/heatmap/HighlightClasses.tsx b/docs/data/charts/heatmap/HighlightClasses.tsx new file mode 100644 index 0000000000000..274118e1a1090 --- /dev/null +++ b/docs/data/charts/heatmap/HighlightClasses.tsx @@ -0,0 +1,62 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import '@mui/x-charts-pro/typeOverloads'; +import { UnstableHeatmap, heatmapClasses } from '@mui/x-charts-pro/Heatmap'; +import { HeatmapValueType } from '@mui/x-charts-pro/models'; + +const data: HeatmapValueType[] = [ + [0, 0, 1], + [0, 1, 2], + [0, 2, 4], + [0, 3, 5], + [0, 4, 2], + [1, 0, 3], + [1, 1, 5], + [1, 2, 1], + [1, 3, 2], + [1, 4, 4], + [2, 0, 5], + [2, 1, 2], + [2, 2, 3], + [2, 3, 1], + [2, 4, 2], + [3, 0, 4], + [3, 1, 5], + [3, 2, 2], + [3, 3, 3], + [3, 4, 5], +]; + +export default function HighlightClasses() { + console.log([`& .${heatmapClasses.cell}.${heatmapClasses.highlighted}`]); + return ( + + + + ); +} diff --git a/docs/data/charts/heatmap/heatmap.md b/docs/data/charts/heatmap/heatmap.md index 30f83d11c6d3d..645ad7624c344 100644 --- a/docs/data/charts/heatmap/heatmap.md +++ b/docs/data/charts/heatmap/heatmap.md @@ -42,6 +42,10 @@ Planned work: {{"demo": "HighlightHeatmap.js"}} +You can modify the styling with CSS selectors. + +{{"demo": "HighlightClasses.js"}} + ### Axes The Heatmap axes can be customized like any other chart axis. diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx index a5b96a7245974..c82c4b27ba2c6 100644 --- a/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx +++ b/packages/x-charts-pro/src/Heatmap/HeatmapItem.tsx @@ -4,7 +4,7 @@ import { useSlotProps } from '@mui/base/utils'; import composeClasses from '@mui/utils/composeClasses'; import { useItemHighlighted } from '@mui/x-charts/context'; import { useInteractionItemProps, SeriesId } from '@mui/x-charts/internals'; -import { HeatmapClasses, getHeatmapUtilityClass, heatmapClasses } from './heatmapClasses'; +import { HeatmapClasses, getHeatmapUtilityClass } from './heatmapClasses'; export interface HeatmapItemSlots { /** @@ -64,14 +64,8 @@ const HeatmapCell = styled('rect', { const useUtilityClasses = (ownerState: HeatmapItemOwnerState) => { const { classes, seriesId, isFaded, isHighlighted } = ownerState; const slots = { - cell: [ - 'root', - `series-${seriesId}`, - isFaded && heatmapClasses.faded, - isHighlighted && heatmapClasses.highlighted, - ], + cell: ['cell', `series-${seriesId}`, isFaded && 'faded', isHighlighted && 'highlighted'], }; - return composeClasses(slots, getHeatmapUtilityClass, classes); }; diff --git a/packages/x-charts-pro/src/Heatmap/heatmapClasses.ts b/packages/x-charts-pro/src/Heatmap/heatmapClasses.ts index f70a56c14d23a..2f50b4bdfa599 100644 --- a/packages/x-charts-pro/src/Heatmap/heatmapClasses.ts +++ b/packages/x-charts-pro/src/Heatmap/heatmapClasses.ts @@ -15,6 +15,10 @@ export interface HeatmapClasses { export type HeatmapClassKey = keyof HeatmapClasses; export function getHeatmapUtilityClass(slot: string) { + // Those should be common to all charts + if (['highlighted', 'faded'].includes(slot)) { + return generateUtilityClass('Charts', slot); + } return generateUtilityClass('MuiHeatmap', slot); } export const heatmapClasses: HeatmapClasses = { diff --git a/packages/x-charts-pro/src/Heatmap/index.ts b/packages/x-charts-pro/src/Heatmap/index.ts index a69d106f47551..042c1a78bacbd 100644 --- a/packages/x-charts-pro/src/Heatmap/index.ts +++ b/packages/x-charts-pro/src/Heatmap/index.ts @@ -1,3 +1,4 @@ export { Heatmap as UnstableHeatmap } from './Heatmap'; export { HeatmapPlot as UnstableHeatmapPlot } from './HeatmapPlot'; export * from './DefaultHeatmapTooltip'; +export * from './heatmapClasses'; From 329102c4ed5fbe0ddc37291ef2eff7c1f9f59d7b Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 20 Jun 2024 10:24:03 +0200 Subject: [PATCH 25/31] merge --- .codesandbox/ci.json | 1 - .../workflows/cherry-pick-master-to-v6.yml | 2 +- .../workflows/cherry-pick-next-to-master.yml | 2 +- .github/workflows/codeql.yml | 6 +- .github/workflows/l10n.yml | 2 +- .github/workflows/scorecards.yml | 4 +- .github/workflows/vale-action.yml | 2 +- .../headless/LogExpandedItems.tsx | 2 +- .../rich-tree-view/headless/headless.md | 4 +- docs/package.json | 2 +- .../pages/x/api/date-pickers/date-picker.json | 5 +- .../x/api/date-pickers/date-range-picker.json | 5 +- .../x/api/date-pickers/date-time-picker.json | 5 +- .../date-pickers/date-time-range-picker.json | 5 +- .../api/date-pickers/desktop-date-picker.json | 5 +- .../desktop-date-range-picker.json | 5 +- .../desktop-date-time-picker.json | 5 +- .../desktop-date-time-range-picker.json | 5 +- .../api/date-pickers/desktop-time-picker.json | 5 +- .../api/date-pickers/mobile-date-picker.json | 5 +- .../mobile-date-range-picker.json | 5 +- .../date-pickers/mobile-date-time-picker.json | 5 +- .../mobile-date-time-range-picker.json | 5 +- .../api/date-pickers/mobile-time-picker.json | 5 +- .../date-pickers/pickers-calendar-header.json | 1 + .../pickers-range-calendar-header.json | 1 + .../api/date-pickers/static-date-picker.json | 5 +- .../static-date-range-picker.json | 5 +- .../date-pickers/static-date-time-picker.json | 5 +- .../api/date-pickers/static-time-picker.json | 5 +- .../pages/x/api/date-pickers/time-picker.json | 5 +- .../date-pickers/date-picker/date-picker.json | 5 +- .../date-range-picker/date-range-picker.json | 5 +- .../date-time-picker/date-time-picker.json | 5 +- .../date-time-range-picker.json | 5 +- .../desktop-date-picker.json | 5 +- .../desktop-date-range-picker.json | 5 +- .../desktop-date-time-picker.json | 5 +- .../desktop-date-time-range-picker.json | 5 +- .../desktop-time-picker.json | 5 +- .../mobile-date-picker.json | 5 +- .../mobile-date-range-picker.json | 5 +- .../mobile-date-time-picker.json | 5 +- .../mobile-date-time-range-picker.json | 5 +- .../mobile-time-picker.json | 5 +- .../pickers-calendar-header.json | 3 + .../pickers-range-calendar-header.json | 3 + .../static-date-picker.json | 5 +- .../static-date-range-picker.json | 5 +- .../static-date-time-picker.json | 5 +- .../static-time-picker.json | 5 +- .../date-pickers/time-picker/time-picker.json | 5 +- package.json | 16 +- .../eslint-plugin-material-ui/package.json | 4 +- packages/x-charts-pro/package.json | 1 + .../ChartContainerPro/ChartContainerPro.tsx | 361 ++++++++++++++++++ .../src/ChartContainerPro/index.ts | 1 + .../ResponsiveChartContainerPro.test.tsx | 9 +- .../ResponsiveChartContainerPro.tsx | 81 ++-- packages/x-charts-pro/src/index.ts | 1 + packages/x-charts/src/BarChart/BarPlot.tsx | 4 +- .../x-charts/src/BarChart/checkScaleErrors.ts | 12 +- .../src/ChartContainer/ChartContainer.tsx | 20 +- .../ChartContainer/useChartContainerHooks.ts | 27 ++ .../src/ChartContainer/usePluginsMerge.ts | 3 +- .../x-charts/src/ChartsAxis/ChartsAxis.tsx | 10 +- .../ChartsAxisHighlight.tsx | 4 +- .../x-charts/src/ChartsGrid/ChartsGrid.tsx | 4 +- .../ChartsOnAxisClickHandler.tsx | 4 +- .../ChartsAxisTooltipContent.tsx | 4 +- .../ChartsItemTooltipContent.tsx | 4 +- .../ChartsVoronoiHandler.tsx | 4 +- .../x-charts/src/ChartsXAxis/ChartsXAxis.tsx | 4 +- .../x-charts/src/ChartsYAxis/ChartsYAxis.tsx | 4 +- packages/x-charts/src/LineChart/AreaPlot.tsx | 7 +- .../src/LineChart/LineHighlightPlot.tsx | 4 +- packages/x-charts/src/LineChart/LinePlot.tsx | 7 +- packages/x-charts/src/LineChart/MarkPlot.tsx | 4 +- .../x-charts/src/ScatterChart/ScatterPlot.tsx | 4 +- .../src/context/CartesianContextProvider.tsx | 358 ----------------- .../CartesianProvider/CartesianContext.ts | 47 +++ .../CartesianProvider/CartesianProvider.tsx | 83 ++++ .../context/CartesianProvider/computeValue.ts | 144 +++++++ .../CartesianProvider/getAxisExtremum.ts | 48 +++ .../src/context/CartesianProvider/index.ts | 13 + .../CartesianProvider/normalizeAxis.ts | 29 ++ .../CartesianProvider/useCartesianContext.ts | 7 + .../x-charts/src/context/ColorProvider.tsx | 2 +- packages/x-charts/src/hooks/useAxisEvents.ts | 4 +- packages/x-charts/src/hooks/useColorScale.ts | 6 +- packages/x-charts/src/hooks/useDrawingArea.ts | 4 +- .../ChartsAxesGradients.tsx | 7 +- packages/x-charts/src/internals/index.ts | 5 +- packages/x-charts/src/models/plugin.ts | 11 +- .../DateRangeCalendar.test.tsx | 2 +- .../DateRangeCalendar/DateRangeCalendar.tsx | 13 +- .../src/DateRangePicker/DateRangePicker.tsx | 2 + .../DateTimeRangePicker.tsx | 2 + .../DesktopDateRangePicker.tsx | 2 + .../tests/DesktopDateRangePicker.test.tsx | 4 +- .../DesktopDateTimeRangePicker.tsx | 2 + .../MobileDateRangePicker.tsx | 2 + .../MobileDateTimeRangePicker.tsx | 2 + .../PickersRangeCalendarHeader.tsx | 9 +- .../StaticDateRangePicker.tsx | 2 + .../src/DatePicker/DatePicker.tsx | 2 + .../src/DateTimePicker/DateTimePicker.tsx | 2 + .../DesktopDatePicker/DesktopDatePicker.tsx | 2 + .../tests/DesktopDatePicker.test.tsx | 24 ++ .../DesktopDateTimePicker.tsx | 2 + .../DesktopTimePicker/DesktopTimePicker.tsx | 2 + .../src/MobileDatePicker/MobileDatePicker.tsx | 2 + .../MobileDateTimePicker.tsx | 2 + .../src/MobileTimePicker/MobileTimePicker.tsx | 2 + .../PickersCalendarHeader.tsx | 4 + .../PickersCalendarHeader.types.ts | 4 + .../src/StaticDatePicker/StaticDatePicker.tsx | 2 + .../StaticDateTimePicker.tsx | 2 + .../src/StaticTimePicker/StaticTimePicker.tsx | 2 + .../src/TimePicker/TimePicker.tsx | 2 + .../PickersArrowSwitcher.tsx | 3 +- .../PickersArrowSwitcher.types.tsx | 1 + .../hooks/usePicker/usePickerValue.ts | 43 ++- .../hooks/usePicker/usePickerValue.types.ts | 4 +- .../hooks/usePicker/usePickerViews.ts | 4 +- .../src/TreeItem/TreeItem.test.tsx | 12 + .../x-tree-view/src/TreeItem/TreeItem.tsx | 9 +- .../src/TreeItem/TreeItem.types.ts | 8 + .../src/TreeItem/useTreeItemState.ts | 4 +- .../useTreeItem2Utils/useTreeItem2Utils.tsx | 10 +- .../TreeViewChildrenItemProvider.tsx | 4 +- .../TreeViewProvider.types.ts | 11 +- .../TreeViewProvider/useTreeViewContext.ts | 10 +- .../src/internals/models/plugin.ts | 54 +-- .../src/internals/models/treeView.ts | 14 +- .../useTreeViewExpansion.types.ts | 2 +- .../useTreeViewFocus.types.ts | 2 +- .../useTreeViewIcons.types.ts | 2 +- .../useTreeViewJSXItems.types.ts | 2 +- .../useTreeViewKeyboardNavigation.types.ts | 2 +- .../useTreeViewSelection.types.ts | 2 +- .../x-tree-view/src/internals/utils/utils.ts | 6 + .../src/useTreeItem2/useTreeItem2.ts | 6 +- .../src/useTreeItem2/useTreeItem2.types.ts | 15 +- pnpm-lock.yaml | 325 ++++++++-------- scripts/x-charts.exports.json | 1 + 146 files changed, 1506 insertions(+), 749 deletions(-) create mode 100644 packages/x-charts-pro/src/ChartContainerPro/ChartContainerPro.tsx create mode 100644 packages/x-charts-pro/src/ChartContainerPro/index.ts create mode 100644 packages/x-charts/src/ChartContainer/useChartContainerHooks.ts delete mode 100644 packages/x-charts/src/context/CartesianContextProvider.tsx create mode 100644 packages/x-charts/src/context/CartesianProvider/CartesianContext.ts create mode 100644 packages/x-charts/src/context/CartesianProvider/CartesianProvider.tsx create mode 100644 packages/x-charts/src/context/CartesianProvider/computeValue.ts create mode 100644 packages/x-charts/src/context/CartesianProvider/getAxisExtremum.ts create mode 100644 packages/x-charts/src/context/CartesianProvider/index.ts create mode 100644 packages/x-charts/src/context/CartesianProvider/normalizeAxis.ts create mode 100644 packages/x-charts/src/context/CartesianProvider/useCartesianContext.ts diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json index 8b8c292b15949..37d8d1c445442 100644 --- a/.codesandbox/ci.json +++ b/.codesandbox/ci.json @@ -11,7 +11,6 @@ "packages/x-date-pickers", "packages/x-date-pickers-pro", "packages/x-charts", - "packages/x-charts-pro", "packages/x-tree-view" ], "publishDirectory": { diff --git a/.github/workflows/cherry-pick-master-to-v6.yml b/.github/workflows/cherry-pick-master-to-v6.yml index e994f648ee927..17479c515c23d 100644 --- a/.github/workflows/cherry-pick-master-to-v6.yml +++ b/.github/workflows/cherry-pick-master-to-v6.yml @@ -18,7 +18,7 @@ jobs: if: ${{ contains(github.event.pull_request.labels.*.name, 'needs cherry-pick') && github.event.pull_request.merged == true }} steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: 0 - name: Cherry pick and create the new PR diff --git a/.github/workflows/cherry-pick-next-to-master.yml b/.github/workflows/cherry-pick-next-to-master.yml index d4d3aaaa82e08..0b1810db65240 100644 --- a/.github/workflows/cherry-pick-next-to-master.yml +++ b/.github/workflows/cherry-pick-next-to-master.yml @@ -18,7 +18,7 @@ jobs: if: ${{ contains(github.event.pull_request.labels.*.name, 'needs cherry-pick') && github.event.pull_request.merged == true }} steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: 0 - name: Cherry pick and create the new PR diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 63bcd837e21f0..ecf1ede8f2cb8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -16,10 +16,10 @@ jobs: security-events: write steps: - name: Checkout repository - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8 + uses: github/codeql-action/init@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10 with: languages: typescript # If you wish to specify custom queries, you can do so here or in a config file. @@ -29,4 +29,4 @@ jobs: # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8 + uses: github/codeql-action/analyze@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10 diff --git a/.github/workflows/l10n.yml b/.github/workflows/l10n.yml index b038b57f64b4e..749da197f79f6 100644 --- a/.github/workflows/l10n.yml +++ b/.github/workflows/l10n.yml @@ -17,7 +17,7 @@ jobs: issues: write steps: - run: echo "${{ github.actor }}" - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 with: run_install: false diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 64aeb90e61075..2fb7dd32df088 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: persist-credentials: false @@ -44,6 +44,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: Upload to code-scanning - uses: github/codeql-action/upload-sarif@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8 + uses: github/codeql-action/upload-sarif@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10 with: sarif_file: results.sarif diff --git a/.github/workflows/vale-action.yml b/.github/workflows/vale-action.yml index 0ff551052faa1..53ce0e90216fe 100644 --- a/.github/workflows/vale-action.yml +++ b/.github/workflows/vale-action.yml @@ -12,7 +12,7 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: errata-ai/vale-action@38bf078c328061f59879b347ca344a718a736018 # v2.1.0 with: reporter: github-pr-review diff --git a/docs/data/tree-view/rich-tree-view/headless/LogExpandedItems.tsx b/docs/data/tree-view/rich-tree-view/headless/LogExpandedItems.tsx index 7a45a2b3e0cd9..70285558cbb90 100644 --- a/docs/data/tree-view/rich-tree-view/headless/LogExpandedItems.tsx +++ b/docs/data/tree-view/rich-tree-view/headless/LogExpandedItems.tsx @@ -37,7 +37,7 @@ type TreeViewLogExpandedSignature = TreeViewPluginSignature<{ // The parameters of this plugin as they are passed to the plugin after calling `plugin.getDefaultizedParams` defaultizedParams: TreeViewLogExpandedDefaultizedParameters; // Dependencies of this plugin (we need the expansion plugin to access its model) - dependantPlugins: [UseTreeViewExpansionSignature]; + dependencies: [UseTreeViewExpansionSignature]; }>; const useTreeViewLogExpanded: TreeViewPlugin = ({ diff --git a/docs/data/tree-view/rich-tree-view/headless/headless.md b/docs/data/tree-view/rich-tree-view/headless/headless.md index 86ca7bfccbc56..6afb2d8403a04 100644 --- a/docs/data/tree-view/rich-tree-view/headless/headless.md +++ b/docs/data/tree-view/rich-tree-view/headless/headless.md @@ -283,7 +283,7 @@ type UseCustomPluginSignature = TreeViewPluginSignature<{ // The name of the models defined by your plugin modelNames: UseCustomPluginModelNames; // The plugins this plugin needs to work correctly - dependantPlugins: UseCustomPluginDependantPlugins; + dependencies: UseCustomPluginDependantPlugins; }>; ``` @@ -317,7 +317,7 @@ type UseCustomPluginSignature = TreeViewPluginSignature<{ contextValue: { customPlugin: { enabled: boolean } }; modelNames: 'customModel'; // We want to have access to the expansion models and methods of the expansion plugin. - dependantPlugins: [UseTreeViewExpansionSignature]; + dependencies: [UseTreeViewExpansionSignature]; }>; ``` diff --git a/docs/package.json b/docs/package.json index cc882be406cf7..e0426a7ce55c0 100644 --- a/docs/package.json +++ b/docs/package.json @@ -82,7 +82,7 @@ "react": "^18.2.0", "react-docgen": "^5.4.3", "react-dom": "^18.2.0", - "react-hook-form": "^7.51.5", + "react-hook-form": "^7.52.0", "react-is": "^18.2.0", "react-router": "^6.23.1", "react-router-dom": "^6.23.1", diff --git a/docs/pages/x/api/date-pickers/date-picker.json b/docs/pages/x/api/date-pickers/date-picker.json index bcfd00412af6e..4ea68fc760de7 100644 --- a/docs/pages/x/api/date-pickers/date-picker.json +++ b/docs/pages/x/api/date-pickers/date-picker.json @@ -44,7 +44,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/date-range-picker.json b/docs/pages/x/api/date-pickers/date-range-picker.json index 025571c76e56a..5d5a3cc60a541 100644 --- a/docs/pages/x/api/date-pickers/date-range-picker.json +++ b/docs/pages/x/api/date-pickers/date-range-picker.json @@ -54,7 +54,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/date-time-picker.json b/docs/pages/x/api/date-pickers/date-time-picker.json index 21dd5ccca51b5..4c1bcbdbad73a 100644 --- a/docs/pages/x/api/date-pickers/date-time-picker.json +++ b/docs/pages/x/api/date-pickers/date-time-picker.json @@ -52,7 +52,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/date-time-range-picker.json b/docs/pages/x/api/date-pickers/date-time-range-picker.json index 727e404614e0e..147b2d9dabe82 100644 --- a/docs/pages/x/api/date-pickers/date-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/date-time-range-picker.json @@ -61,7 +61,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/desktop-date-picker.json b/docs/pages/x/api/date-pickers/desktop-date-picker.json index e596175c9ec02..eba85e4232de3 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-picker.json @@ -40,7 +40,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/desktop-date-range-picker.json b/docs/pages/x/api/date-pickers/desktop-date-range-picker.json index ed5c7c6addee8..21ee7757ea577 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-range-picker.json @@ -50,7 +50,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/desktop-date-time-picker.json b/docs/pages/x/api/date-pickers/desktop-date-time-picker.json index e29f85b22ede8..3f020cd17da5d 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-time-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-time-picker.json @@ -48,7 +48,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/desktop-date-time-range-picker.json b/docs/pages/x/api/date-pickers/desktop-date-time-range-picker.json index 8022414ca2a87..f6ac402daf922 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-time-range-picker.json @@ -57,7 +57,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/desktop-time-picker.json b/docs/pages/x/api/date-pickers/desktop-time-picker.json index a138a9baf6d61..ccd6bfd900019 100644 --- a/docs/pages/x/api/date-pickers/desktop-time-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-time-picker.json @@ -27,7 +27,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/mobile-date-picker.json b/docs/pages/x/api/date-pickers/mobile-date-picker.json index dda2b5f7a06a5..f08c28cc0cc2c 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-picker.json @@ -40,7 +40,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/mobile-date-range-picker.json b/docs/pages/x/api/date-pickers/mobile-date-range-picker.json index b325ddcf307e0..9da74456e2a01 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-range-picker.json @@ -46,7 +46,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/mobile-date-time-picker.json b/docs/pages/x/api/date-pickers/mobile-date-time-picker.json index 77d8cbe0ff4e5..910576d1135be 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-time-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-time-picker.json @@ -48,7 +48,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/mobile-date-time-range-picker.json b/docs/pages/x/api/date-pickers/mobile-date-time-range-picker.json index 2daa3399a014b..63d8de93ae505 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-time-range-picker.json @@ -53,7 +53,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/mobile-time-picker.json b/docs/pages/x/api/date-pickers/mobile-time-picker.json index 6285dff74f334..7eadc80c5316d 100644 --- a/docs/pages/x/api/date-pickers/mobile-time-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-time-picker.json @@ -27,7 +27,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/pickers-calendar-header.json b/docs/pages/x/api/date-pickers/pickers-calendar-header.json index 94aa338f027f2..b2a50f1ad029d 100644 --- a/docs/pages/x/api/date-pickers/pickers-calendar-header.json +++ b/docs/pages/x/api/date-pickers/pickers-calendar-header.json @@ -5,6 +5,7 @@ "type": { "name": "string" }, "default": "`${adapter.formats.month} ${adapter.formats.year}`" }, + "labelId": { "type": { "name": "string" } }, "slotProps": { "type": { "name": "object" }, "default": "{}" }, "slots": { "type": { "name": "object" }, diff --git a/docs/pages/x/api/date-pickers/pickers-range-calendar-header.json b/docs/pages/x/api/date-pickers/pickers-range-calendar-header.json index fbf2f5e605c2a..d3c101a847ab8 100644 --- a/docs/pages/x/api/date-pickers/pickers-range-calendar-header.json +++ b/docs/pages/x/api/date-pickers/pickers-range-calendar-header.json @@ -11,6 +11,7 @@ "type": { "name": "string" }, "default": "`${adapter.formats.month} ${adapter.formats.year}`" }, + "labelId": { "type": { "name": "string" } }, "slotProps": { "type": { "name": "object" }, "default": "{}" }, "slots": { "type": { "name": "object" }, diff --git a/docs/pages/x/api/date-pickers/static-date-picker.json b/docs/pages/x/api/date-pickers/static-date-picker.json index 68b8dd519d9d9..27c865ca2370e 100644 --- a/docs/pages/x/api/date-pickers/static-date-picker.json +++ b/docs/pages/x/api/date-pickers/static-date-picker.json @@ -31,7 +31,10 @@ }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/static-date-range-picker.json b/docs/pages/x/api/date-pickers/static-date-range-picker.json index cf58edc3774ee..57a973451e4c9 100644 --- a/docs/pages/x/api/date-pickers/static-date-range-picker.json +++ b/docs/pages/x/api/date-pickers/static-date-range-picker.json @@ -41,7 +41,10 @@ "minDate": { "type": { "name": "object" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/static-date-time-picker.json b/docs/pages/x/api/date-pickers/static-date-time-picker.json index 0065d1c765853..75caf10f37ff0 100644 --- a/docs/pages/x/api/date-pickers/static-date-time-picker.json +++ b/docs/pages/x/api/date-pickers/static-date-time-picker.json @@ -39,7 +39,10 @@ }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/static-time-picker.json b/docs/pages/x/api/date-pickers/static-time-picker.json index 0af386a2e7b7b..c8ca193d0eb08 100644 --- a/docs/pages/x/api/date-pickers/static-time-picker.json +++ b/docs/pages/x/api/date-pickers/static-time-picker.json @@ -18,7 +18,10 @@ "minutesStep": { "type": { "name": "number" }, "default": "1" }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/date-pickers/time-picker.json b/docs/pages/x/api/date-pickers/time-picker.json index 10cfe474c86f6..f77fd0bcc3550 100644 --- a/docs/pages/x/api/date-pickers/time-picker.json +++ b/docs/pages/x/api/date-pickers/time-picker.json @@ -31,7 +31,10 @@ "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, - "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } }, "onChange": { "type": { "name": "func" }, diff --git a/docs/translations/api-docs/date-pickers/date-picker/date-picker.json b/docs/translations/api-docs/date-pickers/date-picker/date-picker.json index d7d0bc2a81be4..fa776f7501a50 100644 --- a/docs/translations/api-docs/date-pickers/date-picker/date-picker.json +++ b/docs/translations/api-docs/date-pickers/date-picker/date-picker.json @@ -61,7 +61,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/date-range-picker/date-range-picker.json b/docs/translations/api-docs/date-pickers/date-range-picker/date-range-picker.json index 487f016100897..b847113e3e878 100644 --- a/docs/translations/api-docs/date-pickers/date-range-picker/date-range-picker.json +++ b/docs/translations/api-docs/date-pickers/date-range-picker/date-range-picker.json @@ -75,7 +75,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/date-time-picker/date-time-picker.json b/docs/translations/api-docs/date-pickers/date-time-picker/date-time-picker.json index cd9ff892320f6..e6bc667be2c41 100644 --- a/docs/translations/api-docs/date-pickers/date-time-picker/date-time-picker.json +++ b/docs/translations/api-docs/date-pickers/date-time-picker/date-time-picker.json @@ -81,7 +81,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/date-time-range-picker/date-time-range-picker.json b/docs/translations/api-docs/date-pickers/date-time-range-picker/date-time-range-picker.json index b343a9a908235..38ff71b4a0bc2 100644 --- a/docs/translations/api-docs/date-pickers/date-time-range-picker/date-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/date-time-range-picker/date-time-range-picker.json @@ -92,7 +92,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/desktop-date-picker/desktop-date-picker.json b/docs/translations/api-docs/date-pickers/desktop-date-picker/desktop-date-picker.json index b7a8202fe828a..bd5ad6552128e 100644 --- a/docs/translations/api-docs/date-pickers/desktop-date-picker/desktop-date-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-date-picker/desktop-date-picker.json @@ -58,7 +58,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/desktop-date-range-picker/desktop-date-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-date-range-picker/desktop-date-range-picker.json index f84ba97e26a9b..280773356bff1 100644 --- a/docs/translations/api-docs/date-pickers/desktop-date-range-picker/desktop-date-range-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-date-range-picker/desktop-date-range-picker.json @@ -72,7 +72,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/desktop-date-time-picker/desktop-date-time-picker.json b/docs/translations/api-docs/date-pickers/desktop-date-time-picker/desktop-date-time-picker.json index e780c1306adf3..850e02434af95 100644 --- a/docs/translations/api-docs/date-pickers/desktop-date-time-picker/desktop-date-time-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-date-time-picker/desktop-date-time-picker.json @@ -78,7 +78,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/desktop-date-time-range-picker/desktop-date-time-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-date-time-range-picker/desktop-date-time-range-picker.json index b974a4f13026a..44308fe67c437 100644 --- a/docs/translations/api-docs/date-pickers/desktop-date-time-range-picker/desktop-date-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-date-time-range-picker/desktop-date-time-range-picker.json @@ -89,7 +89,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/desktop-time-picker/desktop-time-picker.json b/docs/translations/api-docs/date-pickers/desktop-time-picker/desktop-time-picker.json index f34197ca9139e..cb08e6dbe9b52 100644 --- a/docs/translations/api-docs/date-pickers/desktop-time-picker/desktop-time-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-time-picker/desktop-time-picker.json @@ -50,7 +50,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json b/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json index 3c66bba3cead8..6fdc6eaca82e2 100644 --- a/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json @@ -58,7 +58,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/mobile-date-range-picker/mobile-date-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-date-range-picker/mobile-date-range-picker.json index 238d3a5996e7c..4f31ae0b29206 100644 --- a/docs/translations/api-docs/date-pickers/mobile-date-range-picker/mobile-date-range-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-date-range-picker/mobile-date-range-picker.json @@ -69,7 +69,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json b/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json index ae408ea1af356..3731b8d7d2f73 100644 --- a/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json @@ -78,7 +78,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/mobile-date-time-range-picker/mobile-date-time-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-date-time-range-picker/mobile-date-time-range-picker.json index 90665962517af..743e5f688d34d 100644 --- a/docs/translations/api-docs/date-pickers/mobile-date-time-range-picker/mobile-date-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-date-time-range-picker/mobile-date-time-range-picker.json @@ -86,7 +86,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/mobile-time-picker/mobile-time-picker.json b/docs/translations/api-docs/date-pickers/mobile-time-picker/mobile-time-picker.json index 43f9d92678fec..cd9f9871246e8 100644 --- a/docs/translations/api-docs/date-pickers/mobile-time-picker/mobile-time-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-time-picker/mobile-time-picker.json @@ -50,7 +50,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/pickers-calendar-header/pickers-calendar-header.json b/docs/translations/api-docs/date-pickers/pickers-calendar-header/pickers-calendar-header.json index 6095d04c8b30a..14b1549d337dd 100644 --- a/docs/translations/api-docs/date-pickers/pickers-calendar-header/pickers-calendar-header.json +++ b/docs/translations/api-docs/date-pickers/pickers-calendar-header/pickers-calendar-header.json @@ -3,6 +3,9 @@ "propDescriptions": { "classes": { "description": "Override or extend the styles applied to the component." }, "format": { "description": "Format used to display the date." }, + "labelId": { + "description": "Id of the calendar text element. It is used to establish an aria-labelledby relationship with the calendar grid element." + }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." }, "sx": { diff --git a/docs/translations/api-docs/date-pickers/pickers-range-calendar-header/pickers-range-calendar-header.json b/docs/translations/api-docs/date-pickers/pickers-range-calendar-header/pickers-range-calendar-header.json index a152174c7d953..9affb9834e6d6 100644 --- a/docs/translations/api-docs/date-pickers/pickers-range-calendar-header/pickers-range-calendar-header.json +++ b/docs/translations/api-docs/date-pickers/pickers-range-calendar-header/pickers-range-calendar-header.json @@ -4,6 +4,9 @@ "calendars": { "description": "The number of calendars rendered." }, "classes": { "description": "Override or extend the styles applied to the component." }, "format": { "description": "Format used to display the date." }, + "labelId": { + "description": "Id of the calendar text element. It is used to establish an aria-labelledby relationship with the calendar grid element." + }, "month": { "description": "Month used for this header." }, "monthIndex": { "description": "Index of the month used for this header." }, "slotProps": { "description": "The props used for each component slot." }, diff --git a/docs/translations/api-docs/date-pickers/static-date-picker/static-date-picker.json b/docs/translations/api-docs/date-pickers/static-date-picker/static-date-picker.json index 6642fc5ae6eda..7ebb4803d895d 100644 --- a/docs/translations/api-docs/date-pickers/static-date-picker/static-date-picker.json +++ b/docs/translations/api-docs/date-pickers/static-date-picker/static-date-picker.json @@ -44,7 +44,10 @@ "monthsPerRow": { "description": "Months rendered per row." }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/static-date-range-picker/static-date-range-picker.json b/docs/translations/api-docs/date-pickers/static-date-range-picker/static-date-range-picker.json index 93baad91dff8c..a5948b80f3836 100644 --- a/docs/translations/api-docs/date-pickers/static-date-range-picker/static-date-range-picker.json +++ b/docs/translations/api-docs/date-pickers/static-date-range-picker/static-date-range-picker.json @@ -54,7 +54,10 @@ "minDate": { "description": "Minimal selectable date." }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/static-date-time-picker/static-date-time-picker.json b/docs/translations/api-docs/date-pickers/static-date-time-picker/static-date-time-picker.json index 4da520fb69b3d..49348e6733294 100644 --- a/docs/translations/api-docs/date-pickers/static-date-time-picker/static-date-time-picker.json +++ b/docs/translations/api-docs/date-pickers/static-date-time-picker/static-date-time-picker.json @@ -64,7 +64,10 @@ "monthsPerRow": { "description": "Months rendered per row." }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/static-time-picker/static-time-picker.json b/docs/translations/api-docs/date-pickers/static-time-picker/static-time-picker.json index 407f598837a7e..8ba5b454d5e6b 100644 --- a/docs/translations/api-docs/date-pickers/static-time-picker/static-time-picker.json +++ b/docs/translations/api-docs/date-pickers/static-time-picker/static-time-picker.json @@ -36,7 +36,10 @@ "minutesStep": { "description": "Step over minutes." }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/docs/translations/api-docs/date-pickers/time-picker/time-picker.json b/docs/translations/api-docs/date-pickers/time-picker/time-picker.json index c5a1a885b348d..3e18c58879a8d 100644 --- a/docs/translations/api-docs/date-pickers/time-picker/time-picker.json +++ b/docs/translations/api-docs/date-pickers/time-picker/time-picker.json @@ -53,7 +53,10 @@ }, "onAccept": { "description": "Callback fired when the value is accepted.", - "typeDescriptions": { "value": "The value that was just accepted." } + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } }, "onChange": { "description": "Callback fired when the value changes.", diff --git a/package.json b/package.json index 51ecbf55888c9..024e7851b33be 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "@mui/material": "^5.15.20", "@mui/monorepo": "github:mui/material-ui#22c5206a9e8191b2f81131d6978a0958e55b7032", "@mui/utils": "^5.15.20", - "@next/eslint-plugin-next": "14.2.3", + "@next/eslint-plugin-next": "14.2.4", "@octokit/plugin-retry": "^6.0.1", "@octokit/rest": "^20.1.1", "@playwright/test": "^1.44.1", @@ -112,8 +112,8 @@ "@types/requestidlecallback": "^0.3.7", "@types/sinon": "^17.0.3", "@types/yargs": "^17.0.32", - "@typescript-eslint/eslint-plugin": "^7.12.0", - "@typescript-eslint/parser": "^7.12.0", + "@typescript-eslint/eslint-plugin": "^7.13.1", + "@typescript-eslint/parser": "^7.13.1", "autoprefixer": "^10.4.19", "axe-core": "4.9.1", "babel-loader": "^9.1.3", @@ -141,7 +141,7 @@ "eslint-import-resolver-webpack": "^0.13.8", "eslint-plugin-filenames": "^1.3.2", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsdoc": "^48.2.9", + "eslint-plugin-jsdoc": "^48.2.12", "eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-material-ui": "workspace:^", "eslint-plugin-mocha": "^10.4.3", @@ -171,7 +171,7 @@ "mocha": "^10.4.0", "moment": "^2.30.1", "moment-timezone": "^0.5.45", - "nyc": "^15.1.0", + "nyc": "^17.0.0", "prettier": "^3.3.2", "pretty-quick": "^4.0.0", "process": "^0.11.10", @@ -188,7 +188,7 @@ "typescript": "^5.4.5", "unist-util-visit": "^2.0.3", "util": "^0.12.5", - "webpack": "^5.91.0", + "webpack": "^5.92.0", "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4", "yargs": "^17.7.2" @@ -197,9 +197,9 @@ "react-is": "^18.2.0", "@types/node": "^18.19.34" }, - "packageManager": "pnpm@9.2.0", + "packageManager": "pnpm@9.4.0", "engines": { - "pnpm": "9.2.0" + "pnpm": "9.4.0" }, "pnpm": { "patchedDependencies": { diff --git a/packages/eslint-plugin-material-ui/package.json b/packages/eslint-plugin-material-ui/package.json index 030e2626c2c4d..347ccb8ca25d2 100644 --- a/packages/eslint-plugin-material-ui/package.json +++ b/packages/eslint-plugin-material-ui/package.json @@ -6,8 +6,8 @@ "main": "src/index.js", "devDependencies": { "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.12.0", - "@typescript-eslint/parser": "^7.12.0" + "@typescript-eslint/utils": "^7.13.1", + "@typescript-eslint/parser": "^7.13.1" }, "scripts": { "test": "cd ../../ && cross-env NODE_ENV=test mocha 'packages/eslint-plugin-material-ui/**/*.test.js' --timeout 3000" diff --git a/packages/x-charts-pro/package.json b/packages/x-charts-pro/package.json index 2ec3bf312527d..945293d1ce0b7 100644 --- a/packages/x-charts-pro/package.json +++ b/packages/x-charts-pro/package.json @@ -1,6 +1,7 @@ { "name": "@mui/x-charts-pro", "version": "7.7.0", + "private": true, "description": "The community edition of the Charts components (MUI X).", "author": "MUI Team", "main": "./src/index.ts", diff --git a/packages/x-charts-pro/src/ChartContainerPro/ChartContainerPro.tsx b/packages/x-charts-pro/src/ChartContainerPro/ChartContainerPro.tsx new file mode 100644 index 0000000000000..8361a9df78827 --- /dev/null +++ b/packages/x-charts-pro/src/ChartContainerPro/ChartContainerPro.tsx @@ -0,0 +1,361 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { ChartContainerProps } from '@mui/x-charts/ChartContainer'; +import { ChartsSurface } from '@mui/x-charts/ChartsSurface'; +import { HighlightedProvider, ZAxisContextProvider } from '@mui/x-charts/context'; +import { + CartesianContextProvider, + ChartsAxesGradients, + ColorProvider, + DrawingProvider, + InteractionProvider, + SeriesContextProvider, + useChartContainerHooks, +} from '@mui/x-charts/internals'; +import { useLicenseVerifier } from '@mui/x-license/useLicenseVerifier'; +import { getReleaseInfo } from '../internals/utils/releaseInfo'; + +const releaseInfo = getReleaseInfo(); + +export interface ChartContainerProProps extends ChartContainerProps {} + +const ChartContainerPro = React.forwardRef(function ChartContainer( + props: ChartContainerProProps, + ref, +) { + const { + width, + height, + series, + margin, + xAxis, + yAxis, + zAxis, + colors, + dataset, + sx, + title, + desc, + disableAxisListener, + highlightedItem, + onHighlightChange, + plugins, + children, + } = props; + + useLicenseVerifier('x-charts-pro', releaseInfo); + + const { + svgRef, + handleRef, + xExtremumGetters, + yExtremumGetters, + seriesFormatters, + colorProcessors, + } = useChartContainerHooks(ref, plugins); + + return ( + + + + + + + + + + {children} + + + + + + + + + ); +}); + +ChartContainerPro.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + children: PropTypes.node, + className: PropTypes.string, + /** + * Color palette used to colorize multiple series. + * @default blueberryTwilightPalette + */ + colors: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.string), PropTypes.func]), + /** + * An array of objects that can be used to populate series and axes data using their `dataKey` property. + */ + dataset: PropTypes.arrayOf(PropTypes.object), + desc: PropTypes.string, + /** + * If `true`, the charts will not listen to the mouse move event. + * It might break interactive features, but will improve performance. + * @default false + */ + disableAxisListener: PropTypes.bool, + /** + * The height of the chart in px. + */ + height: PropTypes.number.isRequired, + /** + * The item currently highlighted. Turns highlighting into a controlled prop. + */ + highlightedItem: PropTypes.shape({ + dataIndex: PropTypes.number, + seriesId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + }), + /** + * The margin between the SVG and the drawing area. + * It's used for leaving some space for extra information such as the x- and y-axis or legend. + * Accepts an object with the optional properties: `top`, `bottom`, `left`, and `right`. + * @default object Depends on the charts type. + */ + margin: PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + /** + * The callback fired when the highlighted item changes. + * + * @param {HighlightItemData | null} highlightedItem The newly highlighted item. + */ + onHighlightChange: PropTypes.func, + /** + * An array of plugins defining how to preprocess data. + * If not provided, the container supports line, bar, scatter and pie charts. + */ + plugins: PropTypes.arrayOf(PropTypes.object), + /** + * The array of series to display. + * Each type of series has its own specificity. + * Please refer to the appropriate docs page to learn more about it. + */ + series: PropTypes.arrayOf(PropTypes.object).isRequired, + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + title: PropTypes.string, + viewBox: PropTypes.shape({ + height: PropTypes.number, + width: PropTypes.number, + x: PropTypes.number, + y: PropTypes.number, + }), + /** + * The width of the chart in px. + */ + width: PropTypes.number.isRequired, + /** + * The configuration of the x-axes. + * If not provided, a default axis config is used. + * An array of [[AxisConfig]] objects. + */ + xAxis: PropTypes.arrayOf( + PropTypes.shape({ + axisId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + classes: PropTypes.object, + colorMap: PropTypes.oneOfType([ + PropTypes.shape({ + color: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.string.isRequired), + PropTypes.func, + ]).isRequired, + max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + type: PropTypes.oneOf(['continuous']).isRequired, + }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + thresholds: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]).isRequired, + ).isRequired, + type: PropTypes.oneOf(['piecewise']).isRequired, + }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + type: PropTypes.oneOf(['ordinal']).isRequired, + unknownColor: PropTypes.string, + values: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) + .isRequired, + ), + }), + ]), + data: PropTypes.array, + dataKey: PropTypes.string, + disableLine: PropTypes.bool, + disableTicks: PropTypes.bool, + fill: PropTypes.string, + hideTooltip: PropTypes.bool, + id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + label: PropTypes.string, + labelFontSize: PropTypes.number, + labelStyle: PropTypes.object, + max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + position: PropTypes.oneOf(['bottom', 'top']), + reverse: PropTypes.bool, + scaleType: PropTypes.oneOf(['band', 'linear', 'log', 'point', 'pow', 'sqrt', 'time', 'utc']), + slotProps: PropTypes.object, + slots: PropTypes.object, + stroke: PropTypes.string, + tickFontSize: PropTypes.number, + tickInterval: PropTypes.oneOfType([ + PropTypes.oneOf(['auto']), + PropTypes.array, + PropTypes.func, + ]), + tickLabelInterval: PropTypes.oneOfType([PropTypes.oneOf(['auto']), PropTypes.func]), + tickLabelPlacement: PropTypes.oneOf(['middle', 'tick']), + tickLabelStyle: PropTypes.object, + tickMaxStep: PropTypes.number, + tickMinStep: PropTypes.number, + tickNumber: PropTypes.number, + tickPlacement: PropTypes.oneOf(['end', 'extremities', 'middle', 'start']), + tickSize: PropTypes.number, + valueFormatter: PropTypes.func, + }), + ), + /** + * The configuration of the y-axes. + * If not provided, a default axis config is used. + * An array of [[AxisConfig]] objects. + */ + yAxis: PropTypes.arrayOf( + PropTypes.shape({ + axisId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + classes: PropTypes.object, + colorMap: PropTypes.oneOfType([ + PropTypes.shape({ + color: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.string.isRequired), + PropTypes.func, + ]).isRequired, + max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + type: PropTypes.oneOf(['continuous']).isRequired, + }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + thresholds: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]).isRequired, + ).isRequired, + type: PropTypes.oneOf(['piecewise']).isRequired, + }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + type: PropTypes.oneOf(['ordinal']).isRequired, + unknownColor: PropTypes.string, + values: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) + .isRequired, + ), + }), + ]), + data: PropTypes.array, + dataKey: PropTypes.string, + disableLine: PropTypes.bool, + disableTicks: PropTypes.bool, + fill: PropTypes.string, + hideTooltip: PropTypes.bool, + id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + label: PropTypes.string, + labelFontSize: PropTypes.number, + labelStyle: PropTypes.object, + max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + position: PropTypes.oneOf(['left', 'right']), + reverse: PropTypes.bool, + scaleType: PropTypes.oneOf(['band', 'linear', 'log', 'point', 'pow', 'sqrt', 'time', 'utc']), + slotProps: PropTypes.object, + slots: PropTypes.object, + stroke: PropTypes.string, + tickFontSize: PropTypes.number, + tickInterval: PropTypes.oneOfType([ + PropTypes.oneOf(['auto']), + PropTypes.array, + PropTypes.func, + ]), + tickLabelInterval: PropTypes.oneOfType([PropTypes.oneOf(['auto']), PropTypes.func]), + tickLabelPlacement: PropTypes.oneOf(['middle', 'tick']), + tickLabelStyle: PropTypes.object, + tickMaxStep: PropTypes.number, + tickMinStep: PropTypes.number, + tickNumber: PropTypes.number, + tickPlacement: PropTypes.oneOf(['end', 'extremities', 'middle', 'start']), + tickSize: PropTypes.number, + valueFormatter: PropTypes.func, + }), + ), + /** + * The configuration of the z-axes. + */ + zAxis: PropTypes.arrayOf( + PropTypes.shape({ + colorMap: PropTypes.oneOfType([ + PropTypes.shape({ + color: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.string.isRequired), + PropTypes.func, + ]).isRequired, + max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + type: PropTypes.oneOf(['continuous']).isRequired, + }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + thresholds: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]).isRequired, + ).isRequired, + type: PropTypes.oneOf(['piecewise']).isRequired, + }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + type: PropTypes.oneOf(['ordinal']).isRequired, + unknownColor: PropTypes.string, + values: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) + .isRequired, + ), + }), + ]), + data: PropTypes.array, + dataKey: PropTypes.string, + id: PropTypes.string, + }), + ), +} as any; + +export { ChartContainerPro }; diff --git a/packages/x-charts-pro/src/ChartContainerPro/index.ts b/packages/x-charts-pro/src/ChartContainerPro/index.ts new file mode 100644 index 0000000000000..3ca7bddfcdfc7 --- /dev/null +++ b/packages/x-charts-pro/src/ChartContainerPro/index.ts @@ -0,0 +1 @@ +export * from './ChartContainerPro'; diff --git a/packages/x-charts-pro/src/ResponsiveChartContainerPro/ResponsiveChartContainerPro.test.tsx b/packages/x-charts-pro/src/ResponsiveChartContainerPro/ResponsiveChartContainerPro.test.tsx index e8fcf52be087e..007e7217a8e36 100644 --- a/packages/x-charts-pro/src/ResponsiveChartContainerPro/ResponsiveChartContainerPro.test.tsx +++ b/packages/x-charts-pro/src/ResponsiveChartContainerPro/ResponsiveChartContainerPro.test.tsx @@ -2,11 +2,18 @@ import * as React from 'react'; import { expect } from 'chai'; import { createRenderer, screen, waitFor } from '@mui/internal-test-utils'; import { LicenseInfo } from '@mui/x-license'; +import { sharedLicenseStatuses } from '@mui/x-license/useLicenseVerifier/useLicenseVerifier'; import { ResponsiveChartContainerPro } from './ResponsiveChartContainerPro'; describe(' - License', () => { const { render } = createRenderer(); + beforeEach(() => { + Object.keys(sharedLicenseStatuses).forEach((key) => { + delete sharedLicenseStatuses[key]; + }); + }); + it('should render watermark when the license is missing', async () => { LicenseInfo.setLicenseKey(''); @@ -15,7 +22,7 @@ describe(' - License', () => { ).toErrorDev(['MUI X: Missing license key.']); await waitFor(() => { - expect(screen.getByText('MUI X Missing license key')).to.not.equal(null); + expect(screen.findAllByText('MUI X Missing license key')).to.not.equal(null); }); }); }); diff --git a/packages/x-charts-pro/src/ResponsiveChartContainerPro/ResponsiveChartContainerPro.tsx b/packages/x-charts-pro/src/ResponsiveChartContainerPro/ResponsiveChartContainerPro.tsx index c508e72095141..e65ebb933b405 100644 --- a/packages/x-charts-pro/src/ResponsiveChartContainerPro/ResponsiveChartContainerPro.tsx +++ b/packages/x-charts-pro/src/ResponsiveChartContainerPro/ResponsiveChartContainerPro.tsx @@ -1,10 +1,10 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { useLicenseVerifier, Watermark } from '@mui/x-license'; -import { ChartContainer } from '@mui/x-charts/ChartContainer'; +import { Watermark } from '@mui/x-license/Watermark'; import { ResponsiveChartContainerProps } from '@mui/x-charts/ResponsiveChartContainer'; import { ResizableContainer, useChartContainerDimensions } from '@mui/x-charts/internals'; import { getReleaseInfo } from '../internals/utils/releaseInfo'; +import { ChartContainerPro } from '../ChartContainerPro'; export interface ResponsiveChartContainerProProps extends ResponsiveChartContainerProps {} @@ -17,12 +17,10 @@ const ResponsiveChartContainerPro = React.forwardRef(function ResponsiveChartCon const { width: inWidth, height: inHeight, ...other } = props; const [containerRef, width, height] = useChartContainerDimensions(inWidth, inHeight); - useLicenseVerifier('x-charts-pro', releaseInfo); - return ( {width && height ? ( - + ) : null} @@ -118,15 +116,6 @@ ResponsiveChartContainerPro.propTypes = { axisId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), classes: PropTypes.object, colorMap: PropTypes.oneOfType([ - PropTypes.shape({ - colors: PropTypes.arrayOf(PropTypes.string).isRequired, - type: PropTypes.oneOf(['ordinal']).isRequired, - unknownColor: PropTypes.string, - values: PropTypes.arrayOf( - PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) - .isRequired, - ), - }), PropTypes.shape({ color: PropTypes.oneOfType([ PropTypes.arrayOf(PropTypes.string.isRequired), @@ -143,6 +132,15 @@ ResponsiveChartContainerPro.propTypes = { ).isRequired, type: PropTypes.oneOf(['piecewise']).isRequired, }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + type: PropTypes.oneOf(['ordinal']).isRequired, + unknownColor: PropTypes.string, + values: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) + .isRequired, + ), + }), ]), data: PropTypes.array, dataKey: PropTypes.string, @@ -189,15 +187,6 @@ ResponsiveChartContainerPro.propTypes = { axisId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), classes: PropTypes.object, colorMap: PropTypes.oneOfType([ - PropTypes.shape({ - colors: PropTypes.arrayOf(PropTypes.string).isRequired, - type: PropTypes.oneOf(['ordinal']).isRequired, - unknownColor: PropTypes.string, - values: PropTypes.arrayOf( - PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) - .isRequired, - ), - }), PropTypes.shape({ color: PropTypes.oneOfType([ PropTypes.arrayOf(PropTypes.string.isRequired), @@ -214,6 +203,15 @@ ResponsiveChartContainerPro.propTypes = { ).isRequired, type: PropTypes.oneOf(['piecewise']).isRequired, }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + type: PropTypes.oneOf(['ordinal']).isRequired, + unknownColor: PropTypes.string, + values: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) + .isRequired, + ), + }), ]), data: PropTypes.array, dataKey: PropTypes.string, @@ -250,6 +248,43 @@ ResponsiveChartContainerPro.propTypes = { valueFormatter: PropTypes.func, }), ), + /** + * The configuration of the z-axes. + */ + zAxis: PropTypes.arrayOf( + PropTypes.shape({ + colorMap: PropTypes.oneOfType([ + PropTypes.shape({ + color: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.string.isRequired), + PropTypes.func, + ]).isRequired, + max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + type: PropTypes.oneOf(['continuous']).isRequired, + }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + thresholds: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]).isRequired, + ).isRequired, + type: PropTypes.oneOf(['piecewise']).isRequired, + }), + PropTypes.shape({ + colors: PropTypes.arrayOf(PropTypes.string).isRequired, + type: PropTypes.oneOf(['ordinal']).isRequired, + unknownColor: PropTypes.string, + values: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) + .isRequired, + ), + }), + ]), + data: PropTypes.array, + dataKey: PropTypes.string, + id: PropTypes.string, + }), + ), } as any; export { ResponsiveChartContainerPro }; diff --git a/packages/x-charts-pro/src/index.ts b/packages/x-charts-pro/src/index.ts index f5ea1ce266fe0..42ff9670447d1 100644 --- a/packages/x-charts-pro/src/index.ts +++ b/packages/x-charts-pro/src/index.ts @@ -29,3 +29,4 @@ export * from '@mui/x-charts/ChartsSurface'; // Pro components export * from './Heatmap'; export * from './ResponsiveChartContainerPro'; +export * from './ChartContainerPro'; diff --git a/packages/x-charts/src/BarChart/BarPlot.tsx b/packages/x-charts/src/BarChart/BarPlot.tsx index 7ff1e8999a573..bab8699fe6863 100644 --- a/packages/x-charts/src/BarChart/BarPlot.tsx +++ b/packages/x-charts/src/BarChart/BarPlot.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { useTransition } from '@react-spring/web'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { BarElement, BarElementSlotProps, BarElementSlots } from './BarElement'; import { AxisDefaultized } from '../models/axis'; import { FormatterResult } from '../models/seriesType/config'; @@ -89,7 +89,7 @@ const useAggregatedData = (): { const seriesData = useBarSeries() ?? ({ series: {}, stackingGroups: [], seriesOrder: [] } as FormatterResult<'bar'>); - const axisData = React.useContext(CartesianContext); + const axisData = useCartesianContext(); const chartId = useChartId(); const { series, stackingGroups } = seriesData; diff --git a/packages/x-charts/src/BarChart/checkScaleErrors.ts b/packages/x-charts/src/BarChart/checkScaleErrors.ts index e3b7b0803e968..cbd3137b11d59 100644 --- a/packages/x-charts/src/BarChart/checkScaleErrors.ts +++ b/packages/x-charts/src/BarChart/checkScaleErrors.ts @@ -1,8 +1,8 @@ import { DEFAULT_X_AXIS_KEY, DEFAULT_Y_AXIS_KEY } from '../constants'; -import { AxisDefaultized, isBandScaleConfig, isPointScaleConfig } from '../models/axis'; +import { AxisDefaultized, AxisId, isBandScaleConfig, isPointScaleConfig } from '../models/axis'; import { SeriesId } from '../models/seriesType/common'; -const getAxisMessage = (axisDirection: 'x' | 'y', axisKey: string) => { +const getAxisMessage = (axisDirection: 'x' | 'y', axisKey: AxisId) => { const axisName = `${axisDirection}-axis`; const axisKeyName = `${axisDirection}Axis`; const axisDefaultKey = axisDirection === 'x' ? DEFAULT_X_AXIS_KEY : DEFAULT_Y_AXIS_KEY; @@ -14,10 +14,10 @@ const getAxisMessage = (axisDirection: 'x' | 'y', axisKey: string) => { export function checkScaleErrors( verticalLayout: boolean, seriesId: SeriesId, - xAxisKey: string, - xAxis: { DEFAULT_X_AXIS_KEY: AxisDefaultized } & { [axisKey: string]: AxisDefaultized }, - yAxisKey: string, - yAxis: { DEFAULT_X_AXIS_KEY: AxisDefaultized } & { [axisKey: string]: AxisDefaultized }, + xAxisKey: AxisId, + xAxis: { [axisKey: AxisId]: AxisDefaultized }, + yAxisKey: AxisId, + yAxis: { [axisKey: AxisId]: AxisDefaultized }, ): void { const xAxisConfig = xAxis[xAxisKey]; const yAxisConfig = yAxis[yAxisKey]; diff --git a/packages/x-charts/src/ChartContainer/ChartContainer.tsx b/packages/x-charts/src/ChartContainer/ChartContainer.tsx index 9026e292f5601..1305694424e5d 100644 --- a/packages/x-charts/src/ChartContainer/ChartContainer.tsx +++ b/packages/x-charts/src/ChartContainer/ChartContainer.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import useForkRef from '@mui/utils/useForkRef'; import { DrawingProvider, DrawingProviderProps } from '../context/DrawingProvider'; import { SeriesContextProvider, @@ -8,12 +7,11 @@ import { } from '../context/SeriesContextProvider'; import { InteractionProvider } from '../context/InteractionProvider'; import { ColorProvider } from '../context/ColorProvider'; -import { useReducedMotion } from '../hooks/useReducedMotion'; import { ChartsSurface, ChartsSurfaceProps } from '../ChartsSurface'; import { CartesianContextProvider, CartesianContextProviderProps, -} from '../context/CartesianContextProvider'; +} from '../context/CartesianProvider'; import { ChartsAxesGradients } from '../internals/components/ChartsAxesGradients'; import { HighlightedProvider, @@ -23,7 +21,7 @@ import { } from '../context'; import { ChartsPluginType } from '../models/plugin'; import { ChartSeriesType } from '../models/seriesType/config'; -import { usePluginsMerge } from './usePluginsMerge'; +import { useChartContainerHooks } from './useChartContainerHooks'; export type ChartContainerProps = Omit< ChartsSurfaceProps & @@ -62,12 +60,14 @@ const ChartContainer = React.forwardRef(function ChartContainer(props: ChartCont plugins, children, } = props; - const svgRef = React.useRef(null); - const handleRef = useForkRef(ref, svgRef); - - const { xExtremumGetters, yExtremumGetters, seriesFormatters, colorProcessors } = - usePluginsMerge(plugins); - useReducedMotion(); // a11y reduce motion (see: https://react-spring.dev/docs/utilities/use-reduced-motion) + const { + svgRef, + handleRef, + xExtremumGetters, + yExtremumGetters, + seriesFormatters, + colorProcessors, + } = useChartContainerHooks(ref, plugins); return ( diff --git a/packages/x-charts/src/ChartContainer/useChartContainerHooks.ts b/packages/x-charts/src/ChartContainer/useChartContainerHooks.ts new file mode 100644 index 0000000000000..da8d4834f986b --- /dev/null +++ b/packages/x-charts/src/ChartContainer/useChartContainerHooks.ts @@ -0,0 +1,27 @@ +import useForkRef from '@mui/utils/useForkRef'; +import * as React from 'react'; +import { usePluginsMerge } from './usePluginsMerge'; +import { useReducedMotion } from '../hooks/useReducedMotion'; +import { ChartsPluginType } from '../models'; +import { ChartSeriesType } from '../models/seriesType/config'; + +export const useChartContainerHooks = ( + ref: React.ForwardedRef | null, + plugins?: ChartsPluginType[], +) => { + const svgRef = React.useRef(null); + const handleRef = useForkRef(ref, svgRef); + + const { xExtremumGetters, yExtremumGetters, seriesFormatters, colorProcessors } = + usePluginsMerge(plugins); + useReducedMotion(); // a11y reduce motion (see: https://react-spring.dev/docs/utilities/use-reduced-motion) + + return { + svgRef, + handleRef, + xExtremumGetters, + yExtremumGetters, + seriesFormatters, + colorProcessors, + }; +}; diff --git a/packages/x-charts/src/ChartContainer/usePluginsMerge.ts b/packages/x-charts/src/ChartContainer/usePluginsMerge.ts index ee1043e918f9c..b269bf79adfb1 100644 --- a/packages/x-charts/src/ChartContainer/usePluginsMerge.ts +++ b/packages/x-charts/src/ChartContainer/usePluginsMerge.ts @@ -1,7 +1,6 @@ import * as React from 'react'; -import { ChartsPluginType, ColorProcessorsConfig } from '../models'; +import { ChartsPluginType, ColorProcessorsConfig, ExtremumGettersConfig } from '../models'; import { ChartSeriesType } from '../models/seriesType/config'; -import { ExtremumGettersConfig } from '../context/CartesianContextProvider'; import { SeriesFormatterConfig } from '../context/SeriesContextProvider'; import { defaultPlugins } from './defaultPlugins'; diff --git a/packages/x-charts/src/ChartsAxis/ChartsAxis.tsx b/packages/x-charts/src/ChartsAxis/ChartsAxis.tsx index db42c36c7cb70..4212e2950954c 100644 --- a/packages/x-charts/src/ChartsAxis/ChartsAxis.tsx +++ b/packages/x-charts/src/ChartsAxis/ChartsAxis.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { ChartsXAxis } from '../ChartsXAxis'; import { ChartsYAxis } from '../ChartsYAxis'; import { @@ -49,8 +49,8 @@ export interface ChartsAxisProps { } const getAxisId = ( - propsValue: undefined | null | string | ChartsXAxisProps | ChartsYAxisProps, - defaultAxisId?: string, + propsValue: undefined | null | AxisId | ChartsXAxisProps | ChartsYAxisProps, + defaultAxisId?: AxisId, ): AxisId | null => { if (propsValue == null) { return null; @@ -62,7 +62,7 @@ const getAxisId = ( }; const mergeProps = ( - axisConfig: undefined | null | string | ChartsXAxisProps | ChartsYAxisProps, + axisConfig: undefined | null | AxisId | ChartsXAxisProps | ChartsYAxisProps, slots?: Partial, slotProps?: Partial, ) => { @@ -86,7 +86,7 @@ const mergeProps = ( */ function ChartsAxis(props: ChartsAxisProps) { const { topAxis, leftAxis, rightAxis, bottomAxis, slots, slotProps } = props; - const { xAxis, xAxisIds, yAxis, yAxisIds } = React.useContext(CartesianContext); + const { xAxis, xAxisIds, yAxis, yAxisIds } = useCartesianContext(); // TODO: use for plotting line without ticks or any thing // const drawingArea = React.useContext(DrawingContext); diff --git a/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.tsx b/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.tsx index d72082da7b8d0..6485c9c3f4d63 100644 --- a/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.tsx +++ b/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.tsx @@ -5,7 +5,7 @@ import generateUtilityClass from '@mui/utils/generateUtilityClass'; import generateUtilityClasses from '@mui/utils/generateUtilityClasses'; import { styled } from '@mui/material/styles'; import { InteractionContext } from '../context/InteractionProvider'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { getValueToPositionMapper } from '../hooks/useScale'; import { isBandScale } from '../internals/isBandScale'; @@ -67,7 +67,7 @@ export type ChartsAxisHighlightProps = { */ function ChartsAxisHighlight(props: ChartsAxisHighlightProps) { const { x: xAxisHighlight, y: yAxisHighlight } = props; - const { xAxisIds, xAxis, yAxisIds, yAxis } = React.useContext(CartesianContext); + const { xAxisIds, xAxis, yAxisIds, yAxis } = useCartesianContext(); const classes = useUtilityClasses(); const USED_X_AXIS_ID = xAxisIds[0]; diff --git a/packages/x-charts/src/ChartsGrid/ChartsGrid.tsx b/packages/x-charts/src/ChartsGrid/ChartsGrid.tsx index 01b2539a4ce96..c150244b2d39b 100644 --- a/packages/x-charts/src/ChartsGrid/ChartsGrid.tsx +++ b/packages/x-charts/src/ChartsGrid/ChartsGrid.tsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import composeClasses from '@mui/utils/composeClasses'; import { styled, useThemeProps } from '@mui/material/styles'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { useTicks } from '../hooks/useTicks'; import { ChartsGridClasses, @@ -69,7 +69,7 @@ function ChartsGrid(props: ChartsGridProps) { const themeProps = useThemeProps({ props, name: 'MuiChartsGrid' }); const { vertical, horizontal, ...other } = themeProps; - const { xAxis, xAxisIds, yAxis, yAxisIds } = React.useContext(CartesianContext); + const { xAxis, xAxisIds, yAxis, yAxisIds } = useCartesianContext(); const classes = useUtilityClasses(themeProps); diff --git a/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx b/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx index f134b0b2f5996..8710c72762a03 100644 --- a/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx +++ b/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { InteractionContext } from '../context/InteractionProvider'; -import { CartesianContext } from '../context/CartesianContextProvider'; import { useSeries } from '../hooks/useSeries'; import { useSvgRef } from '../hooks'; +import { useCartesianContext } from '../context/CartesianProvider'; type AxisData = { dataIndex: number; @@ -27,7 +27,7 @@ function ChartsOnAxisClickHandler(props: ChartsOnAxisClickHandlerProps) { const svgRef = useSvgRef(); const series = useSeries(); const { axis } = React.useContext(InteractionContext); - const { xAxisIds, xAxis, yAxisIds, yAxis } = React.useContext(CartesianContext); + const { xAxisIds, xAxis, yAxisIds, yAxis } = useCartesianContext(); React.useEffect(() => { const element = svgRef.current; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx index 8c34671584f9b..4784d5559bf74 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { SxProps, Theme } from '@mui/material/styles'; import { useSlotProps } from '@mui/base/utils'; import { AxisInteractionData } from '../context/InteractionProvider'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { ChartSeriesDefaultized, ChartSeriesType } from '../models/seriesType/config'; import { AxisDefaultized } from '../models/axis'; import { ChartsTooltipClasses } from './chartsTooltipClasses'; @@ -61,7 +61,7 @@ function ChartsAxisTooltipContent(props: { const dataIndex = isXaxis ? axisData.x && axisData.x.index : axisData.y && axisData.y.index; const axisValue = isXaxis ? axisData.x && axisData.x.value : axisData.y && axisData.y.value; - const { xAxisIds, xAxis, yAxisIds, yAxis } = React.useContext(CartesianContext); + const { xAxisIds, xAxis, yAxisIds, yAxis } = useCartesianContext(); const { zAxisIds, zAxis } = React.useContext(ZAxisContext); const series = useSeries(); diff --git a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx index 8c2fa7c8e6bef..099921b4bf330 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx @@ -5,7 +5,7 @@ import { ItemInteractionData } from '../context/InteractionProvider'; import { ChartSeriesDefaultized, ChartSeriesType } from '../models/seriesType/config'; import { ChartsTooltipClasses } from './chartsTooltipClasses'; import { DefaultChartsItemTooltipContent } from './DefaultChartsItemTooltipContent'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { ZAxisContext } from '../context/ZAxisContextProvider'; import { useColorProcessor } from '../hooks/useColor'; import { useSeries } from '../hooks/useSeries'; @@ -50,7 +50,7 @@ function ChartsItemTooltipContent( const series = useSeries()[itemData.type]!.series[itemData.seriesId] as ChartSeriesDefaultized; - const { xAxis, yAxis, xAxisIds, yAxisIds } = React.useContext(CartesianContext); + const { xAxis, yAxis, xAxisIds, yAxisIds } = useCartesianContext(); const { zAxis, zAxisIds } = React.useContext(ZAxisContext); const colorProcessors = useColorProcessor(); diff --git a/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx b/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx index 170c4a71e1123..d9812c0b3baaa 100644 --- a/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx +++ b/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { Delaunay } from 'd3-delaunay'; import useEnhancedEffect from '@mui/utils/useEnhancedEffect'; import { InteractionContext } from '../context/InteractionProvider'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { getValueToPositionMapper } from '../hooks/useScale'; import { getSVGPoint } from '../internals/utils'; import { ScatterItemIdentifier } from '../models'; @@ -32,7 +32,7 @@ function ChartsVoronoiHandler(props: ChartsVoronoiHandlerProps) { const { voronoiMaxRadius, onItemClick } = props; const svgRef = useSvgRef(); const { left, top, width, height } = useDrawingArea(); - const { xAxis, yAxis, xAxisIds, yAxisIds } = React.useContext(CartesianContext); + const { xAxis, yAxis, xAxisIds, yAxisIds } = useCartesianContext(); const { dispatch } = React.useContext(InteractionContext); const { series, seriesOrder } = useScatterSeries() ?? {}; diff --git a/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx b/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx index 98146ac637d4b..ea796b2e333ec 100644 --- a/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx +++ b/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { useSlotProps } from '@mui/base/utils'; import { unstable_composeClasses as composeClasses } from '@mui/utils'; import { useThemeProps, useTheme, Theme } from '@mui/material/styles'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { useTicks, TickItemType } from '../hooks/useTicks'; import { AxisDefaultized, ChartsXAxisProps } from '../models/axis'; import { getAxisUtilityClass } from '../ChartsAxis/axisClasses'; @@ -98,7 +98,7 @@ const defaultProps = { * - [ChartsXAxis API](https://mui.com/x/api/charts/charts-x-axis/) */ function ChartsXAxis(inProps: ChartsXAxisProps) { - const { xAxisIds, xAxis } = React.useContext(CartesianContext); + const { xAxisIds, xAxis } = useCartesianContext(); const { scale: xScale, tickNumber, reverse, ...settings } = xAxis[inProps.axisId ?? xAxisIds[0]]; const isMounted = useMounted(); diff --git a/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx b/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx index 784ed2640ca06..44475ad90f1f6 100644 --- a/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx +++ b/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { useSlotProps } from '@mui/base/utils'; import { unstable_composeClasses as composeClasses } from '@mui/utils'; import { useThemeProps, useTheme, Theme } from '@mui/material/styles'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { useTicks } from '../hooks/useTicks'; import { useDrawingArea } from '../hooks/useDrawingArea'; import { ChartsYAxisProps } from '../models/axis'; @@ -44,7 +44,7 @@ const defaultProps = { * - [ChartsYAxis API](https://mui.com/x/api/charts/charts-y-axis/) */ function ChartsYAxis(inProps: ChartsYAxisProps) { - const { yAxisIds, yAxis } = React.useContext(CartesianContext); + const { yAxisIds, yAxis } = useCartesianContext(); const { scale: yScale, tickNumber, ...settings } = yAxis[inProps.axisId ?? yAxisIds[0]]; const themedProps = useThemeProps({ props: { ...settings, ...inProps }, name: 'MuiChartsYAxis' }); diff --git a/packages/x-charts/src/LineChart/AreaPlot.tsx b/packages/x-charts/src/LineChart/AreaPlot.tsx index 51a62066c83ac..daa51ea9d69ab 100644 --- a/packages/x-charts/src/LineChart/AreaPlot.tsx +++ b/packages/x-charts/src/LineChart/AreaPlot.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { area as d3Area } from 'd3-shape'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { AreaElement, AreaElementProps, @@ -14,6 +14,7 @@ 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 { AxisId } from '../models/axis'; export interface AreaPlotSlots extends AreaElementSlots {} @@ -35,7 +36,7 @@ export interface AreaPlotProps const useAggregatedData = () => { const seriesData = useLineSeries(); - const axisData = React.useContext(CartesianContext); + const axisData = useCartesianContext(); if (seriesData === undefined) { return []; @@ -62,7 +63,7 @@ const useAggregatedData = () => { const yScale = yAxis[yAxisKey].scale; const xData = xAxis[xAxisKey].data; - const gradientUsed: [string, 'x' | 'y'] | undefined = + const gradientUsed: [AxisId, 'x' | 'y'] | undefined = (yAxis[yAxisKey].colorScale && [yAxisKey, 'y']) || (xAxis[xAxisKey].colorScale && [xAxisKey, 'x']) || undefined; diff --git a/packages/x-charts/src/LineChart/LineHighlightPlot.tsx b/packages/x-charts/src/LineChart/LineHighlightPlot.tsx index 25343dd4c129c..d183bd73042d7 100644 --- a/packages/x-charts/src/LineChart/LineHighlightPlot.tsx +++ b/packages/x-charts/src/LineChart/LineHighlightPlot.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { LineHighlightElement, LineHighlightElementProps } from './LineHighlightElement'; import { getValueToPositionMapper } from '../hooks/useScale'; import { InteractionContext } from '../context/InteractionProvider'; @@ -43,7 +43,7 @@ function LineHighlightPlot(props: LineHighlightPlotProps) { const { slots, slotProps, ...other } = props; const seriesData = useLineSeries(); - const axisData = React.useContext(CartesianContext); + const axisData = useCartesianContext(); const { axis } = React.useContext(InteractionContext); const highlightedIndex = axis.x?.index; diff --git a/packages/x-charts/src/LineChart/LinePlot.tsx b/packages/x-charts/src/LineChart/LinePlot.tsx index 7e09416d2f960..6ee5d39eabf1a 100644 --- a/packages/x-charts/src/LineChart/LinePlot.tsx +++ b/packages/x-charts/src/LineChart/LinePlot.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { line as d3Line } from 'd3-shape'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { LineElement, LineElementProps, @@ -14,6 +14,7 @@ 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 { AxisId } from '../models/axis'; export interface LinePlotSlots extends LineElementSlots {} @@ -35,7 +36,7 @@ export interface LinePlotProps const useAggregatedData = () => { const seriesData = useLineSeries(); - const axisData = React.useContext(CartesianContext); + const axisData = useCartesianContext(); if (seriesData === undefined) { return []; @@ -60,7 +61,7 @@ const useAggregatedData = () => { const yScale = yAxis[yAxisKey].scale; const xData = xAxis[xAxisKey].data; - const gradientUsed: [string, 'x' | 'y'] | undefined = + const gradientUsed: [AxisId, 'x' | 'y'] | undefined = (yAxis[yAxisKey].colorScale && [yAxisKey, 'y']) || (xAxis[xAxisKey].colorScale && [xAxisKey, 'x']) || undefined; diff --git a/packages/x-charts/src/LineChart/MarkPlot.tsx b/packages/x-charts/src/LineChart/MarkPlot.tsx index 23c7695f443e4..ceecfbb0b6f77 100644 --- a/packages/x-charts/src/LineChart/MarkPlot.tsx +++ b/packages/x-charts/src/LineChart/MarkPlot.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { MarkElement, MarkElementProps } from './MarkElement'; import { getValueToPositionMapper } from '../hooks/useScale'; import { useChartId } from '../hooks/useChartId'; @@ -56,7 +56,7 @@ function MarkPlot(props: MarkPlotProps) { const { slots, slotProps, skipAnimation, onItemClick, ...other } = props; const seriesData = useLineSeries(); - const axisData = React.useContext(CartesianContext); + const axisData = useCartesianContext(); const chartId = useChartId(); const Mark = slots?.mark ?? MarkElement; diff --git a/packages/x-charts/src/ScatterChart/ScatterPlot.tsx b/packages/x-charts/src/ScatterChart/ScatterPlot.tsx index 9b4129a1fa0cc..0bdc7c1060a2d 100644 --- a/packages/x-charts/src/ScatterChart/ScatterPlot.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterPlot.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { Scatter, ScatterProps } from './Scatter'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import getColor from './getColor'; import { ZAxisContext } from '../context/ZAxisContextProvider'; import { useScatterSeries } from '../hooks/useSeries'; @@ -40,7 +40,7 @@ export interface ScatterPlotProps extends Pick { function ScatterPlot(props: ScatterPlotProps) { const { slots, slotProps, onItemClick } = props; const seriesData = useScatterSeries(); - const axisData = React.useContext(CartesianContext); + const axisData = useCartesianContext(); const { zAxis, zAxisIds } = React.useContext(ZAxisContext); if (seriesData === undefined) { diff --git a/packages/x-charts/src/context/CartesianContextProvider.tsx b/packages/x-charts/src/context/CartesianContextProvider.tsx deleted file mode 100644 index 9a97fbd6e807b..0000000000000 --- a/packages/x-charts/src/context/CartesianContextProvider.tsx +++ /dev/null @@ -1,358 +0,0 @@ -import * as React from 'react'; -import { scaleBand, scalePoint } from 'd3-scale'; -import { - AxisConfig, - AxisDefaultized, - ChartsXAxisProps, - ChartsYAxisProps, - ScaleName, - isBandScaleConfig, - isPointScaleConfig, -} from '../models/axis'; -import { getScale } from '../internals/getScale'; -import { DEFAULT_X_AXIS_KEY, DEFAULT_Y_AXIS_KEY } from '../constants'; -import { - CartesianChartSeriesType, - ChartSeriesType, - ChartSeries, - DatasetType, - ExtremumGetter, - ExtremumGetterResult, -} from '../models/seriesType/config'; -import { MakeOptional } from '../models/helpers'; -import { getTickNumber } from '../hooks/useTicks'; -import { useDrawingArea } from '../hooks/useDrawingArea'; -import { SeriesId } from '../models/seriesType/common'; -import { getColorScale, getOrdinalColorScale } from '../internals/colorScale'; -import { useSeries } from '../hooks/useSeries'; - -export type ExtremumGettersConfig = { - [K in T]?: ExtremumGetter; -}; - -export type CartesianContextProviderProps = { - /** - * The configuration of the x-axes. - * If not provided, a default axis config is used. - * An array of [[AxisConfig]] objects. - */ - xAxis?: MakeOptional, 'id'>[]; - /** - * The configuration of the y-axes. - * If not provided, a default axis config is used. - * An array of [[AxisConfig]] objects. - */ - yAxis?: MakeOptional, 'id'>[]; - /** - * An array of objects that can be used to populate series and axes data using their `dataKey` property. - */ - dataset?: DatasetType; - /** - * An object with x-axis extremum getters per series type. - */ - xExtremumGetters: ExtremumGettersConfig; - /** - * An object with y-axis extremum getters per series type. - */ - yExtremumGetters: ExtremumGettersConfig; - children: React.ReactNode; -}; - -const DEFAULT_CATEGORY_GAP_RATIO = 0.2; -const DEFAULT_BAR_GAP_RATIO = 0.1; - -type DefaultizedAxisConfig = { - [axisKey: string]: AxisDefaultized; -}; - -export const CartesianContext = React.createContext<{ - /** - * Mapping from x-axis key to scaling configuration. - */ - xAxis: { - DEFAULT_X_AXIS_KEY: AxisDefaultized; - } & DefaultizedAxisConfig; - /** - * Mapping from y-axis key to scaling configuration. - */ - yAxis: { - DEFAULT_X_AXIS_KEY: AxisDefaultized; - } & DefaultizedAxisConfig; - /** - * The x-axes IDs sorted by order they got provided. - */ - xAxisIds: string[]; - /** - * The y-axes IDs sorted by order they got provided. - */ - yAxisIds: string[]; - // @ts-ignore -}>({ xAxis: {}, yAxis: {}, xAxisIds: [], yAxisIds: [] }); - -if (process.env.NODE_ENV !== 'production') { - CartesianContext.displayName = 'CartesianContext'; -} - -function CartesianContextProvider(props: CartesianContextProviderProps) { - const { - xAxis: inXAxis, - yAxis: inYAxis, - dataset, - xExtremumGetters, - yExtremumGetters, - children, - } = props; - const formattedSeries = useSeries(); - const drawingArea = useDrawingArea(); - - const xAxis = React.useMemo( - () => - inXAxis?.map((axisConfig) => { - const dataKey = axisConfig.dataKey; - if (dataKey === undefined || axisConfig.data !== undefined) { - return axisConfig; - } - if (dataset === undefined) { - throw Error('MUI X Charts: x-axis uses `dataKey` but no `dataset` is provided.'); - } - return { - ...axisConfig, - data: dataset.map((d) => d[dataKey]), - }; - }), - [inXAxis, dataset], - ); - - const yAxis = React.useMemo( - () => - inYAxis?.map((axisConfig) => { - const dataKey = axisConfig.dataKey; - if (dataKey === undefined || axisConfig.data !== undefined) { - return axisConfig; - } - if (dataset === undefined) { - throw Error('MUI X Charts: y-axis uses `dataKey` but no `dataset` is provided.'); - } - return { - ...axisConfig, - data: dataset.map((d) => d[dataKey]), - }; - }), - [inYAxis, dataset], - ); - - const value = React.useMemo(() => { - const axisExtremumCallback = ( - acc: ExtremumGetterResult, - chartType: T, - axis: AxisConfig, - getters: { [T2 in CartesianChartSeriesType]?: ExtremumGetter }, - isDefaultAxis: boolean, - ): ExtremumGetterResult => { - const getter = getters[chartType]; - const series = (formattedSeries[chartType]?.series as Record>) ?? {}; - - const [minChartTypeData, maxChartTypeData] = getter?.({ - series, - axis, - isDefaultAxis, - }) ?? [null, null]; - - const [minData, maxData] = acc; - - if (minData === null || maxData === null) { - return [minChartTypeData!, maxChartTypeData!]; - } - - if (minChartTypeData === null || maxChartTypeData === null) { - return [minData, maxData]; - } - - return [Math.min(minChartTypeData, minData), Math.max(maxChartTypeData, maxData)]; - }; - - const getAxisExtremum = ( - axis: AxisConfig, - getters: { [T in CartesianChartSeriesType]?: ExtremumGetter }, - isDefaultAxis: boolean, - ) => { - const charTypes = Object.keys(getters) as CartesianChartSeriesType[]; - - return charTypes.reduce( - (acc, charType) => axisExtremumCallback(acc, charType, axis, getters, isDefaultAxis), - [null, null] as ExtremumGetterResult, - ); - }; - - const allXAxis = [ - ...(xAxis?.map((axis, index) => ({ id: `defaultized-x-axis-${index}`, ...axis })) ?? []), - // Allows to specify an axis with id=DEFAULT_X_AXIS_KEY - ...(xAxis === undefined || xAxis.findIndex(({ id }) => id === DEFAULT_X_AXIS_KEY) === -1 - ? [ - { id: DEFAULT_X_AXIS_KEY, scaleType: 'linear' } as AxisConfig< - ScaleName, - any, - ChartsXAxisProps - >, - ] - : []), - ]; - - const completedXAxis: DefaultizedAxisConfig = {}; - allXAxis.forEach((axis, axisIndex) => { - const isDefaultAxis = axisIndex === 0; - const [minData, maxData] = getAxisExtremum(axis, xExtremumGetters, isDefaultAxis); - - const range = axis.reverse - ? [drawingArea.left + drawingArea.width, drawingArea.left] - : [drawingArea.left, drawingArea.left + drawingArea.width]; - - if (isBandScaleConfig(axis)) { - const categoryGapRatio = axis.categoryGapRatio ?? DEFAULT_CATEGORY_GAP_RATIO; - const barGapRatio = axis.barGapRatio ?? DEFAULT_BAR_GAP_RATIO; - completedXAxis[axis.id] = { - categoryGapRatio, - barGapRatio, - ...axis, - scale: scaleBand(axis.data!, range) - .paddingInner(categoryGapRatio) - .paddingOuter(categoryGapRatio / 2), - tickNumber: axis.data!.length, - colorScale: - axis.colorMap && - (axis.colorMap.type === 'ordinal' - ? getOrdinalColorScale({ values: axis.data, ...axis.colorMap }) - : getColorScale(axis.colorMap)), - }; - } - if (isPointScaleConfig(axis)) { - completedXAxis[axis.id] = { - ...axis, - scale: scalePoint(axis.data!, range), - tickNumber: axis.data!.length, - colorScale: - axis.colorMap && - (axis.colorMap.type === 'ordinal' - ? getOrdinalColorScale({ values: axis.data, ...axis.colorMap }) - : getColorScale(axis.colorMap)), - }; - } - if (axis.scaleType === 'band' || axis.scaleType === 'point') { - // Could be merged with the two previous "if conditions" but then TS does not get that `axis.scaleType` can't be `band` or `point`. - return; - } - - const scaleType = axis.scaleType ?? 'linear'; - - const extremums = [axis.min ?? minData, axis.max ?? maxData]; - const tickNumber = getTickNumber({ ...axis, range, domain: extremums }); - - const niceScale = getScale(scaleType, extremums, range).nice(tickNumber); - const niceDomain = niceScale.domain(); - const domain = [axis.min ?? niceDomain[0], axis.max ?? niceDomain[1]]; - - completedXAxis[axis.id] = { - ...axis, - scaleType, - scale: niceScale.domain(domain), - tickNumber, - colorScale: axis.colorMap && getColorScale(axis.colorMap), - } as AxisDefaultized; - }); - - const allYAxis = [ - ...(yAxis?.map((axis, index) => ({ id: `defaultized-y-axis-${index}`, ...axis })) ?? []), - ...(yAxis === undefined || yAxis.findIndex(({ id }) => id === DEFAULT_Y_AXIS_KEY) === -1 - ? [ - { id: DEFAULT_Y_AXIS_KEY, scaleType: 'linear' } as AxisConfig< - ScaleName, - any, - ChartsYAxisProps - >, - ] - : []), - ]; - - const completedYAxis: DefaultizedAxisConfig = {}; - allYAxis.forEach((axis, axisIndex) => { - const isDefaultAxis = axisIndex === 0; - const [minData, maxData] = getAxisExtremum(axis, yExtremumGetters, isDefaultAxis); - const range = axis.reverse - ? [drawingArea.top, drawingArea.top + drawingArea.height] - : [drawingArea.top + drawingArea.height, drawingArea.top]; - - if (isBandScaleConfig(axis)) { - const categoryGapRatio = axis.categoryGapRatio ?? DEFAULT_CATEGORY_GAP_RATIO; - completedYAxis[axis.id] = { - categoryGapRatio, - barGapRatio: 0, - ...axis, - scale: scaleBand(axis.data!, [range[1], range[0]]) - .paddingInner(categoryGapRatio) - .paddingOuter(categoryGapRatio / 2), - tickNumber: axis.data!.length, - colorScale: - axis.colorMap && - (axis.colorMap.type === 'ordinal' - ? getOrdinalColorScale({ values: axis.data, ...axis.colorMap }) - : getColorScale(axis.colorMap)), - }; - } - if (isPointScaleConfig(axis)) { - completedYAxis[axis.id] = { - ...axis, - scale: scalePoint(axis.data!, [range[1], range[0]]), - tickNumber: axis.data!.length, - colorScale: - axis.colorMap && - (axis.colorMap.type === 'ordinal' - ? getOrdinalColorScale({ values: axis.data, ...axis.colorMap }) - : getColorScale(axis.colorMap)), - }; - } - if (axis.scaleType === 'band' || axis.scaleType === 'point') { - // Could be merged with the two previous "if conditions" but then TS does not get that `axis.scaleType` can't be `band` or `point`. - return; - } - - const scaleType = axis.scaleType ?? 'linear'; - - const extremums = [axis.min ?? minData, axis.max ?? maxData]; - const tickNumber = getTickNumber({ ...axis, range, domain: extremums }); - - const niceScale = getScale(scaleType, extremums, range).nice(tickNumber); - const niceDomain = niceScale.domain(); - const domain = [axis.min ?? niceDomain[0], axis.max ?? niceDomain[1]]; - - completedYAxis[axis.id] = { - ...axis, - scaleType, - scale: niceScale.domain(domain), - tickNumber, - colorScale: axis.colorMap && getColorScale(axis.colorMap), - } as AxisDefaultized; - }); - - return { - xAxis: completedXAxis, - yAxis: completedYAxis, - xAxisIds: allXAxis.map(({ id }) => id), - yAxisIds: allYAxis.map(({ id }) => id), - }; - }, [ - drawingArea.height, - drawingArea.left, - drawingArea.top, - drawingArea.width, - formattedSeries, - xAxis, - xExtremumGetters, - yAxis, - yExtremumGetters, - ]); - - // @ts-ignore - return {children}; -} - -export { CartesianContextProvider }; diff --git a/packages/x-charts/src/context/CartesianProvider/CartesianContext.ts b/packages/x-charts/src/context/CartesianProvider/CartesianContext.ts new file mode 100644 index 0000000000000..6406b1e42dcc2 --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/CartesianContext.ts @@ -0,0 +1,47 @@ +import * as React from 'react'; + +import { Initializable } from '../context.types'; +import { + AxisDefaultized, + ScaleName, + ChartsXAxisProps, + ChartsYAxisProps, + AxisId, +} from '../../models/axis'; + +export type DefaultizedAxisConfig = { + [axisKey: AxisId]: AxisDefaultized; +}; + +export type CartesianContextState = { + /** + * Mapping from x-axis key to scaling configuration. + */ + xAxis: DefaultizedAxisConfig; + /** + * Mapping from y-axis key to scaling configuration. + */ + yAxis: DefaultizedAxisConfig; + /** + * The x-axes IDs sorted by order they got provided. + */ + xAxisIds: AxisId[]; + /** + * The y-axes IDs sorted by order they got provided. + */ + yAxisIds: AxisId[]; +}; + +export const CartesianContext = React.createContext>({ + isInitialized: false, + data: { + xAxis: {}, + yAxis: {}, + xAxisIds: [], + yAxisIds: [], + }, +}); + +if (process.env.NODE_ENV !== 'production') { + CartesianContext.displayName = 'CartesianContext'; +} diff --git a/packages/x-charts/src/context/CartesianProvider/CartesianProvider.tsx b/packages/x-charts/src/context/CartesianProvider/CartesianProvider.tsx new file mode 100644 index 0000000000000..847f9e553afdc --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/CartesianProvider.tsx @@ -0,0 +1,83 @@ +import * as React from 'react'; +import { AxisConfig, ChartsXAxisProps, ChartsYAxisProps, ScaleName } from '../../models/axis'; +import { DatasetType } from '../../models/seriesType/config'; +import { MakeOptional } from '../../models/helpers'; +import { useDrawingArea } from '../../hooks/useDrawingArea'; +import { useSeries } from '../../hooks/useSeries'; +import { CartesianContext } from './CartesianContext'; +import { normalizeAxis } from './normalizeAxis'; +import { computeValue } from './computeValue'; +import { ExtremumGettersConfig } from '../../models'; + +export type CartesianContextProviderProps = { + /** + * The configuration of the x-axes. + * If not provided, a default axis config is used. + * An array of [[AxisConfig]] objects. + */ + xAxis?: MakeOptional, 'id'>[]; + /** + * The configuration of the y-axes. + * If not provided, a default axis config is used. + * An array of [[AxisConfig]] objects. + */ + yAxis?: MakeOptional, 'id'>[]; + /** + * An array of objects that can be used to populate series and axes data using their `dataKey` property. + */ + dataset?: DatasetType; + /** + * An object with x-axis extremum getters per series type. + */ + xExtremumGetters: ExtremumGettersConfig; + /** + * An object with y-axis extremum getters per series type. + */ + yExtremumGetters: ExtremumGettersConfig; + children: React.ReactNode; +}; + +function CartesianContextProvider(props: CartesianContextProviderProps) { + const { + xAxis: inXAxis, + yAxis: inYAxis, + dataset, + xExtremumGetters, + yExtremumGetters, + children, + } = props; + + const formattedSeries = useSeries(); + const drawingArea = useDrawingArea(); + + const xAxis = React.useMemo(() => normalizeAxis(inXAxis, dataset, 'x'), [inXAxis, dataset]); + + const yAxis = React.useMemo(() => normalizeAxis(inYAxis, dataset, 'y'), [inYAxis, dataset]); + + const xValues = React.useMemo( + () => computeValue(drawingArea, formattedSeries, xAxis, xExtremumGetters, 'x'), + [drawingArea, formattedSeries, xAxis, xExtremumGetters], + ); + + const yValues = React.useMemo( + () => computeValue(drawingArea, formattedSeries, yAxis, yExtremumGetters, 'y'), + [drawingArea, formattedSeries, yAxis, yExtremumGetters], + ); + + const value = React.useMemo( + () => ({ + isInitialized: true, + data: { + xAxis: xValues.axis, + yAxis: yValues.axis, + xAxisIds: xValues.axisIds, + yAxisIds: yValues.axisIds, + }, + }), + [xValues, yValues], + ); + + return {children}; +} + +export { CartesianContextProvider }; diff --git a/packages/x-charts/src/context/CartesianProvider/computeValue.ts b/packages/x-charts/src/context/CartesianProvider/computeValue.ts new file mode 100644 index 0000000000000..053b51cf1afd6 --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/computeValue.ts @@ -0,0 +1,144 @@ +import { scaleBand, scalePoint } from 'd3-scale'; +import { DEFAULT_X_AXIS_KEY, DEFAULT_Y_AXIS_KEY } from '../../constants'; +import { AxisConfig, ScaleName } from '../../models'; +import { + ChartsXAxisProps, + ChartsAxisProps, + ChartsYAxisProps, + isBandScaleConfig, + isPointScaleConfig, +} from '../../models/axis'; +import { CartesianChartSeriesType, ExtremumGetter } from '../../models/seriesType/config'; +import { DefaultizedAxisConfig } from './CartesianContext'; +import { getColorScale, getOrdinalColorScale } from '../../internals/colorScale'; +import { getTickNumber } from '../../hooks/useTicks'; +import { getScale } from '../../internals/getScale'; +import { DrawingArea } from '../DrawingProvider'; +import { FormattedSeries } from '../SeriesContextProvider'; +import { MakeOptional } from '../../models/helpers'; +import { getAxisExtremum } from './getAxisExtremum'; + +const getRange = (drawingArea: DrawingArea, axisName: 'x' | 'y', isReverse?: boolean) => { + const range = + axisName === 'x' + ? [drawingArea.left, drawingArea.left + drawingArea.width] + : [drawingArea.top + drawingArea.height, drawingArea.top]; + + return isReverse ? range.reverse() : range; +}; + +const DEFAULT_CATEGORY_GAP_RATIO = 0.2; +const DEFAULT_BAR_GAP_RATIO = 0.1; + +export function computeValue( + drawingArea: DrawingArea, + formattedSeries: FormattedSeries, + axis: MakeOptional, 'id'>[] | undefined, + extremumGetters: { [K in CartesianChartSeriesType]?: ExtremumGetter }, + axisName: 'y', +): { + axis: DefaultizedAxisConfig; + axisIds: string[]; +}; +export function computeValue( + drawingArea: DrawingArea, + formattedSeries: FormattedSeries, + inAxis: MakeOptional, 'id'>[] | undefined, + extremumGetters: { [K in CartesianChartSeriesType]?: ExtremumGetter }, + axisName: 'x', +): { + axis: DefaultizedAxisConfig; + axisIds: string[]; +}; +export function computeValue( + drawingArea: DrawingArea, + formattedSeries: FormattedSeries, + inAxis: MakeOptional, 'id'>[] | undefined, + extremumGetters: { [K in CartesianChartSeriesType]?: ExtremumGetter }, + axisName: 'x' | 'y', +) { + const DEFAULT_AXIS_KEY = axisName === 'x' ? DEFAULT_X_AXIS_KEY : DEFAULT_Y_AXIS_KEY; + + const allAxis: AxisConfig[] = [ + ...(inAxis?.map((axis, index) => ({ id: `defaultized-${axisName}-axis-${index}`, ...axis })) ?? + []), + ...(inAxis === undefined || inAxis.findIndex(({ id }) => id === DEFAULT_AXIS_KEY) === -1 + ? [{ id: DEFAULT_AXIS_KEY, scaleType: 'linear' as const }] + : []), + ]; + + const completeAxis: DefaultizedAxisConfig = {}; + allAxis.forEach((axis, axisIndex) => { + const isDefaultAxis = axisIndex === 0; + const [minData, maxData] = getAxisExtremum( + axis, + extremumGetters, + isDefaultAxis, + formattedSeries, + ); + + const range = getRange(drawingArea, axisName, axis.reverse); + + if (isBandScaleConfig(axis)) { + const categoryGapRatio = axis.categoryGapRatio ?? DEFAULT_CATEGORY_GAP_RATIO; + const barGapRatio = axis.barGapRatio ?? DEFAULT_BAR_GAP_RATIO; + // Reverse range because ordinal scales are presented from top to bottom on y-axis + const scaleRange = axisName === 'x' ? range : [range[1], range[0]]; + + completeAxis[axis.id] = { + categoryGapRatio, + barGapRatio, + ...axis, + scale: scaleBand(axis.data!, scaleRange) + .paddingInner(categoryGapRatio) + .paddingOuter(categoryGapRatio / 2), + tickNumber: axis.data!.length, + colorScale: + axis.colorMap && + (axis.colorMap.type === 'ordinal' + ? getOrdinalColorScale({ values: axis.data, ...axis.colorMap }) + : getColorScale(axis.colorMap)), + }; + } + if (isPointScaleConfig(axis)) { + const scaleRange = axisName === 'x' ? range : [...range].reverse(); + + completeAxis[axis.id] = { + ...axis, + scale: scalePoint(axis.data!, scaleRange), + tickNumber: axis.data!.length, + colorScale: + axis.colorMap && + (axis.colorMap.type === 'ordinal' + ? getOrdinalColorScale({ values: axis.data, ...axis.colorMap }) + : getColorScale(axis.colorMap)), + }; + } + if (axis.scaleType === 'band' || axis.scaleType === 'point') { + // Could be merged with the two previous "if conditions" but then TS does not get that `axis.scaleType` can't be `band` or `point`. + return; + } + + const scaleType = axis.scaleType ?? ('linear' as const); + + const extremums = [axis.min ?? minData, axis.max ?? maxData]; + const tickNumber = getTickNumber({ ...axis, range, domain: extremums }); + + const scale = getScale(scaleType, extremums, range).nice(tickNumber); + const [minDomain, maxDomain] = scale.domain(); + const domain = [axis.min ?? minDomain, axis.max ?? maxDomain]; + + completeAxis[axis.id] = { + ...axis, + scaleType: scaleType as any, + scale: scale.domain(domain) as any, + tickNumber, + colorScale: axis.colorMap && getColorScale(axis.colorMap), + }; + }); + + return { + axis: completeAxis, + axisIds: allAxis.map(({ id }) => id), + }; +} diff --git a/packages/x-charts/src/context/CartesianProvider/getAxisExtremum.ts b/packages/x-charts/src/context/CartesianProvider/getAxisExtremum.ts new file mode 100644 index 0000000000000..43a16a657cd4a --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/getAxisExtremum.ts @@ -0,0 +1,48 @@ +import { AxisConfig, ExtremumGettersConfig } from '../../models'; +import { CartesianChartSeriesType, ExtremumGetterResult } from '../../models/seriesType/config'; +import { FormattedSeries } from '../SeriesContextProvider'; + +const axisExtremumCallback = ( + acc: ExtremumGetterResult, + chartType: T, + axis: AxisConfig, + getters: ExtremumGettersConfig, + isDefaultAxis: boolean, + formattedSeries: FormattedSeries, +): ExtremumGetterResult => { + const getter = getters[chartType]; + const series = formattedSeries[chartType]?.series ?? {}; + + const [minChartTypeData, maxChartTypeData] = getter?.({ + series, + axis, + isDefaultAxis, + }) ?? [null, null]; + + const [minData, maxData] = acc; + + if (minData === null || maxData === null) { + return [minChartTypeData!, maxChartTypeData!]; + } + + if (minChartTypeData === null || maxChartTypeData === null) { + return [minData, maxData]; + } + + return [Math.min(minChartTypeData, minData), Math.max(maxChartTypeData, maxData)]; +}; + +export const getAxisExtremum = ( + axis: AxisConfig, + getters: ExtremumGettersConfig, + isDefaultAxis: boolean, + formattedSeries: FormattedSeries, +) => { + const charTypes = Object.keys(getters) as CartesianChartSeriesType[]; + + return charTypes.reduce( + (acc, charType) => + axisExtremumCallback(acc, charType, axis, getters, isDefaultAxis, formattedSeries), + [null, null], + ); +}; diff --git a/packages/x-charts/src/context/CartesianProvider/index.ts b/packages/x-charts/src/context/CartesianProvider/index.ts new file mode 100644 index 0000000000000..b9f4f07059dcb --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/index.ts @@ -0,0 +1,13 @@ +import { computeValue } from './computeValue'; +import { normalizeAxis } from './normalizeAxis'; + +export * from './CartesianProvider'; +export * from './CartesianContext'; +export * from './useCartesianContext'; + +const cartesianProviderUtils = { + computeValue, + normalizeAxis, +}; + +export { cartesianProviderUtils }; diff --git a/packages/x-charts/src/context/CartesianProvider/normalizeAxis.ts b/packages/x-charts/src/context/CartesianProvider/normalizeAxis.ts new file mode 100644 index 0000000000000..619eccdf40a65 --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/normalizeAxis.ts @@ -0,0 +1,29 @@ +import type { AxisConfig, ScaleName } from '../../models'; +import { ChartsAxisProps } from '../../models/axis'; +import { MakeOptional } from '../../models/helpers'; +import { DatasetType } from '../../models/seriesType/config'; + +export const normalizeAxis = < + T extends ChartsAxisProps, + R extends MakeOptional, 'id'>, +>( + axis: R[] | undefined, + dataset: DatasetType | undefined, + axisName: 'x' | 'y', +): R[] | undefined => { + return axis?.map((axisConfig) => { + const dataKey = axisConfig.dataKey; + if (dataKey === undefined || axisConfig.data !== undefined) { + return axisConfig; + } + if (dataset === undefined) { + throw Error( + `MUI X Charts: ${axisName}-axis uses \`dataKey\` but no \`dataset\` is provided.`, + ); + } + return { + ...axisConfig, + data: dataset.map((d) => d[dataKey]), + }; + }); +}; diff --git a/packages/x-charts/src/context/CartesianProvider/useCartesianContext.ts b/packages/x-charts/src/context/CartesianProvider/useCartesianContext.ts new file mode 100644 index 0000000000000..ee53769587459 --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/useCartesianContext.ts @@ -0,0 +1,7 @@ +import * as React from 'react'; +import { CartesianContext, CartesianContextState } from './CartesianContext'; + +export const useCartesianContext = (): CartesianContextState => { + const { data } = React.useContext(CartesianContext); + return data; +}; diff --git a/packages/x-charts/src/context/ColorProvider.tsx b/packages/x-charts/src/context/ColorProvider.tsx index 46faebddded34..e7061912c086d 100644 --- a/packages/x-charts/src/context/ColorProvider.tsx +++ b/packages/x-charts/src/context/ColorProvider.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { ColorProcessorsConfig } from '../models'; -import { ChartSeriesType } from '../internals'; +import { ChartSeriesType } from '../models/seriesType/config'; export interface ColorProviderProps { children: React.ReactNode; diff --git a/packages/x-charts/src/hooks/useAxisEvents.ts b/packages/x-charts/src/hooks/useAxisEvents.ts index 0663d1655ae2a..855ec5985c1aa 100644 --- a/packages/x-charts/src/hooks/useAxisEvents.ts +++ b/packages/x-charts/src/hooks/useAxisEvents.ts @@ -1,6 +1,6 @@ import * as React from 'react'; import { InteractionContext } from '../context/InteractionProvider'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { isBandScale } from '../internals/isBandScale'; import { AxisDefaultized } from '../models/axis'; import { getSVGPoint } from '../internals/utils'; @@ -13,7 +13,7 @@ function getAsANumber(value: number | Date) { export const useAxisEvents = (disableAxisListener: boolean) => { const svgRef = useSvgRef(); const { left, top, width, height } = useDrawingArea(); - const { xAxis, yAxis, xAxisIds, yAxisIds } = React.useContext(CartesianContext); + const { xAxis, yAxis, xAxisIds, yAxisIds } = useCartesianContext(); const { dispatch } = React.useContext(InteractionContext); const usedXAxis = xAxisIds[0]; diff --git a/packages/x-charts/src/hooks/useColorScale.ts b/packages/x-charts/src/hooks/useColorScale.ts index 947d2acbd6ded..1443bfc727bda 100644 --- a/packages/x-charts/src/hooks/useColorScale.ts +++ b/packages/x-charts/src/hooks/useColorScale.ts @@ -1,12 +1,12 @@ import * as React from 'react'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { AxisScaleComputedConfig, ScaleName } from '../models/axis'; import { ZAxisContext } from '../context/ZAxisContextProvider'; export function useXColorScale( identifier?: number | string, ): AxisScaleComputedConfig[S]['colorScale'] | undefined { - const { xAxis, xAxisIds } = React.useContext(CartesianContext); + const { xAxis, xAxisIds } = useCartesianContext(); const id = typeof identifier === 'string' ? identifier : xAxisIds[identifier ?? 0]; @@ -16,7 +16,7 @@ export function useXColorScale( export function useYColorScale( identifier?: number | string, ): AxisScaleComputedConfig[S]['colorScale'] | undefined { - const { yAxis, yAxisIds } = React.useContext(CartesianContext); + const { yAxis, yAxisIds } = useCartesianContext(); const id = typeof identifier === 'string' ? identifier : yAxisIds[identifier ?? 0]; diff --git a/packages/x-charts/src/hooks/useDrawingArea.ts b/packages/x-charts/src/hooks/useDrawingArea.ts index e08c3e3a56b72..7b957071e1cd6 100644 --- a/packages/x-charts/src/hooks/useDrawingArea.ts +++ b/packages/x-charts/src/hooks/useDrawingArea.ts @@ -1,7 +1,7 @@ import * as React from 'react'; -import { DrawingContext } from '../context/DrawingProvider'; +import { DrawingArea, DrawingContext } from '../context/DrawingProvider'; -export function useDrawingArea() { +export function useDrawingArea(): DrawingArea { const { left, top, width, height, bottom, right } = React.useContext(DrawingContext); return React.useMemo( () => ({ left, top, width, height, bottom, right }), diff --git a/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsAxesGradients.tsx b/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsAxesGradients.tsx index 2e388f111c114..b5e0e40e86cb5 100644 --- a/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsAxesGradients.tsx +++ b/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsAxesGradients.tsx @@ -1,14 +1,15 @@ import * as React from 'react'; -import { CartesianContext } from '../../../context/CartesianContextProvider'; +import { useCartesianContext } from '../../../context/CartesianProvider'; import { DrawingContext } from '../../../context/DrawingProvider'; import { useDrawingArea } from '../../../hooks'; import ChartsPiecewiseGradient from './ChartsPiecewiseGradient'; import ChartsContinuousGradient from './ChartsContinuousGradient'; +import { AxisId } from '../../../models/axis'; export function useChartGradient() { const { chartId } = React.useContext(DrawingContext); return React.useCallback( - (axisId: string, direction: 'x' | 'y') => `${chartId}-gradient-${direction}-${axisId}`, + (axisId: AxisId, direction: 'x' | 'y') => `${chartId}-gradient-${direction}-${axisId}`, [chartId], ); } @@ -19,7 +20,7 @@ export function ChartsAxesGradients() { const svgHeight = top + height + bottom; const svgWidth = left + width + right; const getGradientId = useChartGradient(); - const { xAxisIds, xAxis, yAxisIds, yAxis } = React.useContext(CartesianContext); + const { xAxisIds, xAxis, yAxisIds, yAxis } = useCartesianContext(); return ( diff --git a/packages/x-charts/src/internals/index.ts b/packages/x-charts/src/internals/index.ts index 95681c174ccec..7c267400266cd 100644 --- a/packages/x-charts/src/internals/index.ts +++ b/packages/x-charts/src/internals/index.ts @@ -8,6 +8,7 @@ export * from '../ResponsiveChartContainer/ResizableContainer'; export { useReducedMotion } from '../hooks/useReducedMotion'; export { useSeries } from '../hooks/useSeries'; export { useInteractionItemProps } from '../hooks/useInteractionItemProps'; +export { useChartContainerHooks } from '../ChartContainer/useChartContainerHooks'; // utils export * from './defaultizeValueFormatter'; @@ -16,11 +17,13 @@ export * from './getLabel'; // contexts -export * from '../context/CartesianContextProvider'; +export * from '../context/CartesianProvider'; export * from '../context/DrawingProvider'; +export * from '../context/ColorProvider'; export * from '../context/InteractionProvider'; export * from '../context/SeriesContextProvider'; export * from '../context/ZAxisContextProvider'; +export type * from '../context/context.types'; // series configuration export * from '../models/seriesType/config'; diff --git a/packages/x-charts/src/models/plugin.ts b/packages/x-charts/src/models/plugin.ts index a8b4dd5287e5b..49e04baa8a4fb 100644 --- a/packages/x-charts/src/models/plugin.ts +++ b/packages/x-charts/src/models/plugin.ts @@ -1,4 +1,9 @@ -import { ChartSeriesType, ExtremumGetter, Formatter } from './seriesType/config'; +import { + CartesianChartSeriesType, + ChartSeriesType, + ExtremumGetter, + Formatter, +} from './seriesType/config'; import { AxisDefaultized } from './axis'; import { DefaultizedSeriesType } from './seriesType'; import { ZAxisDefaultized } from './z-axis'; @@ -23,3 +28,7 @@ export type ChartsPluginType = T extends ChartSeriesType yExtremumGetter?: ExtremumGetter; } : never; + +export type ExtremumGettersConfig = { + [K in T]?: ExtremumGetter; +}; diff --git a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.test.tsx b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.test.tsx index 1947567216c9c..ffa81a05f51ba 100644 --- a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.test.tsx +++ b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.test.tsx @@ -25,7 +25,7 @@ import { describeConformance } from 'test/utils/describeConformance'; import { RangePosition } from '../models'; const getPickerDay = (name: string, picker = 'January 2018') => - getByRole(screen.getByText(picker)?.parentElement?.parentElement!, 'gridcell', { name }); + getByRole(screen.getByRole('grid', { name: picker }), 'gridcell', { name }); const dynamicShouldDisableDate = (date, position: RangePosition) => { if (position === 'end') { diff --git a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx index 1d8bbc4daa793..4d4e418bea872 100644 --- a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx +++ b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx @@ -5,7 +5,8 @@ import useEventCallback from '@mui/utils/useEventCallback'; import useMediaQuery from '@mui/material/useMediaQuery'; import { resolveComponentProps, useSlotProps } from '@mui/base/utils'; import { styled, useThemeProps } from '@mui/material/styles'; -import { unstable_composeClasses as composeClasses } from '@mui/utils'; +import composeClasses from '@mui/utils/composeClasses'; +import useId from '@mui/utils/useId'; import { Watermark } from '@mui/x-license'; import { applyDefaultDate, @@ -231,6 +232,7 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar< const utils = useUtils(); const now = useNow(timezone); + const id = useId(); const { rangePosition, onRangePositionChange } = useRangePosition({ rangePosition: rangePositionProp, @@ -548,10 +550,16 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar< {calendarMonths.map((monthIndex) => { const month = visibleMonths[monthIndex]; + const labelId = `${id}-grid-${monthIndex}-label`; return ( - {...calendarHeaderProps} month={month} monthIndex={monthIndex} /> + + {...calendarHeaderProps} + month={month} + monthIndex={monthIndex} + labelId={labelId} + /> className={classes.dayCalendar} {...calendarState} @@ -575,6 +583,7 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar< fixedWeekNumber={fixedWeekNumber} displayWeekNumber={displayWeekNumber} timezone={timezone} + gridLabelId={labelId} /> ); diff --git a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.tsx b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.tsx index d07dafc7a0d12..237b8dc110dfa 100644 --- a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.tsx @@ -195,7 +195,9 @@ DateRangePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.tsx index 6a3d955daa368..573a2317e277b 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.tsx @@ -228,7 +228,9 @@ DateTimeRangePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx index eae9bde06a169..f783f0caa8653 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx @@ -230,7 +230,9 @@ DesktopDateRangePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx index 98032d863607d..4c4476eda2eb6 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx @@ -18,8 +18,8 @@ import { const isJSDOM = /jsdom/.test(window.navigator.userAgent); -const getPickerDay = (name: string, picker = 'January 2018'): HTMLButtonElement => - getByRole(screen.getByText(picker)?.parentElement?.parentElement!, 'gridcell', { name }); +const getPickerDay = (name: string, picker = 'January 2018') => + getByRole(screen.getByRole('grid', { name: picker }), 'gridcell', { name }); describe('', () => { const { render, clock } = createPickerRenderer({ diff --git a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx index 5987b65694f42..431bed8573b85 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx @@ -392,7 +392,9 @@ DesktopDateTimeRangePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx index 3fb9e8327ebde..0621f3a26f776 100644 --- a/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx @@ -226,7 +226,9 @@ MobileDateRangePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx index 9aedd2c40dd80..7ba1632219fb2 100644 --- a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx @@ -382,7 +382,9 @@ MobileDateTimeRangePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers-pro/src/PickersRangeCalendarHeader/PickersRangeCalendarHeader.tsx b/packages/x-date-pickers-pro/src/PickersRangeCalendarHeader/PickersRangeCalendarHeader.tsx index faf5ab4b228ae..6657941e84d6a 100644 --- a/packages/x-date-pickers-pro/src/PickersRangeCalendarHeader/PickersRangeCalendarHeader.tsx +++ b/packages/x-date-pickers-pro/src/PickersRangeCalendarHeader/PickersRangeCalendarHeader.tsx @@ -29,7 +29,7 @@ const PickersRangeCalendarHeader = React.forwardRef(function PickersRangeCalenda const utils = useUtils(); const localeText = useLocaleText(); - const { calendars, month, monthIndex, ...other } = props; + const { calendars, month, monthIndex, labelId, ...other } = props; const { format, slots, @@ -56,7 +56,7 @@ const PickersRangeCalendarHeader = React.forwardRef(function PickersRangeCalenda }); if (calendars === 1) { - return ; + return ; } const selectNextMonth = () => onMonthChange(utils.addMonths(currentMonth, 1), 'left'); @@ -76,6 +76,7 @@ const PickersRangeCalendarHeader = React.forwardRef(function PickersRangeCalenda nextLabel={localeText.nextMonth} slots={slots} slotProps={slotProps} + labelId={labelId} > {utils.formatByString(month, format ?? `${utils.formats.month} ${utils.formats.year}`)} @@ -105,6 +106,10 @@ PickersRangeCalendarHeader.propTypes = { * @default `${adapter.formats.month} ${adapter.formats.year}` */ format: PropTypes.string, + /** + * Id of the calendar text element. + * It is used to establish an `aria-labelledby` relationship with the calendar `grid` element. + */ labelId: PropTypes.string, maxDate: PropTypes.object.isRequired, minDate: PropTypes.object.isRequired, diff --git a/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.tsx b/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.tsx index c9b56b0327f3e..5a68a35efe9ae 100644 --- a/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.tsx @@ -174,7 +174,9 @@ StaticDateRangePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers/src/DatePicker/DatePicker.tsx b/packages/x-date-pickers/src/DatePicker/DatePicker.tsx index 0d03dd027d40d..f65788a14bc04 100644 --- a/packages/x-date-pickers/src/DatePicker/DatePicker.tsx +++ b/packages/x-date-pickers/src/DatePicker/DatePicker.tsx @@ -172,7 +172,9 @@ DatePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.tsx b/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.tsx index 7150af6bee521..f931e2606cd48 100644 --- a/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.tsx +++ b/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.tsx @@ -210,7 +210,9 @@ DateTimePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.tsx b/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.tsx index 029e27fb90e93..5a1043e6d2d67 100644 --- a/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.tsx +++ b/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.tsx @@ -216,7 +216,9 @@ DesktopDatePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx b/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx index 33cf7a786af08..3d615adc120f2 100644 --- a/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx @@ -110,6 +110,30 @@ describe('', () => { fireEvent.click(screen.getByText('2020')); expect(document.activeElement).to.have.text('5'); }); + + it('should go to the relevant `view` when `view` prop changes', () => { + const { setProps } = render( + , + ); + + openPicker({ type: 'date', variant: 'desktop' }); + + expect(screen.getByRole('radio', { checked: true, name: 'January' })).to.not.equal(null); + + // Dismiss the picker + userEvent.keyPress(document.activeElement!, { key: 'Escape' }); + setProps({ view: 'year' }); + openPicker({ type: 'date', variant: 'desktop' }); + // wait for all pending changes to be flushed + clock.runToLast(); + + // should have changed the open view + expect(screen.getByRole('radio', { checked: true, name: '2018' })).to.not.equal(null); + }); }); describe('scroll', () => { diff --git a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx index a11c68129fcb9..be5eb451549da 100644 --- a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx +++ b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx @@ -391,7 +391,9 @@ DesktopDateTimePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx b/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx index 26f44fac76b8c..d0a2d8b38c203 100644 --- a/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx +++ b/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx @@ -244,7 +244,9 @@ DesktopTimePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx b/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx index 615392569b1ad..23fe6ab1943e3 100644 --- a/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx +++ b/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx @@ -213,7 +213,9 @@ MobileDatePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx b/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx index 11339d82b1835..9964c55a39482 100644 --- a/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx +++ b/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx @@ -266,7 +266,9 @@ MobileDateTimePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx b/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx index 13242ec98404e..49e09712163b3 100644 --- a/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx +++ b/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx @@ -207,7 +207,9 @@ MobileTimePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx index a172fa35fee2c..d49252d9c441e 100644 --- a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx +++ b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx @@ -281,6 +281,10 @@ PickersCalendarHeader.propTypes = { * @default `${adapter.formats.month} ${adapter.formats.year}` */ format: PropTypes.string, + /** + * Id of the calendar text element. + * It is used to establish an `aria-labelledby` relationship with the calendar `grid` element. + */ labelId: PropTypes.string, maxDate: PropTypes.object.isRequired, minDate: PropTypes.object.isRequired, diff --git a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.types.ts b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.types.ts index 06cbb152849a8..a679a4fe9b6f4 100644 --- a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.types.ts +++ b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.types.ts @@ -67,6 +67,10 @@ export interface PickersCalendarHeaderProps view: DateView; reduceAnimations: boolean; onViewChange?: (view: DateView) => void; + /** + * Id of the calendar text element. + * It is used to establish an `aria-labelledby` relationship with the calendar `grid` element. + */ labelId?: string; /** * Override or extend the styles applied to the component. diff --git a/packages/x-date-pickers/src/StaticDatePicker/StaticDatePicker.tsx b/packages/x-date-pickers/src/StaticDatePicker/StaticDatePicker.tsx index a26561d9b98e6..7fcb43423bc9a 100644 --- a/packages/x-date-pickers/src/StaticDatePicker/StaticDatePicker.tsx +++ b/packages/x-date-pickers/src/StaticDatePicker/StaticDatePicker.tsx @@ -152,7 +152,9 @@ StaticDatePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers/src/StaticDateTimePicker/StaticDateTimePicker.tsx b/packages/x-date-pickers/src/StaticDateTimePicker/StaticDateTimePicker.tsx index e9a97bcf54df0..a8e81bcbd3039 100644 --- a/packages/x-date-pickers/src/StaticDateTimePicker/StaticDateTimePicker.tsx +++ b/packages/x-date-pickers/src/StaticDateTimePicker/StaticDateTimePicker.tsx @@ -204,7 +204,9 @@ StaticDateTimePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers/src/StaticTimePicker/StaticTimePicker.tsx b/packages/x-date-pickers/src/StaticTimePicker/StaticTimePicker.tsx index 39832d96e2f35..b3b2b27047a03 100644 --- a/packages/x-date-pickers/src/StaticTimePicker/StaticTimePicker.tsx +++ b/packages/x-date-pickers/src/StaticTimePicker/StaticTimePicker.tsx @@ -145,7 +145,9 @@ StaticTimePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers/src/TimePicker/TimePicker.tsx b/packages/x-date-pickers/src/TimePicker/TimePicker.tsx index 096406665d1dd..2883b0d1d45bc 100644 --- a/packages/x-date-pickers/src/TimePicker/TimePicker.tsx +++ b/packages/x-date-pickers/src/TimePicker/TimePicker.tsx @@ -162,7 +162,9 @@ TimePicker.propTypes = { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ onAccept: PropTypes.func, /** diff --git a/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx b/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx index 617a71eea6fdc..2ecae8493f14e 100644 --- a/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx +++ b/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx @@ -79,6 +79,7 @@ export const PickersArrowSwitcher = React.forwardRef(function PickersArrowSwitch isPreviousHidden, onGoToPrevious, previousLabel, + labelId, ...other } = props; @@ -169,7 +170,7 @@ export const PickersArrowSwitcher = React.forwardRef(function PickersArrowSwitch )} {children ? ( - + {children} ) : ( diff --git a/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.types.tsx b/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.types.tsx index aaa5552a8c659..0998b6ded18be 100644 --- a/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.types.tsx +++ b/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.types.tsx @@ -38,6 +38,7 @@ export interface PickersArrowSwitcherProps isNextHidden?: boolean; onGoToNext: () => void; nextLabel: string; + labelId?: string; } export type PickersArrowSwitcherOwnerState = PickersArrowSwitcherProps; diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts index 12c8b00617d58..3bd7a5eb08a23 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts @@ -269,29 +269,36 @@ export const usePickerValue = < hasBeenModifiedSinceMount: true, })); - if (shouldPublish) { - const validationError = - action.name === 'setValueFromField' - ? action.context.validationError - : validator({ - adapter, - value: action.value, - props: { ...props, value: action.value, timezone }, - }); - - const context: PickerChangeHandlerContext = { - validationError, - }; - - if (action.name === 'setValueFromShortcut') { - context.shortcut = action.shortcut; + let cachedContext: PickerChangeHandlerContext | null = null; + const getContext = (): PickerChangeHandlerContext => { + if (!cachedContext) { + const validationError = + action.name === 'setValueFromField' + ? action.context.validationError + : validator({ + adapter, + value: action.value, + props: { ...props, value: action.value, timezone }, + }); + + cachedContext = { + validationError, + }; + + if (action.name === 'setValueFromShortcut') { + cachedContext.shortcut = action.shortcut; + } } - handleValueChange(action.value, context); + return cachedContext; + }; + + if (shouldPublish) { + handleValueChange(action.value, getContext()); } if (shouldCommit && onAccept) { - onAccept(action.value); + onAccept(action.value, getContext()); } if (shouldClose) { diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts index 7c878c57e6137..9372640881c4e 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts @@ -229,9 +229,11 @@ export interface UsePickerValueBaseProps { /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. */ - onAccept?: (value: TValue) => void; + onAccept?: (value: TValue, context: PickerChangeHandlerContext) => void; /** * Callback fired when the error associated to the current value changes. * If the error has a non-null value, then the `TextField` will be rendered in `error` state. diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts index 4ed9a1a87277b..e96e3754fe946 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts @@ -183,12 +183,12 @@ export const usePickerViews = < TAdditionalProps >): UsePickerViewsResponse => { const { onChange, open, onClose } = propsFromPickerValue; - const { views, openTo, onViewChange, viewRenderers, timezone } = props; + const { view: inView, views, openTo, onViewChange, viewRenderers, timezone } = props; const { className, sx, ...propsToForwardToView } = props; const { view, setView, defaultView, focusedView, setFocusedView, setValueAndGoToNextView } = useViews({ - view: undefined, + view: inView, views, openTo, onChange, diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx index 426275dd9f682..86f502bb61193 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx @@ -47,6 +47,18 @@ describeTreeView<[]>('TreeItem component', ({ render, treeItemComponentName }) = expect(response.getItemContent('1').textContent).to.equal('ABCDEF'); }); + + it('should render TreeItem when itemId prop is escaping characters without throwing an error', function test() { + if (treeItemComponentName === 'TreeItem2') { + this.skip(); + } + + const response = render({ + items: [{ id: 'C:\\\\', label: 'ABCDEF' }], + }); + + expect(response.getItemContent('C:\\\\').textContent).to.equal('ABCDEF'); + }); }); }); diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.tsx index f4224825ec58a..2f35d89749058 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItem.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItem.tsx @@ -13,7 +13,12 @@ import { unstable_composeClasses as composeClasses } from '@mui/base'; import { styled, createUseThemeProps } from '../internals/zero-styled'; import { TreeItemContent } from './TreeItemContent'; import { treeItemClasses, getTreeItemUtilityClass } from './treeItemClasses'; -import { TreeItemMinimalPlugins, TreeItemOwnerState, TreeItemProps } from './TreeItem.types'; +import { + TreeItemMinimalPlugins, + TreeItemOptionalPlugins, + TreeItemOwnerState, + TreeItemProps, +} from './TreeItem.types'; import { useTreeViewContext } from '../internals/TreeViewProvider/useTreeViewContext'; import { TreeViewCollapseIcon, TreeViewExpandIcon } from '../icons'; import { TreeItem2Provider } from '../TreeItem2Provider'; @@ -185,7 +190,7 @@ export const TreeItem = React.forwardRef(function TreeItem( disabledItemsFocusable, indentationAtItemLevel, instance, - } = useTreeViewContext(); + } = useTreeViewContext(); const depthContext = React.useContext(TreeViewItemDepthContext); const props = useThemeProps({ props: inProps, name: 'MuiTreeItem' }); diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.types.ts b/packages/x-tree-view/src/TreeItem/TreeItem.types.ts index 54df7cbef8dae..c0554c4e4c80f 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItem.types.ts +++ b/packages/x-tree-view/src/TreeItem/TreeItem.types.ts @@ -113,6 +113,9 @@ export interface TreeItemOwnerState extends TreeItemProps { indentationAtItemLevel: boolean; } +/** + * Plugins that need to be present in the Tree View in order for `TreeItem` to work correctly. + */ export type TreeItemMinimalPlugins = readonly [ UseTreeViewIconsSignature, UseTreeViewSelectionSignature, @@ -122,3 +125,8 @@ export type TreeItemMinimalPlugins = readonly [ UseTreeViewKeyboardNavigationSignature, UseTreeViewIdSignature, ]; + +/** + * Plugins that `TreeItem` can use if they are present, but are not required. + */ +export type TreeItemOptionalPlugins = readonly []; diff --git a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts index fea40a777a0f7..09f9ce6f88c2e 100644 --- a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts +++ b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts @@ -12,11 +12,13 @@ type UseTreeItemStateMinimalPlugins = readonly [ UseTreeViewItemsSignature, ]; +type UseTreeItemStateOptionalPlugins = readonly []; + export function useTreeItemState(itemId: string) { const { instance, selection: { multiSelect, checkboxSelection, disableSelection }, - } = useTreeViewContext(); + } = useTreeViewContext(); const expandable = instance.isItemExpandable(itemId); const expanded = instance.isItemExpanded(itemId); diff --git a/packages/x-tree-view/src/hooks/useTreeItem2Utils/useTreeItem2Utils.tsx b/packages/x-tree-view/src/hooks/useTreeItem2Utils/useTreeItem2Utils.tsx index 09e188c73e75b..81e0f169559c9 100644 --- a/packages/x-tree-view/src/hooks/useTreeItem2Utils/useTreeItem2Utils.tsx +++ b/packages/x-tree-view/src/hooks/useTreeItem2Utils/useTreeItem2Utils.tsx @@ -24,6 +24,9 @@ const isItemExpandable = (reactChildren: React.ReactNode) => { return Boolean(reactChildren); }; +/** + * Plugins that need to be present in the Tree View in order for `useTreeItem2Utils` to work correctly. + */ type UseTreeItem2UtilsMinimalPlugins = readonly [ UseTreeViewSelectionSignature, UseTreeViewExpansionSignature, @@ -31,6 +34,11 @@ type UseTreeItem2UtilsMinimalPlugins = readonly [ UseTreeViewFocusSignature, ]; +/** + * Plugins that `useTreeItem2Utils` can use if they are present, but are not required. + */ +export type UseTreeItem2UtilsOptionalPlugins = readonly []; + export const useTreeItem2Utils = ({ itemId, children, @@ -41,7 +49,7 @@ export const useTreeItem2Utils = ({ const { instance, selection: { multiSelect }, - } = useTreeViewContext(); + } = useTreeViewContext(); const status: UseTreeItem2Status = { expandable: isItemExpandable(children), diff --git a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewChildrenItemProvider.tsx b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewChildrenItemProvider.tsx index 48afd8f36c22e..ad1aaf415413f 100644 --- a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewChildrenItemProvider.tsx +++ b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewChildrenItemProvider.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { useTreeViewContext } from './useTreeViewContext'; +import { escapeOperandAttributeSelector } from '../utils/utils'; import type { UseTreeViewJSXItemsSignature } from '../plugins/useTreeViewJSXItems'; import type { UseTreeViewItemsSignature } from '../plugins/useTreeViewItems'; import type { UseTreeViewIdSignature } from '../plugins/useTreeViewId'; @@ -47,8 +48,9 @@ export function TreeViewChildrenItemProvider(props: TreeViewChildrenItemProvider } const previousChildrenIds = instance.getItemOrderedChildrenIds(itemId ?? null) ?? []; + const escapedIdAttr = escapeOperandAttributeSelector(idAttr); const childrenElements = rootRef.current.querySelectorAll( - `${itemId == null ? '' : `*[id="${idAttr}"] `}[role="treeitem"]:not(*[id="${idAttr}"] [role="treeitem"] [role="treeitem"])`, + `${itemId == null ? '' : `*[id="${escapedIdAttr}"] `}[role="treeitem"]:not(*[id="${escapedIdAttr}"] [role="treeitem"] [role="treeitem"])`, ); const childrenIds = Array.from(childrenElements).map( (child) => childrenIdAttrToIdRef.current.get(child.id)!, diff --git a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts index f0af466f0f215..b60339cc59131 100644 --- a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts +++ b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts @@ -13,10 +13,13 @@ export type TreeViewItemPluginsRunner = ( props: TProps, ) => Required; -export type TreeViewContextValue = - MergeSignaturesProperty & { - instance: TreeViewInstance; - publicAPI: TreeViewPublicAPI; +export type TreeViewContextValue< + TSignatures extends readonly TreeViewAnyPluginSignature[], + TOptionalSignatures extends readonly TreeViewAnyPluginSignature[] = [], +> = MergeSignaturesProperty & + Partial> & { + instance: TreeViewInstance; + publicAPI: TreeViewPublicAPI; rootRef: React.RefObject; wrapItem: TreeItemWrapper; wrapRoot: TreeRootWrapper; diff --git a/packages/x-tree-view/src/internals/TreeViewProvider/useTreeViewContext.ts b/packages/x-tree-view/src/internals/TreeViewProvider/useTreeViewContext.ts index 62fbce3ad7397..ee7c8e7ff9ff3 100644 --- a/packages/x-tree-view/src/internals/TreeViewProvider/useTreeViewContext.ts +++ b/packages/x-tree-view/src/internals/TreeViewProvider/useTreeViewContext.ts @@ -3,8 +3,14 @@ import { TreeViewAnyPluginSignature } from '../models'; import { TreeViewContext } from './TreeViewContext'; import { TreeViewContextValue } from './TreeViewProvider.types'; -export const useTreeViewContext = () => { - const context = React.useContext(TreeViewContext) as TreeViewContextValue; +export const useTreeViewContext = < + TSignatures extends readonly TreeViewAnyPluginSignature[], + TOptionalSignatures extends readonly TreeViewAnyPluginSignature[] = [], +>() => { + const context = React.useContext(TreeViewContext) as TreeViewContextValue< + TSignatures, + TOptionalSignatures + >; if (context == null) { throw new Error( [ diff --git a/packages/x-tree-view/src/internals/models/plugin.ts b/packages/x-tree-view/src/internals/models/plugin.ts index fd26dd4c42d7a..b9459acecf931 100644 --- a/packages/x-tree-view/src/internals/models/plugin.ts +++ b/packages/x-tree-view/src/internals/models/plugin.ts @@ -47,7 +47,8 @@ export type TreeViewPluginSignature< slotProps?: { [key in keyof T['slotProps']]: {} | (() => {}) }; modelNames?: keyof T['defaultizedParams']; experimentalFeatures?: string; - dependantPlugins?: readonly TreeViewAnyPluginSignature[]; + dependencies?: readonly TreeViewAnyPluginSignature[]; + optionalDependencies?: readonly TreeViewAnyPluginSignature[]; }, > = { params: T extends { params: {} } ? T['params'] : {}; @@ -67,7 +68,10 @@ export type TreeViewPluginSignature< } : {}; experimentalFeatures: T['experimentalFeatures']; - dependantPlugins: T extends { dependantPlugins: Array } ? T['dependantPlugins'] : []; + dependencies: T extends { dependencies: Array } ? T['dependencies'] : []; + optionalDependencies: T extends { optionalDependencies: Array } + ? T['optionalDependencies'] + : []; }; export type TreeViewAnyPluginSignature = { @@ -75,7 +79,8 @@ export type TreeViewAnyPluginSignature = { instance: any; params: any; defaultizedParams: any; - dependantPlugins: any; + dependencies: any; + optionalDependencies: any; events: any; contextValue: any; slots: any; @@ -85,32 +90,37 @@ export type TreeViewAnyPluginSignature = { publicAPI: any; }; -type TreeViewUsedPlugins = [ +type TreeViewRequiredPlugins = [ ...TreeViewCorePluginSignatures, - ...TSignature['dependantPlugins'], + ...TSignature['dependencies'], ]; +type PluginPropertyWithDependencies< + TSignature extends TreeViewAnyPluginSignature, + TProperty extends keyof TreeViewAnyPluginSignature, +> = TSignature[TProperty] & + MergeSignaturesProperty, TProperty> & + Partial>; + export type TreeViewUsedParams = - TSignature['params'] & MergeSignaturesProperty, 'params'>; + PluginPropertyWithDependencies; type TreeViewUsedDefaultizedParams = - TSignature['defaultizedParams'] & - MergeSignaturesProperty, 'defaultizedParams'>; + PluginPropertyWithDependencies; export type TreeViewUsedInstance = - TSignature['instance'] & - MergeSignaturesProperty, 'instance'> & { - /** - * Private property only defined in TypeScript to be able to access the plugin signature from the instance object. - */ - $$signature: TSignature; - }; + PluginPropertyWithDependencies & { + /** + * Private property only defined in TypeScript to be able to access the plugin signature from the instance object. + */ + $$signature: TSignature; + }; -type TreeViewUsedState = TSignature['state'] & - MergeSignaturesProperty, 'state'>; +type TreeViewUsedState = + PluginPropertyWithDependencies; type TreeViewUsedExperimentalFeatures = - TreeViewExperimentalFeatures<[TSignature, ...TSignature['dependantPlugins']]>; + TreeViewExperimentalFeatures<[TSignature, ...TSignature['dependencies']]>; type RemoveSetValue>> = { [K in keyof Models]: Omit; @@ -118,10 +128,10 @@ type RemoveSetValue>> = { export type TreeViewUsedModels = TSignature['models'] & - RemoveSetValue, 'models'>>; + RemoveSetValue, 'models'>>; export type TreeViewUsedEvents = - TSignature['events'] & MergeSignaturesProperty, 'events'>; + TSignature['events'] & MergeSignaturesProperty, 'events'>; export interface TreeViewItemPluginOptions extends TreeViewItemPluginResponse { props: TProps; @@ -167,11 +177,11 @@ export type TreeViewPlugin = { * @param {{ nodeId: TreeViewItemId; children: React.ReactNode; }} params The params of the item. * @returns {React.ReactNode} The wrapped item. */ - wrapItem?: TreeItemWrapper<[TSignature, ...TSignature['dependantPlugins']]>; + wrapItem?: TreeItemWrapper<[TSignature, ...TSignature['dependencies']]>; /** * Render function used to add React wrappers around the TreeView. * @param {{ children: React.ReactNode; }} params The params of the root. * @returns {React.ReactNode} The wrapped root. */ - wrapRoot?: TreeRootWrapper<[TSignature, ...TSignature['dependantPlugins']]>; + wrapRoot?: TreeRootWrapper<[TSignature, ...TSignature['dependencies']]>; }; diff --git a/packages/x-tree-view/src/internals/models/treeView.ts b/packages/x-tree-view/src/internals/models/treeView.ts index e513e0f8bff52..a9b5e24522030 100644 --- a/packages/x-tree-view/src/internals/models/treeView.ts +++ b/packages/x-tree-view/src/internals/models/treeView.ts @@ -24,11 +24,17 @@ export interface TreeViewModel { setControlledValue: (value: TValue | ((prevValue: TValue) => TValue)) => void; } -export type TreeViewInstance = - MergeSignaturesProperty<[...TreeViewCorePluginSignatures, ...TSignatures], 'instance'>; +export type TreeViewInstance< + TSignatures extends readonly TreeViewAnyPluginSignature[], + TOptionalSignatures extends readonly TreeViewAnyPluginSignature[] = [], +> = MergeSignaturesProperty<[...TreeViewCorePluginSignatures, ...TSignatures], 'instance'> & + Partial>; -export type TreeViewPublicAPI = - MergeSignaturesProperty<[...TreeViewCorePluginSignatures, ...TSignatures], 'publicAPI'>; +export type TreeViewPublicAPI< + TSignatures extends readonly TreeViewAnyPluginSignature[], + TOptionalSignatures extends readonly TreeViewAnyPluginSignature[] = [], +> = MergeSignaturesProperty<[...TreeViewCorePluginSignatures, ...TSignatures], 'publicAPI'> & + Partial>; export type TreeViewExperimentalFeatures< TSignatures extends readonly TreeViewAnyPluginSignature[], diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.ts index 1eabf3ce9daf8..f3e93a059afd5 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.ts @@ -85,5 +85,5 @@ export type UseTreeViewExpansionSignature = TreeViewPluginSignature<{ instance: UseTreeViewExpansionInstance; publicAPI: UseTreeViewExpansionPublicAPI; modelNames: 'expandedItems'; - dependantPlugins: [UseTreeViewItemsSignature]; + dependencies: [UseTreeViewItemsSignature]; }>; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.ts index 993487fcf86db..50c265aa58665 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.ts @@ -61,7 +61,7 @@ export type UseTreeViewFocusSignature = TreeViewPluginSignature<{ instance: UseTreeViewFocusInstance; publicAPI: UseTreeViewFocusPublicAPI; state: UseTreeViewFocusState; - dependantPlugins: [ + dependencies: [ UseTreeViewIdSignature, UseTreeViewItemsSignature, UseTreeViewSelectionSignature, diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewIcons/useTreeViewIcons.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewIcons/useTreeViewIcons.types.ts index 0ceb50b8fe3e2..5705fbbddaa0a 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewIcons/useTreeViewIcons.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewIcons/useTreeViewIcons.types.ts @@ -43,5 +43,5 @@ export type UseTreeViewIconsSignature = TreeViewPluginSignature<{ contextValue: UseTreeViewIconsContextValue; slots: UseTreeViewIconsSlots; slotProps: UseTreeViewIconsSlotProps; - dependantPlugins: [UseTreeViewItemsSignature, UseTreeViewSelectionSignature]; + dependencies: [UseTreeViewItemsSignature, UseTreeViewSelectionSignature]; }>; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.types.ts index 3f613428603ec..45cddbf7350ac 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.types.ts @@ -38,5 +38,5 @@ export type UseTreeViewJSXItemsSignature = TreeViewPluginSignature<{ params: UseTreeViewJSXItemsParameters; defaultizedParams: UseTreeViewItemsDefaultizedParameters; instance: UseTreeViewItemsInstance; - dependantPlugins: [UseTreeViewItemsSignature, UseTreeViewKeyboardNavigationSignature]; + dependencies: [UseTreeViewItemsSignature, UseTreeViewKeyboardNavigationSignature]; }>; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.ts index 9aceca62b73fd..8572a6e75fc22 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.ts @@ -29,7 +29,7 @@ export interface UseTreeViewKeyboardNavigationInstance { export type UseTreeViewKeyboardNavigationSignature = TreeViewPluginSignature<{ instance: UseTreeViewKeyboardNavigationInstance; - dependantPlugins: [ + dependencies: [ UseTreeViewItemsSignature, UseTreeViewSelectionSignature, UseTreeViewFocusSignature, diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts index 56474f46a0ba1..c6fc7cedf450c 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts @@ -131,7 +131,7 @@ export type UseTreeViewSelectionSignature = TreeViewPluginSignature<{ instance: UseTreeViewSelectionInstance; contextValue: UseTreeViewSelectionContextValue; modelNames: 'selectedItems'; - dependantPlugins: [ + dependencies: [ UseTreeViewItemsSignature, UseTreeViewExpansionSignature, UseTreeViewItemsSignature, diff --git a/packages/x-tree-view/src/internals/utils/utils.ts b/packages/x-tree-view/src/internals/utils/utils.ts index 5401ae664aab2..661b342067d7e 100644 --- a/packages/x-tree-view/src/internals/utils/utils.ts +++ b/packages/x-tree-view/src/internals/utils/utils.ts @@ -12,3 +12,9 @@ export const getActiveElement = (root: Document | ShadowRoot = document): Elemen return activeEl; }; + +// TODO, eventually replaces this function with CSS.escape, once available in jsdom, either added manually or built in +// https://github.com/jsdom/jsdom/issues/1550#issuecomment-236734471 +export function escapeOperandAttributeSelector(operand: string): string { + return operand.replace(/["\\]/g, '\\$&'); +} diff --git a/packages/x-tree-view/src/useTreeItem2/useTreeItem2.ts b/packages/x-tree-view/src/useTreeItem2/useTreeItem2.ts index 72fd74f6d23ce..54c6e3dc7435c 100644 --- a/packages/x-tree-view/src/useTreeItem2/useTreeItem2.ts +++ b/packages/x-tree-view/src/useTreeItem2/useTreeItem2.ts @@ -11,6 +11,7 @@ import { UseTreeItemIconContainerSlotProps, UseTreeItem2CheckboxSlotProps, UseTreeItem2MinimalPlugins, + UseTreeItem2OptionalPlugins, } from './useTreeItem2.types'; import { useTreeViewContext } from '../internals/TreeViewProvider/useTreeViewContext'; import { MuiCancellableEvent } from '../internals/models/MuiCancellableEvent'; @@ -19,9 +20,10 @@ import { TreeViewItemDepthContext } from '../internals/TreeViewItemDepthContext' export const useTreeItem2 = < TSignatures extends UseTreeItem2MinimalPlugins = UseTreeItem2MinimalPlugins, + TOptionalSignatures extends UseTreeItem2OptionalPlugins = UseTreeItem2OptionalPlugins, >( parameters: UseTreeItem2Parameters, -): UseTreeItem2ReturnValue => { +): UseTreeItem2ReturnValue => { const { runItemPlugins, selection: { multiSelect, disableSelection, checkboxSelection }, @@ -29,7 +31,7 @@ export const useTreeItem2 = < indentationAtItemLevel, instance, publicAPI, - } = useTreeViewContext(); + } = useTreeViewContext(); const depthContext = React.useContext(TreeViewItemDepthContext); const { id, itemId, label, children, rootRef } = parameters; diff --git a/packages/x-tree-view/src/useTreeItem2/useTreeItem2.types.ts b/packages/x-tree-view/src/useTreeItem2/useTreeItem2.types.ts index 08651b015ad32..321b9d5a14083 100644 --- a/packages/x-tree-view/src/useTreeItem2/useTreeItem2.types.ts +++ b/packages/x-tree-view/src/useTreeItem2/useTreeItem2.types.ts @@ -1,7 +1,7 @@ import * as React from 'react'; import { TreeViewItemId } from '../models'; import { MuiCancellableEventHandler } from '../internals/models/MuiCancellableEvent'; -import { TreeViewAnyPluginSignature, TreeViewPublicAPI } from '../internals/models'; +import { TreeViewPublicAPI } from '../internals/models'; import { UseTreeViewSelectionSignature } from '../internals/plugins/useTreeViewSelection'; import { UseTreeViewItemsSignature } from '../internals/plugins/useTreeViewItems'; import { UseTreeViewIdSignature } from '../internals/plugins/useTreeViewId'; @@ -116,7 +116,8 @@ export interface UseTreeItem2Status { } export interface UseTreeItem2ReturnValue< - TSignatures extends readonly TreeViewAnyPluginSignature[], + TSignatures extends UseTreeItem2MinimalPlugins, + TOptionalSignatures extends UseTreeItem2OptionalPlugins, > { /** * Resolver for the root slot's props. @@ -177,9 +178,12 @@ export interface UseTreeItem2ReturnValue< /** * The object the allows Tree View manipulation. */ - publicAPI: TreeViewPublicAPI; + publicAPI: TreeViewPublicAPI; } +/** + * Plugins that need to be present in the Tree View in order for `useTreeItem2` to work correctly. + */ export type UseTreeItem2MinimalPlugins = readonly [ UseTreeViewSelectionSignature, UseTreeViewItemsSignature, @@ -187,3 +191,8 @@ export type UseTreeItem2MinimalPlugins = readonly [ UseTreeViewFocusSignature, UseTreeViewKeyboardNavigationSignature, ]; + +/** + * Plugins that `useTreeItem2` can use if they are present, but are not required. + */ +export type UseTreeItem2OptionalPlugins = readonly []; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1da6c4abad192..8058b84ec8efb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -99,8 +99,8 @@ importers: specifier: ^5.15.20 version: 5.15.20(@types/react@18.2.60)(react@18.2.0) '@next/eslint-plugin-next': - specifier: 14.2.3 - version: 14.2.3 + specifier: 14.2.4 + version: 14.2.4 '@octokit/plugin-retry': specifier: ^6.0.1 version: 6.0.1(@octokit/core@4.2.4(encoding@0.1.13)) @@ -159,11 +159,11 @@ importers: specifier: ^17.0.32 version: 17.0.32 '@typescript-eslint/eslint-plugin': - specifier: ^7.12.0 - version: 7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) + specifier: ^7.13.1 + version: 7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/parser': - specifier: ^7.12.0 - version: 7.12.0(eslint@8.57.0)(typescript@5.4.5) + specifier: ^7.13.1 + version: 7.13.1(eslint@8.57.0)(typescript@5.4.5) autoprefixer: specifier: ^10.4.19 version: 10.4.19(postcss@8.4.38) @@ -172,7 +172,7 @@ importers: version: 4.9.1 babel-loader: specifier: ^9.1.3 - version: 9.1.3(@babel/core@7.24.7)(webpack@5.91.0(webpack-cli@5.1.4)) + version: 9.1.3(@babel/core@7.24.7)(webpack@5.92.0(webpack-cli@5.1.4)) babel-plugin-istanbul: specifier: ^6.1.1 version: 6.1.1 @@ -202,7 +202,7 @@ importers: version: 1.12.0(chai@4.4.1) compression-webpack-plugin: specifier: ^11.1.0 - version: 11.1.0(webpack@5.91.0(webpack-cli@5.1.4)) + version: 11.1.0(webpack@5.92.0(webpack-cli@5.1.4)) concurrently: specifier: ^8.2.2 version: 8.2.2 @@ -229,25 +229,25 @@ importers: version: 8.57.0 eslint-config-airbnb: specifier: ^19.0.4 - version: 19.0.4(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.34.2(eslint@8.57.0))(eslint@8.57.0) + version: 19.0.4(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.34.2(eslint@8.57.0))(eslint@8.57.0) eslint-config-airbnb-typescript: specifier: ^18.0.0 - version: 18.0.0(@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint@8.57.0) + version: 18.0.0(@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint@8.57.0) eslint-config-prettier: specifier: ^9.1.0 version: 9.1.0(eslint@8.57.0) eslint-import-resolver-webpack: specifier: ^0.13.8 - version: 0.13.8(eslint-plugin-import@2.29.1)(webpack@5.91.0(webpack-cli@5.1.4)) + version: 0.13.8(eslint-plugin-import@2.29.1)(webpack@5.92.0(webpack-cli@5.1.4)) eslint-plugin-filenames: specifier: ^1.3.2 version: 1.3.2(eslint@8.57.0) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0) + version: 2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0) eslint-plugin-jsdoc: - specifier: ^48.2.9 - version: 48.2.9(eslint@8.57.0) + specifier: ^48.2.12 + version: 48.2.12(eslint@8.57.0) eslint-plugin-jsx-a11y: specifier: ^6.8.0 version: 6.8.0(eslint@8.57.0) @@ -286,7 +286,7 @@ importers: version: 14.0.1 html-webpack-plugin: specifier: ^5.6.0 - version: 5.6.0(webpack@5.91.0(webpack-cli@5.1.4)) + version: 5.6.0(webpack@5.92.0(webpack-cli@5.1.4)) jsdom: specifier: 24.1.0 version: 24.1.0 @@ -316,7 +316,7 @@ importers: version: 0.4.0 karma-webpack: specifier: ^5.0.1 - version: 5.0.1(webpack@5.91.0(webpack-cli@5.1.4)) + version: 5.0.1(webpack@5.92.0(webpack-cli@5.1.4)) lerna: specifier: ^8.1.3 version: 8.1.3(encoding@0.1.13) @@ -336,8 +336,8 @@ importers: specifier: ^0.5.45 version: 0.5.45 nyc: - specifier: ^15.1.0 - version: 15.1.0 + specifier: ^17.0.0 + version: 17.0.0 prettier: specifier: ^3.3.2 version: 3.3.2 @@ -370,10 +370,10 @@ importers: version: 3.0.0 string-replace-loader: specifier: ^3.1.0 - version: 3.1.0(webpack@5.91.0(webpack-cli@5.1.4)) + version: 3.1.0(webpack@5.92.0(webpack-cli@5.1.4)) terser-webpack-plugin: specifier: ^5.3.10 - version: 5.3.10(webpack@5.91.0(webpack-cli@5.1.4)) + version: 5.3.10(webpack@5.92.0(webpack-cli@5.1.4)) tsx: specifier: ^4.15.5 version: 4.15.5 @@ -387,14 +387,14 @@ importers: specifier: ^0.12.5 version: 0.12.5 webpack: - specifier: ^5.91.0 - version: 5.91.0(webpack-cli@5.1.4) + specifier: ^5.92.0 + version: 5.92.0(webpack-cli@5.1.4) webpack-bundle-analyzer: specifier: ^4.10.2 version: 4.10.2 webpack-cli: specifier: ^5.1.4 - version: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0) + version: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0) yargs: specifier: ^17.7.2 version: 17.7.2 @@ -591,8 +591,8 @@ importers: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) react-hook-form: - specifier: ^7.51.5 - version: 7.51.5(react@18.2.0) + specifier: ^7.52.0 + version: 7.52.0(react@18.2.0) react-is: specifier: ^18.2.0 version: 18.2.0 @@ -677,7 +677,7 @@ importers: version: 4.2.6 '@types/webpack-bundle-analyzer': specifier: ^4.7.0 - version: 4.7.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0)) + version: 4.7.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0)) gm: specifier: ^1.25.0 version: 1.25.0 @@ -691,11 +691,11 @@ importers: specifier: ^8.56.10 version: 8.56.10 '@typescript-eslint/parser': - specifier: ^7.12.0 - version: 7.12.0(eslint@8.57.0)(typescript@5.4.5) + specifier: ^7.13.1 + version: 7.13.1(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/utils': - specifier: ^7.12.0 - version: 7.12.0(eslint@8.57.0)(typescript@5.4.5) + specifier: ^7.13.1 + version: 7.13.1(eslint@8.57.0)(typescript@5.4.5) packages/x-charts: dependencies: @@ -2951,8 +2951,8 @@ packages: '@next/env@14.2.4': resolution: {integrity: sha512-3EtkY5VDkuV2+lNmKlbkibIJxcO4oIHEhBWne6PaAp+76J9KoSsGvNikp6ivzAT8dhhBMYrm6op2pS1ApG0Hzg==} - '@next/eslint-plugin-next@14.2.3': - resolution: {integrity: sha512-L3oDricIIjgj1AVnRdRor21gI7mShlSwU/1ZGHmqM3LzHhXXhdkrfeNY5zif25Bi5Dd7fiJHsbhoZCHfXYvlAw==} + '@next/eslint-plugin-next@14.2.4': + resolution: {integrity: sha512-svSFxW9f3xDaZA3idQmlFw7SusOuWTpDTAeBlO3AEPDltrraV+lqs7mAc6A27YdnpQVVIA3sODqUAAHdWhVWsA==} '@next/swc-darwin-arm64@14.2.4': resolution: {integrity: sha512-AH3mO4JlFUqsYcwFUHb1wAKlebHU/Hv2u2kb1pAuRanDZ7pD/A/KPD98RHZmwsJpdHQwfEc/06mgpSzwrJYnNg==} @@ -3798,8 +3798,8 @@ packages: '@types/yargs@17.0.32': resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} - '@typescript-eslint/eslint-plugin@7.12.0': - resolution: {integrity: sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==} + '@typescript-eslint/eslint-plugin@7.13.1': + resolution: {integrity: sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: '@typescript-eslint/parser': ^7.0.0 @@ -3809,8 +3809,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@7.12.0': - resolution: {integrity: sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==} + '@typescript-eslint/parser@7.13.1': + resolution: {integrity: sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -3819,12 +3819,12 @@ packages: typescript: optional: true - '@typescript-eslint/scope-manager@7.12.0': - resolution: {integrity: sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==} + '@typescript-eslint/scope-manager@7.13.1': + resolution: {integrity: sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/type-utils@7.12.0': - resolution: {integrity: sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==} + '@typescript-eslint/type-utils@7.13.1': + resolution: {integrity: sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -3833,12 +3833,12 @@ packages: typescript: optional: true - '@typescript-eslint/types@7.12.0': - resolution: {integrity: sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==} + '@typescript-eslint/types@7.13.1': + resolution: {integrity: sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/typescript-estree@7.12.0': - resolution: {integrity: sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==} + '@typescript-eslint/typescript-estree@7.13.1': + resolution: {integrity: sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' @@ -3846,14 +3846,14 @@ packages: typescript: optional: true - '@typescript-eslint/utils@7.12.0': - resolution: {integrity: sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==} + '@typescript-eslint/utils@7.13.1': + resolution: {integrity: sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 - '@typescript-eslint/visitor-keys@7.12.0': - resolution: {integrity: sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==} + '@typescript-eslint/visitor-keys@7.13.1': + resolution: {integrity: sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==} engines: {node: ^18.18.0 || >=20.0.0} '@ungap/structured-clone@1.2.0': @@ -3967,8 +3967,8 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} - acorn-import-assertions@1.9.0: - resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: acorn: ^8 @@ -5331,8 +5331,8 @@ packages: resolution: {integrity: sha512-kxpoMgrdtkXZ5h0SeraBS1iRntpTpQ3R8ussdb38+UAFnMGX5DDyJXePm+OCHOcoXvHDw7mc2erbJBpDnl7TPw==} engines: {node: '>=0.6'} - enhanced-resolve@5.16.0: - resolution: {integrity: sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==} + enhanced-resolve@5.17.0: + resolution: {integrity: sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==} engines: {node: '>=10.13.0'} enquirer@2.3.6: @@ -5528,8 +5528,8 @@ packages: '@typescript-eslint/parser': optional: true - eslint-plugin-jsdoc@48.2.9: - resolution: {integrity: sha512-ErpKyr2mEUEkcdZ4nwW/cvDjClvAcvJMEXkGGll0wf8sro8h6qeQ3qlZyp1vM1dRk8Ap6rMdke8FnP94QBIaVQ==} + eslint-plugin-jsdoc@48.2.12: + resolution: {integrity: sha512-sO9sKkJx5ovWoRk9hV0YiNzXQ4Z6j27CqE/po2E3wddZVuy9wvKPSTiIhpxMTrP/qURvKayJIDB2+o9kyCW1Fw==} engines: {node: '>=18'} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 @@ -6702,14 +6702,14 @@ packages: resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==} engines: {node: '>=8'} - istanbul-lib-instrument@4.0.3: - resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} - engines: {node: '>=8'} - istanbul-lib-instrument@5.2.1: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} + istanbul-lib-instrument@6.0.2: + resolution: {integrity: sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==} + engines: {node: '>=10'} + istanbul-lib-processinfo@2.0.3: resolution: {integrity: sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==} engines: {node: '>=8'} @@ -7741,9 +7741,9 @@ packages: '@swc/core': optional: true - nyc@15.1.0: - resolution: {integrity: sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==} - engines: {node: '>=8.9'} + nyc@17.0.0: + resolution: {integrity: sha512-ISp44nqNCaPugLLGGfknzQwSwt10SSS5IMoPR7GLoMAyS18Iw5js8U7ga2VF9lYuMZ42gOHr3UddZw4WZltxKg==} + engines: {node: '>=18'} hasBin: true object-assign@4.1.1: @@ -8371,11 +8371,11 @@ packages: peerDependencies: react: ^18.2.0 - react-hook-form@7.51.5: - resolution: {integrity: sha512-J2ILT5gWx1XUIJRETiA7M19iXHlG74+6O3KApzvqB/w8S5NQR7AbU8HVZrMALdmDgWpRPYiZJl0zx8Z4L2mP6Q==} + react-hook-form@7.52.0: + resolution: {integrity: sha512-mJX506Xc6mirzLsmXUJyqlAI3Kj9Ph2RhplYhUVffeOQSnubK2uVqBFOBJmvKikvbFV91pxVXmDiR+QMF19x6A==} engines: {node: '>=12.22.0'} peerDependencies: - react: ^16.8.0 || ^17 || ^18 + react: ^16.8.0 || ^17 || ^18 || ^19 react-is@18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} @@ -9636,8 +9636,8 @@ packages: resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} engines: {node: '>=10.13.0'} - webpack@5.91.0: - resolution: {integrity: sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==} + webpack@5.92.0: + resolution: {integrity: sha512-Bsw2X39MYIgxouNATyVpCNVWBCuUwDgWtN78g6lSdPJRLaQ/PUVm/oXcaRAyY/sMFoKFQrsPeqvTizWtq7QPCA==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -11057,7 +11057,7 @@ snapshots: dependencies: '@types/eslint': 8.56.10 '@types/estree': 1.0.5 - '@typescript-eslint/types': 7.12.0 + '@typescript-eslint/types': 7.13.1 comment-parser: 1.4.1 esquery: 1.5.0 jsdoc-type-pratt-parser: 4.0.0 @@ -11699,7 +11699,7 @@ snapshots: '@next/env@14.2.4': {} - '@next/eslint-plugin-next@14.2.3': + '@next/eslint-plugin-next@14.2.4': dependencies: glob: 10.3.10 @@ -12685,11 +12685,11 @@ snapshots: '@types/unist@2.0.10': {} - '@types/webpack-bundle-analyzer@4.7.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0))': + '@types/webpack-bundle-analyzer@4.7.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0))': dependencies: '@types/node': 18.19.34 tapable: 2.2.1 - webpack: 5.91.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0)) + webpack: 5.92.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0)) transitivePeerDependencies: - '@swc/core' - esbuild @@ -12706,14 +12706,14 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.12.0 - '@typescript-eslint/type-utils': 7.12.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.12.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.12.0 + '@typescript-eslint/parser': 7.13.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.13.1 + '@typescript-eslint/type-utils': 7.13.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.13.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.13.1 eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 @@ -12724,12 +12724,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/scope-manager': 7.12.0 - '@typescript-eslint/types': 7.12.0 - '@typescript-eslint/typescript-estree': 7.12.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.12.0 + '@typescript-eslint/scope-manager': 7.13.1 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.13.1 debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 optionalDependencies: @@ -12737,15 +12737,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@7.12.0': + '@typescript-eslint/scope-manager@7.13.1': dependencies: - '@typescript-eslint/types': 7.12.0 - '@typescript-eslint/visitor-keys': 7.12.0 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/visitor-keys': 7.13.1 - '@typescript-eslint/type-utils@7.12.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/type-utils@7.13.1(eslint@8.57.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/typescript-estree': 7.12.0(typescript@5.4.5) - '@typescript-eslint/utils': 7.12.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) + '@typescript-eslint/utils': 7.13.1(eslint@8.57.0)(typescript@5.4.5) debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 ts-api-utils: 1.3.0(typescript@5.4.5) @@ -12754,12 +12754,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@7.12.0': {} + '@typescript-eslint/types@7.13.1': {} - '@typescript-eslint/typescript-estree@7.12.0(typescript@5.4.5)': + '@typescript-eslint/typescript-estree@7.13.1(typescript@5.4.5)': dependencies: - '@typescript-eslint/types': 7.12.0 - '@typescript-eslint/visitor-keys': 7.12.0 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/visitor-keys': 7.13.1 debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 @@ -12771,20 +12771,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@7.12.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/utils@7.13.1(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 7.12.0 - '@typescript-eslint/types': 7.12.0 - '@typescript-eslint/typescript-estree': 7.12.0(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.13.1 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) eslint: 8.57.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/visitor-keys@7.12.0': + '@typescript-eslint/visitor-keys@7.13.1': dependencies: - '@typescript-eslint/types': 7.12.0 + '@typescript-eslint/types': 7.13.1 eslint-visitor-keys: 3.4.3 '@ungap/structured-clone@1.2.0': {} @@ -12865,20 +12865,20 @@ snapshots: '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0))(webpack@5.91.0(webpack-cli@5.1.4))': + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0))(webpack@5.92.0(webpack-cli@5.1.4))': dependencies: - webpack: 5.91.0(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0) + webpack: 5.92.0(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0) - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0))(webpack@5.91.0(webpack-cli@5.1.4))': + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0))(webpack@5.92.0(webpack-cli@5.1.4))': dependencies: - webpack: 5.91.0(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0) + webpack: 5.92.0(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0))(webpack@5.91.0(webpack-cli@5.1.4))': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0))(webpack@5.92.0(webpack-cli@5.1.4))': dependencies: - webpack: 5.91.0(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0) + webpack: 5.92.0(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0) '@xtuc/ieee754@1.2.0': {} @@ -12913,7 +12913,7 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-import-assertions@1.9.0(acorn@8.11.3): + acorn-import-attributes@1.9.5(acorn@8.11.3): dependencies: acorn: 8.11.3 @@ -13301,12 +13301,12 @@ snapshots: dependencies: '@babel/core': 7.24.7 - babel-loader@9.1.3(@babel/core@7.24.7)(webpack@5.91.0(webpack-cli@5.1.4)): + babel-loader@9.1.3(@babel/core@7.24.7)(webpack@5.92.0(webpack-cli@5.1.4)): dependencies: '@babel/core': 7.24.7 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.91.0(webpack-cli@5.1.4) + webpack: 5.92.0(webpack-cli@5.1.4) babel-plugin-istanbul@6.1.1: dependencies: @@ -13881,11 +13881,11 @@ snapshots: dependencies: mime-db: 1.52.0 - compression-webpack-plugin@11.1.0(webpack@5.91.0(webpack-cli@5.1.4)): + compression-webpack-plugin@11.1.0(webpack@5.92.0(webpack-cli@5.1.4)): dependencies: schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.91.0(webpack-cli@5.1.4) + webpack: 5.92.0(webpack-cli@5.1.4) compression@1.7.4: dependencies: @@ -14503,7 +14503,7 @@ snapshots: memory-fs: 0.2.0 tapable: 0.1.10 - enhanced-resolve@5.16.0: + enhanced-resolve@5.17.0: dependencies: graceful-fs: 4.2.11 tapable: 2.2.1 @@ -14726,29 +14726,29 @@ snapshots: optionalDependencies: source-map: 0.2.0 - eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint@8.57.0): + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint@8.57.0): dependencies: confusing-browser-globals: 1.0.11 eslint: 8.57.0 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0) object.assign: 4.1.5 object.entries: 1.1.8 semver: 6.3.1 - eslint-config-airbnb-typescript@18.0.0(@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint@8.57.0): + eslint-config-airbnb-typescript@18.0.0(@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint@8.57.0): dependencies: - '@typescript-eslint/eslint-plugin': 7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/eslint-plugin': 7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.13.1(eslint@8.57.0)(typescript@5.4.5) eslint: 8.57.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - eslint-plugin-import - eslint-config-airbnb@19.0.4(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.34.2(eslint@8.57.0))(eslint@8.57.0): + eslint-config-airbnb@19.0.4(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.34.2(eslint@8.57.0))(eslint@8.57.0): dependencies: eslint: 8.57.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.34.2(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) @@ -14767,12 +14767,12 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.91.0(webpack-cli@5.1.4)): + eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.92.0(webpack-cli@5.1.4)): dependencies: array.prototype.find: 2.2.2 debug: 3.2.7 enhanced-resolve: 0.9.1 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0) find-root: 1.1.0 hasown: 2.0.2 interpret: 1.4.0 @@ -14781,18 +14781,18 @@ snapshots: lodash: 4.17.21 resolve: 2.0.0-next.5 semver: 5.7.2 - webpack: 5.91.0(webpack-cli@5.1.4) + webpack: 5.92.0(webpack-cli@5.1.4) transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.91.0(webpack-cli@5.1.4)))(eslint@8.57.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.92.0(webpack-cli@5.1.4)))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.13.1(eslint@8.57.0)(typescript@5.4.5) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-webpack: 0.13.8(eslint-plugin-import@2.29.1)(webpack@5.91.0(webpack-cli@5.1.4)) + eslint-import-resolver-webpack: 0.13.8(eslint-plugin-import@2.29.1)(webpack@5.92.0(webpack-cli@5.1.4)) transitivePeerDependencies: - supports-color @@ -14804,7 +14804,7 @@ snapshots: lodash.snakecase: 4.1.1 lodash.upperfirst: 4.3.1 - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-webpack@0.13.8)(eslint@8.57.0): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.3 @@ -14814,7 +14814,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.91.0(webpack-cli@5.1.4)))(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.92.0(webpack-cli@5.1.4)))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -14825,13 +14825,13 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.13.1(eslint@8.57.0)(typescript@5.4.5) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsdoc@48.2.9(eslint@8.57.0): + eslint-plugin-jsdoc@48.2.12(eslint@8.57.0): dependencies: '@es-joy/jsdoccomment': 0.43.1 are-docs-informative: 0.0.2 @@ -15792,7 +15792,7 @@ snapshots: readable-stream: 1.0.34 through2: 0.4.2 - html-webpack-plugin@5.6.0(webpack@5.91.0(webpack-cli@5.1.4)): + html-webpack-plugin@5.6.0(webpack@5.92.0(webpack-cli@5.1.4)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -15800,7 +15800,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.91.0(webpack-cli@5.1.4) + webpack: 5.92.0(webpack-cli@5.1.4) htmlparser2@6.1.0: dependencies: @@ -16202,22 +16202,23 @@ snapshots: dependencies: append-transform: 2.0.0 - istanbul-lib-instrument@4.0.3: + istanbul-lib-instrument@5.2.1: dependencies: '@babel/core': 7.24.7 + '@babel/parser': 7.24.7 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 transitivePeerDependencies: - supports-color - istanbul-lib-instrument@5.2.1: + istanbul-lib-instrument@6.0.2: dependencies: '@babel/core': 7.24.7 '@babel/parser': 7.24.7 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 + semver: 7.6.2 transitivePeerDependencies: - supports-color @@ -16565,11 +16566,11 @@ snapshots: dependencies: graceful-fs: 4.2.11 - karma-webpack@5.0.1(webpack@5.91.0(webpack-cli@5.1.4)): + karma-webpack@5.0.1(webpack@5.92.0(webpack-cli@5.1.4)): dependencies: glob: 7.2.3 minimatch: 9.0.4 - webpack: 5.91.0(webpack-cli@5.1.4) + webpack: 5.92.0(webpack-cli@5.1.4) webpack-merge: 4.2.2 karma@6.4.3: @@ -17609,7 +17610,7 @@ snapshots: transitivePeerDependencies: - debug - nyc@15.1.0: + nyc@17.0.0: dependencies: '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.3 @@ -17623,7 +17624,7 @@ snapshots: glob: 7.2.3 istanbul-lib-coverage: 3.2.2 istanbul-lib-hook: 3.0.0 - istanbul-lib-instrument: 4.0.3 + istanbul-lib-instrument: 6.0.2 istanbul-lib-processinfo: 2.0.3 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 4.0.1 @@ -18281,7 +18282,7 @@ snapshots: react: 18.2.0 scheduler: 0.23.0 - react-hook-form@7.51.5(react@18.2.0): + react-hook-form@7.52.0(react@18.2.0): dependencies: react: 18.2.0 @@ -19075,11 +19076,11 @@ snapshots: streamsearch@1.1.0: {} - string-replace-loader@3.1.0(webpack@5.91.0(webpack-cli@5.1.4)): + string-replace-loader@3.1.0(webpack@5.92.0(webpack-cli@5.1.4)): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.91.0(webpack-cli@5.1.4) + webpack: 5.92.0(webpack-cli@5.1.4) string-width@4.2.3: dependencies: @@ -19264,23 +19265,23 @@ snapshots: dependencies: rimraf: 2.6.3 - terser-webpack-plugin@5.3.10(webpack@5.91.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0))): + terser-webpack-plugin@5.3.10(webpack@5.92.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.27.0 - webpack: 5.91.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0)) + webpack: 5.92.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0)) - terser-webpack-plugin@5.3.10(webpack@5.91.0(webpack-cli@5.1.4)): + terser-webpack-plugin@5.3.10(webpack@5.92.0(webpack-cli@5.1.4)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.27.0 - webpack: 5.91.0(webpack-cli@5.1.4) + webpack: 5.92.0(webpack-cli@5.1.4) terser@5.27.0: dependencies: @@ -19714,12 +19715,12 @@ snapshots: - bufferutil - utf-8-validate - webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0): + webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0))(webpack@5.91.0(webpack-cli@5.1.4)) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0))(webpack@5.91.0(webpack-cli@5.1.4)) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0))(webpack@5.91.0(webpack-cli@5.1.4)) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0))(webpack@5.92.0(webpack-cli@5.1.4)) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0))(webpack@5.92.0(webpack-cli@5.1.4)) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0))(webpack@5.92.0(webpack-cli@5.1.4)) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.3 @@ -19728,7 +19729,7 @@ snapshots: import-local: 3.1.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.91.0(webpack-cli@5.1.4) + webpack: 5.92.0(webpack-cli@5.1.4) webpack-merge: 5.10.0 optionalDependencies: webpack-bundle-analyzer: 4.10.2 @@ -19745,7 +19746,7 @@ snapshots: webpack-sources@3.2.3: {} - webpack@5.91.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0)): + webpack@5.92.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0)): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.5 @@ -19753,10 +19754,10 @@ snapshots: '@webassemblyjs/wasm-edit': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 acorn: 8.11.3 - acorn-import-assertions: 1.9.0(acorn@8.11.3) + acorn-import-attributes: 1.9.5(acorn@8.11.3) browserslist: 4.23.0 chrome-trace-event: 1.0.3 - enhanced-resolve: 5.16.0 + enhanced-resolve: 5.17.0 es-module-lexer: 1.4.1 eslint-scope: 5.1.1 events: 3.3.0 @@ -19768,17 +19769,17 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(webpack@5.91.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0))) + terser-webpack-plugin: 5.3.10(webpack@5.92.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0))) watchpack: 2.4.1 webpack-sources: 3.2.3 optionalDependencies: - webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0) transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - webpack@5.91.0(webpack-cli@5.1.4): + webpack@5.92.0(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.5 @@ -19786,10 +19787,10 @@ snapshots: '@webassemblyjs/wasm-edit': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 acorn: 8.11.3 - acorn-import-assertions: 1.9.0(acorn@8.11.3) + acorn-import-attributes: 1.9.5(acorn@8.11.3) browserslist: 4.23.0 chrome-trace-event: 1.0.3 - enhanced-resolve: 5.16.0 + enhanced-resolve: 5.17.0 es-module-lexer: 1.4.1 eslint-scope: 5.1.1 events: 3.3.0 @@ -19801,11 +19802,11 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(webpack@5.91.0(webpack-cli@5.1.4)) + terser-webpack-plugin: 5.3.10(webpack@5.92.0(webpack-cli@5.1.4)) watchpack: 2.4.1 webpack-sources: 3.2.3 optionalDependencies: - webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.91.0) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.92.0) transitivePeerDependencies: - '@swc/core' - esbuild diff --git a/scripts/x-charts.exports.json b/scripts/x-charts.exports.json index 11b63c1a501fb..3dfc2afb4eeca 100644 --- a/scripts/x-charts.exports.json +++ b/scripts/x-charts.exports.json @@ -141,6 +141,7 @@ { "name": "DefaultizedScatterSeriesType", "kind": "Interface" }, { "name": "DefaultizedSeriesType", "kind": "TypeAlias" }, { "name": "Direction", "kind": "TypeAlias" }, + { "name": "ExtremumGettersConfig", "kind": "TypeAlias" }, { "name": "FadeOptions", "kind": "TypeAlias" }, { "name": "Gauge", "kind": "Function" }, { "name": "gaugeClasses", "kind": "Variable" }, From c0bed662f9ccb89b674b855f7d929c52281d05c8 Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 20 Jun 2024 10:27:03 +0200 Subject: [PATCH 26/31] fix --- packages/x-charts/src/hooks/useAxis.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/x-charts/src/hooks/useAxis.ts b/packages/x-charts/src/hooks/useAxis.ts index 2e095a131bd6b..d3f3fd2325bac 100644 --- a/packages/x-charts/src/hooks/useAxis.ts +++ b/packages/x-charts/src/hooks/useAxis.ts @@ -1,8 +1,7 @@ -import * as React from 'react'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; export function useXAxis(identifier?: number | string) { - const { xAxis, xAxisIds } = React.useContext(CartesianContext); + const { xAxis, xAxisIds } = useCartesianContext(); const id = typeof identifier === 'string' ? identifier : xAxisIds[identifier ?? 0]; @@ -10,7 +9,7 @@ export function useXAxis(identifier?: number | string) { } export function useYAxis(identifier?: number | string) { - const { yAxis, yAxisIds } = React.useContext(CartesianContext); + const { yAxis, yAxisIds } = useCartesianContext(); const id = typeof identifier === 'string' ? identifier : yAxisIds[identifier ?? 0]; From 8c7e6355df0bb7f50fe74dd0e7a0d87f0aa1808b Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 20 Jun 2024 10:36:09 +0200 Subject: [PATCH 27/31] document highlight --- docs/data/charts/heatmap/heatmap.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/data/charts/heatmap/heatmap.md b/docs/data/charts/heatmap/heatmap.md index 645ad7624c344..f4ee8dd1317ed 100644 --- a/docs/data/charts/heatmap/heatmap.md +++ b/docs/data/charts/heatmap/heatmap.md @@ -31,18 +31,17 @@ You can either use the piecewise or continuous [color mapping](https://mui.com/x {{"demo": "ColorConfig.js"}} -### Highlight 🚧 +### Highlight -Is this a disco dancefloor? πŸ•ΊπŸͺ© - -Planned work: - -- Add a way to override the styling. I woudl be in favor of adding a CSS classes instead of using styled component with ownerState, to let user apply filters on top of the current color, but they could not do crazy thing like complete color modification. They would need to use slots for that -- Adding an other highlight scopes: `x-axis`, `y-axis`, and `xy-axis` +You can chose to highlight the hovered element by setting `highlightScope.highlight` to `'item'`. +To fade the other item, set `highlightScope.fade` to `'global'`. {{"demo": "HighlightHeatmap.js"}} -You can modify the styling with CSS selectors. +By default highlighted/faded effect is obtained by applying the CSS property `fliter: saturate(...)` to cells. +To modify this styling, use the `heatmapClasses.highlighted` and `heatmapClasses.faded` CSS classes to override the applied style. + +In the following demo, we replace the highlight saturation by a border radius and reduce the saturation of the faded cells. {{"demo": "HighlightClasses.js"}} From edff1b96d70b3e1dc7d71abd479b330799075895 Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 20 Jun 2024 13:38:44 +0200 Subject: [PATCH 28/31] modify default color --- packages/x-charts-pro/src/Heatmap/Heatmap.tsx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx index 817c3eaad15e1..af5f928f83303 100644 --- a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx +++ b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { interpolateRgbBasis } from 'd3-interpolate'; import useId from '@mui/utils/useId'; import { ChartsAxis, ChartsAxisProps } from '@mui/x-charts/ChartsAxis'; import { @@ -86,6 +87,19 @@ export interface HeatmapProps slotProps?: HeatmapSlotProps; } +// The GnBu: https://github.com/d3/d3-scale-chromatic/blob/main/src/sequential-multi/GnBu.js +const defaultColorMap = interpolateRgbBasis([ + '#f7fcf0', + '#e0f3db', + '#ccebc5', + '#a8ddb5', + '#7bccc4', + '#4eb3d3', + '#2b8cbe', + '#0868ac', + '#084081', +]); + export const Heatmap = React.forwardRef(function Heatmap(props: HeatmapProps, ref) { const { xAxis, @@ -132,8 +146,8 @@ export const Heatmap = React.forwardRef(function Heatmap(props: HeatmapProps, re colorMap: { type: 'continuous', min: 0, - max: 10, - color: ['blue', 'red'], + max: 100, + color: defaultColorMap, }, } as const, ], From 3ed6d4614c42e63f40a3e30d9236ce50775b6570 Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 20 Jun 2024 13:38:59 +0200 Subject: [PATCH 29/31] feedback --- docs/data/charts/heatmap/HighlightClasses.js | 1 - docs/data/charts/heatmap/heatmap.md | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/data/charts/heatmap/HighlightClasses.js b/docs/data/charts/heatmap/HighlightClasses.js index 1443819f7f60c..cb57dcfae73ba 100644 --- a/docs/data/charts/heatmap/HighlightClasses.js +++ b/docs/data/charts/heatmap/HighlightClasses.js @@ -27,7 +27,6 @@ const data = [ ]; export default function HighlightClasses() { - console.log([`& .${heatmapClasses.cell}.${heatmapClasses.highlighted}`]); return ( ](/x/introduction/licensing/#pro-plan 'Pro plan')🚧 -

Heatmap charts allow to highlight correlation between categories.

+

Heatmap charts visually represents data with color variations to highlight patterns and trends across two dimensions.

:::warning The Heatmap Chart component isn't stable. Don't hesitate to open issues to give feedback. @@ -38,7 +38,7 @@ To fade the other item, set `highlightScope.fade` to `'global'`. {{"demo": "HighlightHeatmap.js"}} -By default highlighted/faded effect is obtained by applying the CSS property `fliter: saturate(...)` to cells. +By default highlighted/faded effect is obtained by applying the CSS property `filter: saturate(...)` to cells. To modify this styling, use the `heatmapClasses.highlighted` and `heatmapClasses.faded` CSS classes to override the applied style. In the following demo, we replace the highlight saturation by a border radius and reduce the saturation of the faded cells. From fdefab3aa83254784502381eb7d3d9b9793d74c3 Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 20 Jun 2024 13:39:19 +0200 Subject: [PATCH 30/31] share data accross example --- docs/data/charts/heatmap/BasicHeatmap.js | 24 +---------------- docs/data/charts/heatmap/BasicHeatmap.tsx | 25 +----------------- docs/data/charts/heatmap/CustomItem.js | 24 +---------------- docs/data/charts/heatmap/CustomItem.tsx | 25 +----------------- docs/data/charts/heatmap/HighlightClasses.js | 24 +---------------- docs/data/charts/heatmap/HighlightClasses.tsx | 26 +------------------ docs/data/charts/heatmap/HighlightHeatmap.js | 24 +---------------- docs/data/charts/heatmap/HighlightHeatmap.tsx | 25 +----------------- docs/data/charts/heatmap/dumbData.ts | 24 +++++++++++++++++ 9 files changed, 32 insertions(+), 189 deletions(-) create mode 100644 docs/data/charts/heatmap/dumbData.ts diff --git a/docs/data/charts/heatmap/BasicHeatmap.js b/docs/data/charts/heatmap/BasicHeatmap.js index 2f334d1aa000c..1f3410543e9b6 100644 --- a/docs/data/charts/heatmap/BasicHeatmap.js +++ b/docs/data/charts/heatmap/BasicHeatmap.js @@ -2,29 +2,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import '@mui/x-charts-pro/typeOverloads'; import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; - -const data = [ - [0, 0, 1], - [0, 1, 2], - [0, 2, 4], - [0, 3, 5], - [0, 4, 2], - [1, 0, 3], - [1, 1, 5], - [1, 2, 1], - [1, 3, 2], - [1, 4, 4], - [2, 0, 5], - [2, 1, 2], - [2, 2, 3], - [2, 3, 1], - [2, 4, 2], - [3, 0, 4], - [3, 1, 5], - [3, 2, 2], - [3, 3, 3], - [3, 4, 5], -]; +import { data } from './dumbData'; export default function BasicHeatmap() { return ( diff --git a/docs/data/charts/heatmap/BasicHeatmap.tsx b/docs/data/charts/heatmap/BasicHeatmap.tsx index 851d318b1989e..1f3410543e9b6 100644 --- a/docs/data/charts/heatmap/BasicHeatmap.tsx +++ b/docs/data/charts/heatmap/BasicHeatmap.tsx @@ -2,30 +2,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import '@mui/x-charts-pro/typeOverloads'; import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; -import { HeatmapValueType } from '@mui/x-charts-pro/models'; - -const data: HeatmapValueType[] = [ - [0, 0, 1], - [0, 1, 2], - [0, 2, 4], - [0, 3, 5], - [0, 4, 2], - [1, 0, 3], - [1, 1, 5], - [1, 2, 1], - [1, 3, 2], - [1, 4, 4], - [2, 0, 5], - [2, 1, 2], - [2, 2, 3], - [2, 3, 1], - [2, 4, 2], - [3, 0, 4], - [3, 1, 5], - [3, 2, 2], - [3, 3, 3], - [3, 4, 5], -]; +import { data } from './dumbData'; export default function BasicHeatmap() { return ( diff --git a/docs/data/charts/heatmap/CustomItem.js b/docs/data/charts/heatmap/CustomItem.js index a072126f209f4..af945337ef9e2 100644 --- a/docs/data/charts/heatmap/CustomItem.js +++ b/docs/data/charts/heatmap/CustomItem.js @@ -2,29 +2,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import '@mui/x-charts-pro/typeOverloads'; import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; - -const data = [ - [0, 0, 1], - [0, 1, 2], - [0, 2, 4], - [0, 3, 5], - [0, 4, 2], - [1, 0, 3], - [1, 1, 5], - [1, 2, 1], - [1, 3, 2], - [1, 4, 4], - [2, 0, 5], - [2, 1, 2], - [2, 2, 3], - [2, 3, 1], - [2, 4, 2], - [3, 0, 4], - [3, 1, 5], - [3, 2, 2], - [3, 3, 3], - [3, 4, 5], -]; +import { data } from './dumbData'; function CustomCell(props) { const { x, y, width, height, ownerState, ...other } = props; diff --git a/docs/data/charts/heatmap/CustomItem.tsx b/docs/data/charts/heatmap/CustomItem.tsx index 6ee5ff94f19b3..68d8357eba5f6 100644 --- a/docs/data/charts/heatmap/CustomItem.tsx +++ b/docs/data/charts/heatmap/CustomItem.tsx @@ -2,30 +2,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import '@mui/x-charts-pro/typeOverloads'; import { UnstableHeatmap } from '@mui/x-charts-pro/Heatmap'; -import { HeatmapValueType } from '@mui/x-charts-pro/models'; - -const data: HeatmapValueType[] = [ - [0, 0, 1], - [0, 1, 2], - [0, 2, 4], - [0, 3, 5], - [0, 4, 2], - [1, 0, 3], - [1, 1, 5], - [1, 2, 1], - [1, 3, 2], - [1, 4, 4], - [2, 0, 5], - [2, 1, 2], - [2, 2, 3], - [2, 3, 1], - [2, 4, 2], - [3, 0, 4], - [3, 1, 5], - [3, 2, 2], - [3, 3, 3], - [3, 4, 5], -]; +import { data } from './dumbData'; function CustomCell(props: any) { const { x, y, width, height, ownerState, ...other } = props; diff --git a/docs/data/charts/heatmap/HighlightClasses.js b/docs/data/charts/heatmap/HighlightClasses.js index cb57dcfae73ba..b27be9e2dd097 100644 --- a/docs/data/charts/heatmap/HighlightClasses.js +++ b/docs/data/charts/heatmap/HighlightClasses.js @@ -2,29 +2,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import '@mui/x-charts-pro/typeOverloads'; import { UnstableHeatmap, heatmapClasses } from '@mui/x-charts-pro/Heatmap'; - -const data = [ - [0, 0, 1], - [0, 1, 2], - [0, 2, 4], - [0, 3, 5], - [0, 4, 2], - [1, 0, 3], - [1, 1, 5], - [1, 2, 1], - [1, 3, 2], - [1, 4, 4], - [2, 0, 5], - [2, 1, 2], - [2, 2, 3], - [2, 3, 1], - [2, 4, 2], - [3, 0, 4], - [3, 1, 5], - [3, 2, 2], - [3, 3, 3], - [3, 4, 5], -]; +import { data } from './dumbData'; export default function HighlightClasses() { return ( diff --git a/docs/data/charts/heatmap/HighlightClasses.tsx b/docs/data/charts/heatmap/HighlightClasses.tsx index 274118e1a1090..b27be9e2dd097 100644 --- a/docs/data/charts/heatmap/HighlightClasses.tsx +++ b/docs/data/charts/heatmap/HighlightClasses.tsx @@ -2,33 +2,9 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import '@mui/x-charts-pro/typeOverloads'; import { UnstableHeatmap, heatmapClasses } from '@mui/x-charts-pro/Heatmap'; -import { HeatmapValueType } from '@mui/x-charts-pro/models'; - -const data: HeatmapValueType[] = [ - [0, 0, 1], - [0, 1, 2], - [0, 2, 4], - [0, 3, 5], - [0, 4, 2], - [1, 0, 3], - [1, 1, 5], - [1, 2, 1], - [1, 3, 2], - [1, 4, 4], - [2, 0, 5], - [2, 1, 2], - [2, 2, 3], - [2, 3, 1], - [2, 4, 2], - [3, 0, 4], - [3, 1, 5], - [3, 2, 2], - [3, 3, 3], - [3, 4, 5], -]; +import { data } from './dumbData'; export default function HighlightClasses() { - console.log([`& .${heatmapClasses.cell}.${heatmapClasses.highlighted}`]); return ( Date: Mon, 1 Jul 2024 13:58:18 +0200 Subject: [PATCH 31/31] fix --- packages/x-charts/src/BarChart/useBarChartProps.ts | 2 +- packages/x-charts/src/LineChart/useLineChartProps.ts | 2 +- packages/x-charts/src/ScatterChart/useScatterChartProps.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/x-charts/src/BarChart/useBarChartProps.ts b/packages/x-charts/src/BarChart/useBarChartProps.ts index 72d1141b43c92..4370f5d67389a 100644 --- a/packages/x-charts/src/BarChart/useBarChartProps.ts +++ b/packages/x-charts/src/BarChart/useBarChartProps.ts @@ -146,7 +146,7 @@ export const useBarChartProps = (props: BarChartProps) => { slotProps, }; - const tooltipProps: ChartsTooltipProps = { + const tooltipProps: ChartsTooltipProps<'bar'> = { ...tooltip, slots, slotProps, diff --git a/packages/x-charts/src/LineChart/useLineChartProps.ts b/packages/x-charts/src/LineChart/useLineChartProps.ts index 97413791ca0c8..47bbcbc7bd42b 100644 --- a/packages/x-charts/src/LineChart/useLineChartProps.ts +++ b/packages/x-charts/src/LineChart/useLineChartProps.ts @@ -159,7 +159,7 @@ export const useLineChartProps = (props: LineChartProps) => { slotProps, }; - const tooltipProps: ChartsTooltipProps = { + const tooltipProps: ChartsTooltipProps<'line'> = { ...tooltip, slots, slotProps, diff --git a/packages/x-charts/src/ScatterChart/useScatterChartProps.ts b/packages/x-charts/src/ScatterChart/useScatterChartProps.ts index 383e7a105fe0a..b3fe96a66fc6f 100644 --- a/packages/x-charts/src/ScatterChart/useScatterChartProps.ts +++ b/packages/x-charts/src/ScatterChart/useScatterChartProps.ts @@ -104,7 +104,7 @@ export const useScatterChartProps = (props: ScatterChartProps) => { ...axisHighlight, }; - const tooltipProps: ChartsTooltipProps = { + const tooltipProps: ChartsTooltipProps<'scatter'> = { trigger: 'item' as const, ...tooltip, slots,