From 78824d6a14736c13d47ec9c44136152f4c4dd722 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 16 Aug 2024 11:35:25 +0200 Subject: [PATCH 01/25] Fix typo --- packages/x-charts/src/themeAugmentation/overrides.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/x-charts/src/themeAugmentation/overrides.d.ts b/packages/x-charts/src/themeAugmentation/overrides.d.ts index c2699e9f67d0a..bf02bbb9c42e5 100644 --- a/packages/x-charts/src/themeAugmentation/overrides.d.ts +++ b/packages/x-charts/src/themeAugmentation/overrides.d.ts @@ -8,7 +8,7 @@ import { ChartsTooltipClassKey } from '../ChartsTooltip'; import { AreaElementClassKey, LineElementClassKey, MarkElementClassKey } from '../LineChart'; // prettier-ignore -export interface PickersComponentNameToClassKey { +export interface ChartsComponentNameToClassKey { MuiChartsAxis: ChartsAxisClassKey; MuiChartsAxisHighlight: ChartsAxisHighlightClassKey; MuiChartsGrid: ChartsGridClassKey; @@ -29,7 +29,7 @@ export interface PickersComponentNameToClassKey { } declare module '@mui/material/styles' { - interface ComponentNameToClassKey extends PickersComponentNameToClassKey {} + interface ComponentNameToClassKey extends ChartsComponentNameToClassKey {} } // disable automatic export From 3c402754d9d93bbaf1bf75e148ea69bfb034f977 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 16 Aug 2024 11:36:33 +0200 Subject: [PATCH 02/25] Add new class for item background --- packages/x-charts/src/ChartsLegend/ChartsLegend.tsx | 1 + packages/x-charts/src/ChartsLegend/chartsLegendClasses.ts | 3 +++ 2 files changed, 4 insertions(+) diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx index 1fab773c243fe..63753a4f83533 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx @@ -54,6 +54,7 @@ const useUtilityClasses = (ownerState: DefaultizedChartsLegendProps & { theme: T mark: ['mark'], label: ['label'], series: ['series'], + itemBackground: ['itemBackground'], }; return composeClasses(slots, getLegendUtilityClass, classes); diff --git a/packages/x-charts/src/ChartsLegend/chartsLegendClasses.ts b/packages/x-charts/src/ChartsLegend/chartsLegendClasses.ts index 5d710e5540569..3ec9664ff4a54 100644 --- a/packages/x-charts/src/ChartsLegend/chartsLegendClasses.ts +++ b/packages/x-charts/src/ChartsLegend/chartsLegendClasses.ts @@ -8,6 +8,8 @@ export interface ChartsLegendClasses { root: string; /** Styles applied to a series element. */ series: string; + /** Styles applied to the item background. */ + itemBackground: string; /** Styles applied to series mark element. */ mark: string; /** Styles applied to the series label. */ @@ -27,6 +29,7 @@ export function getLegendUtilityClass(slot: string) { export const legendClasses: ChartsLegendClasses = generateUtilityClasses('MuiChartsLegend', [ 'root', 'series', + 'itemBackground', 'mark', 'label', 'column', From 6b17d82ac83ec9c5053cbc96650a0a9c287e54ac Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 16 Aug 2024 11:37:21 +0200 Subject: [PATCH 03/25] Implement on click legend --- .../src/ChartsLegend/ChartsLegendItem.tsx | 92 +++++++++++++++++++ .../src/ChartsLegend/DefaultChartsLegend.tsx | 7 ++ .../src/ChartsLegend/LegendPerItem.tsx | 51 +++++----- .../src/ChartsLegend/PiecewiseColorLegend.tsx | 7 ++ 4 files changed, 133 insertions(+), 24 deletions(-) create mode 100644 packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx new file mode 100644 index 0000000000000..871f37a0bef3b --- /dev/null +++ b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx @@ -0,0 +1,92 @@ +import * as React from 'react'; +import clsx from 'clsx'; +import { useTheme } from '@mui/material/styles'; +import { ChartsText, ChartsTextStyle } from '../ChartsText'; +import { SeriesId } from '../models/seriesType/common'; +import { LegendItemParams } from './chartsLegend.types'; +import { ChartsLegendClasses } from './chartsLegendClasses'; + +export interface ChartsLegendItemProps { + id: SeriesId; + index: number; + positionY: number; + label: string; + positionX: number; + innerHeight: number; + innerWidth: number; + color: string; + gapX: number; + gapY: number; + legendWidth: number; + itemMarkHeight: number; + itemMarkWidth: number; + markGap: number; + labelStyle: ChartsTextStyle; + classes?: Omit, 'column' | 'row' | 'label'>; + onClick?: (legend: LegendItemParams, index: number) => void; +} + +/** + * @ignore - internal component. + */ +function ChartsLegendItem(props: ChartsLegendItemProps) { + const theme = useTheme(); + const isRTL = theme.direction === 'rtl'; + const { + id, + positionY, + label, + positionX, + innerHeight, + innerWidth, + legendWidth, + color, + gapX, + gapY, + itemMarkHeight, + itemMarkWidth, + markGap, + labelStyle, + classes, + index, + onClick, + } = props; + + return ( + + onClick({ id, label, color }, index) : undefined} + style={{ + pointerEvents: onClick ? 'all' : 'none', + cursor: onClick ? 'pointer' : 'unset', + }} + /> + + + + ); +} + +export { ChartsLegendItem }; diff --git a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx index 2c485452fd041..2785f0ce68e6c 100644 --- a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx @@ -74,6 +74,13 @@ DefaultChartsLegend.propTypes = { * @default 5 */ markGap: PropTypes.number, + /** + * Callback fired when a legend item is clicked. + * @param {LegendItemParams} legend The legend item data. + * @param {number} dataIndex The index of the clicked legend item. + * @default undefined + */ + onClick: PropTypes.func, /** * Legend padding (in px). * Can either be a single number, or an object with top, left, bottom, right properties. diff --git a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx index dd61aeb4e9f89..c0e065eab5f75 100644 --- a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx +++ b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx @@ -3,7 +3,7 @@ import NoSsr from '@mui/material/NoSsr'; import { useTheme, styled } from '@mui/material/styles'; import { DrawingArea } from '../context/DrawingProvider'; import { DefaultizedProps } from '../models/helpers'; -import { ChartsText, ChartsTextStyle } from '../ChartsText'; +import { ChartsTextStyle } from '../ChartsText'; import { CardinalDirections } from '../models/layout'; import { getWordsByLines } from '../internals/getWordsByLines'; import type { ChartsLegendProps } from './ChartsLegend'; @@ -11,6 +11,8 @@ import { GetItemSpaceType, LegendItemParams } from './chartsLegend.types'; import { legendItemPlacements } from './legendItemsPlacement'; import { useDrawingArea } from '../hooks/useDrawingArea'; import { AnchorPosition, Direction } from './legend.types'; +import { ChartsLegendItem } from './ChartsLegendItem'; +import { ChartsLegendClasses } from './chartsLegendClasses'; export type ChartsLegendRootOwnerState = { position: AnchorPosition; @@ -36,7 +38,7 @@ export interface LegendPerItemProps * The ordered array of item to display in the legend. */ itemsToDisplay: LegendItemParams[]; - classes?: Record<'mark' | 'series' | 'root', string>; + classes?: Omit, 'column' | 'row'>; /** * Style applied to legend labels. * @default theme.typography.subtitle1 @@ -68,6 +70,13 @@ export interface LegendPerItemProps * @default 10 */ padding?: number | Partial>; + /** + * Callback fired when a legend item is clicked. + * @param {LegendItemParams} legend The legend item data. + * @param {number} dataIndex The index of the clicked legend item. + * @default undefined + */ + onClick?: (legend: LegendItemParams, dataIndex: number) => void; } /** @@ -109,9 +118,9 @@ export function LegendPerItem(props: LegendPerItemProps) { itemGap = 10, padding: paddingProps = 10, labelStyle: inLabelStyle, + onClick, } = props; const theme = useTheme(); - const isRTL = theme.direction === 'rtl'; const drawingArea = useDrawingArea(); const labelStyle = React.useMemo( @@ -196,27 +205,21 @@ export function LegendPerItem(props: LegendPerItemProps) { return ( - {itemsWithPosition.map(({ id, label, color, positionX, positionY }) => ( - - - - + {itemsWithPosition.map((item, i) => ( + ))} diff --git a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx index bfbda66985037..3c15ae212711b 100644 --- a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx @@ -157,6 +157,13 @@ PiecewiseColorLegend.propTypes = { * @default 5 */ markGap: PropTypes.number, + /** + * Callback fired when a legend item is clicked. + * @param {LegendItemParams} legend The legend item data. + * @param {number} dataIndex The index of the clicked legend item. + * @default undefined + */ + onClick: PropTypes.func, /** * Legend padding (in px). * Can either be a single number, or an object with top, left, bottom, right properties. From f46c59883bdbaeef20c13c511cb000714d1b8381 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 16 Aug 2024 11:38:19 +0200 Subject: [PATCH 04/25] fix types --- docs/pages/x/api/charts/charts-legend.json | 6 +++++ .../x/api/charts/default-charts-legend.json | 26 ++++++++++++++++--- .../x/api/charts/piecewise-color-legend.json | 26 ++++++++++++++++--- .../charts/charts-legend/charts-legend.json | 4 +++ .../default-charts-legend.json | 18 ++++++++++--- .../piecewise-color-legend.json | 18 ++++++++++--- 6 files changed, 86 insertions(+), 12 deletions(-) diff --git a/docs/pages/x/api/charts/charts-legend.json b/docs/pages/x/api/charts/charts-legend.json index c11a1cc616f97..7fe4b7ae48a48 100644 --- a/docs/pages/x/api/charts/charts-legend.json +++ b/docs/pages/x/api/charts/charts-legend.json @@ -37,6 +37,12 @@ "description": "Styles applied to the legend with column layout.", "isGlobal": false }, + { + "key": "itemBackground", + "className": "MuiChartsLegend-itemBackground", + "description": "Styles applied to the item background.", + "isGlobal": false + }, { "key": "label", "className": "MuiChartsLegend-label", diff --git a/docs/pages/x/api/charts/default-charts-legend.json b/docs/pages/x/api/charts/default-charts-legend.json index be48bf222e739..d76abe37fd1f2 100644 --- a/docs/pages/x/api/charts/default-charts-legend.json +++ b/docs/pages/x/api/charts/default-charts-legend.json @@ -18,6 +18,14 @@ "itemMarkWidth": { "type": { "name": "number" }, "default": "20" }, "labelStyle": { "type": { "name": "object" }, "default": "theme.typography.subtitle1" }, "markGap": { "type": { "name": "number" }, "default": "5" }, + "onClick": { + "type": { "name": "func" }, + "default": "undefined", + "signature": { + "type": "function(legend: LegendItemParams, dataIndex: number) => void", + "describedArgs": ["legend", "dataIndex"] + } + }, "padding": { "type": { "name": "union", @@ -33,22 +41,34 @@ "import { DefaultChartsLegend } from '@mui/x-charts-pro';" ], "classes": [ + { + "key": "itemBackground", + "className": "MuiDefaultChartsLegend-itemBackground", + "description": "Styles applied to the item background.", + "isGlobal": false + }, + { + "key": "label", + "className": "MuiDefaultChartsLegend-label", + "description": "Styles applied to the series label.", + "isGlobal": false + }, { "key": "mark", "className": "MuiDefaultChartsLegend-mark", - "description": "", + "description": "Styles applied to series mark element.", "isGlobal": false }, { "key": "root", "className": "MuiDefaultChartsLegend-root", - "description": "", + "description": "Styles applied to the root element.", "isGlobal": false }, { "key": "series", "className": "MuiDefaultChartsLegend-series", - "description": "", + "description": "Styles applied to a series element.", "isGlobal": false } ], diff --git a/docs/pages/x/api/charts/piecewise-color-legend.json b/docs/pages/x/api/charts/piecewise-color-legend.json index cd19020d0cd50..46843ddc040b8 100644 --- a/docs/pages/x/api/charts/piecewise-color-legend.json +++ b/docs/pages/x/api/charts/piecewise-color-legend.json @@ -36,6 +36,14 @@ }, "labelStyle": { "type": { "name": "object" }, "default": "theme.typography.subtitle1" }, "markGap": { "type": { "name": "number" }, "default": "5" }, + "onClick": { + "type": { "name": "func" }, + "default": "undefined", + "signature": { + "type": "function(legend: LegendItemParams, dataIndex: number) => void", + "describedArgs": ["legend", "dataIndex"] + } + }, "padding": { "type": { "name": "union", @@ -51,22 +59,34 @@ "import { PiecewiseColorLegend } from '@mui/x-charts-pro';" ], "classes": [ + { + "key": "itemBackground", + "className": "MuiPiecewiseColorLegend-itemBackground", + "description": "Styles applied to the item background.", + "isGlobal": false + }, + { + "key": "label", + "className": "MuiPiecewiseColorLegend-label", + "description": "Styles applied to the series label.", + "isGlobal": false + }, { "key": "mark", "className": "MuiPiecewiseColorLegend-mark", - "description": "", + "description": "Styles applied to series mark element.", "isGlobal": false }, { "key": "root", "className": "MuiPiecewiseColorLegend-root", - "description": "", + "description": "Styles applied to the root element.", "isGlobal": false }, { "key": "series", "className": "MuiPiecewiseColorLegend-series", - "description": "", + "description": "Styles applied to a series element.", "isGlobal": false } ], diff --git a/docs/translations/api-docs/charts/charts-legend/charts-legend.json b/docs/translations/api-docs/charts/charts-legend/charts-legend.json index f48685ad6338b..770d0323bacd2 100644 --- a/docs/translations/api-docs/charts/charts-legend/charts-legend.json +++ b/docs/translations/api-docs/charts/charts-legend/charts-legend.json @@ -15,6 +15,10 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the legend with column layout" }, + "itemBackground": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the item background" + }, "label": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the series label" }, "mark": { "description": "Styles applied to {{nodeName}}.", "nodeName": "series mark element" }, "root": { "description": "Styles applied to the root element." }, diff --git a/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json b/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json index 4f48245b770e5..d239defadb284 100644 --- a/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json +++ b/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json @@ -11,14 +11,26 @@ "itemMarkWidth": { "description": "Width of the item mark (in px)." }, "labelStyle": { "description": "Style applied to legend labels." }, "markGap": { "description": "Space between the mark and the label (in px)." }, + "onClick": { + "description": "Callback fired when a legend item is clicked.", + "typeDescriptions": { + "legend": "The legend item data.", + "dataIndex": "The index of the clicked legend item." + } + }, "padding": { "description": "Legend padding (in px). Can either be a single number, or an object with top, left, bottom, right properties." }, "position": { "description": "The position of the legend." } }, "classDescriptions": { - "mark": { "description": "" }, - "root": { "description": "" }, - "series": { "description": "" } + "itemBackground": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the item background" + }, + "label": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the series label" }, + "mark": { "description": "Styles applied to {{nodeName}}.", "nodeName": "series mark element" }, + "root": { "description": "Styles applied to the root element." }, + "series": { "description": "Styles applied to {{nodeName}}.", "nodeName": "a series element" } } } diff --git a/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json b/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json index e240ffb1f7e91..8ffcccc6db190 100644 --- a/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json +++ b/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json @@ -30,14 +30,26 @@ }, "labelStyle": { "description": "Style applied to legend labels." }, "markGap": { "description": "Space between the mark and the label (in px)." }, + "onClick": { + "description": "Callback fired when a legend item is clicked.", + "typeDescriptions": { + "legend": "The legend item data.", + "dataIndex": "The index of the clicked legend item." + } + }, "padding": { "description": "Legend padding (in px). Can either be a single number, or an object with top, left, bottom, right properties." }, "position": { "description": "The position of the legend." } }, "classDescriptions": { - "mark": { "description": "" }, - "root": { "description": "" }, - "series": { "description": "" } + "itemBackground": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the item background" + }, + "label": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the series label" }, + "mark": { "description": "Styles applied to {{nodeName}}.", "nodeName": "series mark element" }, + "root": { "description": "Styles applied to the root element." }, + "series": { "description": "Styles applied to {{nodeName}}.", "nodeName": "a series element" } } } From 1f4ce27ac2972487213b8496a748ad37afd62814 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 16 Aug 2024 12:39:51 +0200 Subject: [PATCH 05/25] Rename to onItemClick --- docs/data/charts/legend/legend.md | 14 ++++++++++++++ .../pages/x/api/charts/default-charts-legend.json | 6 +++--- .../x/api/charts/piecewise-color-legend.json | 6 +++--- .../default-charts-legend.json | 7 ++++--- .../piecewise-color-legend.json | 7 ++++--- .../src/ChartsLegend/ChartsLegendItem.tsx | 14 +++++++++----- .../src/ChartsLegend/DefaultChartsLegend.tsx | 7 ++++--- .../x-charts/src/ChartsLegend/LegendPerItem.tsx | 15 ++++++++++----- .../src/ChartsLegend/PiecewiseColorLegend.tsx | 7 ++++--- 9 files changed, 55 insertions(+), 28 deletions(-) diff --git a/docs/data/charts/legend/legend.md b/docs/data/charts/legend/legend.md index f3042bc1a75d9..d0b01b6fd9094 100644 --- a/docs/data/charts/legend/legend.md +++ b/docs/data/charts/legend/legend.md @@ -111,3 +111,17 @@ labelFormatter = ({ min, max, formattedMin, formattedMax }) => string | null; ``` {{"demo": "PiecewiseInteractiveDemoNoSnap.js", "hideToolbar": true, "bg": "playground"}} + +## Click event + +You can pass an `onItemClick` function to the `ChartsLegend` or `PiecewiseColorLegend` components to handle click events. + +They both provide the following signature. + +```js +const clickHandler = ( + event, // The mouse event. + params, // An object that identifies the clicked item. + index, // The index of the clicked item. +) => {}; +``` diff --git a/docs/pages/x/api/charts/default-charts-legend.json b/docs/pages/x/api/charts/default-charts-legend.json index d76abe37fd1f2..c43ec14d410a5 100644 --- a/docs/pages/x/api/charts/default-charts-legend.json +++ b/docs/pages/x/api/charts/default-charts-legend.json @@ -18,12 +18,12 @@ "itemMarkWidth": { "type": { "name": "number" }, "default": "20" }, "labelStyle": { "type": { "name": "object" }, "default": "theme.typography.subtitle1" }, "markGap": { "type": { "name": "number" }, "default": "5" }, - "onClick": { + "onItemClick": { "type": { "name": "func" }, "default": "undefined", "signature": { - "type": "function(legend: LegendItemParams, dataIndex: number) => void", - "describedArgs": ["legend", "dataIndex"] + "type": "function(event: React.MouseEvent, legendItem: LegendItemParams, index: number) => void", + "describedArgs": ["event", "legendItem", "index"] } }, "padding": { diff --git a/docs/pages/x/api/charts/piecewise-color-legend.json b/docs/pages/x/api/charts/piecewise-color-legend.json index 46843ddc040b8..4f9e5aaa1b438 100644 --- a/docs/pages/x/api/charts/piecewise-color-legend.json +++ b/docs/pages/x/api/charts/piecewise-color-legend.json @@ -36,12 +36,12 @@ }, "labelStyle": { "type": { "name": "object" }, "default": "theme.typography.subtitle1" }, "markGap": { "type": { "name": "number" }, "default": "5" }, - "onClick": { + "onItemClick": { "type": { "name": "func" }, "default": "undefined", "signature": { - "type": "function(legend: LegendItemParams, dataIndex: number) => void", - "describedArgs": ["legend", "dataIndex"] + "type": "function(event: React.MouseEvent, legendItem: LegendItemParams, index: number) => void", + "describedArgs": ["event", "legendItem", "index"] } }, "padding": { diff --git a/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json b/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json index d239defadb284..2c1d27eddf9ae 100644 --- a/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json +++ b/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json @@ -11,11 +11,12 @@ "itemMarkWidth": { "description": "Width of the item mark (in px)." }, "labelStyle": { "description": "Style applied to legend labels." }, "markGap": { "description": "Space between the mark and the label (in px)." }, - "onClick": { + "onItemClick": { "description": "Callback fired when a legend item is clicked.", "typeDescriptions": { - "legend": "The legend item data.", - "dataIndex": "The index of the clicked legend item." + "event": "The click event.", + "legendItem": "The legend item data.", + "index": "The index of the clicked legend item." } }, "padding": { diff --git a/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json b/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json index 8ffcccc6db190..e5f1808123f33 100644 --- a/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json +++ b/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json @@ -30,11 +30,12 @@ }, "labelStyle": { "description": "Style applied to legend labels." }, "markGap": { "description": "Space between the mark and the label (in px)." }, - "onClick": { + "onItemClick": { "description": "Callback fired when a legend item is clicked.", "typeDescriptions": { - "legend": "The legend item data.", - "dataIndex": "The index of the clicked legend item." + "event": "The click event.", + "legendItem": "The legend item data.", + "index": "The index of the clicked legend item." } }, "padding": { diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx index 871f37a0bef3b..43ea5d018d907 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx @@ -23,7 +23,11 @@ export interface ChartsLegendItemProps { markGap: number; labelStyle: ChartsTextStyle; classes?: Omit, 'column' | 'row' | 'label'>; - onClick?: (legend: LegendItemParams, index: number) => void; + onItemClick?: ( + event: React.MouseEvent, + legendItem: LegendItemParams, + index: number, + ) => void; } /** @@ -49,7 +53,7 @@ function ChartsLegendItem(props: ChartsLegendItemProps) { labelStyle, classes, index, - onClick, + onItemClick, } = props; return ( @@ -64,10 +68,10 @@ function ChartsLegendItem(props: ChartsLegendItemProps) { height={innerHeight + 4} fill="transparent" className={classes?.itemBackground} - onClick={onClick ? () => onClick({ id, label, color }, index) : undefined} + onClick={onItemClick ? (e) => onItemClick(e, { id, label, color }, index) : undefined} style={{ - pointerEvents: onClick ? 'all' : 'none', - cursor: onClick ? 'pointer' : 'unset', + pointerEvents: onItemClick ? 'all' : 'none', + cursor: onItemClick ? 'pointer' : 'unset', }} /> } event The click event. + * @param {LegendItemParams} legendItem The legend item data. + * @param {number} index The index of the clicked legend item. * @default undefined */ - onClick: PropTypes.func, + onItemClick: PropTypes.func, /** * Legend padding (in px). * Can either be a single number, or an object with top, left, bottom, right properties. diff --git a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx index c0e065eab5f75..7ed143efd30cb 100644 --- a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx +++ b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx @@ -72,11 +72,16 @@ export interface LegendPerItemProps padding?: number | Partial>; /** * Callback fired when a legend item is clicked. - * @param {LegendItemParams} legend The legend item data. - * @param {number} dataIndex The index of the clicked legend item. + * @param {React.MouseEvent} event The click event. + * @param {LegendItemParams} legendItem The legend item data. + * @param {number} index The index of the clicked legend item. * @default undefined */ - onClick?: (legend: LegendItemParams, dataIndex: number) => void; + onItemClick?: ( + event: React.MouseEvent, + legendItem: LegendItemParams, + index: number, + ) => void; } /** @@ -118,7 +123,7 @@ export function LegendPerItem(props: LegendPerItemProps) { itemGap = 10, padding: paddingProps = 10, labelStyle: inLabelStyle, - onClick, + onItemClick, } = props; const theme = useTheme(); const drawingArea = useDrawingArea(); @@ -218,7 +223,7 @@ export function LegendPerItem(props: LegendPerItemProps) { markGap={markGap} labelStyle={labelStyle} classes={classes} - onClick={onClick} + onItemClick={onItemClick} /> ))} diff --git a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx index 3c15ae212711b..e6716e41057b1 100644 --- a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx @@ -159,11 +159,12 @@ PiecewiseColorLegend.propTypes = { markGap: PropTypes.number, /** * Callback fired when a legend item is clicked. - * @param {LegendItemParams} legend The legend item data. - * @param {number} dataIndex The index of the clicked legend item. + * @param {React.MouseEvent} event The click event. + * @param {LegendItemParams} legendItem The legend item data. + * @param {number} index The index of the clicked legend item. * @default undefined */ - onClick: PropTypes.func, + onItemClick: PropTypes.func, /** * Legend padding (in px). * Can either be a single number, or an object with top, left, bottom, right properties. From 41208898663c62bf1f9fca5d65fd11a948a2212e Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 21 Aug 2024 12:15:15 +0200 Subject: [PATCH 06/25] Rename type --- .../x/api/charts/default-charts-legend.json | 2 +- .../x/api/charts/piecewise-color-legend.json | 2 +- packages/x-charts/src/BarChart/legend.ts | 4 +- .../src/ChartsLegend/ChartsLegendItem.tsx | 4 +- .../src/ChartsLegend/DefaultChartsLegend.tsx | 2 +- .../src/ChartsLegend/LegendPerItem.tsx | 8 ++-- .../src/ChartsLegend/PiecewiseColorLegend.tsx | 6 +-- .../src/ChartsLegend/chartsLegend.types.ts | 46 ++++++++++++++++++- .../src/ChartsLegend/legendItemsPlacement.ts | 4 +- packages/x-charts/src/LineChart/legend.ts | 4 +- packages/x-charts/src/PieChart/legend.ts | 4 +- packages/x-charts/src/ScatterChart/legend.ts | 4 +- .../PluginProvider/SeriesFormatter.types.ts | 4 +- 13 files changed, 68 insertions(+), 26 deletions(-) diff --git a/docs/pages/x/api/charts/default-charts-legend.json b/docs/pages/x/api/charts/default-charts-legend.json index c43ec14d410a5..e174d90a1b694 100644 --- a/docs/pages/x/api/charts/default-charts-legend.json +++ b/docs/pages/x/api/charts/default-charts-legend.json @@ -22,7 +22,7 @@ "type": { "name": "func" }, "default": "undefined", "signature": { - "type": "function(event: React.MouseEvent, legendItem: LegendItemParams, index: number) => void", + "type": "function(event: React.MouseEvent, legendItem: LegendItem, index: number) => void", "describedArgs": ["event", "legendItem", "index"] } }, diff --git a/docs/pages/x/api/charts/piecewise-color-legend.json b/docs/pages/x/api/charts/piecewise-color-legend.json index 4f9e5aaa1b438..9f52b7875aa4e 100644 --- a/docs/pages/x/api/charts/piecewise-color-legend.json +++ b/docs/pages/x/api/charts/piecewise-color-legend.json @@ -40,7 +40,7 @@ "type": { "name": "func" }, "default": "undefined", "signature": { - "type": "function(event: React.MouseEvent, legendItem: LegendItemParams, index: number) => void", + "type": "function(event: React.MouseEvent, legendItem: LegendItem, index: number) => void", "describedArgs": ["event", "legendItem", "index"] } }, diff --git a/packages/x-charts/src/BarChart/legend.ts b/packages/x-charts/src/BarChart/legend.ts index 6098786b5c55e..4c7be9dbc57fe 100644 --- a/packages/x-charts/src/BarChart/legend.ts +++ b/packages/x-charts/src/BarChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItemParams } from '../ChartsLegend/chartsLegend.types'; +import { LegendItem } from '../ChartsLegend/chartsLegend.types'; import { LegendGetter } from '../context/PluginProvider'; import { getLabel } from '../internals/getLabel'; @@ -17,7 +17,7 @@ const legendGetter: LegendGetter<'bar'> = (params) => { id: seriesId, }); return acc; - }, [] as LegendItemParams[]); + }, [] as LegendItem[]); }; export default legendGetter; diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx index 43ea5d018d907..050587815b84b 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx @@ -3,7 +3,7 @@ import clsx from 'clsx'; import { useTheme } from '@mui/material/styles'; import { ChartsText, ChartsTextStyle } from '../ChartsText'; import { SeriesId } from '../models/seriesType/common'; -import { LegendItemParams } from './chartsLegend.types'; +import { LegendItem } from './chartsLegend.types'; import { ChartsLegendClasses } from './chartsLegendClasses'; export interface ChartsLegendItemProps { @@ -25,7 +25,7 @@ export interface ChartsLegendItemProps { classes?: Omit, 'column' | 'row' | 'label'>; onItemClick?: ( event: React.MouseEvent, - legendItem: LegendItemParams, + legendItem: LegendItem, index: number, ) => void; } diff --git a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx index ff1972be05171..d6a1c323ee936 100644 --- a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx @@ -77,7 +77,7 @@ DefaultChartsLegend.propTypes = { /** * Callback fired when a legend item is clicked. * @param {React.MouseEvent} event The click event. - * @param {LegendItemParams} legendItem The legend item data. + * @param {LegendItem} legendItem The legend item data. * @param {number} index The index of the clicked legend item. * @default undefined */ diff --git a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx index 7ed143efd30cb..ea19c88d02e12 100644 --- a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx +++ b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx @@ -7,7 +7,7 @@ import { ChartsTextStyle } from '../ChartsText'; import { CardinalDirections } from '../models/layout'; import { getWordsByLines } from '../internals/getWordsByLines'; import type { ChartsLegendProps } from './ChartsLegend'; -import { GetItemSpaceType, LegendItemParams } from './chartsLegend.types'; +import { GetItemSpaceType, LegendItem } from './chartsLegend.types'; import { legendItemPlacements } from './legendItemsPlacement'; import { useDrawingArea } from '../hooks/useDrawingArea'; import { AnchorPosition, Direction } from './legend.types'; @@ -37,7 +37,7 @@ export interface LegendPerItemProps /** * The ordered array of item to display in the legend. */ - itemsToDisplay: LegendItemParams[]; + itemsToDisplay: LegendItem[]; classes?: Omit, 'column' | 'row'>; /** * Style applied to legend labels. @@ -73,13 +73,13 @@ export interface LegendPerItemProps /** * Callback fired when a legend item is clicked. * @param {React.MouseEvent} event The click event. - * @param {LegendItemParams} legendItem The legend item data. + * @param {LegendItem} legendItem The legend item data. * @param {number} index The index of the clicked legend item. * @default undefined */ onItemClick?: ( event: React.MouseEvent, - legendItem: LegendItemParams, + legendItem: LegendItem, index: number, ) => void; } diff --git a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx index e6716e41057b1..196496ba3bbef 100644 --- a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx @@ -68,10 +68,10 @@ function PiecewiseColorLegend(props: PiecewiseColorLegendProps) { } const label = labelFormatter({ - ...(index === 0 + ...(isFirst ? { min: null, formattedMin: null } : { min: colorMap.thresholds[index - 1], formattedMin: formattedLabels[index - 1] }), - ...(index === colorMap.colors.length - 1 + ...(isLast ? { max: null, formattedMax: null } : { max: colorMap.thresholds[index], formattedMax: formattedLabels[index] }), }); @@ -160,7 +160,7 @@ PiecewiseColorLegend.propTypes = { /** * Callback fired when a legend item is clicked. * @param {React.MouseEvent} event The click event. - * @param {LegendItemParams} legendItem The legend item data. + * @param {LegendItem} legendItem The legend item data. * @param {number} index The index of the clicked legend item. * @default undefined */ diff --git a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts index bf7d08c31dff2..3166d53a39401 100644 --- a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts +++ b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts @@ -1,6 +1,7 @@ import { ChartsTextStyle } from '../ChartsText'; +import { SeriesId } from '../models/seriesType/common'; -export interface LegendItemParams { +export interface LegendItem { /** * The color used in the legend */ @@ -16,7 +17,48 @@ export interface LegendItemParams { id: number | string; } -export interface LegendItemWithPosition extends LegendItemParams { +interface SeriesLegendItem extends Omit { + /** + * The type of the legend item + * - `series` is used for series legend item + * - `piecewiseColor` is used for piecewise color legend item + */ + type: 'series'; + /** + * The identifier of the series + */ + seriesId: SeriesId; +} +interface PiecewiseColorLegendItem extends Omit { + /** + * The type of the legend item + * - `series` is used for series legend item + * - `piecewiseColor` is used for piecewise color legend item + */ + type: 'piecewiseColor'; + /** + * The identifier of the color map + */ + colorMapId: string; + /** + * The index of the category + */ + categoryIndex: number; + /** + * The minimum value of the category + */ + minValue: number; + /** + * The maximum value of the category + */ + maxValue: number; +} + +export type LegendItemContext = SeriesLegendItem | PiecewiseColorLegendItem; + +// export type LegendItemParams = LegendItem + +export interface LegendItemWithPosition extends LegendItem { positionX: number; positionY: number; innerHeight: number; diff --git a/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts b/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts index f482e3b9a244c..1be84235eed89 100644 --- a/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts +++ b/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts @@ -1,8 +1,8 @@ import { ChartsTextStyle } from '../ChartsText'; -import { GetItemSpaceType, LegendItemParams, LegendItemWithPosition } from './chartsLegend.types'; +import { GetItemSpaceType, LegendItem, LegendItemWithPosition } from './chartsLegend.types'; export function legendItemPlacements( - itemsToDisplay: LegendItemParams[], + itemsToDisplay: LegendItem[], getItemSpace: GetItemSpaceType, labelStyle: ChartsTextStyle, direction: string, diff --git a/packages/x-charts/src/LineChart/legend.ts b/packages/x-charts/src/LineChart/legend.ts index 99038fee1a3c8..781c4ef5f41ba 100644 --- a/packages/x-charts/src/LineChart/legend.ts +++ b/packages/x-charts/src/LineChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItemParams } from '../ChartsLegend/chartsLegend.types'; +import { LegendItem } from '../ChartsLegend/chartsLegend.types'; import { getLabel } from '../internals/getLabel'; import { LegendGetter } from '../context/PluginProvider'; @@ -17,7 +17,7 @@ const legendGetter: LegendGetter<'line'> = (params) => { id: seriesId, }); return acc; - }, [] as LegendItemParams[]); + }, [] as LegendItem[]); }; export default legendGetter; diff --git a/packages/x-charts/src/PieChart/legend.ts b/packages/x-charts/src/PieChart/legend.ts index a3c90e5df464b..549f30f86c3f9 100644 --- a/packages/x-charts/src/PieChart/legend.ts +++ b/packages/x-charts/src/PieChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItemParams } from '../ChartsLegend/chartsLegend.types'; +import { LegendItem } from '../ChartsLegend/chartsLegend.types'; import { getLabel } from '../internals/getLabel'; import { LegendGetter } from '../context/PluginProvider'; @@ -19,7 +19,7 @@ const legendGetter: LegendGetter<'pie'> = (params) => { }); }); return acc; - }, [] as LegendItemParams[]); + }, [] as LegendItem[]); }; export default legendGetter; diff --git a/packages/x-charts/src/ScatterChart/legend.ts b/packages/x-charts/src/ScatterChart/legend.ts index 5e60c7db3644d..e94b380f94bbc 100644 --- a/packages/x-charts/src/ScatterChart/legend.ts +++ b/packages/x-charts/src/ScatterChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItemParams } from '../ChartsLegend/chartsLegend.types'; +import { LegendItem } from '../ChartsLegend/chartsLegend.types'; import { getLabel } from '../internals/getLabel'; import { LegendGetter } from '../context/PluginProvider'; @@ -17,7 +17,7 @@ const legendGetter: LegendGetter<'scatter'> = (params) => { id: seriesId, }); return acc; - }, [] as LegendItemParams[]); + }, [] as LegendItem[]); }; export default legendGetter; diff --git a/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts b/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts index 6462da81a53b8..04541b3b47cd4 100644 --- a/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts +++ b/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts @@ -6,7 +6,7 @@ import type { } from '../../models/seriesType/config'; import type { SeriesId } from '../../models/seriesType/common'; import type { StackingGroupsType } from '../../internals/stackSeries'; -import type { LegendItemParams } from '../../ChartsLegend/chartsLegend.types'; +import type { LegendItem } from '../../ChartsLegend/chartsLegend.types'; export type SeriesFormatterParams = { series: Record; @@ -29,7 +29,7 @@ export type SeriesFormatter = ( export type LegendGetter = ( series: SeriesFormatterResult, -) => LegendItemParams[]; +) => LegendItem[]; export type SeriesFormatterConfig = { // TODO replace the function type by Formatter From 2d99c87717f03f1bfbc970ae83a68a316a5cb2d8 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 21 Aug 2024 15:05:47 +0200 Subject: [PATCH 07/25] OnItemClick to OnClick --- .../x-charts/src/ChartsLegend/ChartsLegendItem.tsx | 10 +++++----- packages/x-charts/src/ChartsLegend/LegendPerItem.tsx | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx index 050587815b84b..6cf16d73dd17c 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx @@ -23,7 +23,7 @@ export interface ChartsLegendItemProps { markGap: number; labelStyle: ChartsTextStyle; classes?: Omit, 'column' | 'row' | 'label'>; - onItemClick?: ( + onClick?: ( event: React.MouseEvent, legendItem: LegendItem, index: number, @@ -53,7 +53,7 @@ function ChartsLegendItem(props: ChartsLegendItemProps) { labelStyle, classes, index, - onItemClick, + onClick, } = props; return ( @@ -68,10 +68,10 @@ function ChartsLegendItem(props: ChartsLegendItemProps) { height={innerHeight + 4} fill="transparent" className={classes?.itemBackground} - onClick={onItemClick ? (e) => onItemClick(e, { id, label, color }, index) : undefined} + onClick={onClick ? (e) => onClick(e, { id, label, color }, index) : undefined} style={{ - pointerEvents: onItemClick ? 'all' : 'none', - cursor: onItemClick ? 'pointer' : 'unset', + pointerEvents: onClick ? 'all' : 'none', + cursor: onClick ? 'pointer' : 'unset', }} /> ))} From f43eb68ed92a0da3c6b7195fdb96b1cd6a45ab7a Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 21 Aug 2024 16:08:23 +0200 Subject: [PATCH 08/25] Provide useful context on legend click --- packages/x-charts/src/BarChart/legend.ts | 6 +- .../src/ChartsLegend/ChartsLegendItem.tsx | 58 +++++++++++++++++-- .../src/ChartsLegend/LegendPerItem.tsx | 8 +-- .../src/ChartsLegend/PiecewiseColorLegend.tsx | 15 ++++- .../src/ChartsLegend/chartsLegend.types.ts | 51 +++++++++++----- .../src/ChartsLegend/legendItemsPlacement.ts | 4 +- packages/x-charts/src/LineChart/legend.ts | 6 +- packages/x-charts/src/PieChart/legend.ts | 6 +- packages/x-charts/src/ScatterChart/legend.ts | 6 +- .../PluginProvider/SeriesFormatter.types.ts | 4 +- 10 files changed, 126 insertions(+), 38 deletions(-) diff --git a/packages/x-charts/src/BarChart/legend.ts b/packages/x-charts/src/BarChart/legend.ts index 4c7be9dbc57fe..1d606cea057a3 100644 --- a/packages/x-charts/src/BarChart/legend.ts +++ b/packages/x-charts/src/BarChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItem } from '../ChartsLegend/chartsLegend.types'; +import { LegendItemConfig } from '../ChartsLegend/chartsLegend.types'; import { LegendGetter } from '../context/PluginProvider'; import { getLabel } from '../internals/getLabel'; @@ -15,9 +15,11 @@ const legendGetter: LegendGetter<'bar'> = (params) => { color: series[seriesId].color, label: formattedLabel, id: seriesId, + type: 'series', + seriesId, }); return acc; - }, [] as LegendItem[]); + }, [] as LegendItemConfig[]); }; export default legendGetter; diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx index 6cf16d73dd17c..9f781396d2483 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx @@ -3,11 +3,10 @@ import clsx from 'clsx'; import { useTheme } from '@mui/material/styles'; import { ChartsText, ChartsTextStyle } from '../ChartsText'; import { SeriesId } from '../models/seriesType/common'; -import { LegendItem } from './chartsLegend.types'; +import { LegendItemConfig, LegendItemContext } from './chartsLegend.types'; import { ChartsLegendClasses } from './chartsLegendClasses'; -export interface ChartsLegendItemProps { - id: SeriesId; +export interface ChartsLegendItemProps extends LegendItemConfig { index: number; positionY: number; label: string; @@ -25,11 +24,40 @@ export interface ChartsLegendItemProps { classes?: Omit, 'column' | 'row' | 'label'>; onClick?: ( event: React.MouseEvent, - legendItem: LegendItem, + legendItem: LegendItemContext, index: number, ) => void; } +const createClickContext = ( + type: LegendItemContext['type'], + { + seriesId, + itemId, + minValue, + maxValue, + color, + label, + }: { + seriesId?: SeriesId; + itemId?: string | number; + minValue?: number | Date | null; + maxValue?: number | Date | null; + color: string; + label: string; + }, +) => { + if (type === 'piecewiseColor') { + return { type, color, label, minValue: minValue ?? null, maxValue: maxValue ?? null }; + } + + if (type === 'pie') { + return { type, seriesId: seriesId!, itemId: itemId!, color, label }; + } + + return { type, seriesId: seriesId!, color, label }; +}; + /** * @ignore - internal component. */ @@ -53,6 +81,10 @@ function ChartsLegendItem(props: ChartsLegendItemProps) { labelStyle, classes, index, + seriesId, + type, + minValue, + maxValue, onClick, } = props; @@ -68,7 +100,23 @@ function ChartsLegendItem(props: ChartsLegendItemProps) { height={innerHeight + 4} fill="transparent" className={classes?.itemBackground} - onClick={onClick ? (e) => onClick(e, { id, label, color }, index) : undefined} + onClick={ + onClick + ? (e) => + onClick( + e, + createClickContext(type, { + seriesId, + itemId: id, + minValue, + maxValue, + color, + label, + }), + index, + ) + : undefined + } style={{ pointerEvents: onClick ? 'all' : 'none', cursor: onClick ? 'pointer' : 'unset', diff --git a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx index 5544a0550a8c7..85ab780081573 100644 --- a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx +++ b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx @@ -7,7 +7,7 @@ import { ChartsTextStyle } from '../ChartsText'; import { CardinalDirections } from '../models/layout'; import { getWordsByLines } from '../internals/getWordsByLines'; import type { ChartsLegendProps } from './ChartsLegend'; -import { GetItemSpaceType, LegendItem } from './chartsLegend.types'; +import { GetItemSpaceType, LegendItemConfig, LegendItemContext } from './chartsLegend.types'; import { legendItemPlacements } from './legendItemsPlacement'; import { useDrawingArea } from '../hooks/useDrawingArea'; import { AnchorPosition, Direction } from './legend.types'; @@ -37,7 +37,7 @@ export interface LegendPerItemProps /** * The ordered array of item to display in the legend. */ - itemsToDisplay: LegendItem[]; + itemsToDisplay: LegendItemConfig[]; classes?: Omit, 'column' | 'row'>; /** * Style applied to legend labels. @@ -73,13 +73,13 @@ export interface LegendPerItemProps /** * Callback fired when a legend item is clicked. * @param {React.MouseEvent} event The click event. - * @param {LegendItem} legendItem The legend item data. + * @param {LegendItemConfig} legendItem The legend item data. * @param {number} index The index of the clicked legend item. * @default undefined */ onItemClick?: ( event: React.MouseEvent, - legendItem: LegendItem, + legendItem: LegendItemContext, index: number, ) => void; } diff --git a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx index 196496ba3bbef..a7b5118491408 100644 --- a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx @@ -67,20 +67,29 @@ function PiecewiseColorLegend(props: PiecewiseColorLegendProps) { return null; } - const label = labelFormatter({ + const data = { ...(isFirst ? { min: null, formattedMin: null } : { min: colorMap.thresholds[index - 1], formattedMin: formattedLabels[index - 1] }), ...(isLast ? { max: null, formattedMax: null } : { max: colorMap.thresholds[index], formattedMax: formattedLabels[index] }), - }); + }; + + const label = labelFormatter(data); if (label === null) { return null; } - return { id: label, color, label }; + return { + id: label, + color, + label, + minValue: data.min, + maxValue: data.max, + type: 'piecewiseColor' as const, + }; }) .filter(notNull); diff --git a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts index 3166d53a39401..0c6360dfb2fd7 100644 --- a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts +++ b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts @@ -1,7 +1,8 @@ import { ChartsTextStyle } from '../ChartsText'; +import { PieItemId } from '../models'; import { SeriesId } from '../models/seriesType/common'; -export interface LegendItem { +interface LegendItemContextBase { /** * The color used in the legend */ @@ -10,18 +11,27 @@ export interface LegendItem { * The label displayed in the legend */ label: string; +} + +export interface LegendItemConfig + extends Partial>, + Partial>, + Partial>, + LegendItemContextBase { /** * The identifier of the legend element. * Used for internal purpose such as `key` props */ id: number | string; + type: 'series' | 'piecewiseColor' | 'pie'; } -interface SeriesLegendItem extends Omit { +interface SeriesLegendItemContext extends LegendItemContextBase { /** * The type of the legend item * - `series` is used for series legend item * - `piecewiseColor` is used for piecewise color legend item + * - `pie` is used for pie legend item */ type: 'series'; /** @@ -29,36 +39,49 @@ interface SeriesLegendItem extends Omit { */ seriesId: SeriesId; } -interface PiecewiseColorLegendItem extends Omit { + +interface PieLegendItemContext extends LegendItemContextBase { /** * The type of the legend item * - `series` is used for series legend item * - `piecewiseColor` is used for piecewise color legend item + * - `pie` is used for pie legend item */ - type: 'piecewiseColor'; + type: 'pie'; /** - * The identifier of the color map + * The identifier of the series */ - colorMapId: string; + seriesId: SeriesId; /** - * The index of the category + * The identifier of the pie item */ - categoryIndex: number; + itemId: PieItemId; +} + +interface PiecewiseColorLegendItemContext extends LegendItemContextBase { + /** + * The type of the legend item + * - `series` is used for series legend item + * - `piecewiseColor` is used for piecewise color legend item + * - `pie` is used for pie legend item + */ + type: 'piecewiseColor'; /** * The minimum value of the category */ - minValue: number; + minValue: number | Date | null; /** * The maximum value of the category */ - maxValue: number; + maxValue: number | Date | null; } -export type LegendItemContext = SeriesLegendItem | PiecewiseColorLegendItem; - -// export type LegendItemParams = LegendItem +export type LegendItemContext = + | SeriesLegendItemContext + | PiecewiseColorLegendItemContext + | PieLegendItemContext; -export interface LegendItemWithPosition extends LegendItem { +export interface LegendItemWithPosition extends LegendItemConfig { positionX: number; positionY: number; innerHeight: number; diff --git a/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts b/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts index 1be84235eed89..ffaf941e67c49 100644 --- a/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts +++ b/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts @@ -1,8 +1,8 @@ import { ChartsTextStyle } from '../ChartsText'; -import { GetItemSpaceType, LegendItem, LegendItemWithPosition } from './chartsLegend.types'; +import { GetItemSpaceType, LegendItemConfig, LegendItemWithPosition } from './chartsLegend.types'; export function legendItemPlacements( - itemsToDisplay: LegendItem[], + itemsToDisplay: LegendItemConfig[], getItemSpace: GetItemSpaceType, labelStyle: ChartsTextStyle, direction: string, diff --git a/packages/x-charts/src/LineChart/legend.ts b/packages/x-charts/src/LineChart/legend.ts index 781c4ef5f41ba..50b8a00004614 100644 --- a/packages/x-charts/src/LineChart/legend.ts +++ b/packages/x-charts/src/LineChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItem } from '../ChartsLegend/chartsLegend.types'; +import { LegendItemConfig } from '../ChartsLegend/chartsLegend.types'; import { getLabel } from '../internals/getLabel'; import { LegendGetter } from '../context/PluginProvider'; @@ -15,9 +15,11 @@ const legendGetter: LegendGetter<'line'> = (params) => { color: series[seriesId].color, label: formattedLabel, id: seriesId, + type: 'series', + seriesId, }); return acc; - }, [] as LegendItem[]); + }, [] as LegendItemConfig[]); }; export default legendGetter; diff --git a/packages/x-charts/src/PieChart/legend.ts b/packages/x-charts/src/PieChart/legend.ts index 549f30f86c3f9..f1e2c7faa4f88 100644 --- a/packages/x-charts/src/PieChart/legend.ts +++ b/packages/x-charts/src/PieChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItem } from '../ChartsLegend/chartsLegend.types'; +import { LegendItemConfig } from '../ChartsLegend/chartsLegend.types'; import { getLabel } from '../internals/getLabel'; import { LegendGetter } from '../context/PluginProvider'; @@ -16,10 +16,12 @@ const legendGetter: LegendGetter<'pie'> = (params) => { color: item.color, label: formattedLabel, id: item.id, + seriesId, + type: 'pie', }); }); return acc; - }, [] as LegendItem[]); + }, [] as LegendItemConfig[]); }; export default legendGetter; diff --git a/packages/x-charts/src/ScatterChart/legend.ts b/packages/x-charts/src/ScatterChart/legend.ts index e94b380f94bbc..9ba5840e48615 100644 --- a/packages/x-charts/src/ScatterChart/legend.ts +++ b/packages/x-charts/src/ScatterChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItem } from '../ChartsLegend/chartsLegend.types'; +import { LegendItemConfig } from '../ChartsLegend/chartsLegend.types'; import { getLabel } from '../internals/getLabel'; import { LegendGetter } from '../context/PluginProvider'; @@ -15,9 +15,11 @@ const legendGetter: LegendGetter<'scatter'> = (params) => { color: series[seriesId].color, label: formattedLabel, id: seriesId, + type: 'series', + seriesId, }); return acc; - }, [] as LegendItem[]); + }, [] as LegendItemConfig[]); }; export default legendGetter; diff --git a/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts b/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts index 04541b3b47cd4..cfa7eceb624b0 100644 --- a/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts +++ b/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts @@ -6,7 +6,7 @@ import type { } from '../../models/seriesType/config'; import type { SeriesId } from '../../models/seriesType/common'; import type { StackingGroupsType } from '../../internals/stackSeries'; -import type { LegendItem } from '../../ChartsLegend/chartsLegend.types'; +import type { LegendItemConfig } from '../../ChartsLegend/chartsLegend.types'; export type SeriesFormatterParams = { series: Record; @@ -29,7 +29,7 @@ export type SeriesFormatter = ( export type LegendGetter = ( series: SeriesFormatterResult, -) => LegendItem[]; +) => LegendItemConfig[]; export type SeriesFormatterConfig = { // TODO replace the function type by Formatter From 45504ab0be349ed148a8997245e16024503e622b Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 21 Aug 2024 16:37:58 +0200 Subject: [PATCH 09/25] Simplify logic --- packages/x-charts/src/BarChart/legend.ts | 7 +++--- .../src/ChartsLegend/ChartsLegendItem.tsx | 6 +---- .../src/ChartsLegend/chartsLegend.types.ts | 24 +++---------------- packages/x-charts/src/LineChart/legend.ts | 6 ++--- packages/x-charts/src/PieChart/legend.ts | 6 ++--- packages/x-charts/src/ScatterChart/legend.ts | 6 ++--- 6 files changed, 17 insertions(+), 38 deletions(-) diff --git a/packages/x-charts/src/BarChart/legend.ts b/packages/x-charts/src/BarChart/legend.ts index 1d606cea057a3..29383d73f43d8 100644 --- a/packages/x-charts/src/BarChart/legend.ts +++ b/packages/x-charts/src/BarChart/legend.ts @@ -12,12 +12,13 @@ const legendGetter: LegendGetter<'bar'> = (params) => { } acc.push({ - color: series[seriesId].color, - label: formattedLabel, - id: seriesId, type: 'series', + id: seriesId, seriesId, + color: series[seriesId].color, + label: formattedLabel, }); + return acc; }, [] as LegendItemConfig[]); }; diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx index 9f781396d2483..8b5646ef033ec 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx @@ -51,11 +51,7 @@ const createClickContext = ( return { type, color, label, minValue: minValue ?? null, maxValue: maxValue ?? null }; } - if (type === 'pie') { - return { type, seriesId: seriesId!, itemId: itemId!, color, label }; - } - - return { type, seriesId: seriesId!, color, label }; + return { type, seriesId: seriesId!, itemId: itemId!, color, label }; }; /** diff --git a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts index 0c6360dfb2fd7..698cd7bb121f5 100644 --- a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts +++ b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts @@ -14,8 +14,7 @@ interface LegendItemContextBase { } export interface LegendItemConfig - extends Partial>, - Partial>, + extends Partial>, Partial>, LegendItemContextBase { /** @@ -23,7 +22,7 @@ export interface LegendItemConfig * Used for internal purpose such as `key` props */ id: number | string; - type: 'series' | 'piecewiseColor' | 'pie'; + type: 'series' | 'piecewiseColor'; } interface SeriesLegendItemContext extends LegendItemContextBase { @@ -38,20 +37,6 @@ interface SeriesLegendItemContext extends LegendItemContextBase { * The identifier of the series */ seriesId: SeriesId; -} - -interface PieLegendItemContext extends LegendItemContextBase { - /** - * The type of the legend item - * - `series` is used for series legend item - * - `piecewiseColor` is used for piecewise color legend item - * - `pie` is used for pie legend item - */ - type: 'pie'; - /** - * The identifier of the series - */ - seriesId: SeriesId; /** * The identifier of the pie item */ @@ -76,10 +61,7 @@ interface PiecewiseColorLegendItemContext extends LegendItemContextBase { maxValue: number | Date | null; } -export type LegendItemContext = - | SeriesLegendItemContext - | PiecewiseColorLegendItemContext - | PieLegendItemContext; +export type LegendItemContext = SeriesLegendItemContext | PiecewiseColorLegendItemContext; export interface LegendItemWithPosition extends LegendItemConfig { positionX: number; diff --git a/packages/x-charts/src/LineChart/legend.ts b/packages/x-charts/src/LineChart/legend.ts index 50b8a00004614..afb9d54a259cc 100644 --- a/packages/x-charts/src/LineChart/legend.ts +++ b/packages/x-charts/src/LineChart/legend.ts @@ -12,11 +12,11 @@ const legendGetter: LegendGetter<'line'> = (params) => { } acc.push({ - color: series[seriesId].color, - label: formattedLabel, - id: seriesId, type: 'series', + id: seriesId, seriesId, + color: series[seriesId].color, + label: formattedLabel, }); return acc; }, [] as LegendItemConfig[]); diff --git a/packages/x-charts/src/PieChart/legend.ts b/packages/x-charts/src/PieChart/legend.ts index f1e2c7faa4f88..744a05f5bb95c 100644 --- a/packages/x-charts/src/PieChart/legend.ts +++ b/packages/x-charts/src/PieChart/legend.ts @@ -13,11 +13,11 @@ const legendGetter: LegendGetter<'pie'> = (params) => { } acc.push({ - color: item.color, - label: formattedLabel, + type: 'series', id: item.id, seriesId, - type: 'pie', + color: item.color, + label: formattedLabel, }); }); return acc; diff --git a/packages/x-charts/src/ScatterChart/legend.ts b/packages/x-charts/src/ScatterChart/legend.ts index 9ba5840e48615..881901f3eda5d 100644 --- a/packages/x-charts/src/ScatterChart/legend.ts +++ b/packages/x-charts/src/ScatterChart/legend.ts @@ -12,11 +12,11 @@ const legendGetter: LegendGetter<'scatter'> = (params) => { } acc.push({ - color: series[seriesId].color, - label: formattedLabel, - id: seriesId, type: 'series', + id: seriesId, seriesId, + color: series[seriesId].color, + label: formattedLabel, }); return acc; }, [] as LegendItemConfig[]); From ab493cca70ace52c015e7a06c74ead9703f4c61a Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 21 Aug 2024 17:15:33 +0200 Subject: [PATCH 10/25] Improve typing --- .../x/api/charts/default-charts-legend.json | 2 +- .../x/api/charts/piecewise-color-legend.json | 2 +- .../src/ChartsLegend/ChartsLegendItem.tsx | 4 ++-- .../src/ChartsLegend/DefaultChartsLegend.tsx | 22 +++++++++++++++++-- .../src/ChartsLegend/LegendPerItem.tsx | 11 ++-------- .../src/ChartsLegend/PiecewiseColorLegend.tsx | 17 ++++++++++++-- .../src/ChartsLegend/chartsLegend.types.ts | 4 ++-- 7 files changed, 43 insertions(+), 19 deletions(-) diff --git a/docs/pages/x/api/charts/default-charts-legend.json b/docs/pages/x/api/charts/default-charts-legend.json index e174d90a1b694..a2f27932916a5 100644 --- a/docs/pages/x/api/charts/default-charts-legend.json +++ b/docs/pages/x/api/charts/default-charts-legend.json @@ -22,7 +22,7 @@ "type": { "name": "func" }, "default": "undefined", "signature": { - "type": "function(event: React.MouseEvent, legendItem: LegendItem, index: number) => void", + "type": "function(event: React.MouseEvent, legendItem: SeriesLegendItemContext, index: number) => void", "describedArgs": ["event", "legendItem", "index"] } }, diff --git a/docs/pages/x/api/charts/piecewise-color-legend.json b/docs/pages/x/api/charts/piecewise-color-legend.json index 9f52b7875aa4e..62ce29a882337 100644 --- a/docs/pages/x/api/charts/piecewise-color-legend.json +++ b/docs/pages/x/api/charts/piecewise-color-legend.json @@ -40,7 +40,7 @@ "type": { "name": "func" }, "default": "undefined", "signature": { - "type": "function(event: React.MouseEvent, legendItem: LegendItem, index: number) => void", + "type": "function(event: React.MouseEvent, legendItem: PiecewiseColorLegendItemContext, index: number) => void", "describedArgs": ["event", "legendItem", "index"] } }, diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx index 8b5646ef033ec..c6e6415d39a47 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx @@ -40,7 +40,7 @@ const createClickContext = ( label, }: { seriesId?: SeriesId; - itemId?: string | number; + itemId: string | number; minValue?: number | Date | null; maxValue?: number | Date | null; color: string; @@ -51,7 +51,7 @@ const createClickContext = ( return { type, color, label, minValue: minValue ?? null, maxValue: maxValue ?? null }; } - return { type, seriesId: seriesId!, itemId: itemId!, color, label }; + return { type, seriesId: seriesId!, itemId, color, label }; }; /** diff --git a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx index d6a1c323ee936..4a157c3abf747 100644 --- a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx @@ -3,14 +3,28 @@ import PropTypes from 'prop-types'; import { FormattedSeries } from '../context/SeriesProvider'; import { LegendPerItem, LegendPerItemProps } from './LegendPerItem'; import { DrawingArea } from '../context/DrawingProvider'; +import { SeriesLegendItemContext } from './chartsLegend.types'; -export interface LegendRendererProps extends Omit { +export interface LegendRendererProps + extends Omit { series: FormattedSeries; seriesToDisplay: LegendPerItemProps['itemsToDisplay']; /** * @deprecated Use the `useDrawingArea` hook instead. */ drawingArea: Omit; + /** + * Callback fired when a legend item is clicked. + * @param {React.MouseEvent} event The click event. + * @param {SeriesLegendItemContext} legendItem The legend item data. + * @param {number} index The index of the clicked legend item. + * @default undefined + */ + onItemClick?: ( + event: React.MouseEvent, + legendItem: SeriesLegendItemContext, + index: number, + ) => void; } function DefaultChartsLegend(props: LegendRendererProps) { @@ -77,7 +91,7 @@ DefaultChartsLegend.propTypes = { /** * Callback fired when a legend item is clicked. * @param {React.MouseEvent} event The click event. - * @param {LegendItem} legendItem The legend item data. + * @param {SeriesLegendItemContext} legendItem The legend item data. * @param {number} index The index of the clicked legend item. * @default undefined */ @@ -109,6 +123,10 @@ DefaultChartsLegend.propTypes = { color: PropTypes.string.isRequired, id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, label: PropTypes.string.isRequired, + maxValue: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + minValue: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), + seriesId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + type: PropTypes.oneOf(['piecewiseColor', 'series']).isRequired, }), ).isRequired, } as any; diff --git a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx index 85ab780081573..00912f74e79dd 100644 --- a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx +++ b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx @@ -7,7 +7,7 @@ import { ChartsTextStyle } from '../ChartsText'; import { CardinalDirections } from '../models/layout'; import { getWordsByLines } from '../internals/getWordsByLines'; import type { ChartsLegendProps } from './ChartsLegend'; -import { GetItemSpaceType, LegendItemConfig, LegendItemContext } from './chartsLegend.types'; +import { GetItemSpaceType, LegendItemConfig } from './chartsLegend.types'; import { legendItemPlacements } from './legendItemsPlacement'; import { useDrawingArea } from '../hooks/useDrawingArea'; import { AnchorPosition, Direction } from './legend.types'; @@ -70,16 +70,9 @@ export interface LegendPerItemProps * @default 10 */ padding?: number | Partial>; - /** - * Callback fired when a legend item is clicked. - * @param {React.MouseEvent} event The click event. - * @param {LegendItemConfig} legendItem The legend item data. - * @param {number} index The index of the clicked legend item. - * @default undefined - */ onItemClick?: ( event: React.MouseEvent, - legendItem: LegendItemContext, + legendItem: any, index: number, ) => void; } diff --git a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx index a7b5118491408..01f844ceca411 100644 --- a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx @@ -5,6 +5,7 @@ import { useAxis } from './useAxis'; import { ColorLegendSelector, PiecewiseLabelFormatterParams } from './legend.types'; import { LegendPerItem, LegendPerItemProps } from './LegendPerItem'; import { notNull } from '../internals/notNull'; +import { PiecewiseColorLegendItemContext } from './chartsLegend.types'; function defaultLabelFormatter(params: PiecewiseLabelFormatterParams) { if (params.min === null) { @@ -18,7 +19,7 @@ function defaultLabelFormatter(params: PiecewiseLabelFormatterParams) { export interface PiecewiseColorLegendProps extends ColorLegendSelector, - Omit { + Omit { /** * Hide the first item of the legend, corresponding to the [-infinity, min] piece. * @default false @@ -35,6 +36,18 @@ export interface PiecewiseColorLegendProps * @returns {string|null} The displayed label, or `null` to skip the item. */ labelFormatter?: (params: PiecewiseLabelFormatterParams) => string | null; + /** + * Callback fired when a legend item is clicked. + * @param {React.MouseEvent} event The click event. + * @param {PiecewiseColorLegendItemContext} legendItem The legend item data. + * @param {number} index The index of the clicked legend item. + * @default undefined + */ + onItemClick?: ( + event: React.MouseEvent, + legendItem: PiecewiseColorLegendItemContext, + index: number, + ) => void; } function PiecewiseColorLegend(props: PiecewiseColorLegendProps) { @@ -169,7 +182,7 @@ PiecewiseColorLegend.propTypes = { /** * Callback fired when a legend item is clicked. * @param {React.MouseEvent} event The click event. - * @param {LegendItem} legendItem The legend item data. + * @param {PiecewiseColorLegendItemContext} legendItem The legend item data. * @param {number} index The index of the clicked legend item. * @default undefined */ diff --git a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts index 698cd7bb121f5..c36e04e28ccf6 100644 --- a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts +++ b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts @@ -25,7 +25,7 @@ export interface LegendItemConfig type: 'series' | 'piecewiseColor'; } -interface SeriesLegendItemContext extends LegendItemContextBase { +export interface SeriesLegendItemContext extends LegendItemContextBase { /** * The type of the legend item * - `series` is used for series legend item @@ -43,7 +43,7 @@ interface SeriesLegendItemContext extends LegendItemContextBase { itemId: PieItemId; } -interface PiecewiseColorLegendItemContext extends LegendItemContextBase { +export interface PiecewiseColorLegendItemContext extends LegendItemContextBase { /** * The type of the legend item * - `series` is used for series legend item From 8f9d2aa2ec75f179d294aa413f6ca0ea08df0ddb Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 21 Aug 2024 17:41:45 +0200 Subject: [PATCH 11/25] Add interactive docs --- docs/data/charts/legend/LegendClickNoSnap.js | 158 +++++++++++++++++++ docs/data/charts/legend/legend.md | 6 +- 2 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 docs/data/charts/legend/LegendClickNoSnap.js diff --git a/docs/data/charts/legend/LegendClickNoSnap.js b/docs/data/charts/legend/LegendClickNoSnap.js new file mode 100644 index 0000000000000..d7e89a4dd1cc7 --- /dev/null +++ b/docs/data/charts/legend/LegendClickNoSnap.js @@ -0,0 +1,158 @@ +import * as React from 'react'; +import Stack from '@mui/material/Stack'; +import Box from '@mui/material/Box'; +import Typography from '@mui/material/Typography'; +import IconButton from '@mui/material/IconButton'; +import UndoOutlinedIcon from '@mui/icons-material/UndoOutlined'; + +import { ChartsLegend, PiecewiseColorLegend } from '@mui/x-charts/ChartsLegend'; + +import { HighlightedCode } from '@mui/docs/HighlightedCode'; +import { ResponsiveChartContainer } from '@mui/x-charts/ResponsiveChartContainer'; + +const pieSeries = [ + { + type: 'pie', + id: 'series-1', + label: 'Series 1', + data: [ + { label: 'Pie A', id: 'P1-A', value: 400 }, + { label: 'Pie B', id: 'P2-B', value: 300 }, + ], + }, +]; + +const barSeries = [ + { + type: 'bar', + id: 'series-1', + label: 'Series 1', + data: [0, 1, 2], + }, + { + type: 'bar', + id: 'series-2', + label: 'Series 2', + data: [0, 1, 2], + }, +]; + +const lineSeries = [ + { + type: 'line', + id: 'series-1', + label: 'Series 1', + data: [0, 1, 2], + }, + { + type: 'line', + id: 'series-2', + label: 'Series 2', + data: [0, 1, 2], + }, +]; + +export default function LegendClickNoSnap() { + const [itemData, setItemData] = React.useState(); + + return ( + + + Chart Legend + + + setItemData([context, index]), + }, + }} + /> + + Pie Chart Legend + + + setItemData([context, index]), + }, + }} + /> + + Pie Chart Legend + + setItemData([context, index])} + /> + + + + + + Click on the chart + { + setItemData(null); + }} + > + + + + + + + ); +} diff --git a/docs/data/charts/legend/legend.md b/docs/data/charts/legend/legend.md index d0b01b6fd9094..8557dd708c939 100644 --- a/docs/data/charts/legend/legend.md +++ b/docs/data/charts/legend/legend.md @@ -121,7 +121,11 @@ They both provide the following signature. ```js const clickHandler = ( event, // The mouse event. - params, // An object that identifies the clicked item. + context, // An object that identifies the clicked item. index, // The index of the clicked item. ) => {}; ``` + +The `context` object contains different properties depending on the legend type. Click the legend items to see their content. + +{{"demo": "LegendClickNoSnap.js"}} From 016139e0b88dd5817a9c535f243c483f189af675 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 29 Aug 2024 16:55:20 +0200 Subject: [PATCH 12/25] Merge commit '6d78f4f039f3c65469ed3089e44f9dbdc491806d' into 12344-charts-legend-actions-eg-highlighting --- .circleci/config.yml | 30 ++- .github/workflows/issue-cleanup.yml | 35 --- .github/workflows/new-issue-triage.yml | 25 +++ CHANGELOG.md | 69 ++++++ docs/.link-check-errors.txt | 3 - docs/data/data-grid/joy-ui/GridJoyUISlots.js | 10 +- docs/data/data-grid/joy-ui/GridJoyUISlots.tsx | 10 +- .../CheckboxSelectionIndeterminateGrid.js | 17 ++ .../CheckboxSelectionIndeterminateGrid.tsx | 17 ++ ...kboxSelectionIndeterminateGrid.tsx.preview | 1 + .../data-grid/row-selection/row-selection.md | 7 + docs/pages/x/api/charts/charts-tooltip.json | 8 +- .../default-charts-axis-tooltip-content.json | 6 + .../default-charts-item-tooltip-content.json | 6 + .../x/api/charts/default-heatmap-tooltip.json | 6 + .../x/api/data-grid/data-grid-premium.json | 4 + docs/pages/x/api/data-grid/data-grid-pro.json | 4 + docs/pages/x/api/data-grid/data-grid.json | 4 + .../modules/components/ChartFeaturesGrid.js | 4 +- .../modules/components/InstallationGrid.js | 4 +- .../charts/charts-tooltip/charts-tooltip.json | 1 + .../default-charts-axis-tooltip-content.json | 1 + .../default-charts-item-tooltip-content.json | 1 + .../default-heatmap-tooltip.json | 1 + .../data-grid-premium/data-grid-premium.json | 3 + .../data-grid-pro/data-grid-pro.json | 3 + .../data-grid/data-grid/data-grid.json | 3 + package.json | 5 +- packages/x-charts-pro/package.json | 8 +- .../src/BarChartPro/BarChartPro.tsx | 2 +- .../src/LineChartPro/LineChartPro.tsx | 2 +- .../src/ScatterChartPro/ScatterChartPro.tsx | 2 +- .../src/tests/materialVersion.test.tsx | 5 + packages/x-charts-vendor/package.json | 2 +- packages/x-charts/package.json | 8 +- packages/x-charts/src/BarChart/BarChart.tsx | 2 +- .../x-charts/src/ChartsGrid/ChartsGrid.tsx | 81 ++----- .../src/ChartsGrid/ChartsHorizontalGrid.tsx | 38 ++++ .../src/ChartsGrid/ChartsVerticalGrid.tsx | 38 ++++ .../src/ChartsGrid/styledCommonents.tsx | 22 ++ .../src/ChartsLegend/ChartsLegend.tsx | 19 +- .../src/ChartsLegend/ChartsLegendItem.tsx | 5 +- .../ChartsLegend/ContinuousColorLegend.tsx | 6 +- .../src/ChartsTooltip/ChartsTooltip.tsx | 17 +- .../src/ChartsTooltip/ChartsTooltipTable.ts | 5 + .../DefaultChartsAxisTooltipContent.tsx | 2 +- .../DefaultChartsItemTooltipContent.tsx | 2 +- .../src/ChartsTooltip/chartsTooltipClasses.ts | 4 +- .../x-charts/src/ChartsXAxis/ChartsXAxis.tsx | 12 +- .../x-charts/src/ChartsYAxis/ChartsYAxis.tsx | 17 +- .../x-charts/src/LineChart/AnimatedArea.tsx | 26 ++- .../x-charts/src/LineChart/AnimatedLine.tsx | 26 ++- packages/x-charts/src/LineChart/AreaPlot.tsx | 185 ++++++++-------- packages/x-charts/src/LineChart/LineChart.tsx | 2 +- packages/x-charts/src/LineChart/LinePlot.tsx | 143 +++++++------ .../x-charts/src/LineChart/MarkElement.tsx | 2 +- packages/x-charts/src/PieChart/PieChart.tsx | 8 +- .../src/ScatterChart/ScatterChart.tsx | 2 +- .../x-charts/src/hooks/useReducedMotion.ts | 29 +-- .../components/AxisSharedComponents.tsx | 8 +- .../x-charts/src/internals/useAnimatedPath.ts | 29 --- packages/x-charts/src/internals/useIsRTL.ts | 6 - .../src/internals/useStringInterpolator.ts | 31 +++ .../src/tests/materialVersion.test.tsx | 5 + .../src/themeAugmentation/components.d.ts | 2 + .../src/themeAugmentation/overrides.d.ts | 10 +- .../themeAugmentation.spec.ts | 12 +- packages/x-codemod/package.json | 2 +- packages/x-data-grid-generator/package.json | 8 +- packages/x-data-grid-premium/package.json | 8 +- .../src/DataGridPremium/DataGridPremium.tsx | 8 + .../aggregation.DataGridPremium.test.tsx | 1 + .../src/tests/materialVersion.test.tsx | 5 + packages/x-data-grid-pro/package.json | 8 +- .../src/DataGridPro/DataGridPro.tsx | 8 + .../components/GridColumnMenuPinningItem.tsx | 6 +- .../columnReorder/useGridColumnReorder.tsx | 14 +- .../src/tests/materialVersion.test.tsx | 5 + packages/x-data-grid/package.json | 8 +- .../x-data-grid/src/DataGrid/DataGrid.tsx | 8 + .../src/DataGrid/useDataGridProps.ts | 2 + .../components/GridScrollbarFillerCell.tsx | 4 + .../src/components/cell/GridActionsCell.tsx | 6 +- .../columnSelection/GridHeaderCheckbox.tsx | 7 +- .../components/containers/GridRootStyles.ts | 16 +- .../x-data-grid/src/constants/gridClasses.ts | 12 +- .../src/hooks/core/gridCoreSelector.ts | 2 +- .../src/hooks/core/useGridInitialization.ts | 4 +- .../src/hooks/core/useGridIsRtl.tsx | 20 ++ .../src/hooks/core/useGridTheme.tsx | 20 -- .../columnHeaders/useGridColumnHeaders.tsx | 25 ++- .../columnResize/useGridColumnResize.tsx | 10 +- .../features/columns/gridColumnsSelector.ts | 12 +- .../useGridKeyboardNavigation.ts | 51 ++--- .../hooks/features/scroll/useGridScroll.ts | 8 +- .../virtualization/useGridVirtualScroller.tsx | 26 +-- .../src/models/gridStateCommunity.ts | 3 +- .../src/models/props/DataGridProps.ts | 8 + .../src/tests/columnHeaders.DataGrid.test.tsx | 55 +++-- .../src/tests/materialVersion.test.tsx | 5 + .../src/tests/rowSelection.DataGrid.test.tsx | 38 +++- packages/x-date-pickers-pro/package.json | 8 +- .../DateRangeCalendar.test.tsx | 7 +- .../tests/DesktopDateRangePicker.test.tsx | 23 +- .../describes.DesktopDateRangePicker.test.tsx | 7 +- .../DesktopDateTimeRangePicker.tsx | 2 +- .../tests/DesktopDateTimeRangePicker.test.tsx | 19 +- ...cribes.DesktopDateTimeRangePicker.test.tsx | 15 +- .../tests/MobileDateRangePicker.test.tsx | 77 ++++--- .../describes.MobileDateRangePicker.test.tsx | 5 +- .../MobileDateTimeRangePicker.tsx | 2 +- ...scribes.MobileDateTimeRangePicker.test.tsx | 17 +- .../src/tests/materialVersion.test.tsx | 5 + packages/x-date-pickers/package.json | 8 +- .../DateCalendar/tests/DateCalendar.test.tsx | 199 +++++++++--------- .../tests/describes.DateCalendar.test.tsx | 5 +- .../tests/timezone.DateCalendar.test.tsx | 9 +- .../tests/DesktopDatePicker.test.tsx | 19 +- .../describes.DesktopDatePicker.test.tsx | 5 +- .../tests/DesktopDateTimePicker.test.tsx | 70 +++--- .../describes.DesktopDateTimePicker.test.tsx | 15 +- .../tests/DesktopTimePicker.test.tsx | 79 ++++--- .../describes.DesktopTimePicker.test.tsx | 13 +- .../tests/timezone.DigitalClock.test.tsx | 9 +- .../tests/MobileDatePicker.test.tsx | 3 +- .../tests/describes.MobileDatePicker.test.tsx | 3 +- .../tests/MobileDateTimePicker.test.tsx | 11 +- .../describes.MobileDateTimePicker.test.tsx | 9 +- .../tests/MobileTimePicker.test.tsx | 27 ++- .../tests/describes.MobileTimePicker.test.tsx | 7 +- .../tests/describes.MonthCalendar.test.tsx | 7 +- .../PickersActionBar.test.tsx | 29 ++- .../x-date-pickers/src/TimeClock/Clock.tsx | 5 +- .../src/TimeClock/tests/TimeClock.test.tsx | 68 ++++-- .../tests/describes.YearCalendar.test.tsx | 5 +- .../src/internals/utils/date-time-utils.ts | 15 +- .../src/tests/materialVersion.test.tsx | 5 + packages/x-internals/package.json | 2 +- packages/x-license/package.json | 2 +- packages/x-tree-view-pro/package.json | 8 +- .../src/tests/materialVersion.test.tsx | 5 + packages/x-tree-view/package.json | 8 +- .../src/tests/materialVersion.test.tsx | 5 + pnpm-lock.yaml | 184 ++++++++-------- renovate.json | 3 +- scripts/githubActions/issueBodyCleanup.js | 86 -------- scripts/githubActions/orderIdValidation.js | 66 ------ scripts/useMaterialUIv6.mjs | 12 ++ test/README.md | 38 +++- test/circleci-workflow.png | Bin 0 -> 40490 bytes test/karma.conf.js | 1 + test/package.json | 8 +- test/regressions/index.test.js | 22 ++ test/utils/checkMaterialVersion.ts | 43 ++++ .../describeValue/testPickerActionBar.tsx | 19 +- .../testPickerOpenCloseLifeCycle.tsx | 24 +-- .../pickers/describeValue/testShortcuts.tsx | 9 +- test/utils/pickers/misc.ts | 2 + test/utils/pickers/openPicker.ts | 21 +- test/utils/pickers/viewHandlers.ts | 13 +- 160 files changed, 1683 insertions(+), 1246 deletions(-) delete mode 100644 .github/workflows/issue-cleanup.yml create mode 100644 .github/workflows/new-issue-triage.yml create mode 100644 docs/data/data-grid/row-selection/CheckboxSelectionIndeterminateGrid.js create mode 100644 docs/data/data-grid/row-selection/CheckboxSelectionIndeterminateGrid.tsx create mode 100644 docs/data/data-grid/row-selection/CheckboxSelectionIndeterminateGrid.tsx.preview create mode 100644 packages/x-charts-pro/src/tests/materialVersion.test.tsx create mode 100644 packages/x-charts/src/ChartsGrid/ChartsHorizontalGrid.tsx create mode 100644 packages/x-charts/src/ChartsGrid/ChartsVerticalGrid.tsx create mode 100644 packages/x-charts/src/ChartsGrid/styledCommonents.tsx delete mode 100644 packages/x-charts/src/internals/useAnimatedPath.ts delete mode 100644 packages/x-charts/src/internals/useIsRTL.ts create mode 100644 packages/x-charts/src/internals/useStringInterpolator.ts create mode 100644 packages/x-charts/src/tests/materialVersion.test.tsx create mode 100644 packages/x-data-grid-premium/src/tests/materialVersion.test.tsx create mode 100644 packages/x-data-grid-pro/src/tests/materialVersion.test.tsx create mode 100644 packages/x-data-grid/src/hooks/core/useGridIsRtl.tsx delete mode 100644 packages/x-data-grid/src/hooks/core/useGridTheme.tsx create mode 100644 packages/x-data-grid/src/tests/materialVersion.test.tsx create mode 100644 packages/x-date-pickers-pro/src/tests/materialVersion.test.tsx create mode 100644 packages/x-date-pickers/src/tests/materialVersion.test.tsx create mode 100644 packages/x-tree-view-pro/src/tests/materialVersion.test.tsx create mode 100644 packages/x-tree-view/src/tests/materialVersion.test.tsx delete mode 100644 scripts/githubActions/issueBodyCleanup.js delete mode 100644 scripts/githubActions/orderIdValidation.js create mode 100644 scripts/useMaterialUIv6.mjs create mode 100644 test/circleci-workflow.png create mode 100644 test/utils/checkMaterialVersion.ts diff --git a/.circleci/config.yml b/.circleci/config.yml index 53f9f97eed6cd..72bff75bfe512 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -99,6 +99,14 @@ commands: # log a patch for maintainers who want to check out this change git --no-pager diff HEAD + - when: + condition: + equal: [material-ui-v6, << pipeline.parameters.workflow >>] + steps: + - run: + name: Install @mui/material@next + command: pnpm use-material-ui-v6 + - when: condition: << parameters.browsers >> steps: @@ -248,7 +256,7 @@ jobs: command: pnpm docs:typescript:formatted --disable-cache - run: name: '`pnpm docs:typescript:formatted` changes committed?' - command: git add -A && git diff --exit-code --staged + command: git add -A && git diff --exit-code --staged docs/src docs/data - run: name: Tests TypeScript definitions command: pnpm typescript:ci @@ -383,3 +391,23 @@ workflows: <<: *default-context react-version: next name: test_e2e-react@next + + material-ui-v6: + when: + equal: [material-ui-v6, << pipeline.parameters.workflow >>] + jobs: + - test_unit: + <<: *default-context + name: test_unit-material@next + - test_browser: + <<: *default-context + name: test_browser-material@next + - test_regressions: + <<: *default-context + name: test_regressions-material@next + - test_e2e: + <<: *default-context + name: test_e2e-material@next + - test_types: + <<: *default-context + name: test_types-material@next diff --git a/.github/workflows/issue-cleanup.yml b/.github/workflows/issue-cleanup.yml deleted file mode 100644 index a4d8839b60aa6..0000000000000 --- a/.github/workflows/issue-cleanup.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Issue cleanup - -on: - issues: - types: - - opened - -permissions: {} - -jobs: - issue_cleanup: - runs-on: ubuntu-latest - name: Clean issue body and add support label - permissions: - issues: write - steps: - - name: Checkout repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - name: Clean issue body - id: cleanup - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - script: | - const script = require('./scripts/githubActions/issueBodyCleanup.js') - await script({core, github, context}) - - name: Add support label - if: steps.cleanup.outputs.ORDER_ID != '' - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - script: | - const script = require('./scripts/githubActions/orderIdValidation.js') - await script({core, github, context}) - env: - ORDER_API_TOKEN: ${{ secrets.SHOP_AUTH_TOKEN }} - ORDER_ID: ${{ steps.cleanup.outputs.ORDER_ID }} diff --git a/.github/workflows/new-issue-triage.yml b/.github/workflows/new-issue-triage.yml new file mode 100644 index 0000000000000..8dc6fbf163242 --- /dev/null +++ b/.github/workflows/new-issue-triage.yml @@ -0,0 +1,25 @@ +name: New issue triage +on: + issues: + types: + - opened + +permissions: {} + +jobs: + issue_cleanup: + name: Clean issue body + uses: mui/mui-public/.github/workflows/issues_body-cleanup.yml@master + permissions: + contents: read + issues: write + order_id_validation: + name: Validate order ID + needs: issue_cleanup + if: needs.issue_cleanup.outputs.orderId != '' + uses: mui/mui-public/.github/workflows/issues_order-id-validation.yml@master + with: + orderId: ${{ needs.issue_cleanup.outputs.orderId }} + permissions: + contents: read + issues: write diff --git a/CHANGELOG.md b/CHANGELOG.md index e31b5b55466df..8373a3661fcb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,75 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## 7.15.0 + +_Aug 29, 2024_ + +We'd like to offer a big thanks to the 8 contributors who made this release possible. Here are some highlights ✨: + +- 💫 Support Material UI v6 (`@mui/material@6`) peer dependency (#14142) @cherniavskii + +You can now use MUI X components with either v5 or v6 of `@mui/material` package 🎉 + +- 🐞 Bugfixes + +### Data Grid + +#### `@mui/x-data-grid-pro@7.15.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan') + +- [DataGridPro] Export `GridRowReorderCell` component (#14079) @genepaul + +#### `@mui/x-data-grid-premium@7.15.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan') + +Same changes as in `@mui/x-data-grid-pro@7.15.0`. + +### Date and Time Pickers + +#### `@mui/x-date-pickers@7.15.0` + +- [pickers] Add `onTouchStart` handler for `TimeClock` (#14305) @arthurbalduini + +#### `@mui/x-date-pickers-pro@7.15.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan') + +Same changes as in `@mui/x-date-pickers@7.15.0`, plus: + +- [DateTimeRangePicker] Fix date format resolving from views on 24hr locales (#14341) @arthurbalduini + +### Charts + +#### `@mui/x-charts@7.15.0` + +- [charts] Add missing `themeAugmentation` in pro plan (#14313) @lhilgert9 +- [charts] Fix `LineChart` transition stopping before completion (#14366) @JCQuintas +- [charts] Fix tooltip with horizontal layout (#14337) @alexfauquette +- [charts] Keep axis root classe usage explicit (#14378) @alexfauquette + +#### `@mui/x-charts-pro@7.0.0-alpha.3` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan') + +Same changes as in `@mui/x-charts@7.15.0`, plus: + +- [charts pro] Avoid relative reference to `@mui/x-charts` package (#14335) @LukasTy + +### Docs + +- [docs] Fix sentence case `h2` @oliviertassinari +- [docs] Clarify contribution guide references @oliviertassinari +- [docs] Fix Stack Overflow issue canned response @oliviertassinari +- [docs] Fix outdated link to support page @oliviertassinari +- [docs] Fix use of Material UI @oliviertassinari +- [docs] Update deprecated props in docs (#14295) @JCQuintas + +### Core + +- [core] Allow only v5.x for `MUI Core` renovate group (#14382) @LukasTy +- [core] Avoid visual regression when using `@mui/material@6` (#14357) @cherniavskii +- [core] Remove renovate rule targeting only `next` releases of `@mui/docs` (#14364) @LukasTy +- [core] Support `@mui/material@6` peer dependency (#14142) @cherniavskii +- [core] Use `useRtl` instead of `useTheme` to access direction (#14359) @LukasTy +- [code-infra] Typecheck nested folders in playground (#14352) @JCQuintas +- [infra] Fix Issue cleanup action @oliviertassinari +- [license] Prepare renaming of argument names @oliviertassinari + ## 7.14.0 _Aug 23, 2024_ diff --git a/docs/.link-check-errors.txt b/docs/.link-check-errors.txt index cbb0918c23631..6ecc503cc78a5 100644 --- a/docs/.link-check-errors.txt +++ b/docs/.link-check-errors.txt @@ -1,5 +1,2 @@ Broken links found by `docs:link-check` that exist: -- https://mui.com/material-ui/customization/theme-components/#creating-new-component-variants -- https://mui.com/material-ui/customization/theme-components/#overrides-based-on-props -- https://mui.com/material-ui/react-grid2/#whats-changed diff --git a/docs/data/data-grid/joy-ui/GridJoyUISlots.js b/docs/data/data-grid/joy-ui/GridJoyUISlots.js index 7d88bad69902c..35c89967fc539 100644 --- a/docs/data/data-grid/joy-ui/GridJoyUISlots.js +++ b/docs/data/data-grid/joy-ui/GridJoyUISlots.js @@ -3,8 +3,8 @@ import Box from '@mui/material/Box'; import { DataGrid, GridToolbar, GridActionsCellItem } from '@mui/x-data-grid'; import { unstable_joySlots } from '@mui/x-data-grid/joy'; import { - experimental_extendTheme as materialExtendTheme, - Experimental_CssVarsProvider as MaterialCssVarsProvider, + createTheme, + ThemeProvider as MaterialThemeProvider, THEME_ID as MATERIAL_THEME_ID, } from '@mui/material/styles'; import { CssVarsProvider as JoyCssVarsProvider } from '@mui/joy/styles'; @@ -18,7 +18,7 @@ import { randomArrayItem, } from '@mui/x-data-grid-generator'; -const materialTheme = materialExtendTheme({ +const materialTheme = createTheme({ components: { MuiSvgIcon: { styleOverrides: { @@ -97,7 +97,7 @@ export default function GridJoyUISlots() { }, []); return ( - + - + ); } diff --git a/docs/data/data-grid/joy-ui/GridJoyUISlots.tsx b/docs/data/data-grid/joy-ui/GridJoyUISlots.tsx index 8bcd13834ceb5..6b1817921dccd 100644 --- a/docs/data/data-grid/joy-ui/GridJoyUISlots.tsx +++ b/docs/data/data-grid/joy-ui/GridJoyUISlots.tsx @@ -3,8 +3,8 @@ import Box from '@mui/material/Box'; import { DataGrid, GridToolbar, GridActionsCellItem } from '@mui/x-data-grid'; import { unstable_joySlots } from '@mui/x-data-grid/joy'; import { - experimental_extendTheme as materialExtendTheme, - Experimental_CssVarsProvider as MaterialCssVarsProvider, + createTheme, + ThemeProvider as MaterialThemeProvider, THEME_ID as MATERIAL_THEME_ID, } from '@mui/material/styles'; import { CssVarsProvider as JoyCssVarsProvider } from '@mui/joy/styles'; @@ -19,7 +19,7 @@ import { } from '@mui/x-data-grid-generator'; import type {} from '@mui/material/themeCssVarsAugmentation'; -const materialTheme = materialExtendTheme({ +const materialTheme = createTheme({ components: { MuiSvgIcon: { styleOverrides: { @@ -106,7 +106,7 @@ export default function GridJoyUISlots() { }, []); return ( - + - + ); } diff --git a/docs/data/data-grid/row-selection/CheckboxSelectionIndeterminateGrid.js b/docs/data/data-grid/row-selection/CheckboxSelectionIndeterminateGrid.js new file mode 100644 index 0000000000000..88493e2bf3a76 --- /dev/null +++ b/docs/data/data-grid/row-selection/CheckboxSelectionIndeterminateGrid.js @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { DataGrid } from '@mui/x-data-grid'; +import { useDemoData } from '@mui/x-data-grid-generator'; + +export default function CheckboxSelectionIndeterminateGrid() { + const { data } = useDemoData({ + dataSet: 'Commodity', + rowLength: 10, + maxColumns: 5, + }); + + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/row-selection/CheckboxSelectionIndeterminateGrid.tsx b/docs/data/data-grid/row-selection/CheckboxSelectionIndeterminateGrid.tsx new file mode 100644 index 0000000000000..88493e2bf3a76 --- /dev/null +++ b/docs/data/data-grid/row-selection/CheckboxSelectionIndeterminateGrid.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { DataGrid } from '@mui/x-data-grid'; +import { useDemoData } from '@mui/x-data-grid-generator'; + +export default function CheckboxSelectionIndeterminateGrid() { + const { data } = useDemoData({ + dataSet: 'Commodity', + rowLength: 10, + maxColumns: 5, + }); + + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/row-selection/CheckboxSelectionIndeterminateGrid.tsx.preview b/docs/data/data-grid/row-selection/CheckboxSelectionIndeterminateGrid.tsx.preview new file mode 100644 index 0000000000000..9091ca3b75cce --- /dev/null +++ b/docs/data/data-grid/row-selection/CheckboxSelectionIndeterminateGrid.tsx.preview @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/data/data-grid/row-selection/row-selection.md b/docs/data/data-grid/row-selection/row-selection.md index 6b4e2f63da464..70f9f43b3f90c 100644 --- a/docs/data/data-grid/row-selection/row-selection.md +++ b/docs/data/data-grid/row-selection/row-selection.md @@ -64,6 +64,13 @@ Always set the `checkboxSelection` prop to `true` even when providing a custom c Otherwise, the data grid might remove your column. ::: +### Customize indeterminate checkbox behavior + +The parent checkboxes (like "Select All" checkbox) when clicked in an indeterminate state will deselect the selected rows. +You can customize this behavior by using the [`indeterminateCheckboxAction` prop](/x/api/data-grid/data-grid/#data-grid-prop-indeterminateCheckboxAction). + +{{"demo": "CheckboxSelectionIndeterminateGrid.js", "bg": "inline"}} + ### Visible rows selection [](/x/introduction/licensing/#pro-plan 'Pro plan') By default, when you click the "Select All" checkbox, all rows in the data grid are selected. diff --git a/docs/pages/x/api/charts/charts-tooltip.json b/docs/pages/x/api/charts/charts-tooltip.json index 4d4e12f08b2d1..cc191b7a0bf88 100644 --- a/docs/pages/x/api/charts/charts-tooltip.json +++ b/docs/pages/x/api/charts/charts-tooltip.json @@ -22,7 +22,7 @@ "name": "enum", "description": "'axis'
| 'item'
| 'none'" }, - "default": "'item'" + "default": "'axis'" } }, "name": "ChartsTooltip", @@ -76,6 +76,12 @@ "description": "Styles applied to the markCell element.", "isGlobal": false }, + { + "key": "paper", + "className": "MuiChartsTooltip-paper", + "description": "Styles applied to the paper element.", + "isGlobal": false + }, { "key": "root", "className": "MuiChartsTooltip-root", diff --git a/docs/pages/x/api/charts/default-charts-axis-tooltip-content.json b/docs/pages/x/api/charts/default-charts-axis-tooltip-content.json index 274550fe14442..2594869a42ab4 100644 --- a/docs/pages/x/api/charts/default-charts-axis-tooltip-content.json +++ b/docs/pages/x/api/charts/default-charts-axis-tooltip-content.json @@ -53,6 +53,12 @@ "description": "Styles applied to the markCell element.", "isGlobal": false }, + { + "key": "paper", + "className": "MuiDefaultChartsAxisTooltipContent-paper", + "description": "Styles applied to the paper element.", + "isGlobal": false + }, { "key": "root", "className": "MuiDefaultChartsAxisTooltipContent-root", diff --git a/docs/pages/x/api/charts/default-charts-item-tooltip-content.json b/docs/pages/x/api/charts/default-charts-item-tooltip-content.json index c3582356897c9..7d76f641a34f6 100644 --- a/docs/pages/x/api/charts/default-charts-item-tooltip-content.json +++ b/docs/pages/x/api/charts/default-charts-item-tooltip-content.json @@ -54,6 +54,12 @@ "description": "Styles applied to the markCell element.", "isGlobal": false }, + { + "key": "paper", + "className": "MuiDefaultChartsItemTooltipContent-paper", + "description": "Styles applied to the paper element.", + "isGlobal": false + }, { "key": "root", "className": "MuiDefaultChartsItemTooltipContent-root", diff --git a/docs/pages/x/api/charts/default-heatmap-tooltip.json b/docs/pages/x/api/charts/default-heatmap-tooltip.json index caa6575ad64ce..66e8ffa29495c 100644 --- a/docs/pages/x/api/charts/default-heatmap-tooltip.json +++ b/docs/pages/x/api/charts/default-heatmap-tooltip.json @@ -53,6 +53,12 @@ "description": "Styles applied to the markCell element.", "isGlobal": false }, + { + "key": "paper", + "className": "MuiDefaultHeatmapTooltip-paper", + "description": "Styles applied to the paper element.", + "isGlobal": false + }, { "key": "root", "className": "MuiDefaultHeatmapTooltip-root", diff --git a/docs/pages/x/api/data-grid/data-grid-premium.json b/docs/pages/x/api/data-grid/data-grid-premium.json index 45c00921edc94..6f4425ee64e0c 100644 --- a/docs/pages/x/api/data-grid/data-grid-premium.json +++ b/docs/pages/x/api/data-grid/data-grid-premium.json @@ -181,6 +181,10 @@ }, "default": "false" }, + "indeterminateCheckboxAction": { + "type": { "name": "enum", "description": "'deselect'
| 'select'" }, + "default": "\"deselect\"" + }, "initialState": { "type": { "name": "object" } }, "isCellEditable": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/data-grid/data-grid-pro.json b/docs/pages/x/api/data-grid/data-grid-pro.json index c3eb24a2ffb89..c5dc3bdb06897 100644 --- a/docs/pages/x/api/data-grid/data-grid-pro.json +++ b/docs/pages/x/api/data-grid/data-grid-pro.json @@ -155,6 +155,10 @@ }, "default": "false" }, + "indeterminateCheckboxAction": { + "type": { "name": "enum", "description": "'deselect'
| 'select'" }, + "default": "\"deselect\"" + }, "initialState": { "type": { "name": "object" } }, "isCellEditable": { "type": { "name": "func" }, diff --git a/docs/pages/x/api/data-grid/data-grid.json b/docs/pages/x/api/data-grid/data-grid.json index 7543c9d9f0abb..c2ecd48ba5129 100644 --- a/docs/pages/x/api/data-grid/data-grid.json +++ b/docs/pages/x/api/data-grid/data-grid.json @@ -123,6 +123,10 @@ }, "default": "false" }, + "indeterminateCheckboxAction": { + "type": { "name": "enum", "description": "'deselect'
| 'select'" }, + "default": "\"deselect\"" + }, "initialState": { "type": { "name": "object" } }, "isCellEditable": { "type": { "name": "func" }, diff --git a/docs/src/modules/components/ChartFeaturesGrid.js b/docs/src/modules/components/ChartFeaturesGrid.js index ecff879e95c20..36af272ba23c0 100644 --- a/docs/src/modules/components/ChartFeaturesGrid.js +++ b/docs/src/modules/components/ChartFeaturesGrid.js @@ -1,5 +1,5 @@ import * as React from 'react'; -import Grid from '@mui/material/Unstable_Grid2'; +import Grid from '@mui/material/Grid'; import { InfoCard } from '@mui/docs/InfoCard'; import LineAxisRoundedIcon from '@mui/icons-material/LineAxisRounded'; import DashboardCustomizeRoundedIcon from '@mui/icons-material/DashboardCustomizeRounded'; @@ -45,7 +45,7 @@ export default function ChartFeaturesGrid() { return ( {content.map(({ icon, title, link }) => ( - + ))} diff --git a/docs/src/modules/components/InstallationGrid.js b/docs/src/modules/components/InstallationGrid.js index a5dcda3059454..a917df909e2a3 100644 --- a/docs/src/modules/components/InstallationGrid.js +++ b/docs/src/modules/components/InstallationGrid.js @@ -1,5 +1,5 @@ import * as React from 'react'; -import Grid from '@mui/material/Unstable_Grid2'; +import Grid from '@mui/material/Grid'; import { InfoCard } from '@mui/docs/InfoCard'; import AccountTreeRounded from '@mui/icons-material/AccountTreeRounded'; import PivotTableChartRoundedIcon from '@mui/icons-material/PivotTableChartRounded'; @@ -38,7 +38,7 @@ export default function InstallationGrid() { return ( {content.map(({ icon, title, description, link }) => ( - + true, the Data Grid will not use valueFormatter when exporting to CSV or copying to clipboard. If an object is provided, you can choose to ignore the valueFormatter for CSV export or clipboard export." }, + "indeterminateCheckboxAction": { + "description": "If select, a group header checkbox in indeterminate state (like "Select All" checkbox) will select all the rows under it. If deselect, it will deselect all the rows under it. Works only if checkboxSelection is enabled." + }, "initialState": { "description": "The initial state of the DataGridPremium. The data in it is set in the state on initialization but isn't controlled. If one of the data in initialState is also being controlled, then the control state wins." }, diff --git a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json index b52063f75d28a..91cce7101fd81 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json @@ -183,6 +183,9 @@ "ignoreValueFormatterDuringExport": { "description": "If true, the Data Grid will not use valueFormatter when exporting to CSV or copying to clipboard. If an object is provided, you can choose to ignore the valueFormatter for CSV export or clipboard export." }, + "indeterminateCheckboxAction": { + "description": "If select, a group header checkbox in indeterminate state (like "Select All" checkbox) will select all the rows under it. If deselect, it will deselect all the rows under it. Works only if checkboxSelection is enabled." + }, "initialState": { "description": "The initial state of the DataGridPro. The data in it will be set in the state on initialization but will not be controlled. If one of the data in initialState is also being controlled, then the control state wins." }, diff --git a/docs/translations/api-docs/data-grid/data-grid/data-grid.json b/docs/translations/api-docs/data-grid/data-grid/data-grid.json index 545e3c09ac3a1..b799ebbc72064 100644 --- a/docs/translations/api-docs/data-grid/data-grid/data-grid.json +++ b/docs/translations/api-docs/data-grid/data-grid/data-grid.json @@ -136,6 +136,9 @@ "ignoreValueFormatterDuringExport": { "description": "If true, the Data Grid will not use valueFormatter when exporting to CSV or copying to clipboard. If an object is provided, you can choose to ignore the valueFormatter for CSV export or clipboard export." }, + "indeterminateCheckboxAction": { + "description": "If select, a group header checkbox in indeterminate state (like "Select All" checkbox) will select all the rows under it. If deselect, it will deselect all the rows under it. Works only if checkboxSelection is enabled." + }, "initialState": { "description": "The initial state of the DataGrid. The data in it will be set in the state on initialization but will not be controlled. If one of the data in initialState is also being controlled, then the control state wins." }, diff --git a/package.json b/package.json index 802da58f6c93c..f96fd51d9dee1 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "7.14.0", + "version": "7.15.0", "private": true, "scripts": { "preinstall": "npx only-allow pnpm", @@ -55,6 +55,7 @@ "typescript": "lerna run --no-bail --parallel typescript", "typescript:ci": "lerna run --concurrency 1 --no-bail --no-sort typescript", "use-react-version": "node scripts/useReactVersion.mjs", + "use-material-ui-v6": "node scripts/useMaterialUIv6.mjs", "build:codesandbox": "lerna run --concurrency 3 --no-private --scope \"@mui/*\" build", "install:codesandbox": "pnpm install --no-frozen-lockfile", "release:changelog": "node scripts/releaseChangelog.mjs", @@ -92,7 +93,7 @@ "@mui/internal-markdown": "^1.0.11", "@mui/internal-test-utils": "^1.0.10", "@mui/material": "^5.16.7", - "@mui/monorepo": "github:mui/material-ui#55bea65c83c1beac77382fe961f8aa72eec21daa", + "@mui/monorepo": "github:mui/material-ui#029eb3b1f4837591e729779da9a82f0a66187770", "@mui/utils": "^5.16.6", "@next/eslint-plugin-next": "14.2.6", "@octokit/plugin-retry": "^7.1.1", diff --git a/packages/x-charts-pro/package.json b/packages/x-charts-pro/package.json index 29939b28bf56c..0c34de9d04b4e 100644 --- a/packages/x-charts-pro/package.json +++ b/packages/x-charts-pro/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-charts-pro", - "version": "7.0.0-alpha.2", + "version": "7.0.0-alpha.3", "description": "The Pro plan edition of the Charts components (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -40,7 +40,6 @@ }, "dependencies": { "@babel/runtime": "^7.25.4", - "@mui/system": "^5.16.7", "@mui/utils": "^5.16.6", "@mui/x-charts": "workspace:*", "@mui/x-charts-vendor": "workspace:*", @@ -53,7 +52,8 @@ "peerDependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@mui/material": "^5.15.14", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" }, @@ -66,6 +66,8 @@ } }, "devDependencies": { + "@mui/material": "^5.16.5", + "@mui/system": "^5.16.7", "@react-spring/core": "^9.7.4", "@react-spring/shared": "^9.7.4", "@types/prop-types": "^15.7.12", diff --git a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx index f07082ebd6281..ef8624363755d 100644 --- a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx +++ b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx @@ -56,7 +56,7 @@ const BarChartPro = React.forwardRef(function BarChartPro(inProps: BarChartProPr onZoomChange={onZoomChange} > {props.onAxisClick && } - {props.grid && } + diff --git a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx index 90782a38be2d4..8075680e6bc4f 100644 --- a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx +++ b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx @@ -66,7 +66,7 @@ const LineChartPro = React.forwardRef(function LineChartPro(inProps: LineChartPr onZoomChange={onZoomChange} > {props.onAxisClick && } - {props.grid && } + diff --git a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx index 06679a1e0b2df..cf9a928faa737 100644 --- a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx +++ b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx @@ -57,7 +57,7 @@ const ScatterChartPro = React.forwardRef(function ScatterChartPro( {!props.disableVoronoi && } - {props.grid && } + {/* The `data-drawing-container` indicates that children are part of the drawing area. Ref: https://github.com/mui/mui-x/issues/13659 */} diff --git a/packages/x-charts-pro/src/tests/materialVersion.test.tsx b/packages/x-charts-pro/src/tests/materialVersion.test.tsx new file mode 100644 index 0000000000000..dc0c0a7e6ee01 --- /dev/null +++ b/packages/x-charts-pro/src/tests/materialVersion.test.tsx @@ -0,0 +1,5 @@ +import materialPackageJson from '@mui/material/package.json'; +import { checkMaterialVersion } from 'test/utils/checkMaterialVersion'; +import packageJson from '../../package.json'; + +checkMaterialVersion({ packageJson, materialPackageJson }); diff --git a/packages/x-charts-vendor/package.json b/packages/x-charts-vendor/package.json index 4acecee461a44..6df175e78974b 100644 --- a/packages/x-charts-vendor/package.json +++ b/packages/x-charts-vendor/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-charts-vendor", - "version": "7.14.0", + "version": "7.15.0", "description": "Vendored dependencies for MUI X Charts", "author": "MUI Team", "main": "./index.js", diff --git a/packages/x-charts/package.json b/packages/x-charts/package.json index 23d1c3b3d248f..89759c8f15185 100644 --- a/packages/x-charts/package.json +++ b/packages/x-charts/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-charts", - "version": "7.14.0", + "version": "7.15.0", "description": "The community edition of the Charts components (MUI X).", "author": "MUI Team", "main": "src/index.js", @@ -40,7 +40,6 @@ }, "dependencies": { "@babel/runtime": "^7.25.4", - "@mui/system": "^5.16.7", "@mui/utils": "^5.16.6", "@mui/x-charts-vendor": "workspace:*", "@react-spring/rafz": "^9.7.4", @@ -51,7 +50,8 @@ "peerDependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@mui/material": "^5.15.14", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" }, @@ -65,6 +65,8 @@ }, "devDependencies": { "@mui/internal-test-utils": "^1.0.10", + "@mui/material": "^5.16.5", + "@mui/system": "^5.16.7", "@react-spring/core": "^9.7.4", "@react-spring/shared": "^9.7.4", "@types/prop-types": "^15.7.12", diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index 7aca01261877e..ffb89e8494d40 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -130,7 +130,7 @@ const BarChart = React.forwardRef(function BarChart(inProps: BarChartProps, ref) return ( {props.onAxisClick && } - {props.grid && } + diff --git a/packages/x-charts/src/ChartsGrid/ChartsGrid.tsx b/packages/x-charts/src/ChartsGrid/ChartsGrid.tsx index 497d23977067c..0480ea912c023 100644 --- a/packages/x-charts/src/ChartsGrid/ChartsGrid.tsx +++ b/packages/x-charts/src/ChartsGrid/ChartsGrid.tsx @@ -1,36 +1,13 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import composeClasses from '@mui/utils/composeClasses'; -import { styled, useThemeProps } from '@mui/material/styles'; - +import { useThemeProps } from '@mui/material/styles'; import { useCartesianContext } from '../context/CartesianProvider'; -import { useTicks } from '../hooks/useTicks'; -import { - ChartsGridClasses, - getChartsGridUtilityClass, - chartsGridClasses, -} from './chartsGridClasses'; +import { ChartsGridClasses, getChartsGridUtilityClass } from './chartsGridClasses'; import { useDrawingArea } from '../hooks/useDrawingArea'; - -const GridRoot = styled('g', { - name: 'MuiChartsGrid', - slot: 'Root', - overridesResolver: (props, styles) => [ - { [`&.${chartsGridClasses.verticalLine}`]: styles.verticalLine }, - { [`&.${chartsGridClasses.horizontalLine}`]: styles.horizontalLine }, - styles.root, - ], -})({}); - -const GridLine = styled('line', { - name: 'MuiChartsGrid', - slot: 'Line', - overridesResolver: (props, styles) => styles.line, -})(({ theme }) => ({ - stroke: (theme.vars || theme).palette.divider, - shapeRendering: 'crispEdges', - strokeWidth: 1, -})); +import { GridRoot } from './styledCommonents'; +import { ChartsGridVertical } from './ChartsVerticalGrid'; +import { ChartsGridHorizontal } from './ChartsHorizontalGrid'; const useUtilityClasses = ({ classes }: ChartsGridProps) => { const slots = { @@ -75,48 +52,18 @@ function ChartsGrid(inProps: ChartsGridProps) { const classes = useUtilityClasses(props); - const horizontalAxisId = yAxisIds[0]; - const verticalAxisId = xAxisIds[0]; - - const { - scale: xScale, - tickNumber: xTickNumber, - tickInterval: xTickInterval, - } = xAxis[verticalAxisId]; - - const { - scale: yScale, - tickNumber: yTickNumber, - tickInterval: yTickInterval, - } = yAxis[horizontalAxisId]; - - const xTicks = useTicks({ scale: xScale, tickNumber: xTickNumber, tickInterval: xTickInterval }); - const yTicks = useTicks({ scale: yScale, tickNumber: yTickNumber, tickInterval: yTickInterval }); + const horizontalAxis = yAxis[yAxisIds[0]]; + const verticalAxis = xAxis[xAxisIds[0]]; return ( - {vertical && - xTicks.map(({ formattedValue, offset }) => ( - - ))} - {horizontal && - yTicks.map(({ formattedValue, offset }) => ( - - ))} + {vertical && ( + + )} + + {horizontal && ( + + )} ); } diff --git a/packages/x-charts/src/ChartsGrid/ChartsHorizontalGrid.tsx b/packages/x-charts/src/ChartsGrid/ChartsHorizontalGrid.tsx new file mode 100644 index 0000000000000..2827e782e4cd4 --- /dev/null +++ b/packages/x-charts/src/ChartsGrid/ChartsHorizontalGrid.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import { DrawingArea } from '../context/DrawingProvider'; +import { useTicks } from '../hooks/useTicks'; +import { AxisDefaultized, ChartsYAxisProps, ScaleName } from '../models/axis'; +import { GridLine } from './styledCommonents'; +import { ChartsGridClasses } from './chartsGridClasses'; + +interface ChartsGridHorizontalProps { + axis: AxisDefaultized; + drawingArea: DrawingArea; + classes: Partial; +} + +/** + * @ignore - internal component. + */ +export function ChartsGridHorizontal(props: ChartsGridHorizontalProps) { + const { axis, drawingArea, classes } = props; + + const { scale, tickNumber, tickInterval } = axis; + + const yTicks = useTicks({ scale, tickNumber, tickInterval }); + + return ( + + {yTicks.map(({ formattedValue, offset }) => ( + + ))} + + ); +} diff --git a/packages/x-charts/src/ChartsGrid/ChartsVerticalGrid.tsx b/packages/x-charts/src/ChartsGrid/ChartsVerticalGrid.tsx new file mode 100644 index 0000000000000..b033d5c1b8ea7 --- /dev/null +++ b/packages/x-charts/src/ChartsGrid/ChartsVerticalGrid.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import { DrawingArea } from '../context/DrawingProvider'; +import { useTicks } from '../hooks/useTicks'; +import { AxisDefaultized, ChartsXAxisProps, ScaleName } from '../models/axis'; +import { GridLine } from './styledCommonents'; +import { ChartsGridClasses } from './chartsGridClasses'; + +interface ChartsGridVerticalProps { + axis: AxisDefaultized; + drawingArea: DrawingArea; + classes: Partial; +} + +/** + * @ignore - internal component. + */ +export function ChartsGridVertical(props: ChartsGridVerticalProps) { + const { axis, drawingArea, classes } = props; + + const { scale, tickNumber, tickInterval } = axis; + + const xTicks = useTicks({ scale, tickNumber, tickInterval }); + + return ( + + {xTicks.map(({ formattedValue, offset }) => ( + + ))} + + ); +} diff --git a/packages/x-charts/src/ChartsGrid/styledCommonents.tsx b/packages/x-charts/src/ChartsGrid/styledCommonents.tsx new file mode 100644 index 0000000000000..02f2ea7a84d22 --- /dev/null +++ b/packages/x-charts/src/ChartsGrid/styledCommonents.tsx @@ -0,0 +1,22 @@ +import { styled } from '@mui/material/styles'; +import { chartsGridClasses } from './chartsGridClasses'; + +export const GridRoot = styled('g', { + name: 'MuiChartsGrid', + slot: 'Root', + overridesResolver: (props, styles) => [ + { [`&.${chartsGridClasses.verticalLine}`]: styles.verticalLine }, + { [`&.${chartsGridClasses.horizontalLine}`]: styles.horizontalLine }, + styles.root, + ], +})({}); + +export const GridLine = styled('line', { + name: 'MuiChartsGrid', + slot: 'Line', + overridesResolver: (props, styles) => styles.line, +})(({ theme }) => ({ + stroke: (theme.vars || theme).palette.divider, + shapeRendering: 'crispEdges', + strokeWidth: 1, +})); diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx index 63753a4f83533..f9b1cd8994664 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx @@ -60,20 +60,21 @@ const useUtilityClasses = (ownerState: DefaultizedChartsLegendProps & { theme: T return composeClasses(slots, getLegendUtilityClass, classes); }; -const defaultProps = { - position: { horizontal: 'middle', vertical: 'top' }, - direction: 'row', -} as const; - function ChartsLegend(inProps: ChartsLegendProps) { - const props: DefaultizedChartsLegendProps = useThemeProps({ - props: { ...defaultProps, ...inProps }, + const props = useThemeProps({ + props: inProps, name: 'MuiChartsLegend', }); - const { position, direction, hidden, slots, slotProps } = props; + const defaultizedProps: DefaultizedChartsLegendProps = { + direction: 'row', + ...props, + position: { horizontal: 'middle', vertical: 'top', ...props.position }, + }; + const { position, direction, hidden, slots, slotProps } = defaultizedProps; + const theme = useTheme(); - const classes = useUtilityClasses({ ...props, theme }); + const classes = useUtilityClasses({ ...defaultizedProps, theme }); const drawingArea = useDrawingArea(); const series = useSeries(); diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx index c6e6415d39a47..3a6fb7a7ed3f5 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import clsx from 'clsx'; -import { useTheme } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import { ChartsText, ChartsTextStyle } from '../ChartsText'; import { SeriesId } from '../models/seriesType/common'; import { LegendItemConfig, LegendItemContext } from './chartsLegend.types'; @@ -58,8 +58,7 @@ const createClickContext = ( * @ignore - internal component. */ function ChartsLegendItem(props: ChartsLegendItemProps) { - const theme = useTheme(); - const isRTL = theme.direction === 'rtl'; + const isRTL = useRtl(); const { id, positionY, diff --git a/packages/x-charts/src/ChartsLegend/ContinuousColorLegend.tsx b/packages/x-charts/src/ChartsLegend/ContinuousColorLegend.tsx index d331e317f945c..00880553da648 100644 --- a/packages/x-charts/src/ChartsLegend/ContinuousColorLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/ContinuousColorLegend.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { ScaleSequential } from '@mui/x-charts-vendor/d3-scale'; import { useTheme } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import ChartsContinuousGradient from '../internals/components/ChartsAxesGradients/ChartsContinuousGradient'; import { AxisDefaultized, ContinuousScaleName } from '../models/axis'; import { useChartId, useDrawingArea } from '../hooks'; @@ -205,6 +206,7 @@ const defaultLabelFormatter: LabelFormatter = ({ formattedValue }) => formattedV function ContinuousColorLegend(props: ContinuousColorLegendProps) { const theme = useTheme(); + const isRtl = useRtl(); const { id: idProp, minLabel = defaultLabelFormatter, @@ -224,8 +226,6 @@ function ContinuousColorLegend(props: ContinuousColorLegendProps) { const chartId = useChartId(); const id = idProp ?? `gradient-legend-${chartId}`; - const isRTL = theme.direction === 'rtl'; - const axisItem = useAxis({ axisDirection, axisId }); const { width, height, left, right, top, bottom } = useDrawingArea(); @@ -277,7 +277,7 @@ function ContinuousColorLegend(props: ContinuousColorLegendProps) { // Place bar and texts const barBox = - direction === 'column' || (isRTL && direction === 'row') + direction === 'column' || (isRtl && direction === 'row') ? { width: thickness, height: size } : { width: size, height: thickness }; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx index 1391416cf3d0c..16265d1e52f49 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx @@ -58,7 +58,7 @@ export interface ChartsTooltipProps { * - 'item': Shows data about the item below the mouse. * - 'axis': Shows values associated with the hovered x value * - 'none': Does not display tooltip - * @default 'item' + * @default 'axis' */ trigger?: TriggerOptions; /** @@ -94,6 +94,7 @@ const useUtilityClasses = (ownerState: { const slots = { root: ['root'], + paper: ['paper'], table: ['table'], row: ['row'], cell: ['cell'], @@ -124,12 +125,12 @@ const ChartsTooltipRoot = styled(Popper, { * * - [ChartsTooltip API](https://mui.com/x/api/charts/charts-tool-tip/) */ -function ChartsTooltip(props: ChartsTooltipProps) { - const themeProps = useThemeProps({ - props, +function ChartsTooltip(inProps: ChartsTooltipProps) { + const props = useThemeProps({ + props: inProps, name: 'MuiChartsTooltip', }); - const { trigger = 'axis', itemContent, axisContent, slots, slotProps } = themeProps; + const { trigger = 'axis', itemContent, axisContent, slots, slotProps } = props; const mousePosition = useMouseTracker(); @@ -140,7 +141,7 @@ function ChartsTooltip(props: ChartsTooltipProps) const tooltipHasData = getTooltipHasData(trigger, displayedData); const popperOpen = mousePosition !== null && tooltipHasData; - const classes = useUtilityClasses({ classes: themeProps.classes }); + const classes = useUtilityClasses({ classes: props.classes }); const PopperComponent = slots?.popper ?? ChartsTooltipRoot; const popperProps = useSlotProps({ @@ -170,7 +171,7 @@ function ChartsTooltip(props: ChartsTooltipProps) return ( {popperOpen && ( - + {trigger === 'item' ? ( } @@ -228,7 +229,7 @@ ChartsTooltip.propTypes = { * - 'item': Shows data about the item below the mouse. * - 'axis': Shows values associated with the hovered x value * - 'none': Does not display tooltip - * @default 'item' + * @default 'axis' */ trigger: PropTypes.oneOf(['axis', 'item', 'none']), } as any; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsTooltipTable.ts b/packages/x-charts/src/ChartsTooltip/ChartsTooltipTable.ts index a83a70ae9e5be..a50e1c462c51c 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsTooltipTable.ts +++ b/packages/x-charts/src/ChartsTooltip/ChartsTooltipTable.ts @@ -8,6 +8,7 @@ import { chartsTooltipClasses } from './chartsTooltipClasses'; export const ChartsTooltipPaper = styled('div', { name: 'MuiChartsTooltip', slot: 'Container', + overridesResolver: (props, styles) => styles.paper, })(({ theme }) => ({ boxShadow: theme.shadows[1], backgroundColor: (theme.vars || theme).palette.background.paper, @@ -22,6 +23,7 @@ export const ChartsTooltipPaper = styled('div', { export const ChartsTooltipTable = styled('table', { name: 'MuiChartsTooltip', slot: 'Table', + overridesResolver: (props, styles) => styles.table, })(({ theme }) => ({ borderSpacing: 0, '& thead td': { @@ -35,6 +37,7 @@ export const ChartsTooltipTable = styled('table', { export const ChartsTooltipRow = styled('tr', { name: 'MuiChartsTooltip', slot: 'Row', + overridesResolver: (props, styles) => styles.row, })(({ theme }) => ({ 'tr:first-of-type& td': { paddingTop: theme.spacing(1), @@ -50,6 +53,7 @@ export const ChartsTooltipRow = styled('tr', { export const ChartsTooltipCell = styled('td', { name: 'MuiChartsTooltip', slot: 'Cell', + overridesResolver: (props, styles) => styles.cell, })(({ theme }) => ({ verticalAlign: 'middle', color: (theme.vars || theme).palette.text.secondary, @@ -74,6 +78,7 @@ export const ChartsTooltipCell = styled('td', { export const ChartsTooltipMark = styled('div', { name: 'MuiChartsTooltip', slot: 'Mark', + overridesResolver: (props, styles) => styles.mark, shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'color', })<{ color: string }>(({ theme, color }) => ({ width: theme.spacing(1), diff --git a/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx index 5f76ce4edd6c6..c0382f27f2a49 100644 --- a/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx @@ -27,7 +27,7 @@ function DefaultChartsAxisTooltipContent(props: ChartsAxisContentProps) { axis.scaleType === 'utc' ? utcFormatter(v) : v.toLocaleString()); return ( - + {axisValue != null && !axis.hideTooltip && ( diff --git a/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx index 29fb6f74338b1..e4dec21ff9afc 100644 --- a/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx @@ -43,7 +43,7 @@ function DefaultChartsItemTooltipContent['valueFormatter'] )?.(value, { dataIndex: itemData.dataIndex }); return ( - + diff --git a/packages/x-charts/src/ChartsTooltip/chartsTooltipClasses.ts b/packages/x-charts/src/ChartsTooltip/chartsTooltipClasses.ts index 0771fbc2dd2c6..b4ada8e0254b8 100644 --- a/packages/x-charts/src/ChartsTooltip/chartsTooltipClasses.ts +++ b/packages/x-charts/src/ChartsTooltip/chartsTooltipClasses.ts @@ -6,6 +6,8 @@ import { export interface ChartsTooltipClasses { /** Styles applied to the root element. */ root: string; + /** Styles applied to the paper element. */ + paper: string; /** Styles applied to the table element. */ table: string; /** Styles applied to the row element. */ @@ -33,5 +35,5 @@ export function getChartsTooltipUtilityClass(slot: string) { } export const chartsTooltipClasses: ChartsTooltipClasses = generateUtilityClasses( 'MuiChartsTooltip', - ['root', 'table', 'row', 'cell', 'mark', 'markCell', 'labelCell', 'valueCell'], + ['root', 'paper', 'table', 'row', 'cell', 'mark', 'markCell', 'labelCell', 'valueCell'], ); diff --git a/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx b/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx index c4929c9d94593..995ef6f370db4 100644 --- a/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx +++ b/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import useSlotProps from '@mui/utils/useSlotProps'; import composeClasses from '@mui/utils/composeClasses'; -import { useThemeProps, useTheme, Theme } from '@mui/material/styles'; +import { useThemeProps, useTheme, Theme, styled } from '@mui/material/styles'; import { useCartesianContext } from '../context/CartesianProvider'; import { useTicks, TickItemType } from '../hooks/useTicks'; import { AxisDefaultized, ChartsXAxisProps } from '../models/axis'; @@ -83,6 +83,12 @@ function addLabelDimension( }); } +const XAxisRoot = styled(AxisRoot, { + name: 'MuiChartsXAxis', + slot: 'Root', + overridesResolver: (props, styles) => styles.root, +})({}); + const defaultProps = { position: 'bottom', disableLine: false, @@ -204,7 +210,7 @@ function ChartsXAxis(inProps: ChartsXAxisProps) { return null; } return ( - )} - + ); } diff --git a/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx b/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx index 281ce8d1b3d23..923a20dc06aa8 100644 --- a/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx +++ b/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx @@ -2,7 +2,8 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import useSlotProps from '@mui/utils/useSlotProps'; import composeClasses from '@mui/utils/composeClasses'; -import { useThemeProps, useTheme, Theme } from '@mui/material/styles'; +import { useThemeProps, useTheme, Theme, styled } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import { useCartesianContext } from '../context/CartesianProvider'; import { useTicks } from '../hooks/useTicks'; import { useDrawingArea } from '../hooks/useDrawingArea'; @@ -27,6 +28,12 @@ const useUtilityClasses = (ownerState: ChartsYAxisProps & { theme: Theme }) => { return composeClasses(slots, getAxisUtilityClass, classes); }; +const YAxisRoot = styled(AxisRoot, { + name: 'MuiChartsYAxis', + slot: 'Root', + overridesResolver: (props, styles) => styles.root, +})({}); + const defaultProps = { position: 'left', disableLine: false, @@ -77,7 +84,7 @@ function ChartsYAxis(inProps: ChartsYAxisProps) { } = defaultizedProps; const theme = useTheme(); - const isRTL = theme.direction === 'rtl'; + const isRtl = useRtl(); const classes = useUtilityClasses({ ...defaultizedProps, theme }); @@ -106,7 +113,7 @@ function ChartsYAxis(inProps: ChartsYAxisProps) { const TickLabel = slots?.axisTickLabel ?? ChartsText; const Label = slots?.axisLabel ?? ChartsText; - const revertAnchor = (!isRTL && position === 'right') || (isRTL && position !== 'right'); + const revertAnchor = (!isRtl && position === 'right') || (isRtl && position !== 'right'); const axisTickLabelProps = useSlotProps({ elementType: TickLabel, externalSlotProps: slotProps?.axisTickLabel, @@ -156,7 +163,7 @@ function ChartsYAxis(inProps: ChartsYAxisProps) { } return ( - )} - + ); } diff --git a/packages/x-charts/src/LineChart/AnimatedArea.tsx b/packages/x-charts/src/LineChart/AnimatedArea.tsx index adebfc0ac8662..0a1c8ec420b3c 100644 --- a/packages/x-charts/src/LineChart/AnimatedArea.tsx +++ b/packages/x-charts/src/LineChart/AnimatedArea.tsx @@ -1,12 +1,12 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { styled } from '@mui/material/styles'; -import { animated, useSpring } from '@react-spring/web'; +import { animated, useTransition } from '@react-spring/web'; import { color as d3Color } from '@mui/x-charts-vendor/d3-color'; -import { useAnimatedPath } from '../internals/useAnimatedPath'; import { cleanId } from '../internals/cleanId'; import type { AreaElementOwnerState } from './AreaElement'; import { useChartId, useDrawingArea } from '../hooks'; +import { useStringInterpolator } from '../internals/useStringInterpolator'; export const AreaElementPath = styled(animated.path, { name: 'MuiAreaElement', @@ -47,11 +47,21 @@ function AnimatedArea(props: AnimatedAreaProps) { const { left, top, right, bottom, width, height } = useDrawingArea(); const chartId = useChartId(); - const path = useAnimatedPath(d, skipAnimation); + const stringInterpolator = useStringInterpolator(d); - const { animatedWidth } = useSpring({ + const transitionAppear = useTransition([1], { from: { animatedWidth: left }, to: { animatedWidth: width + left + right }, + enter: { animatedWidth: width + left + right }, + leave: { animatedWidth: left }, + reset: false, + immediate: skipAnimation, + }); + + const transitionChange = useTransition([stringInterpolator], { + from: { value: 0 }, + to: { value: 1 }, + enter: { value: 1 }, reset: false, immediate: skipAnimation, }); @@ -60,10 +70,14 @@ function AnimatedArea(props: AnimatedAreaProps) { return ( - + {transitionAppear((style) => ( + + ))} - + {transitionChange((style, interpolator) => ( + + ))} ); diff --git a/packages/x-charts/src/LineChart/AnimatedLine.tsx b/packages/x-charts/src/LineChart/AnimatedLine.tsx index 968f44652d01d..50c09474ba44f 100644 --- a/packages/x-charts/src/LineChart/AnimatedLine.tsx +++ b/packages/x-charts/src/LineChart/AnimatedLine.tsx @@ -1,13 +1,13 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { animated, useSpring } from '@react-spring/web'; +import { animated, useTransition } from '@react-spring/web'; import { color as d3Color } from '@mui/x-charts-vendor/d3-color'; import { styled } from '@mui/material/styles'; -import { useAnimatedPath } from '../internals/useAnimatedPath'; import { cleanId } from '../internals/cleanId'; import type { LineElementOwnerState } from './LineElement'; import { useChartId } from '../hooks/useChartId'; import { useDrawingArea } from '../hooks/useDrawingArea'; +import { useStringInterpolator } from '../internals/useStringInterpolator'; export const LineElementPath = styled(animated.path, { name: 'MuiLineElement', @@ -50,11 +50,21 @@ function AnimatedLine(props: AnimatedLineProps) { const { left, top, bottom, width, height, right } = useDrawingArea(); const chartId = useChartId(); - const path = useAnimatedPath(d, skipAnimation); + const stringInterpolator = useStringInterpolator(d); - const { animatedWidth } = useSpring({ + const transitionAppear = useTransition([1], { from: { animatedWidth: left }, to: { animatedWidth: width + left + right }, + enter: { animatedWidth: width + left + right }, + leave: { animatedWidth: left }, + reset: false, + immediate: skipAnimation, + }); + + const transitionChange = useTransition([stringInterpolator], { + from: { value: 0 }, + to: { value: 1 }, + enter: { value: 1 }, reset: false, immediate: skipAnimation, }); @@ -63,10 +73,14 @@ function AnimatedLine(props: AnimatedLineProps) { return ( - + {transitionAppear((style) => ( + + ))} - + {transitionChange((style, interpolator) => ( + + ))} ); diff --git a/packages/x-charts/src/LineChart/AreaPlot.tsx b/packages/x-charts/src/LineChart/AreaPlot.tsx index 01956e3b847bb..e87e4581e1198 100644 --- a/packages/x-charts/src/LineChart/AreaPlot.tsx +++ b/packages/x-charts/src/LineChart/AreaPlot.tsx @@ -38,99 +38,104 @@ const useAggregatedData = () => { const seriesData = useLineSeries(); const axisData = useCartesianContext(); - if (seriesData === undefined) { - return []; - } - - const { series, stackingGroups } = seriesData; - const { xAxis, yAxis, xAxisIds, yAxisIds } = axisData; - const defaultXAxisId = xAxisIds[0]; - const defaultYAxisId = yAxisIds[0]; - - return stackingGroups.flatMap(({ ids: groupIds }) => { - return [...groupIds] - .reverse() // Revert stacked area for a more pleasant animation - .map((seriesId) => { - const { - xAxisId: xAxisIdProp, - yAxisId: yAxisIdProp, - xAxisKey = defaultXAxisId, - yAxisKey = defaultYAxisId, - stackedData, - data, - connectNulls, - baseline, - } = series[seriesId]; - - const xAxisId = xAxisIdProp ?? xAxisKey; - const yAxisId = yAxisIdProp ?? yAxisKey; - - const xScale = getValueToPositionMapper(xAxis[xAxisId].scale); - const yScale = yAxis[yAxisId].scale; - const xData = xAxis[xAxisId].data; - - const gradientUsed: [AxisId, 'x' | 'y'] | undefined = - (yAxis[yAxisId].colorScale && [yAxisId, 'y']) || - (xAxis[xAxisId].colorScale && [xAxisId, 'x']) || - undefined; - - if (process.env.NODE_ENV !== 'production') { - if (xData === undefined) { - throw new Error( - `MUI X: ${ - xAxisId === DEFAULT_X_AXIS_KEY - ? 'The first `xAxis`' - : `The x-axis with id "${xAxisId}"` - } should have data property to be able to display a line plot.`, - ); - } - if (xData.length < stackedData.length) { - throw new Error( - `MUI X: The data length of the x axis (${xData.length} items) is lower than the length of series (${stackedData.length} items).`, - ); - } - } - - const areaPath = d3Area<{ - x: any; - y: [number, number]; - }>() - .x((d) => xScale(d.x)) - .defined((_, i) => connectNulls || data[i] != null) - .y0((d) => { - if (typeof baseline === 'number') { - return yScale(baseline)!; - } - if (baseline === 'max') { - return yScale.range()[1]; + // This memo prevents odd line chart behavior when hydrating. + const allData = React.useMemo(() => { + if (seriesData === undefined) { + return []; + } + + const { series, stackingGroups } = seriesData; + const { xAxis, yAxis, xAxisIds, yAxisIds } = axisData; + const defaultXAxisId = xAxisIds[0]; + const defaultYAxisId = yAxisIds[0]; + + return stackingGroups.flatMap(({ ids: groupIds }) => { + return [...groupIds] + .reverse() // Revert stacked area for a more pleasant animation + .map((seriesId) => { + const { + xAxisId: xAxisIdProp, + yAxisId: yAxisIdProp, + xAxisKey = defaultXAxisId, + yAxisKey = defaultYAxisId, + stackedData, + data, + connectNulls, + baseline, + } = series[seriesId]; + + const xAxisId = xAxisIdProp ?? xAxisKey; + const yAxisId = yAxisIdProp ?? yAxisKey; + + const xScale = getValueToPositionMapper(xAxis[xAxisId].scale); + const yScale = yAxis[yAxisId].scale; + const xData = xAxis[xAxisId].data; + + const gradientUsed: [AxisId, 'x' | 'y'] | undefined = + (yAxis[yAxisId].colorScale && [yAxisId, 'y']) || + (xAxis[xAxisId].colorScale && [xAxisId, 'x']) || + undefined; + + if (process.env.NODE_ENV !== 'production') { + if (xData === undefined) { + throw new Error( + `MUI X: ${ + xAxisId === DEFAULT_X_AXIS_KEY + ? 'The first `xAxis`' + : `The x-axis with id "${xAxisId}"` + } should have data property to be able to display a line plot.`, + ); } - if (baseline === 'min') { - return yScale.range()[0]; + if (xData.length < stackedData.length) { + throw new Error( + `MUI X: The data length of the x axis (${xData.length} items) is lower than the length of series (${stackedData.length} items).`, + ); } + } - const value = d.y && yScale(d.y[0])!; - if (Number.isNaN(value)) { - return yScale.range()[0]; - } - return value; - }) - .y1((d) => d.y && yScale(d.y[1])!); - - const curve = getCurveFactory(series[seriesId].curve); - const formattedData = xData?.map((x, index) => ({ x, y: stackedData[index] })) ?? []; - const d3Data = connectNulls - ? formattedData.filter((_, i) => data[i] != null) - : formattedData; - - const d = areaPath.curve(curve)(d3Data) || ''; - return { - ...series[seriesId], - gradientUsed, - d, - seriesId, - }; - }); - }); + const areaPath = d3Area<{ + x: any; + y: [number, number]; + }>() + .x((d) => xScale(d.x)) + .defined((_, i) => connectNulls || data[i] != null) + .y0((d) => { + if (typeof baseline === 'number') { + return yScale(baseline)!; + } + if (baseline === 'max') { + return yScale.range()[1]; + } + if (baseline === 'min') { + return yScale.range()[0]; + } + + const value = d.y && yScale(d.y[0])!; + if (Number.isNaN(value)) { + return yScale.range()[0]; + } + return value; + }) + .y1((d) => d.y && yScale(d.y[1])!); + + const curve = getCurveFactory(series[seriesId].curve); + const formattedData = xData?.map((x, index) => ({ x, y: stackedData[index] })) ?? []; + const d3Data = connectNulls + ? formattedData.filter((_, i) => data[i] != null) + : formattedData; + + const d = areaPath.curve(curve)(d3Data) || ''; + return { + ...series[seriesId], + gradientUsed, + d, + seriesId, + }; + }); + }); + }, [seriesData, axisData]); + + return allData; }; /** diff --git a/packages/x-charts/src/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index 0bd258bfd715b..94235ce0c79d6 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -159,7 +159,7 @@ const LineChart = React.forwardRef(function LineChart(inProps: LineChartProps, r return ( {props.onAxisClick && } - {props.grid && } + diff --git a/packages/x-charts/src/LineChart/LinePlot.tsx b/packages/x-charts/src/LineChart/LinePlot.tsx index 96603b232d98f..d4e1e579ff2e1 100644 --- a/packages/x-charts/src/LineChart/LinePlot.tsx +++ b/packages/x-charts/src/LineChart/LinePlot.tsx @@ -38,76 +38,83 @@ const useAggregatedData = () => { const seriesData = useLineSeries(); const axisData = useCartesianContext(); - if (seriesData === undefined) { - return []; - } - - const { series, stackingGroups } = seriesData; - const { xAxis, yAxis, xAxisIds, yAxisIds } = axisData; - const defaultXAxisId = xAxisIds[0]; - const defaultYAxisId = yAxisIds[0]; - - return stackingGroups.flatMap(({ ids: groupIds }) => { - return groupIds.flatMap((seriesId) => { - const { - xAxisId: xAxisIdProp, - yAxisId: yAxisIdProp, - xAxisKey = defaultXAxisId, - yAxisKey = defaultYAxisId, - stackedData, - data, - connectNulls, - } = series[seriesId]; - - const xAxisId = xAxisIdProp ?? xAxisKey; - const yAxisId = yAxisIdProp ?? yAxisKey; - - const xScale = getValueToPositionMapper(xAxis[xAxisId].scale); - const yScale = yAxis[yAxisId].scale; - const xData = xAxis[xAxisId].data; - - const gradientUsed: [AxisId, 'x' | 'y'] | undefined = - (yAxis[yAxisId].colorScale && [yAxisId, 'y']) || - (xAxis[xAxisId].colorScale && [xAxisId, 'x']) || - undefined; - - if (process.env.NODE_ENV !== 'production') { - if (xData === undefined) { - throw new Error( - `MUI X: ${ - xAxisId === DEFAULT_X_AXIS_KEY - ? 'The first `xAxis`' - : `The x-axis with id "${xAxisId}"` - } should have data property to be able to display a line plot.`, - ); + // This memo prevents odd line chart behavior when hydrating. + const allData = React.useMemo(() => { + if (seriesData === undefined) { + return []; + } + + const { series, stackingGroups } = seriesData; + const { xAxis, yAxis, xAxisIds, yAxisIds } = axisData; + const defaultXAxisId = xAxisIds[0]; + const defaultYAxisId = yAxisIds[0]; + + return stackingGroups.flatMap(({ ids: groupIds }) => { + return groupIds.flatMap((seriesId) => { + const { + xAxisId: xAxisIdProp, + yAxisId: yAxisIdProp, + xAxisKey = defaultXAxisId, + yAxisKey = defaultYAxisId, + stackedData, + data, + connectNulls, + } = series[seriesId]; + + const xAxisId = xAxisIdProp ?? xAxisKey; + const yAxisId = yAxisIdProp ?? yAxisKey; + + const xScale = getValueToPositionMapper(xAxis[xAxisId].scale); + const yScale = yAxis[yAxisId].scale; + const xData = xAxis[xAxisId].data; + + const gradientUsed: [AxisId, 'x' | 'y'] | undefined = + (yAxis[yAxisId].colorScale && [yAxisId, 'y']) || + (xAxis[xAxisId].colorScale && [xAxisId, 'x']) || + undefined; + + if (process.env.NODE_ENV !== 'production') { + if (xData === undefined) { + throw new Error( + `MUI X: ${ + xAxisId === DEFAULT_X_AXIS_KEY + ? 'The first `xAxis`' + : `The x-axis with id "${xAxisId}"` + } should have data property to be able to display a line plot.`, + ); + } + if (xData.length < stackedData.length) { + throw new Error( + `MUI X: The data length of the x axis (${xData.length} items) is lower than the length of series (${stackedData.length} items).`, + ); + } } - if (xData.length < stackedData.length) { - throw new Error( - `MUI X: The data length of the x axis (${xData.length} items) is lower than the length of series (${stackedData.length} items).`, - ); - } - } - - const linePath = d3Line<{ - x: any; - y: [number, number]; - }>() - .x((d) => xScale(d.x)) - .defined((_, i) => connectNulls || data[i] != null) - .y((d) => yScale(d.y[1])!); - - const formattedData = xData?.map((x, index) => ({ x, y: stackedData[index] })) ?? []; - const d3Data = connectNulls ? formattedData.filter((_, i) => data[i] != null) : formattedData; - - const d = linePath.curve(getCurveFactory(series[seriesId].curve))(d3Data) || ''; - return { - ...series[seriesId], - gradientUsed, - d, - seriesId, - }; + + const linePath = d3Line<{ + x: any; + y: [number, number]; + }>() + .x((d) => xScale(d.x)) + .defined((_, i) => connectNulls || data[i] != null) + .y((d) => yScale(d.y[1])!); + + const formattedData = xData?.map((x, index) => ({ x, y: stackedData[index] })) ?? []; + const d3Data = connectNulls + ? formattedData.filter((_, i) => data[i] != null) + : formattedData; + + const d = linePath.curve(getCurveFactory(series[seriesId].curve))(d3Data) || ''; + return { + ...series[seriesId], + gradientUsed, + d, + seriesId, + }; + }); }); - }); + }, [seriesData, axisData]); + + return allData; }; /** diff --git a/packages/x-charts/src/LineChart/MarkElement.tsx b/packages/x-charts/src/LineChart/MarkElement.tsx index 137f44f252b74..b86ef162168d0 100644 --- a/packages/x-charts/src/LineChart/MarkElement.tsx +++ b/packages/x-charts/src/LineChart/MarkElement.tsx @@ -107,7 +107,7 @@ function MarkElement(props: MarkElementProps) { }); const { axis } = React.useContext(InteractionContext); - const position = useSpring({ x, y, immediate: skipAnimation }); + const position = useSpring({ to: { x, y }, immediate: skipAnimation }); const ownerState = { id, classes: innerClasses, diff --git a/packages/x-charts/src/PieChart/PieChart.tsx b/packages/x-charts/src/PieChart/PieChart.tsx index dca99305017f5..51fe9e0d87a31 100644 --- a/packages/x-charts/src/PieChart/PieChart.tsx +++ b/packages/x-charts/src/PieChart/PieChart.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; +import { useRtl } from '@mui/system/RtlProvider'; import { useThemeProps } from '@mui/material/styles'; import { ResponsiveChartContainer, @@ -30,7 +31,6 @@ import { ChartsXAxisProps, ChartsYAxisProps, } from '../models/axis'; -import { useIsRTL } from '../internals/useIsRTL'; import { ChartsOverlay, ChartsOverlayProps, @@ -153,12 +153,12 @@ const PieChart = React.forwardRef(function PieChart(inProps: PieChartProps, ref) className, ...other } = props; - const isRTL = useIsRTL(); + const isRtl = useRtl(); - const margin = { ...(isRTL ? defaultRTLMargin : defaultMargin), ...marginProps }; + const margin = { ...(isRtl ? defaultRTLMargin : defaultMargin), ...marginProps }; const legend: ChartsLegendProps = { direction: 'column', - position: { vertical: 'middle', horizontal: isRTL ? 'left' : 'right' }, + position: { vertical: 'middle', horizontal: isRtl ? 'left' : 'right' }, ...legendProps, }; diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index ecd3bbe6c2c3e..d8ae6735b52b7 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -139,7 +139,7 @@ const ScatterChart = React.forwardRef(function ScatterChart(inProps: ScatterChar {!props.disableVoronoi && } - {props.grid && } + {/* The `data-drawing-container` indicates that children are part of the drawing area. Ref: https://github.com/mui/mui-x/issues/13659 */} diff --git a/packages/x-charts/src/hooks/useReducedMotion.ts b/packages/x-charts/src/hooks/useReducedMotion.ts index b95f28d4a9da5..724e2da21fbed 100644 --- a/packages/x-charts/src/hooks/useReducedMotion.ts +++ b/packages/x-charts/src/hooks/useReducedMotion.ts @@ -1,5 +1,12 @@ import { useIsomorphicLayoutEffect, Globals } from '@react-spring/web'; +const handleMediaChange = (e: { matches: boolean | undefined }) => { + Globals.assign({ + // Modification such the react-spring implementation such that this hook can remove animation but never activate animation. + skipAnimation: e.matches || undefined, + }); +}; + /** * Returns `boolean` or `null`, used to automatically * set skipAnimations to the value of the user's @@ -8,24 +15,18 @@ import { useIsomorphicLayoutEffect, Globals } from '@react-spring/web'; * The return value, post-effect, is the value of their preferred setting */ export const useReducedMotion = () => { - // Taken from: https://github.com/pmndrs/react-spring/blob/02ec877bbfab0df46da0e4a47d5f68d3e731206a/packages/shared/src/hooks/useReducedMotion.ts#L13 + // Taken from: https://github.com/pmndrs/react-spring/blob/fd65b605b85c3a24143c4ce9dd322fdfca9c66be/packages/shared/src/hooks/useReducedMotion.ts useIsomorphicLayoutEffect(() => { - if (!window.matchMedia) { - // skip animation in environments where `window.matchMedia` would not be available (i.e. test/jsdom) - Globals.assign({ - skipAnimation: true, - }); - return () => {}; + // Skip animation test/jsdom + const shouldSkipAnimation = !window?.matchMedia; + + if (shouldSkipAnimation) { + handleMediaChange({ matches: true }); + return undefined; } - const mql = window.matchMedia('(prefers-reduced-motion)'); - const handleMediaChange = (event: MediaQueryListEvent | MediaQueryList) => { - Globals.assign({ - // Modification such the react-spring implementation such that this hook can remove animation but never activate animation. - skipAnimation: event.matches || undefined, - }); - }; + const mql = window.matchMedia('(prefers-reduced-motion)'); handleMediaChange(mql); diff --git a/packages/x-charts/src/internals/components/AxisSharedComponents.tsx b/packages/x-charts/src/internals/components/AxisSharedComponents.tsx index 5fb7076d5455c..ba6078ebe23b6 100644 --- a/packages/x-charts/src/internals/components/AxisSharedComponents.tsx +++ b/packages/x-charts/src/internals/components/AxisSharedComponents.tsx @@ -6,21 +6,21 @@ export const AxisRoot = styled('g', { slot: 'Root', overridesResolver: (props, styles) => styles.root, })(({ theme }) => ({ - [`.${axisClasses.tickLabel}`]: { + [`& .${axisClasses.tickLabel}`]: { ...theme.typography.caption, fill: (theme.vars || theme).palette.text.primary, }, - [`.${axisClasses.label}`]: { + [`& .${axisClasses.label}`]: { ...theme.typography.body1, fill: (theme.vars || theme).palette.text.primary, }, - [`.${axisClasses.line}`]: { + [`& .${axisClasses.line}`]: { stroke: (theme.vars || theme).palette.text.primary, shapeRendering: 'crispEdges', strokeWidth: 1, }, - [`.${axisClasses.tick}`]: { + [`& .${axisClasses.tick}`]: { stroke: (theme.vars || theme).palette.text.primary, shapeRendering: 'crispEdges', }, diff --git a/packages/x-charts/src/internals/useAnimatedPath.ts b/packages/x-charts/src/internals/useAnimatedPath.ts deleted file mode 100644 index 9f29447fe138c..0000000000000 --- a/packages/x-charts/src/internals/useAnimatedPath.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as React from 'react'; -import { interpolateString } from '@mui/x-charts-vendor/d3-interpolate'; -import { useSpring, to } from '@react-spring/web'; - -function usePrevious(value: T) { - const ref = React.useRef(null); - React.useEffect(() => { - ref.current = value; - }, [value]); - return ref.current; -} - -// Taken from Nivo -export const useAnimatedPath = (path: string, skipAnimation?: boolean) => { - const previousPath = usePrevious(path); - const interpolator = React.useMemo( - () => (previousPath ? interpolateString(previousPath, path) : () => path), - [previousPath, path], - ); - - const { value } = useSpring({ - from: { value: 0 }, - to: { value: 1 }, - reset: true, - immediate: skipAnimation, - }); - - return to([value], interpolator); -}; diff --git a/packages/x-charts/src/internals/useIsRTL.ts b/packages/x-charts/src/internals/useIsRTL.ts deleted file mode 100644 index 21e7f0fe692d6..0000000000000 --- a/packages/x-charts/src/internals/useIsRTL.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { useTheme } from '@mui/material/styles'; - -export const useIsRTL = () => { - const theme = useTheme(); - return theme.direction === 'rtl'; -}; diff --git a/packages/x-charts/src/internals/useStringInterpolator.ts b/packages/x-charts/src/internals/useStringInterpolator.ts new file mode 100644 index 0000000000000..2b0faa3cd851b --- /dev/null +++ b/packages/x-charts/src/internals/useStringInterpolator.ts @@ -0,0 +1,31 @@ +import * as React from 'react'; +import { interpolateString } from '@mui/x-charts-vendor/d3-interpolate'; + +function usePrevious(value: T) { + const ref = React.useRef<{ currentPath: T; previousPath?: T }>({ + currentPath: value, + previousPath: undefined, + }); + if (ref.current.currentPath !== value) { + ref.current = { + currentPath: value, + previousPath: ref.current.currentPath, + }; + } + + return ref.current; +} + +export const useStringInterpolator = (path: string) => { + const memoryRef = usePrevious(path); + + const interpolator = React.useMemo( + () => + memoryRef.previousPath + ? interpolateString(memoryRef.previousPath, memoryRef.currentPath) + : () => memoryRef.currentPath, + [memoryRef.currentPath, memoryRef.previousPath], + ); + + return interpolator; +}; diff --git a/packages/x-charts/src/tests/materialVersion.test.tsx b/packages/x-charts/src/tests/materialVersion.test.tsx new file mode 100644 index 0000000000000..dc0c0a7e6ee01 --- /dev/null +++ b/packages/x-charts/src/tests/materialVersion.test.tsx @@ -0,0 +1,5 @@ +import materialPackageJson from '@mui/material/package.json'; +import { checkMaterialVersion } from 'test/utils/checkMaterialVersion'; +import packageJson from '../../package.json'; + +checkMaterialVersion({ packageJson, materialPackageJson }); diff --git a/packages/x-charts/src/themeAugmentation/components.d.ts b/packages/x-charts/src/themeAugmentation/components.d.ts index fbb03f04b14ae..3302ca499b7b4 100644 --- a/packages/x-charts/src/themeAugmentation/components.d.ts +++ b/packages/x-charts/src/themeAugmentation/components.d.ts @@ -6,9 +6,11 @@ export interface ChartsComponents { }; MuiChartsXAxis?: { defaultProps?: ComponentsProps['MuiChartsXAxis']; + styleOverrides?: ComponentsOverrides['MuiChartsXAxis']; }; MuiChartsYAxis?: { defaultProps?: ComponentsProps['MuiChartsYAxis']; + styleOverrides?: ComponentsOverrides['MuiChartsYAxis']; }; MuiChartsAxisHighlight?: { styleOverrides?: ComponentsOverrides['MuiChartsAxisHighlight']; diff --git a/packages/x-charts/src/themeAugmentation/overrides.d.ts b/packages/x-charts/src/themeAugmentation/overrides.d.ts index 24f6ce49c23fd..8049913a70bea 100644 --- a/packages/x-charts/src/themeAugmentation/overrides.d.ts +++ b/packages/x-charts/src/themeAugmentation/overrides.d.ts @@ -2,19 +2,21 @@ import { BarLabelClassKey } from '../BarChart'; import { BarElementClassKey } from '../BarChart/BarElement'; import { ChartsAxisHighlightClassKey } from '../ChartsAxisHighlight'; import { ChartsGridClassKey } from '../ChartsGrid'; -import { ChartsLegendClassKey } from '../ChartsLegend'; - import { ChartsTooltipClassKey } from '../ChartsTooltip'; import { AreaElementClassKey, LineElementClassKey, MarkElementClassKey } from '../LineChart'; export interface ChartsComponentNameToClassKey { - MuiChartsAxis: 'root'; // Only the root component of axes is styled + MuiChartsAxis: 'root'; // Only the root component of axes is styled. We should probably remove this one in v8 + MuiChartsXAxis: 'root'; // Only the root component of axes is styled + MuiChartsYAxis: 'root'; // Only the root component of axes is styled + MuiChartsAxisHighlight: ChartsAxisHighlightClassKey; + MuiChartsLegend: 'root'; MuiChartsGrid: ChartsGridClassKey; - MuiChartsLegend: ChartsLegendClassKey; MuiChartsTooltip: ChartsTooltipClassKey; MuiChartsSurface: 'root'; + // BarChart components MuiBarElement: BarElementClassKey; MuiBarLabel: BarLabelClassKey; diff --git a/packages/x-charts/src/themeAugmentation/themeAugmentation.spec.ts b/packages/x-charts/src/themeAugmentation/themeAugmentation.spec.ts index 1c71789139c71..8412c5c669cf7 100644 --- a/packages/x-charts/src/themeAugmentation/themeAugmentation.spec.ts +++ b/packages/x-charts/src/themeAugmentation/themeAugmentation.spec.ts @@ -15,6 +15,11 @@ createTheme({ // @ts-expect-error invalid MuiChartsXAxis prop someRandomProp: true, }, + styleOverrides: { + root: { backgroundColor: 'red' }, + // @ts-expect-error invalid MuiChartsXAxis class key + line: { color: 'red' }, + }, }, MuiChartsYAxis: { defaultProps: { @@ -22,6 +27,11 @@ createTheme({ // @ts-expect-error invalid MuiChartsYAxis prop someRandomProp: true, }, + styleOverrides: { + root: { backgroundColor: 'red' }, + // @ts-expect-error invalid MuiChartsYAxis class key + line: { color: 'red' }, + }, }, MuiChartsAxisHighlight: { styleOverrides: { @@ -39,7 +49,7 @@ createTheme({ styleOverrides: { root: { backgroundColor: 'red' }, // @ts-expect-error invalid MuiChartsLegend class key - constent: { color: 'red' }, + mark: { color: 'red' }, }, }, MuiChartsTooltip: { diff --git a/packages/x-codemod/package.json b/packages/x-codemod/package.json index f37f5c4f5027d..aeec4871a4802 100644 --- a/packages/x-codemod/package.json +++ b/packages/x-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-codemod", - "version": "7.14.0", + "version": "7.15.0", "bin": "./codemod.js", "private": false, "author": "MUI Team", diff --git a/packages/x-data-grid-generator/package.json b/packages/x-data-grid-generator/package.json index d536e8f6f65d2..d4e1aa9687bca 100644 --- a/packages/x-data-grid-generator/package.json +++ b/packages/x-data-grid-generator/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid-generator", - "version": "7.14.0", + "version": "7.15.0", "description": "Generate fake data for demo purposes only.", "author": "MUI Team", "main": "src/index.ts", @@ -40,14 +40,16 @@ "lru-cache": "^10.4.3" }, "devDependencies": { + "@mui/icons-material": "^5.16.5", + "@mui/material": "^5.16.5", "@types/chance": "^1.1.6", "rimraf": "^5.0.10" }, "peerDependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@mui/icons-material": "^5.4.1", - "@mui/material": "^5.15.14", + "@mui/icons-material": "^5.4.1 || ^6.0.0", + "@mui/material": "^5.15.14 || ^6.0.0", "react": "^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { diff --git a/packages/x-data-grid-premium/package.json b/packages/x-data-grid-premium/package.json index be6f543e42c97..d3207ad28ee9c 100644 --- a/packages/x-data-grid-premium/package.json +++ b/packages/x-data-grid-premium/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid-premium", - "version": "7.14.0", + "version": "7.15.0", "description": "The Premium plan edition of the Data Grid Components (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -44,7 +44,6 @@ }, "dependencies": { "@babel/runtime": "^7.25.4", - "@mui/system": "^5.16.7", "@mui/utils": "^5.16.6", "@mui/x-data-grid": "workspace:*", "@mui/x-data-grid-pro": "workspace:*", @@ -59,7 +58,8 @@ "peerDependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@mui/material": "^5.15.14", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" }, @@ -73,6 +73,8 @@ }, "devDependencies": { "@mui/internal-test-utils": "^1.0.10", + "@mui/material": "^5.16.5", + "@mui/system": "^5.16.7", "@types/prop-types": "^15.7.12", "date-fns": "^2.30.0", "rimraf": "^5.0.10" diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index fb0abd4f63b0c..459496e6f7455 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -472,6 +472,14 @@ DataGridPremiumRaw.propTypes = { }), PropTypes.bool, ]), + /** + * If `select`, a group header checkbox in indeterminate state (like "Select All" checkbox) + * will select all the rows under it. + * If `deselect`, it will deselect all the rows under it. + * Works only if `checkboxSelection` is enabled. + * @default "deselect" + */ + indeterminateCheckboxAction: PropTypes.oneOf(['deselect', 'select']), /** * The initial state of the DataGridPremium. * The data in it is set in the state on initialization but isn't controlled. diff --git a/packages/x-data-grid-premium/src/tests/aggregation.DataGridPremium.test.tsx b/packages/x-data-grid-premium/src/tests/aggregation.DataGridPremium.test.tsx index ab65dab64c7d4..a397d549e0377 100644 --- a/packages/x-data-grid-premium/src/tests/aggregation.DataGridPremium.test.tsx +++ b/packages/x-data-grid-premium/src/tests/aggregation.DataGridPremium.test.tsx @@ -411,6 +411,7 @@ describe(' - Aggregation', () => { }), ).getByText('max'), ); + clock.runToLast(); expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3', '4', '5', '5' /* Agg */]); }); diff --git a/packages/x-data-grid-premium/src/tests/materialVersion.test.tsx b/packages/x-data-grid-premium/src/tests/materialVersion.test.tsx new file mode 100644 index 0000000000000..dc0c0a7e6ee01 --- /dev/null +++ b/packages/x-data-grid-premium/src/tests/materialVersion.test.tsx @@ -0,0 +1,5 @@ +import materialPackageJson from '@mui/material/package.json'; +import { checkMaterialVersion } from 'test/utils/checkMaterialVersion'; +import packageJson from '../../package.json'; + +checkMaterialVersion({ packageJson, materialPackageJson }); diff --git a/packages/x-data-grid-pro/package.json b/packages/x-data-grid-pro/package.json index 72204827ec4c8..fbf78ec33b7b9 100644 --- a/packages/x-data-grid-pro/package.json +++ b/packages/x-data-grid-pro/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid-pro", - "version": "7.14.0", + "version": "7.15.0", "description": "The Pro plan edition of the Data Grid components (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -44,7 +44,6 @@ }, "dependencies": { "@babel/runtime": "^7.25.4", - "@mui/system": "^5.16.7", "@mui/utils": "^5.16.6", "@mui/x-data-grid": "workspace:*", "@mui/x-internals": "workspace:*", @@ -57,7 +56,8 @@ "peerDependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@mui/material": "^5.15.14", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" }, @@ -71,6 +71,8 @@ }, "devDependencies": { "@mui/internal-test-utils": "^1.0.10", + "@mui/material": "^5.16.5", + "@mui/system": "^5.16.7", "@types/prop-types": "^15.7.12", "rimraf": "^5.0.10" }, diff --git a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index b168aad4b0b4a..ec3feaa5f00f6 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -427,6 +427,14 @@ DataGridProRaw.propTypes = { }), PropTypes.bool, ]), + /** + * If `select`, a group header checkbox in indeterminate state (like "Select All" checkbox) + * will select all the rows under it. + * If `deselect`, it will deselect all the rows under it. + * Works only if `checkboxSelection` is enabled. + * @default "deselect" + */ + indeterminateCheckboxAction: PropTypes.oneOf(['deselect', 'select']), /** * The initial state of the DataGridPro. * The data in it will be set in the state on initialization but will not be controlled. diff --git a/packages/x-data-grid-pro/src/components/GridColumnMenuPinningItem.tsx b/packages/x-data-grid-pro/src/components/GridColumnMenuPinningItem.tsx index 743fcb3fc3412..0a07624dc3067 100644 --- a/packages/x-data-grid-pro/src/components/GridColumnMenuPinningItem.tsx +++ b/packages/x-data-grid-pro/src/components/GridColumnMenuPinningItem.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { useTheme } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import PropTypes from 'prop-types'; import MenuItem from '@mui/material/MenuItem'; import ListItemIcon from '@mui/material/ListItemIcon'; @@ -12,7 +12,7 @@ function GridColumnMenuPinningItem(props: GridColumnMenuItemProps) { const { colDef, onClick } = props; const apiRef = useGridApiContext(); const rootProps = useGridRootProps(); - const theme = useTheme(); + const isRtl = useRtl(); const pinColumn = React.useCallback( (side: GridPinnedColumnPosition) => (event: React.MouseEvent) => { @@ -76,7 +76,7 @@ function GridColumnMenuPinningItem(props: GridColumnMenuItemProps) { ); } - if (theme.direction === 'rtl') { + if (isRtl) { return ( {pinToRightMenuItem} diff --git a/packages/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx b/packages/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx index e882e42ea10a3..9f47e47ab4976 100644 --- a/packages/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import composeClasses from '@mui/utils/composeClasses'; -import { useTheme } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import { CursorCoordinates, useGridApiEventHandler, @@ -75,7 +75,7 @@ export const useGridColumnReorder = ( const removeDnDStylesTimeout = React.useRef>(); const ownerState = { classes: props.classes }; const classes = useUtilityClasses(ownerState); - const theme = useTheme(); + const isRtl = useRtl(); React.useEffect(() => { return () => { @@ -219,14 +219,10 @@ export const useGridColumnReorder = ( const cursorMoveDirectionX = getCursorMoveDirectionX(cursorPosition.current, coordinates); const hasMovedLeft = cursorMoveDirectionX === CURSOR_MOVE_DIRECTION_LEFT && - (theme.direction === 'rtl' - ? dragColIndex < targetColIndex - : targetColIndex < dragColIndex); + (isRtl ? dragColIndex < targetColIndex : targetColIndex < dragColIndex); const hasMovedRight = cursorMoveDirectionX === CURSOR_MOVE_DIRECTION_RIGHT && - (theme.direction === 'rtl' - ? targetColIndex < dragColIndex - : dragColIndex < targetColIndex); + (isRtl ? targetColIndex < dragColIndex : dragColIndex < targetColIndex); if (hasMovedLeft || hasMovedRight) { let canBeReordered: boolean; @@ -298,7 +294,7 @@ export const useGridColumnReorder = ( cursorPosition.current = coordinates; } }, - [apiRef, logger, theme.direction], + [apiRef, logger, isRtl], ); const handleDragEnd = React.useCallback>( diff --git a/packages/x-data-grid-pro/src/tests/materialVersion.test.tsx b/packages/x-data-grid-pro/src/tests/materialVersion.test.tsx new file mode 100644 index 0000000000000..dc0c0a7e6ee01 --- /dev/null +++ b/packages/x-data-grid-pro/src/tests/materialVersion.test.tsx @@ -0,0 +1,5 @@ +import materialPackageJson from '@mui/material/package.json'; +import { checkMaterialVersion } from 'test/utils/checkMaterialVersion'; +import packageJson from '../../package.json'; + +checkMaterialVersion({ packageJson, materialPackageJson }); diff --git a/packages/x-data-grid/package.json b/packages/x-data-grid/package.json index b15ac1b96fbd8..d5a1f2af8749b 100644 --- a/packages/x-data-grid/package.json +++ b/packages/x-data-grid/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid", - "version": "7.14.0", + "version": "7.15.0", "description": "The Community plan edition of the Data Grid components (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -48,7 +48,6 @@ }, "dependencies": { "@babel/runtime": "^7.25.4", - "@mui/system": "^5.16.7", "@mui/utils": "^5.16.6", "@mui/x-internals": "workspace:*", "clsx": "^2.1.1", @@ -58,7 +57,8 @@ "peerDependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@mui/material": "^5.15.14", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" }, @@ -73,6 +73,8 @@ "devDependencies": { "@mui/internal-test-utils": "^1.0.10", "@mui/joy": "^5.0.0-beta.48", + "@mui/material": "^5.16.5", + "@mui/system": "^5.16.7", "@mui/types": "^7.2.15", "@types/prop-types": "^15.7.12", "rimraf": "^5.0.10" diff --git a/packages/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/x-data-grid/src/DataGrid/DataGrid.tsx index 72fcb94533209..d428bf358b411 100644 --- a/packages/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/x-data-grid/src/DataGrid/DataGrid.tsx @@ -354,6 +354,14 @@ DataGridRaw.propTypes = { }), PropTypes.bool, ]), + /** + * If `select`, a group header checkbox in indeterminate state (like "Select All" checkbox) + * will select all the rows under it. + * If `deselect`, it will deselect all the rows under it. + * Works only if `checkboxSelection` is enabled. + * @default "deselect" + */ + indeterminateCheckboxAction: PropTypes.oneOf(['deselect', 'select']), /** * The initial state of the DataGrid. * The data in it will be set in the state on initialization but will not be controlled. diff --git a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts index 4e29d17e4f7bc..fb7e047f38238 100644 --- a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts +++ b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts @@ -58,6 +58,8 @@ export const DATA_GRID_PROPS_DEFAULT_VALUES: DataGridPropsWithDefaultValues = { hideFooterSelectedRowCount: false, ignoreDiacritics: false, ignoreValueFormatterDuringExport: false, + // TODO v8: Update to 'select' + indeterminateCheckboxAction: 'deselect', keepColumnPositionIfDraggedOutside: false, keepNonExistentRowsSelected: false, loading: false, diff --git a/packages/x-data-grid/src/components/GridScrollbarFillerCell.tsx b/packages/x-data-grid/src/components/GridScrollbarFillerCell.tsx index fc2fd61381ada..c1caf5aabada3 100644 --- a/packages/x-data-grid/src/components/GridScrollbarFillerCell.tsx +++ b/packages/x-data-grid/src/components/GridScrollbarFillerCell.tsx @@ -6,16 +6,19 @@ const classes = { root: gridClasses.scrollbarFiller, header: gridClasses['scrollbarFiller--header'], borderTop: gridClasses['scrollbarFiller--borderTop'], + borderBottom: gridClasses['scrollbarFiller--borderBottom'], pinnedRight: gridClasses['scrollbarFiller--pinnedRight'], }; function GridScrollbarFillerCell({ header, borderTop = true, + borderBottom, pinnedRight, }: { header?: boolean; borderTop?: boolean; + borderBottom?: boolean; pinnedRight?: boolean; }) { return ( @@ -25,6 +28,7 @@ function GridScrollbarFillerCell({ classes.root, header && classes.header, borderTop && classes.borderTop, + borderBottom && classes.borderBottom, pinnedRight && classes.pinnedRight, )} /> diff --git a/packages/x-data-grid/src/components/cell/GridActionsCell.tsx b/packages/x-data-grid/src/components/cell/GridActionsCell.tsx index 2abc7adc0e456..39c20b5c639e2 100644 --- a/packages/x-data-grid/src/components/cell/GridActionsCell.tsx +++ b/packages/x-data-grid/src/components/cell/GridActionsCell.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import MenuList from '@mui/material/MenuList'; -import { useTheme } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import { unstable_useId as useId } from '@mui/utils'; import { GridRenderCellParams } from '../../models/params/gridCellParams'; import { gridClasses } from '../../constants/gridClasses'; @@ -47,7 +47,7 @@ function GridActionsCell(props: GridActionsCellProps) { const buttonRef = React.useRef(null); const ignoreCallToFocus = React.useRef(false); const touchRippleRefs = React.useRef>({}); - const theme = useTheme(); + const isRtl = useRtl(); const menuId = useId(); const buttonId = useId(); const rootProps = useGridRootProps(); @@ -149,7 +149,7 @@ function GridActionsCell(props: GridActionsCellProps) { } // for rtl mode we need to reverse the direction - const rtlMod = theme.direction === 'rtl' ? -1 : 1; + const rtlMod = isRtl ? -1 : 1; const indexMod = (direction === 'left' ? -1 : 1) * rtlMod; // if the button that should receive focus is disabled go one more step diff --git a/packages/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx b/packages/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx index 71e12c5db38be..f968f9108669e 100644 --- a/packages/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx +++ b/packages/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx @@ -129,11 +129,16 @@ const GridHeaderCheckbox = React.forwardRef('MuiDataGrid', [ 'editBooleanCell', 'editInputCell', 'filler', - 'filler--borderTop', + 'filler--borderBottom', 'filler--pinnedLeft', 'filler--pinnedRight', 'filterForm', @@ -764,6 +769,7 @@ export const gridClasses = generateUtilityClasses('MuiDataGrid', [ 'scrollbarFiller', 'scrollbarFiller--header', 'scrollbarFiller--borderTop', + 'scrollbarFiller--borderBottom', 'scrollbarFiller--pinnedRight', 'selectedRowCount', 'sortIcon', diff --git a/packages/x-data-grid/src/hooks/core/gridCoreSelector.ts b/packages/x-data-grid/src/hooks/core/gridCoreSelector.ts index b48fbbb0d2a04..3ec68fdafab05 100644 --- a/packages/x-data-grid/src/hooks/core/gridCoreSelector.ts +++ b/packages/x-data-grid/src/hooks/core/gridCoreSelector.ts @@ -4,4 +4,4 @@ import { GridStateCommunity } from '../../models/gridStateCommunity'; * Get the theme state * @category Core */ -export const gridThemeSelector = (state: GridStateCommunity) => state.theme; +export const gridIsRtlSelector = (state: GridStateCommunity) => state.isRtl; diff --git a/packages/x-data-grid/src/hooks/core/useGridInitialization.ts b/packages/x-data-grid/src/hooks/core/useGridInitialization.ts index 104363f8ba807..d59852b43a54a 100644 --- a/packages/x-data-grid/src/hooks/core/useGridInitialization.ts +++ b/packages/x-data-grid/src/hooks/core/useGridInitialization.ts @@ -2,7 +2,7 @@ import * as React from 'react'; import type { GridApiCommon, GridPrivateApiCommon } from '../../models/api/gridApiCommon'; import { DataGridProcessedProps } from '../../models/props/DataGridProps'; import { useGridRefs } from './useGridRefs'; -import { useGridTheme } from './useGridTheme'; +import { useGridIsRtl } from './useGridIsRtl'; import { useGridLoggerFactory } from './useGridLoggerFactory'; import { useGridApiInitialization } from './useGridApiInitialization'; import { useGridLocaleText } from './useGridLocaleText'; @@ -23,7 +23,7 @@ export const useGridInitialization = < const privateApiRef = useGridApiInitialization(inputApiRef, props); useGridRefs(privateApiRef); - useGridTheme(privateApiRef); + useGridIsRtl(privateApiRef); useGridLoggerFactory(privateApiRef, props); useGridStateInitialization(privateApiRef); useGridPipeProcessing(privateApiRef); diff --git a/packages/x-data-grid/src/hooks/core/useGridIsRtl.tsx b/packages/x-data-grid/src/hooks/core/useGridIsRtl.tsx new file mode 100644 index 0000000000000..576952df12ca4 --- /dev/null +++ b/packages/x-data-grid/src/hooks/core/useGridIsRtl.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; +import { useRtl } from '@mui/system/RtlProvider'; +import { GridPrivateApiCommon } from '../../models/api/gridApiCommon'; + +export const useGridIsRtl = (apiRef: React.MutableRefObject): void => { + const isRtl = useRtl(); + + if (apiRef.current.state.isRtl === undefined) { + apiRef.current.state.isRtl = isRtl; + } + + const isFirstEffect = React.useRef(true); + React.useEffect(() => { + if (isFirstEffect.current) { + isFirstEffect.current = false; + } else { + apiRef.current.setState((state) => ({ ...state, isRtl })); + } + }, [apiRef, isRtl]); +}; diff --git a/packages/x-data-grid/src/hooks/core/useGridTheme.tsx b/packages/x-data-grid/src/hooks/core/useGridTheme.tsx deleted file mode 100644 index 9647f596bd28e..0000000000000 --- a/packages/x-data-grid/src/hooks/core/useGridTheme.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import * as React from 'react'; -import { useTheme } from '@mui/material/styles'; -import { GridPrivateApiCommon } from '../../models/api/gridApiCommon'; - -export const useGridTheme = (apiRef: React.MutableRefObject): void => { - const theme = useTheme(); - - if (!apiRef.current.state.theme) { - apiRef.current.state.theme = theme; - } - - const isFirstEffect = React.useRef(true); - React.useEffect(() => { - if (isFirstEffect.current) { - isFirstEffect.current = false; - } else { - apiRef.current.setState((state) => ({ ...state, theme })); - } - }, [apiRef, theme]); -}; diff --git a/packages/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx b/packages/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx index de3a72f4a8445..10866db97f845 100644 --- a/packages/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx +++ b/packages/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import clsx from 'clsx'; -import { styled, useTheme } from '@mui/material/styles'; +import { styled } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import { DataGridProcessedProps } from '../../../models/props/DataGridProps'; import { useGridSelector } from '../../utils'; import { useGridRootProps } from '../../utils/useGridRootProps'; @@ -28,7 +29,6 @@ import { gridColumnPositionsSelector, gridVisiblePinnedColumnDefinitionsSelector, } from '../columns'; -import { gridPinnedRowsSelector } from '../rows/gridRowsSelector'; import { GridGroupingStructure } from '../columnGrouping/gridColumnGroupsInterfaces'; import { gridColumnGroupsUnwrappedModelSelector } from '../columnGrouping/gridColumnGroupsSelector'; import { GridScrollbarFillerCell as ScrollbarFiller } from '../../../components/GridScrollbarFillerCell'; @@ -98,7 +98,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { const [resizeCol, setResizeCol] = React.useState(''); const apiRef = useGridPrivateApiContext(); - const theme = useTheme(); + const isRtl = useRtl(); const rootProps = useGridRootProps(); const dimensions = useGridSelector(apiRef, gridDimensionsSelector); const hasVirtualization = useGridSelector(apiRef, gridVirtualizationColumnEnabledSelector); @@ -106,11 +106,10 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { const columnPositions = useGridSelector(apiRef, gridColumnPositionsSelector); const renderContext = useGridSelector(apiRef, gridRenderContextColumnsSelector); const pinnedColumns = useGridSelector(apiRef, gridVisiblePinnedColumnDefinitionsSelector); - const pinnedRows = useGridSelector(apiRef, gridPinnedRowsSelector); const offsetLeft = computeOffsetLeft( columnPositions, renderContext, - theme.direction, + isRtl, pinnedColumns.left.length, ); const gridHasFiller = dimensions.columnsTotalWidth < dimensions.viewportOuterSize.width; @@ -183,7 +182,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { params: GetHeadersParams | undefined, children: React.ReactNode, leftOverflow: number, - borderTop: boolean = false, + borderBottom: boolean = false, ) => { const isPinnedRight = params?.position === GridPinnedColumnPosition.RIGHT; const isNotPinned = params?.position === undefined; @@ -201,11 +200,19 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { {isNotPinned && (
)} {hasScrollbarFiller && ( - + )} ); @@ -300,7 +307,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { role="row" aria-rowindex={headerGroupingMaxDepth + 1} ownerState={rootProps} - className={pinnedRows.top.length === 0 ? gridClasses['row--borderBottom'] : undefined} + className={gridClasses['row--borderBottom']} > {leftRenderContext && getColumnHeaders( diff --git a/packages/x-data-grid/src/hooks/features/columnResize/useGridColumnResize.tsx b/packages/x-data-grid/src/hooks/features/columnResize/useGridColumnResize.tsx index 6e4b3cc9573ec..b087e8243b9eb 100644 --- a/packages/x-data-grid/src/hooks/features/columnResize/useGridColumnResize.tsx +++ b/packages/x-data-grid/src/hooks/features/columnResize/useGridColumnResize.tsx @@ -4,7 +4,7 @@ import { unstable_useEventCallback as useEventCallback, } from '@mui/utils'; import useLazyRef from '@mui/utils/useLazyRef'; -import { useTheme, Direction } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import { findGridCellElementsFromCol, findGridElement, @@ -112,11 +112,11 @@ function flipResizeDirection(side: ResizeDirection) { return 'Right'; } -function getResizeDirection(separator: HTMLElement, direction: Direction) { +function getResizeDirection(separator: HTMLElement, isRtl: boolean) { const side = separator.classList.contains(gridClasses['columnSeparator--sideRight']) ? 'Right' : 'Left'; - if (direction === 'rtl') { + if (isRtl) { // Resizing logic should be mirrored in the RTL case return flipResizeDirection(side); } @@ -280,7 +280,7 @@ export const useGridColumnResize = ( | 'onColumnWidthChange' >, ) => { - const theme = useTheme(); + const isRtl = useRtl(); const logger = useGridLogger(apiRef, 'useGridColumnResize'); const refs = useLazyRef(createResizeRefs).current; @@ -491,7 +491,7 @@ export const useGridColumnResize = ( ? [] : findRightPinnedHeadersBeforeCol(apiRef.current, refs.columnHeaderElement); - resizeDirection.current = getResizeDirection(separator, theme.direction); + resizeDirection.current = getResizeDirection(separator, isRtl); initialOffsetToSeparator.current = computeOffsetToSeparator( xStart, diff --git a/packages/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts b/packages/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts index c06920307eb8f..f252388bc18f0 100644 --- a/packages/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts +++ b/packages/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts @@ -5,7 +5,7 @@ import { GridPinnedColumnFields, EMPTY_PINNED_COLUMN_FIELDS, } from './gridColumnsInterfaces'; -import { gridThemeSelector } from '../../core/gridCoreSelector'; +import { gridIsRtlSelector } from '../../core/gridCoreSelector'; /** * Get the columns state @@ -85,13 +85,9 @@ export const gridVisiblePinnedColumnDefinitionsSelector = createSelectorMemoized gridColumnsStateSelector, gridPinnedColumnsSelector, gridVisibleColumnFieldsSelector, - gridThemeSelector, - (columnsState, model, visibleColumnFields, theme) => { - const visiblePinnedFields = filterVisibleColumns( - model, - visibleColumnFields, - theme.direction === 'rtl', - ); + gridIsRtlSelector, + (columnsState, model, visibleColumnFields, isRtl) => { + const visiblePinnedFields = filterVisibleColumns(model, visibleColumnFields, isRtl); const visiblePinnedColumns = { left: visiblePinnedFields.left.map((field) => columnsState.lookup[field]), right: visiblePinnedFields.right.map((field) => columnsState.lookup[field]), diff --git a/packages/x-data-grid/src/hooks/features/keyboardNavigation/useGridKeyboardNavigation.ts b/packages/x-data-grid/src/hooks/features/keyboardNavigation/useGridKeyboardNavigation.ts index 1854e8a134b05..d11ecf537ce0c 100644 --- a/packages/x-data-grid/src/hooks/features/keyboardNavigation/useGridKeyboardNavigation.ts +++ b/packages/x-data-grid/src/hooks/features/keyboardNavigation/useGridKeyboardNavigation.ts @@ -1,5 +1,5 @@ import * as React from 'react'; -import { useTheme } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import { GridEventListener } from '../../../models/events'; import { GridApiCommunity, GridPrivateApiCommunity } from '../../../models/api/gridApiCommunity'; import { GridCellParams } from '../../../models/params/gridCellParams'; @@ -38,18 +38,18 @@ const getLeftColumnIndex = ({ currentColIndex, firstColIndex, lastColIndex, - direction, + isRtl, }: { currentColIndex: number; firstColIndex: number; lastColIndex: number; - direction: 'rtl' | 'ltr'; + isRtl: boolean; }) => { - if (direction === 'rtl') { + if (isRtl) { if (currentColIndex < lastColIndex) { return currentColIndex + 1; } - } else if (direction === 'ltr') { + } else if (!isRtl) { if (currentColIndex > firstColIndex) { return currentColIndex - 1; } @@ -61,18 +61,18 @@ const getRightColumnIndex = ({ currentColIndex, firstColIndex, lastColIndex, - direction, + isRtl, }: { currentColIndex: number; firstColIndex: number; lastColIndex: number; - direction: 'rtl' | 'ltr'; + isRtl: boolean; }) => { - if (direction === 'rtl') { + if (isRtl) { if (currentColIndex > firstColIndex) { return currentColIndex - 1; } - } else if (direction === 'ltr') { + } else if (!isRtl) { if (currentColIndex < lastColIndex) { return currentColIndex + 1; } @@ -103,7 +103,7 @@ export const useGridKeyboardNavigation = ( ): void => { const logger = useGridLogger(apiRef, 'useGridKeyboardNavigation'); const initialCurrentPageRows = useGridVisibleRows(apiRef, props).rows; - const theme = useTheme(); + const isRtl = useRtl(); const currentPageRows = React.useMemo( () => enrichPageRowsWithPinnedRows(apiRef, initialCurrentPageRows), @@ -220,7 +220,7 @@ export const useGridKeyboardNavigation = ( currentColIndex: colIndexBefore, firstColIndex, lastColIndex, - direction: theme.direction, + isRtl, }); if (rightColIndex !== null) { @@ -235,7 +235,7 @@ export const useGridKeyboardNavigation = ( currentColIndex: colIndexBefore, firstColIndex, lastColIndex, - direction: theme.direction, + isRtl, }); if (leftColIndex !== null) { goToHeader(leftColIndex, event); @@ -300,7 +300,7 @@ export const useGridKeyboardNavigation = ( goToHeaderFilter, goToCell, getRowIdFromIndex, - theme.direction, + isRtl, goToHeader, goToGroupHeader, ], @@ -337,7 +337,7 @@ export const useGridKeyboardNavigation = ( currentColIndex: colIndexBefore, firstColIndex, lastColIndex, - direction: theme.direction, + isRtl, }); if (rightColIndex !== null) { @@ -352,7 +352,7 @@ export const useGridKeyboardNavigation = ( currentColIndex: colIndexBefore, firstColIndex, lastColIndex, - direction: theme.direction, + isRtl, }); if (leftColIndex !== null) { goToHeaderFilter(leftColIndex, event); @@ -407,7 +407,7 @@ export const useGridKeyboardNavigation = ( apiRef, currentPageRows.length, goToHeaderFilter, - theme.direction, + isRtl, goToHeader, goToCell, getRowIdFromIndex, @@ -535,7 +535,6 @@ export const useGridKeyboardNavigation = ( return; } - const direction = theme.direction; const viewportPageSize = apiRef.current.getViewportPageSize(); const colIndexBefore = (params as GridCellParams).field @@ -573,14 +572,10 @@ export const useGridKeyboardNavigation = ( currentColIndex: colIndexBefore, firstColIndex, lastColIndex, - direction, + isRtl, }); if (rightColIndex !== null) { - goToCell( - rightColIndex, - getRowIdFromIndex(rowIndexBefore), - direction === 'rtl' ? 'left' : 'right', - ); + goToCell(rightColIndex, getRowIdFromIndex(rowIndexBefore), isRtl ? 'left' : 'right'); } break; } @@ -590,14 +585,10 @@ export const useGridKeyboardNavigation = ( currentColIndex: colIndexBefore, firstColIndex, lastColIndex, - direction, + isRtl, }); if (leftColIndex !== null) { - goToCell( - leftColIndex, - getRowIdFromIndex(rowIndexBefore), - direction === 'rtl' ? 'right' : 'left', - ); + goToCell(leftColIndex, getRowIdFromIndex(rowIndexBefore), isRtl ? 'right' : 'left'); } break; } @@ -685,7 +676,7 @@ export const useGridKeyboardNavigation = ( [ apiRef, currentPageRows, - theme.direction, + isRtl, goToCell, getRowIdFromIndex, headerFilteringEnabled, diff --git a/packages/x-data-grid/src/hooks/features/scroll/useGridScroll.ts b/packages/x-data-grid/src/hooks/features/scroll/useGridScroll.ts index 0c5543e0d12ef..798ffd854c01b 100644 --- a/packages/x-data-grid/src/hooks/features/scroll/useGridScroll.ts +++ b/packages/x-data-grid/src/hooks/features/scroll/useGridScroll.ts @@ -1,5 +1,5 @@ import * as React from 'react'; -import { useTheme } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import { GridCellIndexCoordinates } from '../../../models/gridCell'; import { GridPrivateApiCommunity } from '../../../models/api/gridApiCommunity'; import { useGridLogger } from '../../utils/useGridLogger'; @@ -55,7 +55,7 @@ export const useGridScroll = ( apiRef: React.MutableRefObject, props: Pick, ): void => { - const theme = useTheme(); + const isRtl = useRtl(); const logger = useGridLogger(apiRef, 'useGridScroll'); const colRef = apiRef.current.columnHeadersContainerRef; const virtualScrollerRef = apiRef.current.virtualScrollerRef!; @@ -145,7 +145,7 @@ export const useGridScroll = ( const scroll = React.useCallback( (params: Partial) => { if (virtualScrollerRef.current && params.left !== undefined && colRef.current) { - const direction = theme.direction === 'rtl' ? -1 : 1; + const direction = isRtl ? -1 : 1; colRef.current.scrollLeft = params.left; virtualScrollerRef.current.scrollLeft = direction * params.left; logger.debug(`Scrolling left: ${params.left}`); @@ -156,7 +156,7 @@ export const useGridScroll = ( } logger.debug(`Scrolling, updating container, and viewport`); }, - [virtualScrollerRef, theme.direction, colRef, logger], + [virtualScrollerRef, isRtl, colRef, logger], ); const getScrollPosition = React.useCallback(() => { diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 4c12b9b87a56e..614af3bf08479 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -7,7 +7,7 @@ import { import useLazyRef from '@mui/utils/useLazyRef'; import useTimeout from '@mui/utils/useTimeout'; import { useResizeObserver } from '@mui/x-internals/useResizeObserver'; -import { useTheme, Theme } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import type { GridPrivateApiCommunity } from '../../../models/api/gridApiCommunity'; import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext'; import { useGridRootProps } from '../../utils/useGridRootProps'; @@ -68,7 +68,7 @@ const EMPTY_SCROLL_POSITION = { top: 0, left: 0 }; export const EMPTY_DETAIL_PANELS = Object.freeze(new Map()); const createScrollCache = ( - mode: 'ltr' | 'rtl', + isRtl: boolean, rowBufferPx: number, columnBufferPx: number, verticalBuffer: number, @@ -76,7 +76,7 @@ const createScrollCache = ( ) => ({ direction: ScrollDirection.NONE, buffer: bufferForDirection( - mode, + isRtl, ScrollDirection.NONE, rowBufferPx, columnBufferPx, @@ -109,7 +109,7 @@ export const useGridVirtualScroller = () => { const hasBottomPinnedRows = pinnedRows.bottom.length > 0; const [panels, setPanels] = React.useState(EMPTY_DETAIL_PANELS); - const theme = useTheme(); + const isRtl = useRtl(); const cellFocus = useGridSelector(apiRef, gridFocusCellSelector); const cellTabIndex = useGridSelector(apiRef, gridTabIndexCellSelector); const rowsMeta = useGridSelector(apiRef, gridRowsMetaSelector); @@ -149,7 +149,7 @@ export const useGridVirtualScroller = () => { const frozenContext = React.useRef(undefined); const scrollCache = useLazyRef(() => createScrollCache( - theme.direction, + isRtl, rootProps.rowBufferPx, rootProps.columnBufferPx, dimensions.rowHeight * 15, @@ -254,7 +254,7 @@ export const useGridVirtualScroller = () => { scrollCache.direction = direction; scrollCache.buffer = bufferForDirection( - theme.direction, + isRtl, direction, rootProps.rowBufferPx, rootProps.columnBufferPx, @@ -290,12 +290,12 @@ export const useGridVirtualScroller = () => { if (scrollTop < 0) { return; } - if (theme.direction === 'ltr') { + if (!isRtl) { if (scrollLeft < 0) { return; } } - if (theme.direction === 'rtl') { + if (isRtl) { if (scrollLeft > 0) { return; } @@ -466,7 +466,7 @@ export const useGridVirtualScroller = () => { const offsetLeft = computeOffsetLeft( columnPositions, currentRenderContext, - theme.direction, + isRtl, pinnedColumns.left.length, ); const showBottomBorder = isLastVisibleInSection && params.position === 'top'; @@ -943,10 +943,10 @@ export function areRenderContextsEqual(context1: GridRenderContext, context2: Gr export function computeOffsetLeft( columnPositions: number[], renderContext: GridColumnsRenderContext, - direction: Theme['direction'], + isRtl: boolean, pinnedLeftLength: number, ) { - const factor = direction === 'ltr' ? 1 : -1; + const factor = isRtl ? -1 : 1; const left = factor * (columnPositions[renderContext.firstColumnIndex] ?? 0) - (columnPositions[pinnedLeftLength] ?? 0); @@ -976,14 +976,14 @@ function directionForDelta(dx: number, dy: number) { } function bufferForDirection( - mode: 'ltr' | 'rtl', + isRtl: boolean, direction: ScrollDirection, rowBufferPx: number, columnBufferPx: number, verticalBuffer: number, horizontalBuffer: number, ) { - if (mode === 'rtl') { + if (isRtl) { switch (direction) { case ScrollDirection.LEFT: direction = ScrollDirection.RIGHT; diff --git a/packages/x-data-grid/src/models/gridStateCommunity.ts b/packages/x-data-grid/src/models/gridStateCommunity.ts index 7e00992692bf8..ee737b4b8a51d 100644 --- a/packages/x-data-grid/src/models/gridStateCommunity.ts +++ b/packages/x-data-grid/src/models/gridStateCommunity.ts @@ -1,4 +1,3 @@ -import type { Theme } from '@mui/material/styles'; import type { GridColumnMenuState, GridColumnsInitialState, @@ -31,7 +30,7 @@ import type { GridColumnResizeState } from '../hooks/features/columnResize'; * The state of `DataGrid`. */ export interface GridStateCommunity { - theme: Theme; + isRtl: boolean; dimensions: GridDimensionsState; rows: GridRowsState; visibleRowsLookup: GridVisibleRowsLookupState; diff --git a/packages/x-data-grid/src/models/props/DataGridProps.ts b/packages/x-data-grid/src/models/props/DataGridProps.ts index 97b44620eca30..0943252da8d39 100644 --- a/packages/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/x-data-grid/src/models/props/DataGridProps.ts @@ -244,6 +244,14 @@ export interface DataGridPropsWithDefaultValues - Column headers', () => { - const { render, clock } = createRenderer({ clock: 'fake' }); + const { render } = createRenderer(); const baselineProps = { autoHeight: isJSDOM, @@ -52,8 +51,8 @@ describe(' - Column headers', () => { }); describe('Column menu', () => { - it('should allow to hide column', () => { - render( + it('should allow to hide column', async () => { + const { user } = render(
- Column headers', () => { expect(getColumnHeadersTextContent()).to.deep.equal(['id', 'brand']); - fireEvent.click(within(getColumnHeaderCell(0)).getByLabelText('Menu')); - fireEvent.click(screen.getByRole('menuitem', { name: 'Hide column' })); - clock.runToLast(); + await user.click(within(getColumnHeaderCell(0)).getByLabelText('Menu')); + await user.click(screen.getByRole('menuitem', { name: 'Hide column' })); expect(getColumnHeadersTextContent()).to.deep.equal(['brand']); }); - it('should not allow to hide the only visible column', () => { - render( + it('should not allow to hide the only visible column', async () => { + const { user } = render(
- Column headers', () => { expect(getColumnHeadersTextContent()).to.deep.equal(['id']); - fireEvent.click(within(getColumnHeaderCell(0)).getByLabelText('Menu')); - fireEvent.click(screen.getByRole('menuitem', { name: 'Hide column' })); - clock.runToLast(); + await user.click(within(getColumnHeaderCell(0)).getByLabelText('Menu')); + await user + .setup({ pointerEventsCheck: 0 }) + .click(screen.getByRole('menuitem', { name: 'Hide column' })); expect(getColumnHeadersTextContent()).to.deep.equal(['id']); }); - it('should not allow to hide the only visible column that has menu', () => { - render( + it('should not allow to hide the only visible column that has menu', async () => { + const { user } = render(
- Column headers', () => { expect(getColumnHeadersTextContent()).to.deep.equal(['id', 'brand']); - fireEvent.click(within(getColumnHeaderCell(1)).getByLabelText('Menu')); - fireEvent.click(screen.getByRole('menuitem', { name: 'Hide column' })); - clock.runToLast(); + await user.click(within(getColumnHeaderCell(1)).getByLabelText('Menu')); + await user + .setup({ pointerEventsCheck: 0 }) + .click(screen.getByRole('menuitem', { name: 'Hide column' })); expect(getColumnHeadersTextContent()).to.deep.equal(['id', 'brand']); }); it('menu icon button should close column menu when already open', async () => { - render( + const { user } = render(
, ); - fireUserEvent.mousePress(within(getColumnHeaderCell(0)).getByLabelText('Menu')); - clock.runToLast(); + await user.click(within(getColumnHeaderCell(0)).getByLabelText('Menu')); expect(screen.queryByRole('menu')).not.to.equal(null); - fireUserEvent.mousePress(within(getColumnHeaderCell(0)).getByLabelText('Menu')); - clock.runToLast(); - expect(screen.queryByRole('menu')).to.equal(null); + await user.click(within(getColumnHeaderCell(0)).getByLabelText('Menu')); + await waitFor(() => { + expect(screen.queryByRole('menu')).to.equal(null); + }); }); }); - it('should display sort column menu items as per sortingOrder prop', () => { - render( + it('should display sort column menu items as per sortingOrder prop', async () => { + const { user } = render(
- Column headers', () => { ); const columnCell = getColumnHeaderCell(0); const menuIconButton = columnCell.querySelector('button[aria-label="Menu"]')!; - fireEvent.click(menuIconButton); - clock.runToLast(); + await user.click(menuIconButton); expect(screen.queryByRole('menuitem', { name: /asc/i })).not.to.equal(null); expect(screen.queryByRole('menuitem', { name: /desc/i })).not.to.equal(null); diff --git a/packages/x-data-grid/src/tests/materialVersion.test.tsx b/packages/x-data-grid/src/tests/materialVersion.test.tsx new file mode 100644 index 0000000000000..dc0c0a7e6ee01 --- /dev/null +++ b/packages/x-data-grid/src/tests/materialVersion.test.tsx @@ -0,0 +1,5 @@ +import materialPackageJson from '@mui/material/package.json'; +import { checkMaterialVersion } from 'test/utils/checkMaterialVersion'; +import packageJson from '../../package.json'; + +checkMaterialVersion({ packageJson, materialPackageJson }); diff --git a/packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx b/packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx index 23f1c8f406d22..45ddd727ca212 100644 --- a/packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx +++ b/packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx @@ -1,7 +1,14 @@ import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; -import { createRenderer, fireEvent, screen, act, waitFor } from '@mui/internal-test-utils'; +import { + createRenderer, + fireEvent, + screen, + act, + waitFor, + flushMicrotasks, +} from '@mui/internal-test-utils'; import { DataGrid, DataGridProps, @@ -221,7 +228,7 @@ describe(' - Row selection', () => { expect(getRow(0).querySelector('input')).to.have.property('checked', false); }); - it('should set focus on the cell when clicking the checkbox', () => { + it('should set focus on the cell when clicking the checkbox', async () => { render(); expect(getActiveCell()).to.equal(null); @@ -230,7 +237,9 @@ describe(' - Row selection', () => { fireUserEvent.mousePress(checkboxInput!); - expect(getActiveCell()).to.equal('0-0'); + await waitFor(() => { + expect(getActiveCell()).to.equal('0-0'); + }); }); it('should select all visible rows regardless of pagination', () => { @@ -398,6 +407,26 @@ describe(' - Row selection', () => { }); expect(grid('selectedRowCount')?.textContent).to.equal('1 row selected'); }); + + describe('prop: indeterminateCheckboxAction = "select"', () => { + it('should select all the rows when clicking on "Select All" checkbox in indeterminate state', () => { + render(); + const selectAllCheckbox = screen.getByRole('checkbox', { name: 'Select all rows' }); + fireEvent.click(screen.getAllByRole('checkbox', { name: /select row/i })[0]); + fireEvent.click(selectAllCheckbox); + expect(getSelectedRowIds()).to.deep.equal([0, 1, 2, 3]); + }); + }); + + describe('prop: indeterminateCheckboxAction = "deselect"', () => { + it('should deselect all the rows when clicking on "Select All" checkbox in indeterminate state', () => { + render(); + const selectAllCheckbox = screen.getByRole('checkbox', { name: 'Select all rows' }); + fireEvent.click(screen.getAllByRole('checkbox', { name: /select row/i })[0]); + fireEvent.click(selectAllCheckbox); + expect(getSelectedRowIds()).to.deep.equal([]); + }); + }); }); describe('prop: checkboxSelection = true (multi selection), with keyboard events', () => { @@ -527,7 +556,7 @@ describe(' - Row selection', () => { describe('ripple', () => { clock.withFakeTimers(); - it('should keep only one ripple visible when navigating between checkboxes', function test() { + it('should keep only one ripple visible when navigating between checkboxes', async function test() { if (isJSDOM) { // JSDOM doesn't fire "blur" when .focus is called in another element // FIXME Firefox doesn't show any ripple @@ -539,6 +568,7 @@ describe(' - Row selection', () => { fireEvent.keyDown(cell, { key: 'ArrowLeft' }); fireEvent.keyDown(getCell(1, 0).querySelector('input')!, { key: 'ArrowUp' }); clock.runToLast(); // Wait for transition + await flushMicrotasks(); expect(document.querySelectorAll('.MuiTouchRipple-rippleVisible')).to.have.length(1); }); }); diff --git a/packages/x-date-pickers-pro/package.json b/packages/x-date-pickers-pro/package.json index 015d92f04b602..db67ef12f606b 100644 --- a/packages/x-date-pickers-pro/package.json +++ b/packages/x-date-pickers-pro/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-date-pickers-pro", - "version": "7.14.0", + "version": "7.15.0", "description": "The Pro plan edition of the Date and Time Picker components (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -43,7 +43,6 @@ }, "dependencies": { "@babel/runtime": "^7.25.4", - "@mui/system": "^5.16.7", "@mui/utils": "^5.16.6", "@mui/x-date-pickers": "workspace:*", "@mui/x-license": "workspace:*", @@ -54,7 +53,8 @@ "peerDependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@mui/material": "^5.15.14", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", "date-fns": "^2.25.0 || ^3.2.0", "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0", "dayjs": "^1.10.7", @@ -96,6 +96,8 @@ }, "devDependencies": { "@mui/internal-test-utils": "^1.0.10", + "@mui/material": "^5.16.5", + "@mui/system": "^5.16.7", "@types/luxon": "^3.4.2", "@types/prop-types": "^15.7.12", "date-fns": "^2.30.0", 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 2dc85c2aa91d3..6c4f54626d5a0 100644 --- a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.test.tsx +++ b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.test.tsx @@ -15,7 +15,6 @@ import { } from '@mui/x-date-pickers-pro/DateRangeCalendar'; import { DateRangePickerDay } from '@mui/x-date-pickers-pro/DateRangePickerDay'; import { describeConformance } from 'test/utils/describeConformance'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; import { RangePosition } from '../models'; const getPickerDay = (name: string, picker = 'January 2018') => @@ -535,7 +534,7 @@ describe('', () => { ); const renderCountBeforeChange = RenderCount.callCount; - fireUserEvent.mousePress(getPickerDay('2')); + fireEvent.click(getPickerDay('2')); expect(RenderCount.callCount - renderCountBeforeChange).to.equal(2); // 2 render * 1 day }); @@ -550,10 +549,10 @@ describe('', () => { />, ); - fireUserEvent.mousePress(getPickerDay('2')); + fireEvent.click(getPickerDay('2')); const renderCountBeforeChange = RenderCount.callCount; - fireUserEvent.mousePress(getPickerDay('4')); + fireEvent.click(getPickerDay('4')); expect(RenderCount.callCount - renderCountBeforeChange).to.equal(6); // 2 render * 3 day }); }); 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 ee452e3e68ad8..8ec9617073430 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 @@ -15,7 +15,6 @@ import { getFieldSectionsContainer, getTextbox, } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; const isJSDOM = /jsdom/.test(window.navigator.userAgent); @@ -48,7 +47,7 @@ describe('', () => { expect(screen.getByText('May 2019')).toBeVisible(); }); - it(`should not crash when opening picker with invalid date value`, async () => { + it(`should not crash when opening picker with invalid date value`, () => { render( ', () => { expect(onClose.callCount).to.equal(0); // Change the start date - fireUserEvent.mousePress(getPickerDay('3')); + fireEvent.click(getPickerDay('3')); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.args[0][0]).toEqualDateTime(new Date(2018, 0, 3)); expect(onChange.lastCall.args[0][1]).toEqualDateTime(defaultValue[1]); // Change the end date - fireUserEvent.mousePress(getPickerDay('5')); + fireEvent.click(getPickerDay('5')); expect(onChange.callCount).to.equal(2); expect(onChange.lastCall.args[0][0]).toEqualDateTime(new Date(2018, 0, 3)); expect(onChange.lastCall.args[0][1]).toEqualDateTime(new Date(2018, 0, 5)); @@ -288,7 +287,7 @@ describe('', () => { expect(onClose.callCount).to.equal(0); // Change the end date - fireUserEvent.mousePress(getPickerDay('3')); + fireEvent.click(getPickerDay('3')); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.args[0][0]).toEqualDateTime(defaultValue[0]); expect(onChange.lastCall.args[0][1]).toEqualDateTime(new Date(2018, 0, 3)); @@ -319,7 +318,7 @@ describe('', () => { openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'end' }); // Change the end date - fireUserEvent.mousePress(getPickerDay('3')); + fireEvent.click(getPickerDay('3')); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); @@ -347,7 +346,7 @@ describe('', () => { openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); // Change the start date (already tested) - fireUserEvent.mousePress(getPickerDay('3')); + fireEvent.click(getPickerDay('3')); // Dismiss the picker // eslint-disable-next-line material-ui/disallow-active-element-as-key-event-target -- don't care @@ -418,7 +417,7 @@ describe('', () => { openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); // Change the start date (already tested) - fireUserEvent.mousePress(getPickerDay('3')); + fireEvent.click(getPickerDay('3')); clock.runToLast(); // Dismiss the picker @@ -454,7 +453,7 @@ describe('', () => { ); // Dismiss the picker - fireUserEvent.mousePress(document.body); + fireEvent.click(document.body); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); @@ -522,7 +521,7 @@ describe('', () => { expect(screen.getByRole('tooltip')).toBeVisible(); // Change the start date (already tested) - fireUserEvent.mousePress(getPickerDay('3')); + fireEvent.click(getPickerDay('3')); clock.runToLast(); act(() => { @@ -560,7 +559,7 @@ describe('', () => { openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); // Clear the date - fireUserEvent.mousePress(screen.getByText(/clear/i)); + fireEvent.click(screen.getByText(/clear/i)); expect(onChange.callCount).to.equal(1); // Start date change expect(onChange.lastCall.args[0]).to.deep.equal([null, null]); expect(onAccept.callCount).to.equal(1); @@ -587,7 +586,7 @@ describe('', () => { openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); // Clear the date - fireUserEvent.mousePress(screen.getByText(/clear/i)); + fireEvent.click(screen.getByText(/clear/i)); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(1); diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/describes.DesktopDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/describes.DesktopDateRangePicker.test.tsx index 2639cbebef6bd..640ac3b6c5f3d 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/describes.DesktopDateRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/describes.DesktopDateRangePicker.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { adapterToUse, createPickerRenderer, @@ -13,7 +13,6 @@ import { import { DesktopDateRangePicker } from '@mui/x-date-pickers-pro/DesktopDateRangePicker'; import { SingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; import { describeConformance } from 'test/utils/describeConformance'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe(' - Describes', () => { const { render, clock } = createPickerRenderer({ @@ -87,7 +86,7 @@ describe(' - Describes', () => { } if (isOpened) { - fireUserEvent.mousePress( + fireEvent.click( screen.getAllByRole('gridcell', { name: adapterToUse.getDate(newValue[setEndDate ? 1 : 0]).toString(), })[0], @@ -149,7 +148,7 @@ describe(' - Describes', () => { } if (isOpened) { - fireUserEvent.mousePress( + fireEvent.click( screen.getAllByRole('gridcell', { name: adapterToUse.getDate(newValue[setEndDate ? 1 : 0]).toString(), })[0], diff --git a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx index f3d52bc90d1f0..069e4d66cc750 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx @@ -173,7 +173,7 @@ const DesktopDateTimeRangePicker = React.forwardRef(function DesktopDateTimeRang ...defaultizedProps, views, viewRenderers, - format: resolveDateTimeFormat(utils, defaultizedProps), + format: resolveDateTimeFormat(utils, defaultizedProps, true), // force true to correctly handle `renderTimeViewClock` as a renderer ampmInClock: true, calendars: defaultizedProps.calendars ?? 1, diff --git a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/DesktopDateTimeRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/DesktopDateTimeRangePicker.test.tsx index e866a51400818..078ffbc61c0b9 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/DesktopDateTimeRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/DesktopDateTimeRangePicker.test.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { expect } from 'chai'; -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { createPickerRenderer, adapterToUse, @@ -8,7 +8,6 @@ import { getFieldSectionsContainer, expectFieldValueV7, } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; import { DesktopDateTimeRangePicker } from '../DesktopDateTimeRangePicker'; describe('', () => { @@ -24,16 +23,16 @@ describe('', () => { openPicker({ type: 'date-time-range', variant: 'desktop', initialFocus: 'start' }); // select start date range - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '11' })); - fireUserEvent.mousePress(screen.getByRole('option', { name: '4 hours' })); - fireUserEvent.mousePress(screen.getByRole('option', { name: '5 minutes' })); - fireUserEvent.mousePress(screen.getByRole('option', { name: 'PM' })); + fireEvent.click(screen.getByRole('gridcell', { name: '11' })); + fireEvent.click(screen.getByRole('option', { name: '4 hours' })); + fireEvent.click(screen.getByRole('option', { name: '5 minutes' })); + fireEvent.click(screen.getByRole('option', { name: 'PM' })); // select end date range on the same day - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '11' })); - fireUserEvent.mousePress(screen.getByRole('option', { name: '5 hours' })); - fireUserEvent.mousePress(screen.getByRole('option', { name: '10 minutes' })); - fireUserEvent.mousePress(screen.getByRole('option', { name: 'PM' })); + fireEvent.click(screen.getByRole('gridcell', { name: '11' })); + fireEvent.click(screen.getByRole('option', { name: '5 hours' })); + fireEvent.click(screen.getByRole('option', { name: '10 minutes' })); + fireEvent.click(screen.getByRole('option', { name: 'PM' })); const startSectionsContainer = getFieldSectionsContainer(0); const endSectionsContainer = getFieldSectionsContainer(1); diff --git a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx index bd7c125ec4b4a..d9b960a960376 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { describeConformance, screen } from '@mui/internal-test-utils'; +import { describeConformance, fireEvent, screen } from '@mui/internal-test-utils'; import { createPickerRenderer, adapterToUse, @@ -9,7 +9,6 @@ import { describeRangeValidation, getFieldSectionsContainer, } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; import { DesktopDateTimeRangePicker } from '../DesktopDateTimeRangePicker'; describe(' - Describes', () => { @@ -102,7 +101,7 @@ describe(' - Describes', () => { ]; } if (isOpened) { - fireUserEvent.mousePress( + fireEvent.click( screen.getByRole('gridcell', { name: adapterToUse.getDate(newValue[setEndDate ? 1 : 0]).toString(), }), @@ -113,10 +112,8 @@ describe(' - Describes', () => { hasMeridiem ? 'hours12h' : 'hours24h', ); const hoursNumber = adapterToUse.getHours(newValue[setEndDate ? 1 : 0]); - fireUserEvent.mousePress( - screen.getByRole('option', { name: `${parseInt(hours, 10)} hours` }), - ); - fireUserEvent.mousePress( + fireEvent.click(screen.getByRole('option', { name: `${parseInt(hours, 10)} hours` })); + fireEvent.click( screen.getByRole('option', { name: `${adapterToUse.getMinutes(newValue[setEndDate ? 1 : 0])} minutes`, }), @@ -124,9 +121,7 @@ describe(' - Describes', () => { if (hasMeridiem) { // meridiem is an extra view on `DesktopDateTimeRangePicker` // we need to click it to finish selection - fireUserEvent.mousePress( - screen.getByRole('option', { name: hoursNumber >= 12 ? 'PM' : 'AM' }), - ); + fireEvent.click(screen.getByRole('option', { name: hoursNumber >= 12 ? 'PM' : 'AM' })); } } else { selectSection('day'); diff --git a/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/MobileDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/MobileDateRangePicker.test.tsx index 177cf4752e9ae..76383fe45d87a 100644 --- a/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/MobileDateRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/MobileDateRangePicker.test.tsx @@ -9,12 +9,11 @@ import { openPicker, getFieldSectionsContainer, } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; import { DateRange } from '@mui/x-date-pickers-pro/models'; import { SingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; describe('', () => { - const { render } = createPickerRenderer({ clock: 'fake' }); + const { render } = createPickerRenderer(); describe('Field slot: SingleInputDateRangeField', () => { it('should render the input with a given `name` when `SingleInputDateRangeField` is used', () => { @@ -37,29 +36,43 @@ describe('', () => { }); describe('picker state', () => { - it('should open when focusing the start input', () => { + it('should open when focusing the start input', async () => { const onOpen = spy(); - render(); + const { user } = render( + , + ); - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + await openPicker({ + type: 'date-range', + variant: 'mobile', + initialFocus: 'start', + click: user.click, + }); expect(onOpen.callCount).to.equal(1); expect(screen.queryByRole('dialog')).toBeVisible(); }); - it('should open when focusing the end input', () => { + it('should open when focusing the end input', async () => { const onOpen = spy(); - render(); + const { user } = render( + , + ); - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'end' }); + await openPicker({ + type: 'date-range', + variant: 'mobile', + initialFocus: 'end', + click: user.click, + }); expect(onOpen.callCount).to.equal(1); expect(screen.queryByRole('dialog')).toBeVisible(); }); - it('should call onChange with updated start date then call onChange with updated end date when opening from start input', () => { + it('should call onChange with updated start date then call onChange with updated end date when opening from start input', async () => { const onChange = spy(); const onAccept = spy(); const onClose = spy(); @@ -68,7 +81,7 @@ describe('', () => { adapterToUse.date('2018-01-06'), ]; - render( + const { user } = render( ', () => { expect(onClose.callCount).to.equal(0); // Change the start date - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); + await user.click(screen.getByRole('gridcell', { name: '3' })); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.args[0][0]).toEqualDateTime(new Date(2018, 0, 3)); expect(onChange.lastCall.args[0][1]).toEqualDateTime(defaultValue[1]); // Change the end date - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '5' })); + await user.click(screen.getByRole('gridcell', { name: '5' })); expect(onChange.callCount).to.equal(2); expect(onChange.lastCall.args[0][0]).toEqualDateTime(new Date(2018, 0, 3)); expect(onChange.lastCall.args[0][1]).toEqualDateTime(new Date(2018, 0, 5)); @@ -100,7 +113,7 @@ describe('', () => { expect(onClose.callCount).to.equal(0); }); - it('should call onChange with updated end date when opening from end input', () => { + it('should call onChange with updated end date when opening from end input', async () => { const onChange = spy(); const onAccept = spy(); const onClose = spy(); @@ -109,7 +122,7 @@ describe('', () => { adapterToUse.date('2018-01-06'), ]; - render( + const { user } = render( ', () => { expect(onClose.callCount).to.equal(0); // Change the end date - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); + await user.click(screen.getByRole('gridcell', { name: '3' })); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.args[0][0]).toEqualDateTime(defaultValue[0]); expect(onChange.lastCall.args[0][1]).toEqualDateTime(new Date(2018, 0, 3)); @@ -134,7 +147,7 @@ describe('', () => { expect(onClose.callCount).to.equal(0); }); - it('should call onClose and onAccept when selecting the end date if props.closeOnSelect = true', () => { + it('should call onClose and onAccept when selecting the end date if props.closeOnSelect = true', async () => { const onAccept = spy(); const onClose = spy(); const defaultValue: DateRange = [ @@ -142,7 +155,7 @@ describe('', () => { adapterToUse.date('2018-01-06'), ]; - render( + const { user } = render( ', () => { openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'end' }); // Change the end date - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); + await user.click(screen.getByRole('gridcell', { name: '3' })); expect(onAccept.callCount).to.equal(1); expect(onAccept.lastCall.args[0][0]).toEqualDateTime(defaultValue[0]); @@ -163,7 +176,7 @@ describe('', () => { expect(onClose.callCount).to.equal(1); }); - it('should call onClose and onChange with the initial value when clicking "Cancel" button', () => { + it('should call onClose and onChange with the initial value when clicking "Cancel" button', async () => { const onChange = spy(); const onAccept = spy(); const onClose = spy(); @@ -172,7 +185,7 @@ describe('', () => { adapterToUse.date('2018-01-06'), ]; - render( + const { user } = render( ', () => { openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); // Change the start date (already tested) - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); + await user.click(screen.getByRole('gridcell', { name: '3' })); // Cancel the modifications - fireUserEvent.mousePress(screen.getByText(/cancel/i)); + await user.click(screen.getByText(/cancel/i)); expect(onChange.callCount).to.equal(2); // Start date change + reset expect(onChange.lastCall.args[0][0]).toEqualDateTime(defaultValue[0]); expect(onChange.lastCall.args[0][1]).toEqualDateTime(defaultValue[1]); @@ -197,7 +210,7 @@ describe('', () => { expect(onClose.callCount).to.equal(1); }); - it('should call onClose and onAccept with the live value and onAccept with the live value when clicking the "OK"', () => { + it('should call onClose and onAccept with the live value and onAccept with the live value when clicking the "OK"', async () => { const onChange = spy(); const onAccept = spy(); const onClose = spy(); @@ -206,7 +219,7 @@ describe('', () => { adapterToUse.date('2018-01-06'), ]; - render( + const { user } = render( ', () => { openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); // Change the start date (already tested) - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); + await user.click(screen.getByRole('gridcell', { name: '3' })); // Accept the modifications - fireUserEvent.mousePress(screen.getByText(/ok/i)); + await user.click(screen.getByText(/ok/i)); expect(onChange.callCount).to.equal(1); // Start date change expect(onAccept.callCount).to.equal(1); expect(onAccept.lastCall.args[0][0]).toEqualDateTime(new Date(2018, 0, 3)); @@ -230,7 +243,7 @@ describe('', () => { expect(onClose.callCount).to.equal(1); }); - it('should call onClose, onChange with empty value and onAccept with empty value when pressing the "Clear" button', () => { + it('should call onClose, onChange with empty value and onAccept with empty value when pressing the "Clear" button', async () => { const onChange = spy(); const onAccept = spy(); const onClose = spy(); @@ -239,7 +252,7 @@ describe('', () => { adapterToUse.date('2018-01-06'), ]; - render( + const { user } = render( ', () => { openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); // Clear the date - fireUserEvent.mousePress(screen.getByText(/clear/i)); + await user.click(screen.getByText(/clear/i)); expect(onChange.callCount).to.equal(1); // Start date change expect(onChange.lastCall.args[0]).to.deep.equal([null, null]); expect(onAccept.callCount).to.equal(1); @@ -261,12 +274,12 @@ describe('', () => { expect(onClose.callCount).to.equal(1); }); - it('should not call onChange or onAccept when pressing "Clear" button with an already null value', () => { + it('should not call onChange or onAccept when pressing "Clear" button with an already null value', async () => { const onChange = spy(); const onAccept = spy(); const onClose = spy(); - render( + const { user } = render( ', () => { openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); // Clear the date - fireUserEvent.mousePress(screen.getByText(/clear/i)); + await user.click(screen.getByText(/clear/i)); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(1); diff --git a/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/describes.MobileDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/describes.MobileDateRangePicker.test.tsx index 7503ccadc73ef..3410aec62f209 100644 --- a/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/describes.MobileDateRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/describes.MobileDateRangePicker.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { screen, fireDiscreteEvent } from '@mui/internal-test-utils'; +import { screen, fireDiscreteEvent, fireEvent } from '@mui/internal-test-utils'; import { MobileDateRangePicker } from '@mui/x-date-pickers-pro/MobileDateRangePicker'; import { adapterToUse, @@ -12,7 +12,6 @@ import { getFieldSectionsContainer, } from 'test/utils/pickers'; import { describeConformance } from 'test/utils/describeConformance'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe(' - Describes', () => { const { render, clock } = createPickerRenderer({ @@ -87,7 +86,7 @@ describe(' - Describes', () => { openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); } - fireUserEvent.mousePress( + fireEvent.click( screen.getAllByRole('gridcell', { name: adapterToUse.getDate(newValue[setEndDate ? 1 : 0]).toString(), })[0], diff --git a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx index 504484d7f3442..27036c430d8e7 100644 --- a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx @@ -172,7 +172,7 @@ const MobileDateTimeRangePicker = React.forwardRef(function MobileDateTimeRangeP const props = { ...defaultizedProps, viewRenderers, - format: resolveDateTimeFormat(utils, defaultizedProps), + format: resolveDateTimeFormat(utils, defaultizedProps, true), // Force one calendar on mobile to avoid layout issues calendars: 1, // force true to correctly handle `renderTimeViewClock` as a renderer diff --git a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/describes.MobileDateTimeRangePicker.test.tsx b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/describes.MobileDateTimeRangePicker.test.tsx index 1422ba7bb2332..06f204cc0cf60 100644 --- a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/describes.MobileDateTimeRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/describes.MobileDateTimeRangePicker.test.tsx @@ -10,7 +10,6 @@ import { getFieldSectionsContainer, openPicker, } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; import { MobileDateTimeRangePicker } from '../MobileDateTimeRangePicker'; describe(' - Describes', () => { @@ -109,12 +108,12 @@ describe(' - Describes', () => { // if we want to set the end date, we firstly need to switch to end date "range position" if (setEndDate) { - fireUserEvent.mousePress( + fireEvent.click( screen.getByRole('button', { name: adapterToUse.format(value[1], 'shortDate') }), ); } - fireUserEvent.mousePress( + fireEvent.click( screen.getByRole('gridcell', { name: adapterToUse.getDate(newValue[setEndDate ? 1 : 0]).toString(), }), @@ -125,10 +124,8 @@ describe(' - Describes', () => { hasMeridiem ? 'hours12h' : 'hours24h', ); const hoursNumber = adapterToUse.getHours(newValue[setEndDate ? 1 : 0]); - fireUserEvent.mousePress( - screen.getByRole('option', { name: `${parseInt(hours, 10)} hours` }), - ); - fireUserEvent.mousePress( + fireEvent.click(screen.getByRole('option', { name: `${parseInt(hours, 10)} hours` })); + fireEvent.click( screen.getByRole('option', { name: `${adapterToUse.getMinutes(newValue[setEndDate ? 1 : 0])} minutes`, }), @@ -136,9 +133,7 @@ describe(' - Describes', () => { if (hasMeridiem) { // meridiem is an extra view on `MobileDateTimeRangePicker` // we need to click it to finish selection - fireUserEvent.mousePress( - screen.getByRole('option', { name: hoursNumber >= 12 ? 'PM' : 'AM' }), - ); + fireEvent.click(screen.getByRole('option', { name: hoursNumber >= 12 ? 'PM' : 'AM' })); } // Close the picker if (!isOpened) { @@ -147,7 +142,7 @@ describe(' - Describes', () => { clock.runToLast(); } else { // return to the start date view in case we'd like to repeat the selection process - fireUserEvent.mousePress( + fireEvent.click( screen.getByRole('button', { name: adapterToUse.format(newValue[0], 'shortDate') }), ); } diff --git a/packages/x-date-pickers-pro/src/tests/materialVersion.test.tsx b/packages/x-date-pickers-pro/src/tests/materialVersion.test.tsx new file mode 100644 index 0000000000000..dc0c0a7e6ee01 --- /dev/null +++ b/packages/x-date-pickers-pro/src/tests/materialVersion.test.tsx @@ -0,0 +1,5 @@ +import materialPackageJson from '@mui/material/package.json'; +import { checkMaterialVersion } from 'test/utils/checkMaterialVersion'; +import packageJson from '../../package.json'; + +checkMaterialVersion({ packageJson, materialPackageJson }); diff --git a/packages/x-date-pickers/package.json b/packages/x-date-pickers/package.json index 7a5ea6153cc8a..3db487bfd2d96 100644 --- a/packages/x-date-pickers/package.json +++ b/packages/x-date-pickers/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-date-pickers", - "version": "7.14.0", + "version": "7.15.0", "description": "The community edition of the Date and Time Picker components (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -46,7 +46,6 @@ }, "dependencies": { "@babel/runtime": "^7.25.4", - "@mui/system": "^5.16.7", "@mui/utils": "^5.16.6", "@types/react-transition-group": "^4.4.11", "clsx": "^2.1.1", @@ -56,7 +55,8 @@ "peerDependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@mui/material": "^5.15.14", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", "date-fns": "^2.25.0 || ^3.2.0", "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0", "dayjs": "^1.10.7", @@ -98,6 +98,8 @@ }, "devDependencies": { "@mui/internal-test-utils": "^1.0.10", + "@mui/material": "^5.16.5", + "@mui/system": "^5.16.7", "@types/luxon": "^3.4.2", "@types/moment-hijri": "^2.1.4", "@types/moment-jalaali": "^0.7.9", diff --git a/packages/x-date-pickers/src/DateCalendar/tests/DateCalendar.test.tsx b/packages/x-date-pickers/src/DateCalendar/tests/DateCalendar.test.tsx index 8cfd7af3ad1e5..bf13515b44c83 100644 --- a/packages/x-date-pickers/src/DateCalendar/tests/DateCalendar.test.tsx +++ b/packages/x-date-pickers/src/DateCalendar/tests/DateCalendar.test.tsx @@ -1,40 +1,36 @@ import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; -import { fireEvent, screen } from '@mui/internal-test-utils'; +import { fireEvent, screen, waitFor } from '@mui/internal-test-utils'; import { DateCalendar } from '@mui/x-date-pickers/DateCalendar'; import { PickersDay } from '@mui/x-date-pickers/PickersDay'; import { createPickerRenderer, adapterToUse } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; const isJSDOM = /jsdom/.test(window.navigator.userAgent); describe('', () => { - const { render, clock } = createPickerRenderer({ - clock: 'fake', - clockConfig: new Date('2019-01-02'), - }); + const { render } = createPickerRenderer(); - it('switches between views uncontrolled', () => { + it('switches between views uncontrolled', async () => { const handleViewChange = spy(); - render( + const { user } = render( , ); - fireEvent.click(screen.getByLabelText(/switch to year view/i)); + await user.click(screen.getByLabelText(/switch to year view/i)); expect(handleViewChange.callCount).to.equal(1); expect(screen.queryByLabelText(/switch to year view/i)).to.equal(null); expect(screen.getByLabelText('year view is open, switch to calendar view')).toBeVisible(); }); - it('should allow month and view changing, but not selection when readOnly prop is passed', () => { + it('should allow month and view changing, but not selection when readOnly prop is passed', async () => { const onChangeMock = spy(); const onMonthChangeMock = spy(); - render( + const { user } = render( ', () => { />, ); - fireEvent.click(screen.getByTitle('Previous month')); + await user.click(screen.getByTitle('Previous month')); expect(onMonthChangeMock.callCount).to.equal(1); - fireEvent.click(screen.getByTitle('Next month')); + await user.click(screen.getByTitle('Next month')); expect(onMonthChangeMock.callCount).to.equal(2); - clock.runToLast(); + await waitFor(() => expect(screen.getAllByRole('rowgroup').length).to.equal(1)); - fireEvent.click(screen.getByRole('gridcell', { name: '5' })); + await user.click(screen.getByRole('gridcell', { name: '5' })); expect(onChangeMock.callCount).to.equal(0); - fireEvent.click(screen.getByText('January 2019')); + await user.click(screen.getByText('January 2019')); expect(screen.queryByLabelText('year view is open, switch to calendar view')).toBeVisible(); }); - it('should not allow interaction when disabled prop is passed', () => { + it('should not allow interaction when disabled prop is passed', async () => { const onChangeMock = spy(); const onMonthChangeMock = spy(); - render( + const { user } = render( ', () => { />, ); - fireEvent.click(screen.getByText('January 2019')); + await user.click(screen.getByText('January 2019')); expect(screen.queryByText('January 2019')).toBeVisible(); expect(screen.queryByLabelText('year view is open, switch to calendar view')).to.equal(null); - fireEvent.click(screen.getByTitle('Previous month')); + await user.setup({ pointerEventsCheck: 0 }).click(screen.getByTitle('Previous month')); expect(onMonthChangeMock.callCount).to.equal(0); - fireEvent.click(screen.getByTitle('Next month')); + await user.setup({ pointerEventsCheck: 0 }).click(screen.getByTitle('Next month')); expect(onMonthChangeMock.callCount).to.equal(0); - fireEvent.click(screen.getByRole('gridcell', { name: '5' })); + await user.setup({ pointerEventsCheck: 0 }).click(screen.getByRole('gridcell', { name: '5' })); expect(onChangeMock.callCount).to.equal(0); }); @@ -131,28 +127,35 @@ describe('', () => { expect(screen.getAllByRole('rowheader').length).to.equal(5); }); - // test: https://github.com/mui/mui-x/issues/12373 - it('should not reset day to `startOfDay` if value already exists when finding the closest enabled date', () => { - const onChange = spy(); - const defaultDate = adapterToUse.date('2019-01-02T11:12:13.550Z'); - render(); - - fireUserEvent.mousePress( - screen.getByRole('button', { name: 'calendar view is open, switch to year view' }), - ); - fireUserEvent.mousePress(screen.getByRole('radio', { name: '2020' })); + describe('with fake timers', () => { + const { render: renderWithFakeTimers, clock } = createPickerRenderer({ + clock: 'fake', + clockConfig: new Date('2019-01-02'), + }); + // test: https://github.com/mui/mui-x/issues/12373 + it('should not reset day to `startOfDay` if value already exists when finding the closest enabled date', () => { + const onChange = spy(); + const defaultDate = adapterToUse.date('2019-01-02T11:12:13.550Z'); + renderWithFakeTimers( + , + ); - // Finish the transition to the day view - clock.runToLast(); + fireEvent.click( + screen.getByRole('button', { name: 'calendar view is open, switch to year view' }), + ); + fireEvent.click(screen.getByRole('radio', { name: '2020' })); + // Finish the transition to the day view + clock.runToLast(); - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '1' })); - fireUserEvent.mousePress( - screen.getByRole('button', { name: 'calendar view is open, switch to year view' }), - ); - // select the current year with a date in the past to trigger "findClosestEnabledDate" - fireUserEvent.mousePress(screen.getByRole('radio', { name: '2019' })); + fireEvent.click(screen.getByRole('gridcell', { name: '1' })); + fireEvent.click( + screen.getByRole('button', { name: 'calendar view is open, switch to year view' }), + ); + // select the current year with a date in the past to trigger "findClosestEnabledDate" + fireEvent.click(screen.getByRole('radio', { name: '2019' })); - expect(onChange.lastCall.firstArg).toEqualDateTime(defaultDate); + expect(onChange.lastCall.firstArg).toEqualDateTime(defaultDate); + }); }); describe('Slot: calendarHeader', () => { @@ -182,10 +185,10 @@ describe('', () => { ).to.have.text('1'); }); - it('should use `referenceDate` when no value defined', () => { + it('should use `referenceDate` when no value defined', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { // should make the reference day firstly focusable expect(screen.getByRole('gridcell', { name: '17' })).to.have.attribute('tabindex', '0'); - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '2' })); + await user.click(screen.getByRole('gridcell', { name: '2' })); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2022, 3, 2, 12, 30)); }); - it('should not use `referenceDate` when a value is defined', () => { + it('should not use `referenceDate` when a value is defined', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { />, ); - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '2' })); + await user.click(screen.getByRole('gridcell', { name: '2' })); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2019, 0, 2, 12, 20)); }); - it('should not use `referenceDate` when a defaultValue is defined', () => { + it('should not use `referenceDate` when a defaultValue is defined', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { />, ); - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '2' })); + await user.click(screen.getByRole('gridcell', { name: '2' })); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2019, 0, 2, 12, 20)); }); - it('should keep the time of the currently provided date', () => { + it('should keep the time of the currently provided date', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { />, ); - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '2' })); + await user.click(screen.getByRole('gridcell', { name: '2' })); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime( adapterToUse.date('2018-01-02T11:11:11.111'), @@ -290,10 +293,10 @@ describe('', () => { }); describe('view: month', () => { - it('should select the closest enabled date in the month if the current date is disabled', () => { + it('should select the closest enabled date in the month if the current date is disabled', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const april = screen.getByText('Apr', { selector: 'button' }); - fireEvent.click(april); + await user.click(april); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2019, 3, 6)); }); - it('should respect minDate when selecting closest enabled date', () => { + it('should respect minDate when selecting closest enabled date', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const april = screen.getByText('Apr', { selector: 'button' }); - fireEvent.click(april); + await user.click(april); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2019, 3, 7)); }); - it('should respect maxDate when selecting closest enabled date', () => { + it('should respect maxDate when selecting closest enabled date', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const april = screen.getByText('Apr', { selector: 'button' }); - fireEvent.click(april); + await user.click(april); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2019, 3, 22)); }); - it('should go to next view without changing the date when no date of the new month is enabled', () => { + it('should go to next view without changing the date when no date of the new month is enabled', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const april = screen.getByText('Apr', { selector: 'button' }); - fireEvent.click(april); - clock.runToLast(); + await user.click(april); expect(onChange.callCount).to.equal(0); expect(screen.getByMuiTest('calendar-month-and-year-text')).to.have.text('April 2019'); }); - it('should use `referenceDate` when no value defined', () => { + it('should use `referenceDate` when no value defined', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const april = screen.getByText('Apr', { selector: 'button' }); - fireEvent.click(april); + await user.click(april); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2018, 3, 1, 12, 30)); }); - it('should not use `referenceDate` when a value is defined', () => { + it('should not use `referenceDate` when a value is defined', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const april = screen.getByText('Apr', { selector: 'button' }); - fireEvent.click(april); + await user.click(april); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2019, 3, 1, 12, 20)); }); - it('should not use `referenceDate` when a defaultValue is defined', () => { + it('should not use `referenceDate` when a defaultValue is defined', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const april = screen.getByText('Apr', { selector: 'button' }); - fireEvent.click(april); + await user.click(april); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2019, 3, 1, 12, 20)); @@ -440,10 +442,10 @@ describe('', () => { expect(screen.getAllByMuiTest('year')).to.have.length(200); }); - it('should select the closest enabled date in the month if the current date is disabled', () => { + it('should select the closest enabled date in the month if the current date is disabled', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const year2022 = screen.getByText('2022', { selector: 'button' }); - fireEvent.click(year2022); + await user.click(year2022); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2022, 4, 1)); }); - it('should respect minDate when selecting closest enabled date', () => { + it('should respect minDate when selecting closest enabled date', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const year2017 = screen.getByText('2017', { selector: 'button' }); - fireEvent.click(year2017); + await user.click(year2017); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2017, 4, 12)); }); - it('should respect maxDate when selecting closest enabled date', () => { + it('should respect maxDate when selecting closest enabled date', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const year2022 = screen.getByText('2022', { selector: 'button' }); - fireEvent.click(year2022); + await user.click(year2022); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2022, 2, 31)); }); - it('should go to next view without changing the date when no date of the new year is enabled', () => { + it('should go to next view without changing the date when no date of the new year is enabled', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const year2022 = screen.getByText('2022', { selector: 'button' }); - fireEvent.click(year2022); - clock.runToLast(); + await user.click(year2022); expect(onChange.callCount).to.equal(0); expect(screen.getByMuiTest('calendar-month-and-year-text')).to.have.text('January 2022'); @@ -548,10 +549,10 @@ describe('', () => { expect(parentBoundingBox.bottom).not.to.lessThan(buttonBoundingBox.bottom); }); - it('should use `referenceDate` when no value defined', () => { + it('should use `referenceDate` when no value defined', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const year2022 = screen.getByText('2022', { selector: 'button' }); - fireEvent.click(year2022); + await user.click(year2022); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2022, 0, 1, 12, 30)); }); - it('should not use `referenceDate` when a value is defined', () => { + it('should not use `referenceDate` when a value is defined', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const year2022 = screen.getByText('2022', { selector: 'button' }); - fireEvent.click(year2022); + await user.click(year2022); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2022, 0, 1, 12, 20)); }); - it('should not use `referenceDate` when a defaultValue is defined', () => { + it('should not use `referenceDate` when a defaultValue is defined', async () => { const onChange = spy(); - render( + const { user } = render( ', () => { ); const year2022 = screen.getByText('2022', { selector: 'button' }); - fireEvent.click(year2022); + await user.click(year2022); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2022, 0, 1, 12, 20)); @@ -621,7 +622,7 @@ describe('', () => { ); const renderCountBeforeChange = RenderCount.callCount; - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '2' })); + fireEvent.click(screen.getByRole('gridcell', { name: '2' })); expect(RenderCount.callCount - renderCountBeforeChange).to.equal(2); // 2 render * 1 day }); @@ -638,7 +639,7 @@ describe('', () => { ); const renderCountBeforeChange = RenderCount.callCount; - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '2' })); + fireEvent.click(screen.getByRole('gridcell', { name: '2' })); expect(RenderCount.callCount - renderCountBeforeChange).to.equal(4); // 2 render * 2 days }); }); diff --git a/packages/x-date-pickers/src/DateCalendar/tests/describes.DateCalendar.test.tsx b/packages/x-date-pickers/src/DateCalendar/tests/describes.DateCalendar.test.tsx index d3ab8212f0d77..248fbb6e620e8 100644 --- a/packages/x-date-pickers/src/DateCalendar/tests/describes.DateCalendar.test.tsx +++ b/packages/x-date-pickers/src/DateCalendar/tests/describes.DateCalendar.test.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { expect } from 'chai'; -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { DateCalendar, dateCalendarClasses as classes } from '@mui/x-date-pickers/DateCalendar'; import { pickersDayClasses } from '@mui/x-date-pickers/PickersDay'; import { @@ -10,7 +10,6 @@ import { describeValue, } from 'test/utils/pickers'; import { describeConformance } from 'test/utils/describeConformance'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe(' - Describes', () => { const { render, clock } = createPickerRenderer({ clock: 'fake' }); @@ -48,7 +47,7 @@ describe(' - Describes', () => { }, setNewValue: (value) => { const newValue = adapterToUse.addDays(value, 1); - fireUserEvent.mousePress( + fireEvent.click( screen.getByRole('gridcell', { name: adapterToUse.getDate(newValue).toString() }), ); diff --git a/packages/x-date-pickers/src/DateCalendar/tests/timezone.DateCalendar.test.tsx b/packages/x-date-pickers/src/DateCalendar/tests/timezone.DateCalendar.test.tsx index 795a3bf042afa..b6f1ef24905b9 100644 --- a/packages/x-date-pickers/src/DateCalendar/tests/timezone.DateCalendar.test.tsx +++ b/packages/x-date-pickers/src/DateCalendar/tests/timezone.DateCalendar.test.tsx @@ -1,9 +1,8 @@ import * as React from 'react'; import { spy } from 'sinon'; import { expect } from 'chai'; -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { describeAdapters } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; import { DateCalendar } from '@mui/x-date-pickers/DateCalendar'; const TIMEZONE_TO_TEST = ['UTC', 'system', 'America/New_York']; @@ -18,7 +17,7 @@ describe(' - Timezone', () => { const onChange = spy(); render(); - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '25' })); + fireEvent.click(screen.getByRole('gridcell', { name: '25' })); const expectedDate = adapter.setDate(adapter.date(undefined, 'default'), 25); // Check the `onChange` value (uses default timezone, e.g: UTC, see TZ env variable) @@ -35,7 +34,7 @@ describe(' - Timezone', () => { it('should use timezone prop for onChange when no value is provided', () => { const onChange = spy(); render(); - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '25' })); + fireEvent.click(screen.getByRole('gridcell', { name: '25' })); const expectedDate = adapter.setDate( adapter.startOfDay(adapter.date(undefined, timezone)), 25, @@ -53,7 +52,7 @@ describe(' - Timezone', () => { render(); - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '25' })); + fireEvent.click(screen.getByRole('gridcell', { name: '25' })); const expectedDate = adapter.setDate(value, 25); // Check the `onChange` value (uses timezone prop) 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 4078e7548eb3a..5d90362ce0788 100644 --- a/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx @@ -6,7 +6,6 @@ import { inputBaseClasses } from '@mui/material/InputBase'; import { fireEvent, screen } from '@mui/internal-test-utils'; import { DesktopDatePicker } from '@mui/x-date-pickers/DesktopDatePicker'; import { createPickerRenderer, adapterToUse, openPicker } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; const isJSDOM = /jsdom/.test(window.navigator.userAgent); @@ -47,7 +46,8 @@ describe('', () => { expect(handleViewChange.callCount).to.equal(1); // Dismiss the picker - fireUserEvent.keyPress(document.activeElement!, { key: 'Escape' }); + // eslint-disable-next-line material-ui/disallow-active-element-as-key-event-target + fireEvent.keyDown(document.activeElement!, { key: 'Escape' }); openPicker({ type: 'date', variant: 'desktop' }); expect(handleViewChange.callCount).to.equal(2); @@ -72,7 +72,8 @@ describe('', () => { expect(handleViewChange.callCount).to.equal(1); // Dismiss the picker - fireUserEvent.keyPress(document.activeElement!, { key: 'Escape' }); + // eslint-disable-next-line material-ui/disallow-active-element-as-key-event-target + fireEvent.keyDown(document.activeElement!, { key: 'Escape' }); openPicker({ type: 'date', variant: 'desktop' }); expect(handleViewChange.callCount).to.equal(2); @@ -89,7 +90,8 @@ describe('', () => { expect(screen.getByRole('radio', { checked: true, name: '2018' })).not.to.equal(null); // Dismiss the picker - fireUserEvent.keyPress(document.activeElement!, { key: 'Escape' }); + // eslint-disable-next-line material-ui/disallow-active-element-as-key-event-target + fireEvent.keyDown(document.activeElement!, { key: 'Escape' }); setProps({ views: ['month', 'year'] }); openPicker({ type: 'date', variant: 'desktop' }); // wait for all pending changes to be flushed @@ -126,7 +128,8 @@ describe('', () => { expect(screen.getByRole('radio', { checked: true, name: 'January' })).not.to.equal(null); // Dismiss the picker - fireUserEvent.keyPress(document.activeElement!, { key: 'Escape' }); + // eslint-disable-next-line material-ui/disallow-active-element-as-key-event-target + fireEvent.keyDown(document.activeElement!, { key: 'Escape' }); setProps({ view: 'year' }); openPicker({ type: 'date', variant: 'desktop' }); // wait for all pending changes to be flushed @@ -221,7 +224,7 @@ describe('', () => { render(); - fireUserEvent.mousePress(screen.getByLabelText(/Choose date/)); + fireEvent.click(screen.getByLabelText(/Choose date/)); expect(onOpen.callCount).to.equal(1); expect(screen.queryByRole('dialog')).toBeVisible(); @@ -245,14 +248,14 @@ describe('', () => { openPicker({ type: 'date', variant: 'desktop' }); // Select year - fireUserEvent.mousePress(screen.getByRole('radio', { name: '2025' })); + fireEvent.click(screen.getByRole('radio', { name: '2025' })); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.args[0]).toEqualDateTime(new Date(2025, 0, 1)); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); // Change the date (same value) - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '1' })); + fireEvent.click(screen.getByRole('gridcell', { name: '1' })); expect(onChange.callCount).to.equal(1); // Don't call onChange again since the value did not change expect(onAccept.callCount).to.equal(1); expect(onAccept.lastCall.args[0]).toEqualDateTime(new Date(2025, 0, 1)); diff --git a/packages/x-date-pickers/src/DesktopDatePicker/tests/describes.DesktopDatePicker.test.tsx b/packages/x-date-pickers/src/DesktopDatePicker/tests/describes.DesktopDatePicker.test.tsx index 782794ba18ebb..5c56072e2b190 100644 --- a/packages/x-date-pickers/src/DesktopDatePicker/tests/describes.DesktopDatePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopDatePicker/tests/describes.DesktopDatePicker.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { createPickerRenderer, adapterToUse, @@ -11,7 +11,6 @@ import { } from 'test/utils/pickers'; import { DesktopDatePicker } from '@mui/x-date-pickers/DesktopDatePicker'; import { describeConformance } from 'test/utils/describeConformance'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe(' - Describes', () => { const { render, clock } = createPickerRenderer({ clock: 'fake' }); @@ -63,7 +62,7 @@ describe(' - Describes', () => { const newValue = applySameValue ? value : adapterToUse.addDays(value, 1); if (isOpened) { - fireUserEvent.mousePress( + fireEvent.click( screen.getByRole('gridcell', { name: adapterToUse.getDate(newValue).toString() }), ); } else { diff --git a/packages/x-date-pickers/src/DesktopDateTimePicker/tests/DesktopDateTimePicker.test.tsx b/packages/x-date-pickers/src/DesktopDateTimePicker/tests/DesktopDateTimePicker.test.tsx index fbaa727814752..c298769075bb2 100644 --- a/packages/x-date-pickers/src/DesktopDateTimePicker/tests/DesktopDateTimePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopDateTimePicker/tests/DesktopDateTimePicker.test.tsx @@ -4,32 +4,28 @@ import { spy } from 'sinon'; import { screen } from '@mui/internal-test-utils'; import { DesktopDateTimePicker } from '@mui/x-date-pickers/DesktopDateTimePicker'; import { adapterToUse, createPickerRenderer, openPicker } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe('', () => { - const { render } = createPickerRenderer({ - clock: 'fake', - clockConfig: new Date('2018-01-01T10:05:05.000'), - }); + const { render } = createPickerRenderer(); describe('picker state', () => { - it('should open when clicking "Choose date"', () => { + it('should open when clicking "Choose date"', async () => { const onOpen = spy(); - render(); + const { user } = render(); - fireUserEvent.mousePress(screen.getByLabelText(/Choose date/)); + await user.click(screen.getByLabelText(/Choose date/)); expect(onOpen.callCount).to.equal(1); expect(screen.queryByRole('dialog')).toBeVisible(); }); - it('should call onAccept when selecting the same date and time after changing the year', () => { + it('should call onAccept when selecting the same date and time after changing the year', async () => { const onChange = spy(); const onAccept = spy(); const onClose = spy(); - render( + const { user } = render( ', () => { />, ); - openPicker({ type: 'date-time', variant: 'desktop' }); + await openPicker({ type: 'date-time', variant: 'desktop', click: user.click }); // Select year - fireUserEvent.mousePress(screen.getByRole('radio', { name: '2025' })); + await user.click(screen.getByRole('radio', { name: '2025' })); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.args[0]).toEqualDateTime(new Date(2025, 0, 1, 11, 55)); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); // Change the date (same value) - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '1' })); + await user.click(screen.getByRole('gridcell', { name: '1' })); expect(onChange.callCount).to.equal(1); // Don't call onChange again since the value did not change // Change the hours (same value) - fireUserEvent.mousePress(screen.getByRole('option', { name: '11 hours' })); + await user.click(screen.getByRole('option', { name: '11 hours' })); expect(onChange.callCount).to.equal(1); // Don't call onChange again since the value did not change // Change the minutes (same value) - fireUserEvent.mousePress(screen.getByRole('option', { name: '55 minutes' })); + await user.click(screen.getByRole('option', { name: '55 minutes' })); expect(onChange.callCount).to.equal(1); // Don't call onChange again since the value did not change // Change the meridiem (same value) - fireUserEvent.mousePress(screen.getByRole('option', { name: 'AM' })); + await user.click(screen.getByRole('option', { name: 'AM' })); expect(onChange.callCount).to.equal(1); // Don't call onChange again since the value did not change expect(onAccept.callCount).to.equal(1); expect(onClose.callCount).to.equal(1); }); }); - it('should allow selecting same view multiple times', () => { + it('should allow selecting same view multiple times', async () => { const onChange = spy(); const onAccept = spy(); const onClose = spy(); - render( + const { user } = render( ', () => { />, ); - openPicker({ type: 'date-time', variant: 'desktop' }); + await openPicker({ type: 'date-time', variant: 'desktop', click: user.click }); // Change the date multiple times to check that picker doesn't close after cycling through all views internally - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '2' })); - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '4' })); - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '5' })); + await user.click(screen.getByRole('gridcell', { name: '2' })); + await user.click(screen.getByRole('gridcell', { name: '3' })); + await user.click(screen.getByRole('gridcell', { name: '4' })); + await user.click(screen.getByRole('gridcell', { name: '5' })); expect(onChange.callCount).to.equal(4); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); // Change the hours - fireUserEvent.mousePress(screen.getByRole('option', { name: '10 hours' })); - fireUserEvent.mousePress(screen.getByRole('option', { name: '9 hours' })); + await user.click(screen.getByRole('option', { name: '10 hours' })); + await user.click(screen.getByRole('option', { name: '9 hours' })); expect(onChange.callCount).to.equal(6); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); // Change the minutes - fireUserEvent.mousePress(screen.getByRole('option', { name: '50 minutes' })); + await user.click(screen.getByRole('option', { name: '50 minutes' })); expect(onChange.callCount).to.equal(7); // Change the meridiem - fireUserEvent.mousePress(screen.getByRole('option', { name: 'PM' })); + await user.click(screen.getByRole('option', { name: 'PM' })); expect(onChange.callCount).to.equal(8); expect(onAccept.callCount).to.equal(1); expect(onClose.callCount).to.equal(1); }); describe('prop: timeSteps', () => { - it('should use "DigitalClock" view renderer, when "timeSteps.minutes" = 60', () => { + it('should use "DigitalClock" view renderer, when "timeSteps.minutes" = 60', async () => { const onChange = spy(); const onAccept = spy(); - render( + const { user } = render( , ); - fireUserEvent.mousePress(screen.getByLabelText(/Choose date/)); + await user.click(screen.getByLabelText(/Choose date/)); - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '2' })); - fireUserEvent.mousePress(screen.getByRole('option', { name: '03:00 AM' })); + await user.click(screen.getByRole('gridcell', { name: '2' })); + await user.click(screen.getByRole('option', { name: '03:00 AM' })); expect(onChange.callCount).to.equal(2); expect(onChange.lastCall.args[0]).toEqualDateTime(new Date(2018, 0, 2, 3, 0, 0)); expect(onAccept.callCount).to.equal(1); }); - it('should accept value and close picker when selecting time on "DigitalClock" view renderer', () => { + it('should accept value and close picker when selecting time on "DigitalClock" view renderer', async () => { const onChange = spy(); const onAccept = spy(); - render( + const { user } = render( , ); - fireUserEvent.mousePress(screen.getByLabelText(/Choose date/)); + await user.click(screen.getByLabelText(/Choose date/)); - fireUserEvent.mousePress(screen.getByRole('option', { name: '03:00 AM' })); + await user.click(screen.getByRole('option', { name: '03:00 AM' })); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.args[0]).toEqualDateTime(new Date(2018, 0, 1, 3, 0, 0)); diff --git a/packages/x-date-pickers/src/DesktopDateTimePicker/tests/describes.DesktopDateTimePicker.test.tsx b/packages/x-date-pickers/src/DesktopDateTimePicker/tests/describes.DesktopDateTimePicker.test.tsx index dc66bec63c589..c59e43a86486e 100644 --- a/packages/x-date-pickers/src/DesktopDateTimePicker/tests/describes.DesktopDateTimePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopDateTimePicker/tests/describes.DesktopDateTimePicker.test.tsx @@ -1,4 +1,4 @@ -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { createPickerRenderer, adapterToUse, @@ -12,7 +12,6 @@ import { DesktopDateTimePicker } from '@mui/x-date-pickers/DesktopDateTimePicker import { expect } from 'chai'; import * as React from 'react'; import { describeConformance } from 'test/utils/describeConformance'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe(' - Describes', () => { const { render, clock } = createPickerRenderer({ clock: 'fake' }); @@ -85,24 +84,20 @@ describe(' - Describes', () => { : adapterToUse.addMinutes(adapterToUse.addHours(adapterToUse.addDays(value, 1), 1), 5); if (isOpened) { - fireUserEvent.mousePress( + fireEvent.click( screen.getByRole('gridcell', { name: adapterToUse.getDate(newValue).toString() }), ); const hasMeridiem = adapterToUse.is12HourCycleInCurrentLocale(); const hours = adapterToUse.format(newValue, hasMeridiem ? 'hours12h' : 'hours24h'); const hoursNumber = adapterToUse.getHours(newValue); - fireUserEvent.mousePress( - screen.getByRole('option', { name: `${parseInt(hours, 10)} hours` }), - ); - fireUserEvent.mousePress( + fireEvent.click(screen.getByRole('option', { name: `${parseInt(hours, 10)} hours` })); + fireEvent.click( screen.getByRole('option', { name: `${adapterToUse.getMinutes(newValue)} minutes` }), ); if (hasMeridiem) { // meridiem is an extra view on `DesktopDateTimePicker` // we need to click it to finish selection - fireUserEvent.mousePress( - screen.getByRole('option', { name: hoursNumber >= 12 ? 'PM' : 'AM' }), - ); + fireEvent.click(screen.getByRole('option', { name: hoursNumber >= 12 ? 'PM' : 'AM' })); } } else { selectSection('day'); diff --git a/packages/x-date-pickers/src/DesktopTimePicker/tests/DesktopTimePicker.test.tsx b/packages/x-date-pickers/src/DesktopTimePicker/tests/DesktopTimePicker.test.tsx index b60fa37d20fb8..28663c2a75572 100644 --- a/packages/x-date-pickers/src/DesktopTimePicker/tests/DesktopTimePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopTimePicker/tests/DesktopTimePicker.test.tsx @@ -3,16 +3,15 @@ import { expect } from 'chai'; import { spy } from 'sinon'; import { screen } from '@mui/internal-test-utils'; import { DesktopTimePicker } from '@mui/x-date-pickers/DesktopTimePicker'; -import { createPickerRenderer, openPicker } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; +import { adapterToUse, createPickerRenderer, openPicker } from 'test/utils/pickers'; describe('', () => { - const { render } = createPickerRenderer({ - clock: 'fake', - clockConfig: new Date('2018-01-01T10:05:05.000'), - }); - describe('rendering behavior', () => { + const { render } = createPickerRenderer({ + clock: 'fake', + clockConfig: new Date('2018-01-01T10:05:05.000'), + }); + it('should render "accept" action and 3 time sections by default', () => { render(); @@ -61,23 +60,26 @@ describe('', () => { }); describe('selecting behavior', () => { - it('should call "onAccept", "onChange", and "onClose" when selecting a single option', () => { + const { render } = createPickerRenderer(); + + it('should call "onAccept", "onChange", and "onClose" when selecting a single option', async () => { const onChange = spy(); const onAccept = spy(); const onClose = spy(); - render( + const { user } = render( , ); - openPicker({ type: 'time', variant: 'desktop' }); + await openPicker({ type: 'time', variant: 'desktop', click: user.click }); - fireUserEvent.mousePress(screen.getByRole('option', { name: '09:00 AM' })); + await user.click(screen.getByRole('option', { name: '09:00 AM' })); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.args[0]).toEqualDateTime(new Date(2018, 0, 1, 9, 0)); expect(onAccept.callCount).to.equal(1); @@ -85,73 +87,94 @@ describe('', () => { expect(onClose.callCount).to.equal(1); }); - it('should call "onAccept", "onChange", and "onClose" when selecting all section', () => { + it('should call "onAccept", "onChange", and "onClose" when selecting all section', async () => { const onChange = spy(); const onAccept = spy(); const onClose = spy(); - render(); + const { user } = render( + , + ); - openPicker({ type: 'time', variant: 'desktop' }); + await openPicker({ type: 'time', variant: 'desktop', click: user.click }); - fireUserEvent.mousePress(screen.getByRole('option', { name: '2 hours' })); + await user.click(screen.getByRole('option', { name: '2 hours' })); expect(onChange.callCount).to.equal(1); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); - fireUserEvent.mousePress(screen.getByRole('option', { name: '15 minutes' })); + await user.click(screen.getByRole('option', { name: '15 minutes' })); expect(onChange.callCount).to.equal(2); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); - fireUserEvent.mousePress(screen.getByRole('option', { name: 'PM' })); + await user.click(screen.getByRole('option', { name: 'PM' })); expect(onChange.callCount).to.equal(3); expect(onAccept.callCount).to.equal(1); expect(onAccept.lastCall.args[0]).toEqualDateTime(new Date(2018, 0, 1, 14, 15)); expect(onClose.callCount).to.equal(1); }); - it('should allow out of order section selection', () => { + it('should allow out of order section selection', async () => { const onChange = spy(); const onAccept = spy(); const onClose = spy(); - render(); + const { user } = render( + , + ); - openPicker({ type: 'time', variant: 'desktop' }); + await openPicker({ type: 'time', variant: 'desktop', click: user.click }); - fireUserEvent.mousePress(screen.getByRole('option', { name: '15 minutes' })); + await user.click(screen.getByRole('option', { name: '15 minutes' })); expect(onChange.callCount).to.equal(1); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); - fireUserEvent.mousePress(screen.getByRole('option', { name: '2 hours' })); + await user.click(screen.getByRole('option', { name: '2 hours' })); expect(onChange.callCount).to.equal(2); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); - fireUserEvent.mousePress(screen.getByRole('option', { name: '25 minutes' })); + await user.click(screen.getByRole('option', { name: '25 minutes' })); expect(onChange.callCount).to.equal(3); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); - fireUserEvent.mousePress(screen.getByRole('option', { name: 'PM' })); + await user.click(screen.getByRole('option', { name: 'PM' })); expect(onChange.callCount).to.equal(4); expect(onAccept.callCount).to.equal(1); expect(onAccept.lastCall.args[0]).toEqualDateTime(new Date(2018, 0, 1, 14, 25)); expect(onClose.callCount).to.equal(1); }); - it('should finish selection when selecting only the last section', () => { + it('should finish selection when selecting only the last section', async () => { const onChange = spy(); const onAccept = spy(); const onClose = spy(); - render(); + const { user } = render( + , + ); - openPicker({ type: 'time', variant: 'desktop' }); + await openPicker({ type: 'time', variant: 'desktop', click: user.click }); - fireUserEvent.mousePress(screen.getByRole('option', { name: 'PM' })); + await user.click(screen.getByRole('option', { name: 'PM' })); expect(onChange.callCount).to.equal(1); expect(onAccept.callCount).to.equal(1); expect(onAccept.lastCall.args[0]).toEqualDateTime(new Date(2018, 0, 1, 12, 0)); diff --git a/packages/x-date-pickers/src/DesktopTimePicker/tests/describes.DesktopTimePicker.test.tsx b/packages/x-date-pickers/src/DesktopTimePicker/tests/describes.DesktopTimePicker.test.tsx index 2fe4730f6fd18..7d4652b6c4df5 100644 --- a/packages/x-date-pickers/src/DesktopTimePicker/tests/describes.DesktopTimePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopTimePicker/tests/describes.DesktopTimePicker.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { createPickerRenderer, adapterToUse, @@ -12,7 +12,6 @@ import { } from 'test/utils/pickers'; import { DesktopTimePicker } from '@mui/x-date-pickers/DesktopTimePicker'; import { describeConformance } from 'test/utils/describeConformance'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe(' - Describes', () => { const { render, clock } = createPickerRenderer({ clock: 'fake' }); @@ -77,18 +76,14 @@ describe(' - Describes', () => { const hasMeridiem = adapterToUse.is12HourCycleInCurrentLocale(); const hours = adapterToUse.format(newValue, hasMeridiem ? 'hours12h' : 'hours24h'); const hoursNumber = adapterToUse.getHours(newValue); - fireUserEvent.mousePress( - screen.getByRole('option', { name: `${parseInt(hours, 10)} hours` }), - ); - fireUserEvent.mousePress( + fireEvent.click(screen.getByRole('option', { name: `${parseInt(hours, 10)} hours` })); + fireEvent.click( screen.getByRole('option', { name: `${adapterToUse.getMinutes(newValue)} minutes` }), ); if (hasMeridiem) { // meridiem is an extra view on `DesktopTimePicker` // we need to click it to finish selection - fireUserEvent.mousePress( - screen.getByRole('option', { name: hoursNumber >= 12 ? 'PM' : 'AM' }), - ); + fireEvent.click(screen.getByRole('option', { name: hoursNumber >= 12 ? 'PM' : 'AM' })); } } else { selectSection('hours'); diff --git a/packages/x-date-pickers/src/DigitalClock/tests/timezone.DigitalClock.test.tsx b/packages/x-date-pickers/src/DigitalClock/tests/timezone.DigitalClock.test.tsx index 070c9b9243f52..5d7a0aa650d86 100644 --- a/packages/x-date-pickers/src/DigitalClock/tests/timezone.DigitalClock.test.tsx +++ b/packages/x-date-pickers/src/DigitalClock/tests/timezone.DigitalClock.test.tsx @@ -1,10 +1,9 @@ import * as React from 'react'; import { spy } from 'sinon'; import { expect } from 'chai'; -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { DigitalClock } from '@mui/x-date-pickers/DigitalClock'; import { getDateOffset, describeAdapters } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; const TIMEZONE_TO_TEST = ['UTC', 'system', 'America/New_York']; @@ -26,7 +25,7 @@ describe(' - Timezone', () => { const onChange = spy(); render(); - fireUserEvent.mousePress(screen.getByRole('option', { name: '08:00 AM' })); + fireEvent.click(screen.getByRole('option', { name: '08:00 AM' })); const expectedDate = adapter.setHours(adapter.date(), 8); @@ -45,7 +44,7 @@ describe(' - Timezone', () => { const onChange = spy(); render(); - fireUserEvent.mousePress(screen.getByRole('option', { name: '08:00 AM' })); + fireEvent.click(screen.getByRole('option', { name: '08:00 AM' })); const expectedDate = adapter.setHours( adapter.startOfDay(adapter.date(undefined, timezone)), @@ -76,7 +75,7 @@ describe(' - Timezone', () => { (adapter.getHours(value) + offsetDiff / 60 + 24) % 24, ); - fireUserEvent.mousePress(screen.getByRole('option', { name: '08:30 PM' })); + fireEvent.click(screen.getByRole('option', { name: '08:30 PM' })); const actualDate = onChange.lastCall.firstArg; diff --git a/packages/x-date-pickers/src/MobileDatePicker/tests/MobileDatePicker.test.tsx b/packages/x-date-pickers/src/MobileDatePicker/tests/MobileDatePicker.test.tsx index 3dc67b8065386..8491613b26228 100644 --- a/packages/x-date-pickers/src/MobileDatePicker/tests/MobileDatePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileDatePicker/tests/MobileDatePicker.test.tsx @@ -13,7 +13,6 @@ import { openPicker, getFieldSectionsContainer, } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe('', () => { const { render, clock } = createPickerRenderer({ clock: 'fake' }); @@ -156,7 +155,7 @@ describe('', () => { render(); - fireUserEvent.mousePress(getFieldSectionsContainer()); + fireEvent.click(getFieldSectionsContainer()); expect(onOpen.callCount).to.equal(1); expect(screen.queryByRole('dialog')).toBeVisible(); diff --git a/packages/x-date-pickers/src/MobileDatePicker/tests/describes.MobileDatePicker.test.tsx b/packages/x-date-pickers/src/MobileDatePicker/tests/describes.MobileDatePicker.test.tsx index b988c49e5827e..431e6682e182d 100644 --- a/packages/x-date-pickers/src/MobileDatePicker/tests/describes.MobileDatePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileDatePicker/tests/describes.MobileDatePicker.test.tsx @@ -12,7 +12,6 @@ import { } from 'test/utils/pickers'; import { MobileDatePicker } from '@mui/x-date-pickers/MobileDatePicker'; import { describeConformance } from 'test/utils/describeConformance'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe(' - Describes', () => { const { render, clock } = createPickerRenderer({ clock: 'fake' }); @@ -65,7 +64,7 @@ describe(' - Describes', () => { } const newValue = applySameValue ? value : adapterToUse.addDays(value, 1); - fireUserEvent.mousePress( + fireEvent.click( screen.getByRole('gridcell', { name: adapterToUse.getDate(newValue).toString() }), ); diff --git a/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx b/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx index 34849b1b5dc0b..1e21c3dbc9355 100644 --- a/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; -import { fireTouchChangedEvent, screen } from '@mui/internal-test-utils'; +import { fireEvent, fireTouchChangedEvent, screen } from '@mui/internal-test-utils'; import { MobileDateTimePicker } from '@mui/x-date-pickers/MobileDateTimePicker'; import { adapterToUse, @@ -10,7 +10,6 @@ import { getClockTouchEvent, getFieldSectionsContainer, } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe('', () => { const { render, clock } = createPickerRenderer({ clock: 'fake' }); @@ -99,7 +98,7 @@ describe('', () => { render(); - fireUserEvent.mousePress(getFieldSectionsContainer()); + fireEvent.click(getFieldSectionsContainer()); expect(onOpen.callCount).to.equal(1); expect(screen.queryByRole('dialog')).toBeVisible(); @@ -132,8 +131,8 @@ describe('', () => { expect(onClose.callCount).to.equal(0); // Change the year view - fireUserEvent.mousePress(screen.getByLabelText(/switch to year view/)); - fireUserEvent.mousePress(screen.getByText('2010', { selector: 'button' })); + fireEvent.click(screen.getByLabelText(/switch to year view/)); + fireEvent.click(screen.getByText('2010', { selector: 'button' })); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.args[0]).toEqualDateTime(new Date(2010, 0, 1)); @@ -141,7 +140,7 @@ describe('', () => { clock.runToLast(); // Change the date - fireUserEvent.mousePress(screen.getByRole('gridcell', { name: '15' })); + fireEvent.click(screen.getByRole('gridcell', { name: '15' })); expect(onChange.callCount).to.equal(2); expect(onChange.lastCall.args[0]).toEqualDateTime(new Date(2010, 0, 15)); diff --git a/packages/x-date-pickers/src/MobileDateTimePicker/tests/describes.MobileDateTimePicker.test.tsx b/packages/x-date-pickers/src/MobileDateTimePicker/tests/describes.MobileDateTimePicker.test.tsx index 7db743bb1c2ea..49ebb8d558371 100644 --- a/packages/x-date-pickers/src/MobileDateTimePicker/tests/describes.MobileDateTimePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileDateTimePicker/tests/describes.MobileDateTimePicker.test.tsx @@ -13,7 +13,6 @@ import { } from 'test/utils/pickers'; import { MobileDateTimePicker } from '@mui/x-date-pickers/MobileDateTimePicker'; import { describeConformance } from 'test/utils/describeConformance'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe(' - Describes', () => { const { render, clock } = createPickerRenderer({ @@ -79,7 +78,7 @@ describe(' - Describes', () => { const newValue = applySameValue ? value : adapterToUse.addMinutes(adapterToUse.addHours(adapterToUse.addDays(value, 1), 1), 5); - fireUserEvent.mousePress( + fireEvent.click( screen.getByRole('gridcell', { name: adapterToUse.getDate(newValue).toString() }), ); const hasMeridiem = adapterToUse.is12HourCycleInCurrentLocale(); @@ -98,9 +97,7 @@ describe(' - Describes', () => { if (hasMeridiem) { const newHours = adapterToUse.getHours(newValue); // select appropriate meridiem - fireUserEvent.mousePress( - screen.getByRole('button', { name: newHours >= 12 ? 'PM' : 'AM' }), - ); + fireEvent.click(screen.getByRole('button', { name: newHours >= 12 ? 'PM' : 'AM' })); } // Close the picker @@ -110,7 +107,7 @@ describe(' - Describes', () => { clock.runToLast(); } else { // return to the date view in case we'd like to repeat the selection process - fireUserEvent.mousePress(screen.getByRole('tab', { name: 'pick date' })); + fireEvent.click(screen.getByRole('tab', { name: 'pick date' })); } return newValue; diff --git a/packages/x-date-pickers/src/MobileTimePicker/tests/MobileTimePicker.test.tsx b/packages/x-date-pickers/src/MobileTimePicker/tests/MobileTimePicker.test.tsx index 16e28b5b3c295..62d073d3c10ca 100644 --- a/packages/x-date-pickers/src/MobileTimePicker/tests/MobileTimePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileTimePicker/tests/MobileTimePicker.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { spy } from 'sinon'; import { expect } from 'chai'; -import { fireTouchChangedEvent, screen, act } from '@mui/internal-test-utils'; +import { fireTouchChangedEvent, screen } from '@mui/internal-test-utils'; import { MobileTimePicker } from '@mui/x-date-pickers/MobileTimePicker'; import { createPickerRenderer, @@ -10,26 +10,27 @@ import { getClockTouchEvent, getFieldSectionsContainer, } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe('', () => { - const { render } = createPickerRenderer({ clock: 'fake' }); + const { render } = createPickerRenderer(); describe('picker state', () => { - it('should open when clicking the input', () => { + it('should open when clicking the input', async () => { const onOpen = spy(); - render(); + const { user } = render( + , + ); - fireUserEvent.mousePress(getFieldSectionsContainer()); + await user.click(getFieldSectionsContainer()); expect(onOpen.callCount).to.equal(1); expect(screen.queryByRole('dialog')).toBeVisible(); }); - it('should fire a change event when meridiem changes', () => { + it('should fire a change event when meridiem changes', async () => { const handleChange = spy(); - render( + const { user } = render( ', () => { ); const buttonPM = screen.getByRole('button', { name: 'PM' }); - act(() => { - buttonPM.click(); - }); + await user.click(buttonPM); expect(handleChange.callCount).to.equal(1); expect(handleChange.firstCall.args[0]).toEqualDateTime(new Date(2019, 0, 1, 16, 20)); }); - it('should call onChange when selecting each view', function test() { + it('should call onChange when selecting each view', async function test() { if (typeof window.Touch === 'undefined' || typeof window.TouchEvent === 'undefined') { this.skip(); } @@ -59,7 +58,7 @@ describe('', () => { const onClose = spy(); const defaultValue = adapterToUse.date('2018-01-01'); - render( + const { user } = render( ', () => { />, ); - openPicker({ type: 'time', variant: 'mobile' }); + await openPicker({ type: 'time', variant: 'mobile', click: user.click }); // Change the hours const hourClockEvent = getClockTouchEvent(11, '12hours'); diff --git a/packages/x-date-pickers/src/MobileTimePicker/tests/describes.MobileTimePicker.test.tsx b/packages/x-date-pickers/src/MobileTimePicker/tests/describes.MobileTimePicker.test.tsx index 8a694129a7840..b3fa12461d7b5 100644 --- a/packages/x-date-pickers/src/MobileTimePicker/tests/describes.MobileTimePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileTimePicker/tests/describes.MobileTimePicker.test.tsx @@ -14,7 +14,6 @@ import { } from 'test/utils/pickers'; import { MobileTimePicker } from '@mui/x-date-pickers/MobileTimePicker'; import { describeConformance } from 'test/utils/describeConformance'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe(' - Describes', () => { const { render, clock } = createPickerRenderer({ @@ -93,9 +92,7 @@ describe(' - Describes', () => { if (hasMeridiem) { const newHours = adapterToUse.getHours(newValue); // select appropriate meridiem - fireUserEvent.mousePress( - screen.getByRole('button', { name: newHours >= 12 ? 'PM' : 'AM' }), - ); + fireEvent.click(screen.getByRole('button', { name: newHours >= 12 ? 'PM' : 'AM' })); } // Close the picker @@ -105,7 +102,7 @@ describe(' - Describes', () => { clock.runToLast(); } else { // return to the hours view in case we'd like to repeat the selection process - fireUserEvent.mousePress(screen.getByRole('button', { name: 'Open previous view' })); + fireEvent.click(screen.getByRole('button', { name: 'Open previous view' })); } return newValue; diff --git a/packages/x-date-pickers/src/MonthCalendar/tests/describes.MonthCalendar.test.tsx b/packages/x-date-pickers/src/MonthCalendar/tests/describes.MonthCalendar.test.tsx index ef370265decd6..2f289f70a5524 100644 --- a/packages/x-date-pickers/src/MonthCalendar/tests/describes.MonthCalendar.test.tsx +++ b/packages/x-date-pickers/src/MonthCalendar/tests/describes.MonthCalendar.test.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { expect } from 'chai'; -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { createPickerRenderer, adapterToUse, @@ -9,7 +9,6 @@ import { } from 'test/utils/pickers'; import { MonthCalendar, monthCalendarClasses as classes } from '@mui/x-date-pickers/MonthCalendar'; import { describeConformance } from 'test/utils/describeConformance'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe(' - Describes', () => { const { render, clock } = createPickerRenderer({ clock: 'fake' }); @@ -55,9 +54,7 @@ describe(' - Describes', () => { setNewValue: (value) => { const newValue = adapterToUse.addMonths(value, 1); - fireUserEvent.mousePress( - screen.getByRole('radio', { name: adapterToUse.format(newValue, 'month') }), - ); + fireEvent.click(screen.getByRole('radio', { name: adapterToUse.format(newValue, 'month') })); return newValue; }, diff --git a/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.test.tsx b/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.test.tsx index 465baad26ceef..58d3b35893ac1 100644 --- a/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.test.tsx +++ b/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.test.tsx @@ -4,12 +4,9 @@ import { spy } from 'sinon'; import { screen } from '@mui/internal-test-utils'; import { PickersActionBar } from '@mui/x-date-pickers/PickersActionBar'; import { createPickerRenderer } from 'test/utils/pickers'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe('', () => { - const { render } = createPickerRenderer({ - clock: 'fake', - }); + const { render } = createPickerRenderer(); it('should not render buttons if actions array is empty', () => { const onAccept = () => {}; @@ -29,13 +26,13 @@ describe('', () => { expect(screen.queryByRole('button')).to.equal(null); }); - it('should render button for "clear" action calling the associated callback', () => { + it('should render button for "clear" action calling the associated callback', async () => { const onAccept = spy(); const onClear = spy(); const onCancel = spy(); const onSetToday = spy(); - render( + const { user } = render( ', () => { />, ); - fireUserEvent.mousePress(screen.getByText(/clear/i)); + await user.click(screen.getByText(/clear/i)); expect(onClear.callCount).to.equal(1); }); - it('should render button for "cancel" action calling the associated callback', () => { + it('should render button for "cancel" action calling the associated callback', async () => { const onAccept = spy(); const onClear = spy(); const onCancel = spy(); const onSetToday = spy(); - render( + const { user } = render( ', () => { />, ); - fireUserEvent.mousePress(screen.getByText(/cancel/i)); + await user.click(screen.getByText(/cancel/i)); expect(onCancel.callCount).to.equal(1); }); - it('should render button for "accept" action calling the associated callback', () => { + it('should render button for "accept" action calling the associated callback', async () => { const onAccept = spy(); const onClear = spy(); const onCancel = spy(); const onSetToday = spy(); - render( + const { user } = render( ', () => { />, ); - fireUserEvent.mousePress(screen.getByText(/ok/i)); + await user.click(screen.getByText(/ok/i)); expect(onAccept.callCount).to.equal(1); }); - it('should render button for "today" action calling the associated callback', () => { + it('should render button for "today" action calling the associated callback', async () => { const onAccept = spy(); const onClear = spy(); const onCancel = spy(); const onSetToday = spy(); - render( + const { user } = render( ', () => { />, ); - fireUserEvent.mousePress(screen.getByText(/today/i)); + await user.click(screen.getByText(/today/i)); expect(onSetToday.callCount).to.equal(1); }); diff --git a/packages/x-date-pickers/src/TimeClock/Clock.tsx b/packages/x-date-pickers/src/TimeClock/Clock.tsx index d04f7c4f7ebe9..fc69d7d028fe9 100644 --- a/packages/x-date-pickers/src/TimeClock/Clock.tsx +++ b/packages/x-date-pickers/src/TimeClock/Clock.tsx @@ -261,7 +261,7 @@ export function Clock(inProps: ClockProps) handleValueChange(newSelectedValue, isFinish); }; - const handleTouchMove = (event: React.TouchEvent) => { + const handleTouchSelection = (event: React.TouchEvent) => { isMoving.current = true; setTime(event, 'shallow'); }; @@ -347,7 +347,8 @@ export function Clock(inProps: ClockProps) ', () => { const onChangeMock = spy(); render(); - fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchmove', selectEvent); + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchstart', selectEvent); expect(onChangeMock.callCount).to.equal(0); // hours are not disabled @@ -224,7 +224,7 @@ describe('', () => { const onChangeMock = spy(); render(); - fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchmove', selectEvent); + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchstart', selectEvent); expect(onChangeMock.callCount).to.equal(0); // hours are disabled @@ -252,7 +252,7 @@ describe('', () => { }, ], }, - '20:--': { + '19:--': { changedTouches: [ { clientX: 66, @@ -292,7 +292,7 @@ describe('', () => { />, ); - fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchmove', clockTouchEvent['13:--']); + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchstart', clockTouchEvent['13:--']); expect(handleChange.callCount).to.equal(1); const [date, selectionState] = handleChange.firstCall.args; @@ -316,7 +316,7 @@ describe('', () => { />, ); - fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchmove', clockTouchEvent['--:20']); + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchstart', clockTouchEvent['--:20']); expect(handleChange.callCount).to.equal(1); const [date, selectionState] = handleChange.firstCall.args; @@ -338,7 +338,7 @@ describe('', () => { />, ); - fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchmove', clockTouchEvent['--:20']); + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchstart', clockTouchEvent['--:20']); expect(handleChange.callCount).to.equal(0); }); @@ -356,7 +356,7 @@ describe('', () => { />, ); - fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchmove', clockTouchEvent['--:20']); + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchstart', clockTouchEvent['--:20']); expect(handleChange.callCount).to.equal(0); }); @@ -374,7 +374,7 @@ describe('', () => { />, ); - fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchmove', clockTouchEvent['20:--']); + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchstart', clockTouchEvent['19:--']); expect(handleChange.callCount).to.equal(0); }); @@ -392,7 +392,7 @@ describe('', () => { />, ); - fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchmove', clockTouchEvent['20:--']); + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchstart', clockTouchEvent['19:--']); expect(handleChange.callCount).to.equal(0); }); @@ -427,7 +427,7 @@ describe('', () => { />, ); - fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchmove', clockTouchEvent['--:10']); + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchstart', clockTouchEvent['--:10']); expect(handleChange.callCount).to.equal(1); const [date, selectionState] = handleChange.firstCall.args; @@ -449,7 +449,7 @@ describe('', () => { />, ); - fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchmove', clockTouchEvent['--:20']); + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchstart', clockTouchEvent['--:20']); expect(handleChange.callCount).to.equal(0); }); @@ -467,10 +467,54 @@ describe('', () => { />, ); - fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchmove', clockTouchEvent['--:20']); + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchstart', clockTouchEvent['--:20']); expect(handleChange.callCount).to.equal(0); }); + + it('should select enabled hour on touch and drag', () => { + const handleChange = spy(); + const handleViewChange = spy(); + render( + , + ); + + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchstart', clockTouchEvent['13:--']); + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchmove', clockTouchEvent['19:--']); + + expect(handleChange.callCount).to.equal(2); + const [date, selectionState] = handleChange.lastCall.args; + expect(date).toEqualDateTime(new Date(2018, 0, 1, 19)); + expect(selectionState).to.equal('shallow'); + expect(handleViewChange.callCount).to.equal(0); + }); + + it('should select enabled hour and move to next view on touch end', () => { + const handleChange = spy(); + const handleViewChange = spy(); + render( + , + ); + + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchstart', clockTouchEvent['13:--']); + fireTouchChangedEvent(screen.getByMuiTest('clock'), 'touchend', clockTouchEvent['13:--']); + + expect(handleChange.callCount).to.equal(2); + const [date, selectionState] = handleChange.lastCall.args; + expect(date).toEqualDateTime(new Date(2018, 0, 1, 13)); + expect(selectionState).to.equal('partial'); + expect(handleViewChange.callCount).to.equal(1); + }); }); describe('default value', () => { diff --git a/packages/x-date-pickers/src/YearCalendar/tests/describes.YearCalendar.test.tsx b/packages/x-date-pickers/src/YearCalendar/tests/describes.YearCalendar.test.tsx index 87eeb7fee9f4f..06c4de6035f45 100644 --- a/packages/x-date-pickers/src/YearCalendar/tests/describes.YearCalendar.test.tsx +++ b/packages/x-date-pickers/src/YearCalendar/tests/describes.YearCalendar.test.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { expect } from 'chai'; -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { YearCalendar, yearCalendarClasses as classes } from '@mui/x-date-pickers/YearCalendar'; import { createPickerRenderer, @@ -9,7 +9,6 @@ import { describeValue, } from 'test/utils/pickers'; import { describeConformance } from 'test/utils/describeConformance'; -import { fireUserEvent } from 'test/utils/fireUserEvent'; describe(' - Describes', () => { const { render, clock } = createPickerRenderer({ @@ -52,7 +51,7 @@ describe(' - Describes', () => { }, setNewValue: (value) => { const newValue = adapterToUse.addYears(value, 1); - fireUserEvent.mousePress( + fireEvent.click( screen.getByRole('radio', { name: adapterToUse.getYear(newValue).toString() }), ); diff --git a/packages/x-date-pickers/src/internals/utils/date-time-utils.ts b/packages/x-date-pickers/src/internals/utils/date-time-utils.ts index 47688559cf1b2..eb7c100e9468c 100644 --- a/packages/x-date-pickers/src/internals/utils/date-time-utils.ts +++ b/packages/x-date-pickers/src/internals/utils/date-time-utils.ts @@ -7,7 +7,7 @@ import { TimeView, } from '../../models'; import { resolveTimeFormat, isTimeView, isInternalTimeView } from './time-utils'; -import { resolveDateFormat } from './date-utils'; +import { isDatePickerView, resolveDateFormat } from './date-utils'; import { DateOrTimeViewWithMeridiem } from '../models'; import { DesktopOnlyTimePickerProps } from '../models/props/clock'; import { DefaultizedProps } from '../models/helpers'; @@ -18,7 +18,12 @@ export const resolveDateTimeFormat = ( views, format, ...other - }: { format?: string; views: readonly DateOrTimeViewWithMeridiem[]; ampm: boolean }, + }: { + format?: string; + views: readonly DateOrTimeViewWithMeridiem[]; + ampm: boolean; + }, + ignoreDateResolving?: boolean, ) => { if (format) { return format; @@ -30,7 +35,7 @@ export const resolveDateTimeFormat = ( views.forEach((view) => { if (isTimeView(view)) { timeViews.push(view as TimeView); - } else { + } else if (isDatePickerView(view)) { dateViews.push(view as DateView); } }); @@ -44,7 +49,9 @@ export const resolveDateTimeFormat = ( } const timeFormat = resolveTimeFormat(utils, { views: timeViews, ...other }); - const dateFormat = resolveDateFormat(utils, { views: dateViews, ...other }, false); + const dateFormat = ignoreDateResolving + ? utils.formats.keyboardDate + : resolveDateFormat(utils, { views: dateViews, ...other }, false); return `${dateFormat} ${timeFormat}`; }; diff --git a/packages/x-date-pickers/src/tests/materialVersion.test.tsx b/packages/x-date-pickers/src/tests/materialVersion.test.tsx new file mode 100644 index 0000000000000..dc0c0a7e6ee01 --- /dev/null +++ b/packages/x-date-pickers/src/tests/materialVersion.test.tsx @@ -0,0 +1,5 @@ +import materialPackageJson from '@mui/material/package.json'; +import { checkMaterialVersion } from 'test/utils/checkMaterialVersion'; +import packageJson from '../../package.json'; + +checkMaterialVersion({ packageJson, materialPackageJson }); diff --git a/packages/x-internals/package.json b/packages/x-internals/package.json index 94f4803fdbd66..1b2695fa2e380 100644 --- a/packages/x-internals/package.json +++ b/packages/x-internals/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-internals", - "version": "7.14.0", + "version": "7.15.0", "description": "Utility functions for the MUI X packages (internal use only).", "author": "MUI Team", "license": "MIT", diff --git a/packages/x-license/package.json b/packages/x-license/package.json index 8bb6e2528f4ab..dbaf9004390a0 100644 --- a/packages/x-license/package.json +++ b/packages/x-license/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-license", - "version": "7.14.0", + "version": "7.15.0", "description": "MUI X License verification", "author": "MUI Team", "main": "src/index.ts", diff --git a/packages/x-tree-view-pro/package.json b/packages/x-tree-view-pro/package.json index 5db48bc3e1930..46f651a038df6 100644 --- a/packages/x-tree-view-pro/package.json +++ b/packages/x-tree-view-pro/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-tree-view-pro", - "version": "7.14.0", + "version": "7.15.0", "description": "The Pro plan edition of the Tree View components (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -44,7 +44,6 @@ }, "dependencies": { "@babel/runtime": "^7.25.4", - "@mui/system": "^5.16.7", "@mui/utils": "^5.16.6", "@mui/x-internals": "workspace:*", "@mui/x-license": "workspace:*", @@ -57,7 +56,8 @@ "peerDependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@mui/material": "^5.15.14", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" }, @@ -71,6 +71,8 @@ }, "devDependencies": { "@mui/internal-test-utils": "^1.0.10", + "@mui/material": "^5.16.5", + "@mui/system": "^5.16.7", "@types/prop-types": "^15.7.12", "rimraf": "^5.0.10" }, diff --git a/packages/x-tree-view-pro/src/tests/materialVersion.test.tsx b/packages/x-tree-view-pro/src/tests/materialVersion.test.tsx new file mode 100644 index 0000000000000..dc0c0a7e6ee01 --- /dev/null +++ b/packages/x-tree-view-pro/src/tests/materialVersion.test.tsx @@ -0,0 +1,5 @@ +import materialPackageJson from '@mui/material/package.json'; +import { checkMaterialVersion } from 'test/utils/checkMaterialVersion'; +import packageJson from '../../package.json'; + +checkMaterialVersion({ packageJson, materialPackageJson }); diff --git a/packages/x-tree-view/package.json b/packages/x-tree-view/package.json index 520e0c8825398..067903ffcd307 100644 --- a/packages/x-tree-view/package.json +++ b/packages/x-tree-view/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-tree-view", - "version": "7.14.0", + "version": "7.15.0", "description": "The community edition of the Tree View components (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -44,7 +44,6 @@ }, "dependencies": { "@babel/runtime": "^7.25.4", - "@mui/system": "^5.16.7", "@mui/utils": "^5.16.6", "@mui/x-internals": "workspace:*", "@types/react-transition-group": "^4.4.11", @@ -55,7 +54,8 @@ "peerDependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@mui/material": "^5.15.14", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" }, @@ -69,6 +69,8 @@ }, "devDependencies": { "@mui/internal-test-utils": "^1.0.10", + "@mui/material": "^5.16.5", + "@mui/system": "^5.16.7", "@types/prop-types": "^15.7.12", "rimraf": "^5.0.10" }, diff --git a/packages/x-tree-view/src/tests/materialVersion.test.tsx b/packages/x-tree-view/src/tests/materialVersion.test.tsx new file mode 100644 index 0000000000000..dc0c0a7e6ee01 --- /dev/null +++ b/packages/x-tree-view/src/tests/materialVersion.test.tsx @@ -0,0 +1,5 @@ +import materialPackageJson from '@mui/material/package.json'; +import { checkMaterialVersion } from 'test/utils/checkMaterialVersion'; +import packageJson from '../../package.json'; + +checkMaterialVersion({ packageJson, materialPackageJson }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 91a7006a09dc0..a377b74e87df6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -96,8 +96,8 @@ importers: specifier: ^5.16.7 version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mui/monorepo': - specifier: github:mui/material-ui#55bea65c83c1beac77382fe961f8aa72eec21daa - version: https://codeload.github.com/mui/material-ui/tar.gz/55bea65c83c1beac77382fe961f8aa72eec21daa(encoding@0.1.13) + specifier: github:mui/material-ui#029eb3b1f4837591e729779da9a82f0a66187770 + version: https://codeload.github.com/mui/material-ui/tar.gz/029eb3b1f4837591e729779da9a82f0a66187770(encoding@0.1.13) '@mui/utils': specifier: ^5.16.6 version: 5.16.6(@types/react@18.3.4)(react@18.3.1) @@ -717,12 +717,6 @@ importers: '@emotion/styled': specifier: ^11.8.1 version: 11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) - '@mui/material': - specifier: ^5.15.14 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/system': - specifier: ^5.16.7 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@mui/utils': specifier: ^5.16.6 version: 5.16.6(@types/react@18.3.4)(react@18.3.1) @@ -751,6 +745,12 @@ importers: '@mui/internal-test-utils': specifier: ^1.0.10 version: 1.0.10(@babel/core@7.25.2)(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/material': + specifier: ^5.16.5 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/system': + specifier: ^5.16.7 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@react-spring/core': specifier: ^9.7.4 version: 9.7.4(react@18.3.1) @@ -779,12 +779,6 @@ importers: '@emotion/styled': specifier: ^11.8.1 version: 11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) - '@mui/material': - specifier: ^5.15.14 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/system': - specifier: ^5.16.7 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@mui/utils': specifier: ^5.16.6 version: 5.16.6(@types/react@18.3.4)(react@18.3.1) @@ -816,6 +810,12 @@ importers: specifier: ^17.0.0 || ^18.0.0 version: 18.3.1(react@18.3.1) devDependencies: + '@mui/material': + specifier: ^5.16.5 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/system': + specifier: ^5.16.7 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@react-spring/core': specifier: ^9.7.4 version: 9.7.4(react@18.3.1) @@ -961,12 +961,6 @@ importers: '@emotion/styled': specifier: ^11.8.1 version: 11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) - '@mui/material': - specifier: ^5.15.14 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/system': - specifier: ^5.16.7 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@mui/utils': specifier: ^5.16.6 version: 5.16.6(@types/react@18.3.4)(react@18.3.1) @@ -995,6 +989,12 @@ importers: '@mui/joy': specifier: ^5.0.0-beta.48 version: 5.0.0-beta.48(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/material': + specifier: ^5.16.5 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/system': + specifier: ^5.16.7 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@mui/types': specifier: ^7.2.15 version: 7.2.15(@types/react@18.3.4) @@ -1017,12 +1017,6 @@ importers: '@emotion/styled': specifier: ^11.8.1 version: 11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) - '@mui/icons-material': - specifier: ^5.4.1 - version: 5.16.7(@mui/material@5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) - '@mui/material': - specifier: ^5.15.14 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mui/x-data-grid-premium': specifier: workspace:* version: link:../x-data-grid-premium/build @@ -1039,6 +1033,12 @@ importers: specifier: ^17.0.0 || ^18.0.0 version: 18.3.1 devDependencies: + '@mui/icons-material': + specifier: ^5.16.5 + version: 5.16.7(@mui/material@5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) + '@mui/material': + specifier: ^5.16.5 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/chance': specifier: ^1.1.6 version: 1.1.6 @@ -1058,12 +1058,6 @@ importers: '@emotion/styled': specifier: ^11.8.1 version: 11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) - '@mui/material': - specifier: ^5.15.14 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/system': - specifier: ^5.16.7 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@mui/utils': specifier: ^5.16.6 version: 5.16.6(@types/react@18.3.4)(react@18.3.1) @@ -1104,6 +1098,12 @@ importers: '@mui/internal-test-utils': specifier: ^1.0.10 version: 1.0.10(@babel/core@7.25.2)(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/material': + specifier: ^5.16.5 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/system': + specifier: ^5.16.7 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@types/prop-types': specifier: ^15.7.12 version: 15.7.12 @@ -1126,12 +1126,6 @@ importers: '@emotion/styled': specifier: ^11.8.1 version: 11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) - '@mui/material': - specifier: ^5.15.14 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/system': - specifier: ^5.16.7 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@mui/utils': specifier: ^5.16.6 version: 5.16.6(@types/react@18.3.4)(react@18.3.1) @@ -1166,6 +1160,12 @@ importers: '@mui/internal-test-utils': specifier: ^1.0.10 version: 1.0.10(@babel/core@7.25.2)(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/material': + specifier: ^5.16.5 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/system': + specifier: ^5.16.7 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@types/prop-types': specifier: ^15.7.12 version: 15.7.12 @@ -1185,12 +1185,6 @@ importers: '@emotion/styled': specifier: ^11.8.1 version: 11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) - '@mui/material': - specifier: ^5.15.14 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/system': - specifier: ^5.16.7 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@mui/utils': specifier: ^5.16.6 version: 5.16.6(@types/react@18.3.4)(react@18.3.1) @@ -1216,6 +1210,12 @@ importers: '@mui/internal-test-utils': specifier: ^1.0.10 version: 1.0.10(@babel/core@7.25.2)(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/material': + specifier: ^5.16.5 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/system': + specifier: ^5.16.7 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@types/luxon': specifier: ^3.4.2 version: 3.4.2 @@ -1268,12 +1268,6 @@ importers: '@emotion/styled': specifier: ^11.8.1 version: 11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) - '@mui/material': - specifier: ^5.15.14 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/system': - specifier: ^5.16.7 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@mui/utils': specifier: ^5.16.6 version: 5.16.6(@types/react@18.3.4)(react@18.3.1) @@ -1308,6 +1302,12 @@ importers: '@mui/internal-test-utils': specifier: ^1.0.10 version: 1.0.10(@babel/core@7.25.2)(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/material': + specifier: ^5.16.5 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/system': + specifier: ^5.16.7 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@types/luxon': specifier: ^3.4.2 version: 3.4.2 @@ -1385,12 +1385,6 @@ importers: '@emotion/styled': specifier: ^11.8.1 version: 11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) - '@mui/material': - specifier: ^5.15.14 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/system': - specifier: ^5.16.7 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@mui/utils': specifier: ^5.16.6 version: 5.16.6(@types/react@18.3.4)(react@18.3.1) @@ -1419,6 +1413,12 @@ importers: '@mui/internal-test-utils': specifier: ^1.0.10 version: 1.0.10(@babel/core@7.25.2)(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/material': + specifier: ^5.16.5 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/system': + specifier: ^5.16.7 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@types/prop-types': specifier: ^15.7.12 version: 15.7.12 @@ -1438,12 +1438,6 @@ importers: '@emotion/styled': specifier: ^11.8.1 version: 11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) - '@mui/material': - specifier: ^5.15.14 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/system': - specifier: ^5.16.7 - version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@mui/utils': specifier: ^5.16.6 version: 5.16.6(@types/react@18.3.4)(react@18.3.1) @@ -1478,6 +1472,12 @@ importers: '@mui/internal-test-utils': specifier: ^1.0.10 version: 1.0.10(@babel/core@7.25.2)(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/material': + specifier: ^5.16.5 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/system': + specifier: ^5.16.7 + version: 5.16.7(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@types/prop-types': specifier: ^15.7.12 version: 15.7.12 @@ -1545,6 +1545,9 @@ importers: '@types/react': specifier: ^18.3.4 version: 18.3.4 + '@types/semver': + specifier: ^7.5.8 + version: 7.5.8 chai: specifier: ^4.5.0 version: 4.5.0 @@ -1569,6 +1572,9 @@ importers: react-router-dom: specifier: ^6.26.1 version: 6.26.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + semver: + specifier: ^7.6.3 + version: 7.6.3 stylis: specifier: ^4.3.2 version: 4.3.2 @@ -3031,8 +3037,8 @@ packages: '@jridgewell/source-map@0.3.5': resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} - '@jridgewell/sourcemap-codec@1.4.15': - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} @@ -3045,7 +3051,7 @@ packages: resolution: {integrity: sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==} engines: {node: '>=12.0.0'} peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 + '@types/react': 18.3.3 react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 peerDependenciesMeta: @@ -3168,9 +3174,9 @@ packages: '@types/react': optional: true - '@mui/monorepo@https://codeload.github.com/mui/material-ui/tar.gz/55bea65c83c1beac77382fe961f8aa72eec21daa': - resolution: {tarball: https://codeload.github.com/mui/material-ui/tar.gz/55bea65c83c1beac77382fe961f8aa72eec21daa} - version: 6.0.0-rc.0 + '@mui/monorepo@https://codeload.github.com/mui/material-ui/tar.gz/029eb3b1f4837591e729779da9a82f0a66187770': + resolution: {tarball: https://codeload.github.com/mui/material-ui/tar.gz/029eb3b1f4837591e729779da9a82f0a66187770} + version: 6.0.0 engines: {pnpm: 9.7.1} '@mui/private-theming@5.16.6': @@ -5038,8 +5044,8 @@ packages: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} - chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} chownr@2.0.0: @@ -7546,8 +7552,8 @@ packages: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true - magic-string@0.30.10: - resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + magic-string@0.30.11: + resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} make-array@1.0.5: resolution: {integrity: sha512-sgK2SAzxT19rWU+qxKUcn6PAh/swiIiz2F8C2cZjLc1z4iwYIfdoihqFIDQ8BDzAGtWPYJ6Sr13K1j/DXynDLA==} @@ -8341,8 +8347,8 @@ packages: path-to-regexp@2.2.1: resolution: {integrity: sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==} - path-to-regexp@6.2.1: - resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} + path-to-regexp@6.2.2: + resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} path-type@3.0.0: resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} @@ -10312,7 +10318,7 @@ snapshots: slash: 2.0.0 optionalDependencies: '@nicolo-ribaudo/chokidar-2': 2.1.8-no-fsevents.3 - chokidar: 3.5.3 + chokidar: 3.6.0 '@babel/code-frame@7.24.7': dependencies: @@ -11714,7 +11720,7 @@ snapshots: '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/resolve-uri@3.1.1': {} @@ -11726,12 +11732,12 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@jridgewell/sourcemap-codec@1.4.15': {} + '@jridgewell/sourcemap-codec@1.5.0': {} '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@lerna/create@8.1.8(@swc/core@1.6.13(@swc/helpers@0.5.5))(babel-plugin-macros@3.1.0)(encoding@0.1.13)(typescript@5.5.4)': dependencies: @@ -11985,7 +11991,7 @@ snapshots: '@emotion/styled': 11.13.0(@emotion/react@11.13.3(@types/react@18.3.4)(react@18.3.1))(@types/react@18.3.4)(react@18.3.1) '@types/react': 18.3.4 - '@mui/monorepo@https://codeload.github.com/mui/material-ui/tar.gz/55bea65c83c1beac77382fe961f8aa72eec21daa(encoding@0.1.13)': + '@mui/monorepo@https://codeload.github.com/mui/material-ui/tar.gz/029eb3b1f4837591e729779da9a82f0a66187770(encoding@0.1.13)': dependencies: '@googleapis/sheets': 9.3.0(encoding@0.1.13) '@netlify/functions': 2.8.1 @@ -12771,7 +12777,7 @@ snapshots: '@types/tsscmp': 1.0.2 axios: 1.7.4(debug@4.3.6) express: 4.18.2 - path-to-regexp: 6.2.1 + path-to-regexp: 6.2.2 please-upgrade-node: 3.2.0 promise.allsettled: 1.0.7 raw-body: 2.5.2 @@ -13364,7 +13370,7 @@ snapshots: '@vitest/snapshot@2.0.5': dependencies: '@vitest/pretty-format': 2.0.5 - magic-string: 0.30.10 + magic-string: 0.30.11 pathe: 1.1.2 '@vitest/spy@2.0.5': @@ -14214,7 +14220,7 @@ snapshots: check-error@2.1.1: {} - chokidar@3.5.3: + chokidar@3.6.0: dependencies: anymatch: 3.1.3 braces: 3.0.3 @@ -16936,7 +16942,7 @@ snapshots: '@colors/colors': 1.5.0 body-parser: 1.20.2 braces: 3.0.3 - chokidar: 3.5.3 + chokidar: 3.6.0 connect: 3.7.0 di: 0.0.1 dom-serialize: 2.2.1 @@ -17283,9 +17289,9 @@ snapshots: lz-string@1.5.0: {} - magic-string@0.30.10: + magic-string@0.30.11: dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 make-array@1.0.5: {} @@ -17534,7 +17540,7 @@ snapshots: dependencies: ansi-colors: 4.1.3 browser-stdout: 1.3.1 - chokidar: 3.5.3 + chokidar: 3.6.0 debug: 4.3.6(supports-color@8.1.1) diff: 5.2.0 escape-string-regexp: 4.0.0 @@ -17648,7 +17654,7 @@ snapshots: '@sinonjs/fake-timers': 11.2.2 '@sinonjs/text-encoding': 0.7.2 just-extend: 6.2.0 - path-to-regexp: 6.2.1 + path-to-regexp: 6.2.2 no-case@3.0.4: dependencies: @@ -18237,7 +18243,7 @@ snapshots: path-to-regexp@2.2.1: {} - path-to-regexp@6.2.1: {} + path-to-regexp@6.2.2: {} path-type@3.0.0: dependencies: @@ -19856,7 +19862,7 @@ snapshots: chai: 5.1.1 debug: 4.3.6(supports-color@8.1.1) execa: 8.0.1 - magic-string: 0.30.10 + magic-string: 0.30.11 pathe: 1.1.2 std-env: 3.7.0 tinybench: 2.8.0 diff --git a/renovate.json b/renovate.json index e8960ee9db0dc..4196a9df8edad 100644 --- a/renovate.json +++ b/renovate.json @@ -90,7 +90,8 @@ "@mui/system", "@mui/types", "@mui/utils" - ] + ], + "allowedVersions": "< 6.0.0" }, { "groupName": "MUI Internal", diff --git a/scripts/githubActions/issueBodyCleanup.js b/scripts/githubActions/issueBodyCleanup.js deleted file mode 100644 index 98156d6305ea0..0000000000000 --- a/scripts/githubActions/issueBodyCleanup.js +++ /dev/null @@ -1,86 +0,0 @@ -function extractInputSection(lines, title) { - const index = lines.findIndex((line) => line.startsWith('###') && line.includes(title)); - if (index === -1) { - return ''; - } - return lines.splice(index, 4)[2].trim(); -} - -/** - * @param {Object} params - * @param {import("@actions/core")} params.core - * @param {ReturnType} params.github - * @param {import("@actions/github").context} params.context - */ -module.exports = async ({ core, context, github }) => { - try { - const owner = context.repo.owner; - const repo = context.repo.repo; - const issueNumber = context.issue.number; - - const issue = await github.rest.issues.get({ - owner, - repo, - issue_number: issueNumber, - }); - - const lines = issue.data.body.split('\n'); - - // this is here to remove this section from the issue body - extractInputSection(lines, 'Latest version'); - - const searchKeywords = extractInputSection(lines, 'Search keywords'); - const products = extractInputSection(lines, 'Affected products'); - - // get the order id and set it as an output for the support label step - let orderID = extractInputSection(lines, 'Order ID or Support key'); - if (orderID === '_No response_') { - orderID = ''; - } - - core.setOutput('ORDER_ID', orderID); - - // debug log all values - core.debug(`>>> Search Keywords: ${searchKeywords}`); - core.debug(`>>> Order ID: ${orderID}`); - core.debug(`>>> Affected Products: ${products}`); - - lines.push(''); - lines.push(`**Search keywords**: ${searchKeywords}`); - if (orderID !== '') { - lines.push(`**Order ID**: ${orderID}`); - } - - const body = lines.join('\n'); - core.debug(`>>> Cleaned issue body: ${body}`); - - const labels = issue.data.labels.map((label) => label.name); - - const productMap = { - 'Data Grid': 'data grid', - 'Date and Time Pickers': 'pickers', - Charts: 'charts', - 'Tree View': 'tree view', - }; - - if (products !== '') { - products.split(',').forEach((product) => { - if (productMap[product.trim()]) { - labels.push(`component: ${productMap[product.trim()]}`); - } - }); - } - - core.debug(`>>> Labels: ${labels.join(',')}`); - - await github.rest.issues.update({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - body, - labels, - }); - } catch (error) { - core.setFailed(error.message); - } -}; diff --git a/scripts/githubActions/orderIdValidation.js b/scripts/githubActions/orderIdValidation.js deleted file mode 100644 index 1acc23cc1d00c..0000000000000 --- a/scripts/githubActions/orderIdValidation.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @param {Object} params - * @param {import("@actions/core")} params.core - * @param {ReturnType} params.github - * @param {import("@actions/github").context} params.context - */ -module.exports = async ({ core, context, github }) => { - try { - const owner = context.repo.owner; - const repo = context.repo.repo; - const issueNumber = context.issue.number; - - const orderId = process.env.ORDER_ID; - const orderApiToken = process.env.ORDER_API_TOKEN; - - const orderApi = 'https://store-wp.mui.com/wp-json/wc/v3/orders/'; - - core.debug(`>>> Order ID: ${orderId}`); - - if (!orderId) { - core.info('No Order ID'); - } else { - const order = await fetch(`${orderApi}${orderId}`, { - headers: { - Authorization: orderApiToken, - 'User-Agent': 'MUI-Tools-Private/X-Orders-Inspector v1', - }, - }); - - const orderDetails = await order.json(); - - core.debug(`>>> Order Items: ${orderDetails.line_items?.join(',')}`); - - const plan = - orderDetails.line_items?.filter((item) => /\b(pro|premium)\b/i.test(item.name))[0].name || - ''; - - if (!plan) { - core.info('No Pro or Premium plan found in order'); - return; - } - - const planName = plan.match(/\b(pro|premium)\b/i)[0].toLowerCase(); - - if (planName !== 'pro' && planName !== 'premium') { - core.debug(`>>> planName: ${planName}`); - core.info('planName could not be extracted'); - return; - } - - const labelName = `support: ${planName} standard`; - - core.debug(`>>> planName: ${planName}`); - core.debug(`>>> labelName: ${labelName}`); - - await github.rest.issues.addLabels({ - owner, - repo, - issue_number: issueNumber, - labels: [labelName], - }); - } - } catch (error) { - core.setFailed(error.message); - } -}; diff --git a/scripts/useMaterialUIv6.mjs b/scripts/useMaterialUIv6.mjs new file mode 100644 index 0000000000000..d6d0c4b4966a1 --- /dev/null +++ b/scripts/useMaterialUIv6.mjs @@ -0,0 +1,12 @@ +import childProcess from 'child_process'; + +const pnpmUpdate = childProcess.spawnSync( + 'pnpm', + ['update', '-r', '@mui/material@6.x', '@mui/system@6.x', '@mui/icons-material@6.x'], + { + shell: true, + stdio: ['inherit', 'inherit', 'inherit'], + }, +); + +process.exit(pnpmUpdate.status); diff --git a/test/README.md b/test/README.md index f2cf5858e304c..1b571acc841d9 100644 --- a/test/README.md +++ b/test/README.md @@ -2,17 +2,15 @@ ## Testing multiple versions of React -You can check integration of different versions of React (for example different [release channels](https://react.dev/community/versioning-policy) or PRs to React) by running the following commands: +You can check integration of different versions of React (for example different [release channels](https://react.dev/community/versioning-policy) or PRs to React) by running the following command: -1. `pnpm use-react-version `. +`pnpm use-react-version ` - Possible values for `version`: +Possible values for `version`: - - default: `stable` (minimum supported React version) - - a tag on npm, for example `next`, `experimental` or `latest` - - an older version, for example `^17.0.0` - -2. `pnpm install` +- default: `stable` (minimum supported React version) +- a tag on npm, for example `next`, `experimental` or `latest` +- an older version, for example `^17.0.0` ### CI @@ -44,3 +42,27 @@ curl --request POST \ --header 'Circle-Token: $CIRCLE_TOKEN' \ --data-raw '{"branch":"pull/24289/head","parameters":{"react-version":"next"}}' ``` + +## Testing multiple versions of Material UI + +Currently, we use `@mui/material` v5 in the MUI X repo and all tests are run against it. +But MUI X packages are compatible with v5 and v6. +You can run the tests against `@mui/material` v6 by running the following command: + +`pnpm use-material-ui-v6` + +### CI + +There's a `material-ui-v6` workflow in our CircleCI pipeline that you can trigger in CircleCI on the PR you want to test: + +1. Go to https://app.circleci.com/pipelines/github/mui/mui-x?branch=pull/PR_NUMBER and replace `PR_NUMBER` with the PR number you want to test. +2. Click `Trigger Pipeline` button. +3. Expand `Add parameters (optional)` and add the following parameter: + + | Parameter type | Name | Value | + | :------------- | :--------- | :--------------- | + | `string` | `workflow` | `material-ui-v6` | + +4. Click `Trigger Pipeline` button. + +![CircleCI workflow](./circleci-workflow.png) diff --git a/test/circleci-workflow.png b/test/circleci-workflow.png new file mode 100644 index 0000000000000000000000000000000000000000..de549e5eef462be7883674ae50802b25d19febc9 GIT binary patch literal 40490 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�wj=4Iw$jk=8`dK>%du4UK2k>a{ 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%0AHEz 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 YTlwqNav@vcA`1Krbuv65(0J}>0IRF3v literal 0 HcmV?d00001 diff --git a/test/karma.conf.js b/test/karma.conf.js index 3da8db12d5404..87070fd88d443 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -80,6 +80,7 @@ module.exports = function setKarmaConfig(config) { fs: false, // Some tests import fs, stream: require.resolve('stream-browserify'), // util > inherits breaks with `false` path: false, + child_process: false, }, }, }, diff --git a/test/package.json b/test/package.json index 411ccad2a47b0..aaa299ac3ed09 100644 --- a/test/package.json +++ b/test/package.json @@ -10,13 +10,13 @@ "@emotion/cache": "^11.13.1", "@emotion/react": "^11.13.3", "@mui/material": "^5.16.7", + "@mui/x-charts": "workspace:*", + "@mui/x-charts-pro": "workspace:*", + "@mui/x-charts-vendor": "workspace:*", "@mui/x-data-grid": "workspace:*", "@mui/x-data-grid-pro": "workspace:*", "@mui/x-date-pickers": "workspace:*", "@mui/x-date-pickers-pro": "workspace:*", - "@mui/x-charts": "workspace:*", - "@mui/x-charts-pro": "workspace:*", - "@mui/x-charts-vendor": "workspace:*", "@mui/x-license": "workspace:*", "@playwright/test": "^1.44.1", "@react-spring/web": "^9.7.4", @@ -25,6 +25,7 @@ "@types/moment-jalaali": "^0.7.9", "@types/prop-types": "^15.7.12", "@types/react": "^18.3.4", + "@types/semver": "^7.5.8", "chai": "^4.5.0", "dayjs": "^1.11.11", "moment": "^2.30.1", @@ -33,6 +34,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.26.1", + "semver": "^7.6.3", "stylis": "^4.3.2", "stylis-plugin-rtl": "^2.1.1" } diff --git a/test/regressions/index.test.js b/test/regressions/index.test.js index cb4971f830104..cc3f44deeb07d 100644 --- a/test/regressions/index.test.js +++ b/test/regressions/index.test.js @@ -3,6 +3,7 @@ import { expect } from 'chai'; import * as path from 'path'; import * as childProcess from 'child_process'; import { chromium } from '@playwright/test'; +import materialPackageJson from '@mui/material/package.json'; function sleep(timeoutMS) { return new Promise((resolve) => { @@ -10,6 +11,21 @@ function sleep(timeoutMS) { }); } +const isMaterialUIv6 = materialPackageJson.version.startsWith('6.'); + +const isConsoleWarningIgnored = (msg) => { + if ( + msg && + isMaterialUIv6 && + msg.startsWith( + 'MUI: The Experimental_CssVarsProvider component has been ported into ThemeProvider.', + ) + ) { + return true; + } + return false; +}; + async function main() { const baseUrl = 'http://localhost:5001'; const screenshotDir = path.resolve(__dirname, './screenshots/chrome'); @@ -85,6 +101,9 @@ async function main() { it('should have no errors after the initial render', () => { const msg = errorConsole; errorConsole = undefined; + if (isConsoleWarningIgnored(msg)) { + return; + } expect(msg).to.equal(undefined); }); @@ -147,6 +166,9 @@ async function main() { it(`should have no errors rendering ${pathURL}`, () => { const msg = errorConsole; errorConsole = undefined; + if (isConsoleWarningIgnored(msg)) { + return; + } expect(msg).to.equal(undefined); }); }); diff --git a/test/utils/checkMaterialVersion.ts b/test/utils/checkMaterialVersion.ts new file mode 100644 index 0000000000000..9ebaa81b7d6c7 --- /dev/null +++ b/test/utils/checkMaterialVersion.ts @@ -0,0 +1,43 @@ +import { expect } from 'chai'; +import semver from 'semver'; +import childProcess from 'child_process'; + +type PackageJson = { + name: string; + version: string; +}; + +const isJSDOM = /jsdom/.test(window.navigator.userAgent); + +export function checkMaterialVersion({ + packageJson, + materialPackageJson, +}: { + packageJson: PackageJson & { devDependencies: { '@mui/material': string } }; + materialPackageJson: PackageJson; +}) { + if (!isJSDOM) { + return undefined; + } + + const expectedVersion = packageJson.devDependencies['@mui/material']; + + const versions = childProcess.execSync(`npm dist-tag ls ${'@mui/material'} ${expectedVersion}`, { + encoding: 'utf8', + }); + const tagMapping = versions + .split('\n') + .find((mapping) => { + return mapping.startsWith(`${expectedVersion}: `); + }) + ?.split(': ')[1]; + + const version = tagMapping ?? expectedVersion; + + return it(`${packageJson.name} should resolve proper @mui/material version`, () => { + expect(semver.satisfies(materialPackageJson.version, version)).to.equal( + true, + `Expected @mui/material ${version}, but found ${materialPackageJson.version}`, + ); + }); +} diff --git a/test/utils/pickers/describeValue/testPickerActionBar.tsx b/test/utils/pickers/describeValue/testPickerActionBar.tsx index 850189c47294a..1491dc6b8856f 100644 --- a/test/utils/pickers/describeValue/testPickerActionBar.tsx +++ b/test/utils/pickers/describeValue/testPickerActionBar.tsx @@ -1,14 +1,13 @@ import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { adapterToUse, getExpectedOnChangeCount, expectPickerChangeHandlerValue, } from 'test/utils/pickers'; import { DescribeValueTestSuite } from './describeValue.types'; -import { fireUserEvent } from '../../fireUserEvent'; export const testPickerActionBar: DescribeValueTestSuite = ( ElementToTest, @@ -50,7 +49,7 @@ export const testPickerActionBar: DescribeValueTestSuite = ( ); // Clear the date - fireUserEvent.mousePress(screen.getByText(/clear/i)); + fireEvent.click(screen.getByText(/clear/i)); expect(onChange.callCount).to.equal(1); expectPickerChangeHandlerValue(pickerParams.type, onChange, emptyValue); expect(onAccept.callCount).to.equal(1); @@ -76,7 +75,7 @@ export const testPickerActionBar: DescribeValueTestSuite = ( ); // Clear the date - fireUserEvent.mousePress(screen.getByText(/clear/i)); + fireEvent.click(screen.getByText(/clear/i)); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(1); @@ -104,7 +103,7 @@ export const testPickerActionBar: DescribeValueTestSuite = ( setNewValue(values[0], { isOpened: true, selectSection, pressKey }); // Cancel the modifications - fireUserEvent.mousePress(screen.getByText(/cancel/i)); + fireEvent.click(screen.getByText(/cancel/i)); expect(onChange.callCount).to.equal( getExpectedOnChangeCount(componentFamily, pickerParams) + 1, ); @@ -138,7 +137,7 @@ export const testPickerActionBar: DescribeValueTestSuite = ( ); // Cancel the modifications - fireUserEvent.mousePress(screen.getByText(/cancel/i)); + fireEvent.click(screen.getByText(/cancel/i)); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(1); @@ -166,7 +165,7 @@ export const testPickerActionBar: DescribeValueTestSuite = ( setNewValue(values[0], { isOpened: true, selectSection, pressKey }); // Accept the modifications - fireUserEvent.mousePress(screen.getByText(/ok/i)); + fireEvent.click(screen.getByText(/ok/i)); expect(onChange.callCount).to.equal( getExpectedOnChangeCount(componentFamily, pickerParams), ); // The accepted value as already been committed, don't call onChange again @@ -193,7 +192,7 @@ export const testPickerActionBar: DescribeValueTestSuite = ( ); // Accept the modifications - fireUserEvent.mousePress(screen.getByText(/ok/i)); + fireEvent.click(screen.getByText(/ok/i)); expect(onChange.callCount).to.equal(1); expect(onAccept.callCount).to.equal(1); expect(onClose.callCount).to.equal(1); @@ -218,7 +217,7 @@ export const testPickerActionBar: DescribeValueTestSuite = ( ); // Accept the modifications - fireUserEvent.mousePress(screen.getByText(/ok/i)); + fireEvent.click(screen.getByText(/ok/i)); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(1); @@ -243,7 +242,7 @@ export const testPickerActionBar: DescribeValueTestSuite = ( />, ); - fireUserEvent.mousePress(screen.getByText(/today/i)); + fireEvent.click(screen.getByText(/today/i)); let startOfToday: any; if (pickerParams.type === 'date') { diff --git a/test/utils/pickers/describeValue/testPickerOpenCloseLifeCycle.tsx b/test/utils/pickers/describeValue/testPickerOpenCloseLifeCycle.tsx index d2e1d14944392..57aa07b9e9c6f 100644 --- a/test/utils/pickers/describeValue/testPickerOpenCloseLifeCycle.tsx +++ b/test/utils/pickers/describeValue/testPickerOpenCloseLifeCycle.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { getExpectedOnChangeCount, getFieldInputRoot, openPicker } from 'test/utils/pickers'; import { DescribeValueTestSuite } from './describeValue.types'; import { fireUserEvent } from '../../fireUserEvent'; @@ -10,7 +10,7 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite ElementToTest, options, ) => { - const { componentFamily, render, renderWithProps, values, setNewValue, ...pickerParams } = + const { componentFamily, render, renderWithProps, values, setNewValue, clock, ...pickerParams } = options; if (componentFamily !== 'picker') { @@ -82,7 +82,7 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite expect(onChange.lastCall.args[0][index]).toEqualDateTime(value); }); } else { - expect(onChange.lastCall.args[0]).toEqualDateTime(newValue as any); + expect(onChange.lastCall.args[0]).toEqualDateTime(newValue); } expect(onAccept.callCount).to.equal(pickerParams.variant === 'mobile' ? 0 : 1); expect(onClose.callCount).to.equal(pickerParams.variant === 'mobile' ? 0 : 1); @@ -140,7 +140,7 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite expect(onChange.lastCall.args[0][index]).toEqualDateTime(value); }); } else { - expect(onChange.lastCall.args[0]).toEqualDateTime(newValue as any); + expect(onChange.lastCall.args[0]).toEqualDateTime(newValue); } expect(onAccept.callCount).to.equal(1); expect(onClose.callCount).to.equal(1); @@ -216,7 +216,7 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite expect(onChange.lastCall.args[0][index]).toEqualDateTime(value); }); } else { - expect(onChange.lastCall.args[0]).toEqualDateTime(newValue as any); + expect(onChange.lastCall.args[0]).toEqualDateTime(newValue); } expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); @@ -245,7 +245,7 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite // meridiem does not change this time in case of multi section digital clock (pickerParams.type === 'time' || pickerParams.type === 'date-time' ? 1 : 0), ); - expect(onChange.lastCall.args[0]).toEqualDateTime(newValueBis as any); + expect(onChange.lastCall.args[0]).toEqualDateTime(newValueBis); } expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); @@ -273,7 +273,7 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite const newValue = setNewValue(values[0], { isOpened: true, selectSection, pressKey }); // Dismiss the picker - fireUserEvent.keyPress(document.activeElement!, { key: 'Escape' }); + fireEvent.keyDown(document.activeElement!, { key: 'Escape' }); expect(onChange.callCount).to.equal(getExpectedOnChangeCount(componentFamily, pickerParams)); expect(onAccept.callCount).to.equal(1); if (isRangeType) { @@ -281,7 +281,7 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite expect(onChange.lastCall.args[0][index]).toEqualDateTime(value); }); } else { - expect(onChange.lastCall.args[0]).toEqualDateTime(newValue as any); + expect(onChange.lastCall.args[0]).toEqualDateTime(newValue); } expect(onClose.callCount).to.equal(1); }); @@ -342,10 +342,10 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite const newValue = setNewValue(values[0], { isOpened: true, selectSection, pressKey }); // Dismiss the picker - fireUserEvent.mousePress(document.body); + fireUserEvent.keyPress(document.activeElement!, { key: 'Escape' }); expect(onChange.callCount).to.equal(getExpectedOnChangeCount(componentFamily, pickerParams)); expect(onAccept.callCount).to.equal(1); - expect(onAccept.lastCall.args[0]).toEqualDateTime(newValue as any); + expect(onAccept.lastCall.args[0]).toEqualDateTime(newValue); expect(onClose.callCount).to.equal(1); }); @@ -365,7 +365,7 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite ); // Dismiss the picker - fireUserEvent.mousePress(document.body); + fireEvent.click(document.body); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); @@ -386,7 +386,7 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite ); // Dismiss the picker - fireUserEvent.keyPress(document.body, { key: 'Escape' }); + fireEvent.keyDown(document.body, { key: 'Escape' }); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); diff --git a/test/utils/pickers/describeValue/testShortcuts.tsx b/test/utils/pickers/describeValue/testShortcuts.tsx index 4e4493b442c27..ae14f1ddc8018 100644 --- a/test/utils/pickers/describeValue/testShortcuts.tsx +++ b/test/utils/pickers/describeValue/testShortcuts.tsx @@ -2,9 +2,8 @@ import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; import { expectPickerChangeHandlerValue } from 'test/utils/pickers'; -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { DescribeValueTestSuite } from './describeValue.types'; -import { fireUserEvent } from '../../fireUserEvent'; export const testShortcuts: DescribeValueTestSuite = (ElementToTest, options) => { const { @@ -50,7 +49,7 @@ export const testShortcuts: DescribeValueTestSuite = (ElementToTe ); const shortcut = screen.getByRole('button', { name: 'Test shortcut' }); - fireUserEvent.mousePress(shortcut); + fireEvent.click(shortcut); expect(onChange.callCount).to.equal(1); expectPickerChangeHandlerValue(pickerParams.type, onChange, values[1]); @@ -88,7 +87,7 @@ export const testShortcuts: DescribeValueTestSuite = (ElementToTe ); const shortcut = screen.getByRole('button', { name: 'Test shortcut' }); - fireUserEvent.mousePress(shortcut); + fireEvent.click(shortcut); expect(onChange.callCount).to.equal(1); expectPickerChangeHandlerValue(pickerParams.type, onChange, values[1]); @@ -126,7 +125,7 @@ export const testShortcuts: DescribeValueTestSuite = (ElementToTe ); const shortcut = screen.getByRole('button', { name: 'Test shortcut' }); - fireUserEvent.mousePress(shortcut); + fireEvent.click(shortcut); expect(onChange.callCount).to.equal(1); expectPickerChangeHandlerValue(pickerParams.type, onChange, values[1]); diff --git a/test/utils/pickers/misc.ts b/test/utils/pickers/misc.ts index 9e189dc2c8dc8..f5fcf9c40ee7d 100644 --- a/test/utils/pickers/misc.ts +++ b/test/utils/pickers/misc.ts @@ -7,7 +7,9 @@ export const stubMatchMedia = (matches = true) => sinon.stub().returns({ matches, addListener: () => {}, + addEventListener: () => {}, removeListener: () => {}, + removeEventListener: () => {}, }); const getChangeCountForComponentFamily = (componentFamily: PickerComponentFamily) => { diff --git a/test/utils/pickers/openPicker.ts b/test/utils/pickers/openPicker.ts index 67293e7a3cce9..229510842e610 100644 --- a/test/utils/pickers/openPicker.ts +++ b/test/utils/pickers/openPicker.ts @@ -1,12 +1,12 @@ -import { screen } from '@mui/internal-test-utils'; +import { fireEvent, screen } from '@mui/internal-test-utils'; import { getFieldSectionsContainer } from 'test/utils/pickers/fields'; import { pickersInputBaseClasses } from '@mui/x-date-pickers/PickersTextField'; -import { fireUserEvent } from '../fireUserEvent'; export type OpenPickerParams = | { type: 'date' | 'date-time' | 'time'; variant: 'mobile' | 'desktop'; + click?: (element: Element) => Promise; } | { type: 'date-range' | 'date-time-range'; @@ -16,30 +16,34 @@ export type OpenPickerParams = * @default false */ isSingleInput?: boolean; + click?: (element: Element) => Promise; }; -export const openPicker = (params: OpenPickerParams) => { +export const openPicker = async (params: OpenPickerParams) => { const isRangeType = params.type === 'date-range' || params.type === 'date-time-range'; const fieldSectionsContainer = getFieldSectionsContainer( isRangeType && !params.isSingleInput && params.initialFocus === 'end' ? 1 : 0, ); + const { click = fireEvent.click } = params; if (isRangeType) { - fireUserEvent.mousePress(fieldSectionsContainer); + await click(fieldSectionsContainer); if (params.isSingleInput && params.initialFocus === 'end') { const sections = fieldSectionsContainer.querySelectorAll( `.${pickersInputBaseClasses.sectionsContainer}`, ); - fireUserEvent.mousePress(sections[sections.length - 1]); + await click(sections[sections.length - 1]); } - return undefined; + return true; } if (params.variant === 'mobile') { - return fireUserEvent.mousePress(fieldSectionsContainer); + await click(fieldSectionsContainer); + + return true; } const target = @@ -47,5 +51,6 @@ export const openPicker = (params: OpenPickerParams) => { ? screen.getByLabelText(/choose time/i) : screen.getByLabelText(/choose date/i); - return fireUserEvent.mousePress(target); + await click(target); + return true; }; diff --git a/test/utils/pickers/viewHandlers.ts b/test/utils/pickers/viewHandlers.ts index 2b3ab36c387f6..845261f64156b 100644 --- a/test/utils/pickers/viewHandlers.ts +++ b/test/utils/pickers/viewHandlers.ts @@ -1,8 +1,7 @@ -import { fireTouchChangedEvent, screen } from '@mui/internal-test-utils'; +import { fireEvent, fireTouchChangedEvent, screen } from '@mui/internal-test-utils'; import { getClockTouchEvent, formatFullTimeValue } from 'test/utils/pickers'; import { MuiPickersAdapter, TimeView } from '@mui/x-date-pickers/models'; import { formatMeridiem } from '@mui/x-date-pickers/internals'; -import { fireUserEvent } from '../fireUserEvent'; type TDate = any; @@ -36,9 +35,7 @@ export const timeClockHandler: ViewHandler = { export const digitalClockHandler: ViewHandler = { setViewValue: (adapter, value) => { - fireUserEvent.mousePress( - screen.getByRole('option', { name: formatFullTimeValue(adapter, value) }), - ); + fireEvent.click(screen.getByRole('option', { name: formatFullTimeValue(adapter, value) })); }, }; @@ -47,10 +44,10 @@ export const multiSectionDigitalClockHandler: ViewHandler = { const hasMeridiem = adapter.is12HourCycleInCurrentLocale(); const hoursLabel = parseInt(adapter.format(value, hasMeridiem ? 'hours12h' : 'hours24h'), 10); const minutesLabel = adapter.getMinutes(value).toString(); - fireUserEvent.mousePress(screen.getByRole('option', { name: `${hoursLabel} hours` })); - fireUserEvent.mousePress(screen.getByRole('option', { name: `${minutesLabel} minutes` })); + fireEvent.click(screen.getByRole('option', { name: `${hoursLabel} hours` })); + fireEvent.click(screen.getByRole('option', { name: `${minutesLabel} minutes` })); if (hasMeridiem) { - fireUserEvent.mousePress( + fireEvent.click( screen.getByRole('option', { name: formatMeridiem(adapter, adapter.getHours(value) >= 12 ? 'pm' : 'am'), }), From ef76263f385037a6ee64a0ccb9ba56f9c22c119b Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 29 Aug 2024 17:00:59 +0200 Subject: [PATCH 13/25] Allow onItemClick on the base of the legend --- docs/data/charts/legend/LegendClickNoSnap.js | 14 ++------------ .../x-charts/src/ChartsLegend/ChartsLegend.tsx | 7 +++++-- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/docs/data/charts/legend/LegendClickNoSnap.js b/docs/data/charts/legend/LegendClickNoSnap.js index d7e89a4dd1cc7..6c022e0982c5f 100644 --- a/docs/data/charts/legend/LegendClickNoSnap.js +++ b/docs/data/charts/legend/LegendClickNoSnap.js @@ -70,12 +70,7 @@ export default function LegendClickNoSnap() { horizontal: 'left', vertical: 'top', }} - slotProps={{ - legend: { - onItemClick: (event, context, index) => - setItemData([context, index]), - }, - }} + onItemClick={(event, context, index) => setItemData([context, index])} /> Pie Chart Legend @@ -86,12 +81,7 @@ export default function LegendClickNoSnap() { horizontal: 'left', vertical: 'top', }} - slotProps={{ - legend: { - onItemClick: (event, context, index) => - setItemData([context, index]), - }, - }} + onItemClick={(event, context, index) => setItemData([context, index])} /> Pie Chart Legend diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx index f9b1cd8994664..8cea2c869d365 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx @@ -23,7 +23,9 @@ export interface ChartsLegendSlotProps { legend?: Partial; } -export interface ChartsLegendProps extends LegendPlacement { +export interface ChartsLegendProps + extends LegendPlacement, + Pick { /** * Override or extend the styles applied to the component. */ @@ -71,7 +73,7 @@ function ChartsLegend(inProps: ChartsLegendProps) { ...props, position: { horizontal: 'middle', vertical: 'top', ...props.position }, }; - const { position, direction, hidden, slots, slotProps } = defaultizedProps; + const { position, direction, hidden, slots, slotProps, onItemClick } = defaultizedProps; const theme = useTheme(); const classes = useUtilityClasses({ ...defaultizedProps, theme }); @@ -93,6 +95,7 @@ function ChartsLegend(inProps: ChartsLegendProps) { series, hidden, seriesToDisplay, + onItemClick, }, ownerState: {}, }); From 07d4be005d721c411ce632b7d7f786f907d155fb Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 29 Aug 2024 20:26:34 +0200 Subject: [PATCH 14/25] Align typings and expose styling props --- packages/x-charts/src/BarChart/legend.ts | 1 - .../src/ChartsLegend/ChartsLegend.tsx | 32 ++++------ .../src/ChartsLegend/ChartsLegendItem.tsx | 58 +------------------ .../src/ChartsLegend/DefaultChartsLegend.tsx | 21 ++++++- .../src/ChartsLegend/LegendPerItem.tsx | 27 +++++---- .../src/ChartsLegend/PiecewiseColorLegend.tsx | 22 +++++-- .../src/ChartsLegend/chartsLegend.types.ts | 5 +- packages/x-charts/src/LineChart/legend.ts | 1 - packages/x-charts/src/PieChart/legend.ts | 1 - packages/x-charts/src/ScatterChart/legend.ts | 1 - 10 files changed, 69 insertions(+), 100 deletions(-) diff --git a/packages/x-charts/src/BarChart/legend.ts b/packages/x-charts/src/BarChart/legend.ts index 29383d73f43d8..6f1ba3d8c86bd 100644 --- a/packages/x-charts/src/BarChart/legend.ts +++ b/packages/x-charts/src/BarChart/legend.ts @@ -12,7 +12,6 @@ const legendGetter: LegendGetter<'bar'> = (params) => { } acc.push({ - type: 'series', id: seriesId, seriesId, color: series[seriesId].color, diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx index 8cea2c869d365..0676ceb160c35 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx @@ -4,37 +4,32 @@ import useSlotProps from '@mui/utils/useSlotProps'; import composeClasses from '@mui/utils/composeClasses'; import { useThemeProps, useTheme, Theme } from '@mui/material/styles'; import { getSeriesToDisplay } from './utils'; -import { ChartsLegendClasses, getLegendUtilityClass } from './chartsLegendClasses'; +import { getLegendUtilityClass } from './chartsLegendClasses'; import { DefaultizedProps } from '../models/helpers'; import { DefaultChartsLegend, LegendRendererProps } from './DefaultChartsLegend'; import { useDrawingArea } from '../hooks'; import { useSeries } from '../hooks/useSeries'; import { LegendPlacement } from './legend.types'; +export type ChartsLegendPropsBase = Omit< + LegendRendererProps, + keyof LegendPlacement | 'contextBuilder' | 'series' | 'seriesToDisplay' +> & + LegendPlacement; + export interface ChartsLegendSlots { /** * Custom rendering of the legend. * @default DefaultChartsLegend */ - legend?: React.JSXElementConstructor; + legend?: React.JSXElementConstructor; } export interface ChartsLegendSlotProps { - legend?: Partial; + legend?: Partial; } -export interface ChartsLegendProps - extends LegendPlacement, - Pick { - /** - * Override or extend the styles applied to the component. - */ - classes?: Partial; - /** - * Set to true to hide the legend. - * @default false - */ - hidden?: boolean; +export interface ChartsLegendProps extends ChartsLegendPropsBase { /** * Overridable component slots. * @default {} @@ -73,7 +68,7 @@ function ChartsLegend(inProps: ChartsLegendProps) { ...props, position: { horizontal: 'middle', vertical: 'top', ...props.position }, }; - const { position, direction, hidden, slots, slotProps, onItemClick } = defaultizedProps; + const { slots, slotProps, ...other } = defaultizedProps; const theme = useTheme(); const classes = useUtilityClasses({ ...defaultizedProps, theme }); @@ -88,14 +83,11 @@ function ChartsLegend(inProps: ChartsLegendProps) { elementType: ChartLegendRender, externalSlotProps: slotProps?.legend, additionalProps: { - position, - direction, + ...other, classes, drawingArea, series, - hidden, seriesToDisplay, - onItemClick, }, ownerState: {}, }); diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx index 3a6fb7a7ed3f5..85a13d0673eae 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx @@ -2,12 +2,10 @@ import * as React from 'react'; import clsx from 'clsx'; import { useRtl } from '@mui/system/RtlProvider'; import { ChartsText, ChartsTextStyle } from '../ChartsText'; -import { SeriesId } from '../models/seriesType/common'; -import { LegendItemConfig, LegendItemContext } from './chartsLegend.types'; +import { LegendItemConfig } from './chartsLegend.types'; import { ChartsLegendClasses } from './chartsLegendClasses'; export interface ChartsLegendItemProps extends LegendItemConfig { - index: number; positionY: number; label: string; positionX: number; @@ -22,38 +20,9 @@ export interface ChartsLegendItemProps extends LegendItemConfig { markGap: number; labelStyle: ChartsTextStyle; classes?: Omit, 'column' | 'row' | 'label'>; - onClick?: ( - event: React.MouseEvent, - legendItem: LegendItemContext, - index: number, - ) => void; + onClick?: (event: React.MouseEvent) => void; } -const createClickContext = ( - type: LegendItemContext['type'], - { - seriesId, - itemId, - minValue, - maxValue, - color, - label, - }: { - seriesId?: SeriesId; - itemId: string | number; - minValue?: number | Date | null; - maxValue?: number | Date | null; - color: string; - label: string; - }, -) => { - if (type === 'piecewiseColor') { - return { type, color, label, minValue: minValue ?? null, maxValue: maxValue ?? null }; - } - - return { type, seriesId: seriesId!, itemId, color, label }; -}; - /** * @ignore - internal component. */ @@ -75,11 +44,6 @@ function ChartsLegendItem(props: ChartsLegendItemProps) { markGap, labelStyle, classes, - index, - seriesId, - type, - minValue, - maxValue, onClick, } = props; @@ -95,23 +59,7 @@ function ChartsLegendItem(props: ChartsLegendItemProps) { height={innerHeight + 4} fill="transparent" className={classes?.itemBackground} - onClick={ - onClick - ? (e) => - onClick( - e, - createClickContext(type, { - seriesId, - itemId: id, - minValue, - maxValue, - color, - label, - }), - index, - ) - : undefined - } + onClick={onClick} style={{ pointerEvents: onClick ? 'all' : 'none', cursor: onClick ? 'pointer' : 'unset', diff --git a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx index 4a157c3abf747..84cf4d8f4be94 100644 --- a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx @@ -3,10 +3,19 @@ import PropTypes from 'prop-types'; import { FormattedSeries } from '../context/SeriesProvider'; import { LegendPerItem, LegendPerItemProps } from './LegendPerItem'; import { DrawingArea } from '../context/DrawingProvider'; -import { SeriesLegendItemContext } from './chartsLegend.types'; +import { LegendItemConfig, SeriesLegendItemContext } from './chartsLegend.types'; + +const seriesContextBuilder = (context: LegendItemConfig): SeriesLegendItemContext => + ({ + type: 'series', + color: context.color, + label: context.label, + seriesId: context.seriesId!, + itemId: context.id, + }) as const; export interface LegendRendererProps - extends Omit { + extends Omit { series: FormattedSeries; seriesToDisplay: LegendPerItemProps['itemsToDisplay']; /** @@ -30,7 +39,13 @@ export interface LegendRendererProps function DefaultChartsLegend(props: LegendRendererProps) { const { drawingArea, seriesToDisplay, ...other } = props; - return ; + return ( + + ); } DefaultChartsLegend.propTypes = { diff --git a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx index 00912f74e79dd..1122da33637e0 100644 --- a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx +++ b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx @@ -2,17 +2,16 @@ import * as React from 'react'; import NoSsr from '@mui/material/NoSsr'; import { useTheme, styled } from '@mui/material/styles'; import { DrawingArea } from '../context/DrawingProvider'; -import { DefaultizedProps } from '../models/helpers'; import { ChartsTextStyle } from '../ChartsText'; import { CardinalDirections } from '../models/layout'; import { getWordsByLines } from '../internals/getWordsByLines'; -import type { ChartsLegendProps } from './ChartsLegend'; -import { GetItemSpaceType, LegendItemConfig } from './chartsLegend.types'; +import { GetItemSpaceType, LegendItemConfig, LegendItemContext } from './chartsLegend.types'; import { legendItemPlacements } from './legendItemsPlacement'; import { useDrawingArea } from '../hooks/useDrawingArea'; -import { AnchorPosition, Direction } from './legend.types'; +import { AnchorPosition, Direction, LegendPlacement } from './legend.types'; import { ChartsLegendItem } from './ChartsLegendItem'; import { ChartsLegendClasses } from './chartsLegendClasses'; +import { DefaultizedProps } from '../models/helpers'; export type ChartsLegendRootOwnerState = { position: AnchorPosition; @@ -30,15 +29,15 @@ export const ChartsLegendRoot = styled('g', { })({}); export interface LegendPerItemProps - extends DefaultizedProps< - Omit, - 'direction' | 'position' - > { + extends DefaultizedProps { /** * The ordered array of item to display in the legend. */ itemsToDisplay: LegendItemConfig[]; - classes?: Omit, 'column' | 'row'>; + /** + * Override or extend the styles applied to the component. + */ + classes?: Partial; /** * Style applied to legend labels. * @default theme.typography.subtitle1 @@ -70,6 +69,12 @@ export interface LegendPerItemProps * @default 10 */ padding?: number | Partial>; + /** + * Set to true to hide the legend. + * @default false + */ + hidden?: boolean; + contextBuilder: (context: LegendItemConfig) => LegendItemContext; onItemClick?: ( event: React.MouseEvent, legendItem: any, @@ -117,6 +122,7 @@ export function LegendPerItem(props: LegendPerItemProps) { padding: paddingProps = 10, labelStyle: inLabelStyle, onItemClick, + contextBuilder, } = props; const theme = useTheme(); const drawingArea = useDrawingArea(); @@ -207,7 +213,6 @@ export function LegendPerItem(props: LegendPerItemProps) { onItemClick?.(e, contextBuilder(item), i)} /> ))} diff --git a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx index 01f844ceca411..95b06f608c8fe 100644 --- a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx @@ -5,7 +5,7 @@ import { useAxis } from './useAxis'; import { ColorLegendSelector, PiecewiseLabelFormatterParams } from './legend.types'; import { LegendPerItem, LegendPerItemProps } from './LegendPerItem'; import { notNull } from '../internals/notNull'; -import { PiecewiseColorLegendItemContext } from './chartsLegend.types'; +import { LegendItemConfig, PiecewiseColorLegendItemContext } from './chartsLegend.types'; function defaultLabelFormatter(params: PiecewiseLabelFormatterParams) { if (params.min === null) { @@ -19,7 +19,7 @@ function defaultLabelFormatter(params: PiecewiseLabelFormatterParams) { export interface PiecewiseColorLegendProps extends ColorLegendSelector, - Omit { + Omit { /** * Hide the first item of the legend, corresponding to the [-infinity, min] piece. * @default false @@ -50,6 +50,15 @@ export interface PiecewiseColorLegendProps ) => void; } +const piecewiseColorContextBuilder = (context: LegendItemConfig): PiecewiseColorLegendItemContext => + ({ + type: 'piecewiseColor', + color: context.color, + label: context.label, + maxValue: context.maxValue!, + minValue: context.minValue!, + }) as const; + function PiecewiseColorLegend(props: PiecewiseColorLegendProps) { const { axisDirection, @@ -101,12 +110,17 @@ function PiecewiseColorLegend(props: PiecewiseColorLegendProps) { label, minValue: data.min, maxValue: data.max, - type: 'piecewiseColor' as const, }; }) .filter(notNull); - return ; + return ( + + ); } PiecewiseColorLegend.propTypes = { diff --git a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts index c36e04e28ccf6..ed5ad0391ae55 100644 --- a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts +++ b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts @@ -14,15 +14,14 @@ interface LegendItemContextBase { } export interface LegendItemConfig - extends Partial>, - Partial>, + extends Partial>, + Partial>, LegendItemContextBase { /** * The identifier of the legend element. * Used for internal purpose such as `key` props */ id: number | string; - type: 'series' | 'piecewiseColor'; } export interface SeriesLegendItemContext extends LegendItemContextBase { diff --git a/packages/x-charts/src/LineChart/legend.ts b/packages/x-charts/src/LineChart/legend.ts index afb9d54a259cc..d32d368540ea8 100644 --- a/packages/x-charts/src/LineChart/legend.ts +++ b/packages/x-charts/src/LineChart/legend.ts @@ -12,7 +12,6 @@ const legendGetter: LegendGetter<'line'> = (params) => { } acc.push({ - type: 'series', id: seriesId, seriesId, color: series[seriesId].color, diff --git a/packages/x-charts/src/PieChart/legend.ts b/packages/x-charts/src/PieChart/legend.ts index 744a05f5bb95c..f01bf4e728241 100644 --- a/packages/x-charts/src/PieChart/legend.ts +++ b/packages/x-charts/src/PieChart/legend.ts @@ -13,7 +13,6 @@ const legendGetter: LegendGetter<'pie'> = (params) => { } acc.push({ - type: 'series', id: item.id, seriesId, color: item.color, diff --git a/packages/x-charts/src/ScatterChart/legend.ts b/packages/x-charts/src/ScatterChart/legend.ts index 881901f3eda5d..a466d2c8dd8cb 100644 --- a/packages/x-charts/src/ScatterChart/legend.ts +++ b/packages/x-charts/src/ScatterChart/legend.ts @@ -12,7 +12,6 @@ const legendGetter: LegendGetter<'scatter'> = (params) => { } acc.push({ - type: 'series', id: seriesId, seriesId, color: series[seriesId].color, From c15951591c2cb305a6a45be337a804c16d8a17c5 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 29 Aug 2024 20:29:56 +0200 Subject: [PATCH 15/25] run scripts --- docs/pages/x/api/charts/charts-legend.json | 20 ++++++++ .../x/api/charts/default-charts-legend.json | 12 +++++ docs/pages/x/api/charts/pie-chart.json | 2 +- .../x/api/charts/piecewise-color-legend.json | 12 +++++ .../charts/charts-legend/charts-legend.json | 16 ++++++ .../default-charts-legend.json | 8 +++ .../piecewise-color-legend.json | 8 +++ .../src/ScatterChartPro/ScatterChartPro.tsx | 15 ++++++ packages/x-charts/src/BarChart/BarChart.tsx | 15 ++++++ .../src/ChartsLegend/ChartsLegend.tsx | 49 ++++++++++++++++++- .../src/ChartsLegend/DefaultChartsLegend.tsx | 1 - packages/x-charts/src/LineChart/LineChart.tsx | 15 ++++++ packages/x-charts/src/PieChart/PieChart.tsx | 15 ++++++ .../src/ScatterChart/ScatterChart.tsx | 15 ++++++ scripts/x-charts-pro.exports.json | 1 + scripts/x-charts.exports.json | 1 + 16 files changed, 202 insertions(+), 3 deletions(-) diff --git a/docs/pages/x/api/charts/charts-legend.json b/docs/pages/x/api/charts/charts-legend.json index 7fe4b7ae48a48..5abdc1852b6a8 100644 --- a/docs/pages/x/api/charts/charts-legend.json +++ b/docs/pages/x/api/charts/charts-legend.json @@ -3,6 +3,26 @@ "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "direction": { "type": { "name": "enum", "description": "'column'
| 'row'" } }, "hidden": { "type": { "name": "bool" }, "default": "false" }, + "itemGap": { "type": { "name": "number" }, "default": "10" }, + "itemMarkHeight": { "type": { "name": "number" }, "default": "20" }, + "itemMarkWidth": { "type": { "name": "number" }, "default": "20" }, + "labelStyle": { "type": { "name": "object" }, "default": "theme.typography.subtitle1" }, + "markGap": { "type": { "name": "number" }, "default": "5" }, + "onItemClick": { + "type": { "name": "func" }, + "default": "undefined", + "signature": { + "type": "function(event: React.MouseEvent, legendItem: SeriesLegendItemContext, index: number) => void", + "describedArgs": ["event", "legendItem", "index"] + } + }, + "padding": { + "type": { + "name": "union", + "description": "number
| { bottom?: number, left?: number, right?: number, top?: number }" + }, + "default": "10" + }, "position": { "type": { "name": "shape", diff --git a/docs/pages/x/api/charts/default-charts-legend.json b/docs/pages/x/api/charts/default-charts-legend.json index a2f27932916a5..1cb15587029bb 100644 --- a/docs/pages/x/api/charts/default-charts-legend.json +++ b/docs/pages/x/api/charts/default-charts-legend.json @@ -41,6 +41,12 @@ "import { DefaultChartsLegend } from '@mui/x-charts-pro';" ], "classes": [ + { + "key": "column", + "className": "MuiDefaultChartsLegend-column", + "description": "Styles applied to the legend with column layout.", + "isGlobal": false + }, { "key": "itemBackground", "className": "MuiDefaultChartsLegend-itemBackground", @@ -65,6 +71,12 @@ "description": "Styles applied to the root element.", "isGlobal": false }, + { + "key": "row", + "className": "MuiDefaultChartsLegend-row", + "description": "Styles applied to the legend with row layout.", + "isGlobal": false + }, { "key": "series", "className": "MuiDefaultChartsLegend-series", diff --git a/docs/pages/x/api/charts/pie-chart.json b/docs/pages/x/api/charts/pie-chart.json index cc208bd3f97c9..dfb20738cb2a4 100644 --- a/docs/pages/x/api/charts/pie-chart.json +++ b/docs/pages/x/api/charts/pie-chart.json @@ -39,7 +39,7 @@ "legend": { "type": { "name": "shape", - "description": "{ classes?: object, direction?: 'column'
| 'row', hidden?: bool, position?: { horizontal: 'left'
| 'middle'
| 'right', vertical: 'bottom'
| 'middle'
| 'top' }, slotProps?: object, slots?: object }" + "description": "{ classes?: object, direction?: 'column'
| 'row', hidden?: bool, itemGap?: number, itemMarkHeight?: number, itemMarkWidth?: number, labelStyle?: object, markGap?: number, onItemClick?: func, padding?: number
| { bottom?: number, left?: number, right?: number, top?: number }, position?: { horizontal: 'left'
| 'middle'
| 'right', vertical: 'bottom'
| 'middle'
| 'top' }, slotProps?: object, slots?: object }" }, "default": "{ direction: 'column', position: { vertical: 'middle', horizontal: 'right' } }", "deprecated": true, diff --git a/docs/pages/x/api/charts/piecewise-color-legend.json b/docs/pages/x/api/charts/piecewise-color-legend.json index 62ce29a882337..75feb96aaf546 100644 --- a/docs/pages/x/api/charts/piecewise-color-legend.json +++ b/docs/pages/x/api/charts/piecewise-color-legend.json @@ -59,6 +59,12 @@ "import { PiecewiseColorLegend } from '@mui/x-charts-pro';" ], "classes": [ + { + "key": "column", + "className": "MuiPiecewiseColorLegend-column", + "description": "Styles applied to the legend with column layout.", + "isGlobal": false + }, { "key": "itemBackground", "className": "MuiPiecewiseColorLegend-itemBackground", @@ -83,6 +89,12 @@ "description": "Styles applied to the root element.", "isGlobal": false }, + { + "key": "row", + "className": "MuiPiecewiseColorLegend-row", + "description": "Styles applied to the legend with row layout.", + "isGlobal": false + }, { "key": "series", "className": "MuiPiecewiseColorLegend-series", diff --git a/docs/translations/api-docs/charts/charts-legend/charts-legend.json b/docs/translations/api-docs/charts/charts-legend/charts-legend.json index 770d0323bacd2..697f19e692d3b 100644 --- a/docs/translations/api-docs/charts/charts-legend/charts-legend.json +++ b/docs/translations/api-docs/charts/charts-legend/charts-legend.json @@ -6,6 +6,22 @@ "description": "The direction of the legend layout. The default depends on the chart." }, "hidden": { "description": "Set to true to hide the legend." }, + "itemGap": { "description": "Space between two legend items (in px)." }, + "itemMarkHeight": { "description": "Height of the item mark (in px)." }, + "itemMarkWidth": { "description": "Width of the item mark (in px)." }, + "labelStyle": { "description": "Style applied to legend labels." }, + "markGap": { "description": "Space between the mark and the label (in px)." }, + "onItemClick": { + "description": "Callback fired when a legend item is clicked.", + "typeDescriptions": { + "event": "The click event.", + "legendItem": "The legend item data.", + "index": "The index of the clicked legend item." + } + }, + "padding": { + "description": "Legend padding (in px). Can either be a single number, or an object with top, left, bottom, right properties." + }, "position": { "description": "The position of the legend." }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." } diff --git a/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json b/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json index 2c1d27eddf9ae..eea8fa28c58f3 100644 --- a/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json +++ b/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json @@ -25,6 +25,10 @@ "position": { "description": "The position of the legend." } }, "classDescriptions": { + "column": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the legend with column layout" + }, "itemBackground": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the item background" @@ -32,6 +36,10 @@ "label": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the series label" }, "mark": { "description": "Styles applied to {{nodeName}}.", "nodeName": "series mark element" }, "root": { "description": "Styles applied to the root element." }, + "row": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the legend with row layout" + }, "series": { "description": "Styles applied to {{nodeName}}.", "nodeName": "a series element" } } } diff --git a/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json b/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json index e5f1808123f33..a804d3089d3cb 100644 --- a/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json +++ b/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json @@ -44,6 +44,10 @@ "position": { "description": "The position of the legend." } }, "classDescriptions": { + "column": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the legend with column layout" + }, "itemBackground": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the item background" @@ -51,6 +55,10 @@ "label": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the series label" }, "mark": { "description": "Styles applied to {{nodeName}}.", "nodeName": "series mark element" }, "root": { "description": "Styles applied to the root element." }, + "row": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the legend with row layout" + }, "series": { "description": "Styles applied to {{nodeName}}.", "nodeName": "a series element" } } } diff --git a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx index cf9a928faa737..5c086e242dc2d 100644 --- a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx +++ b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx @@ -147,6 +147,21 @@ ScatterChartPro.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, + itemGap: PropTypes.number, + itemMarkHeight: PropTypes.number, + itemMarkWidth: PropTypes.number, + labelStyle: PropTypes.object, + markGap: PropTypes.number, + onItemClick: PropTypes.func, + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index ffb89e8494d40..5e5929c6d8cec 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -232,6 +232,21 @@ BarChart.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, + itemGap: PropTypes.number, + itemMarkHeight: PropTypes.number, + itemMarkWidth: PropTypes.number, + labelStyle: PropTypes.object, + markGap: PropTypes.number, + onItemClick: PropTypes.func, + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx index 0676ceb160c35..104cfa8b452cb 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx @@ -13,7 +13,7 @@ import { LegendPlacement } from './legend.types'; export type ChartsLegendPropsBase = Omit< LegendRendererProps, - keyof LegendPlacement | 'contextBuilder' | 'series' | 'seriesToDisplay' + keyof LegendPlacement | 'contextBuilder' | 'series' | 'seriesToDisplay' | 'drawingArea' > & LegendPlacement; @@ -114,6 +114,53 @@ ChartsLegend.propTypes = { * @default false */ hidden: PropTypes.bool, + /** + * Space between two legend items (in px). + * @default 10 + */ + itemGap: PropTypes.number, + /** + * Height of the item mark (in px). + * @default 20 + */ + itemMarkHeight: PropTypes.number, + /** + * Width of the item mark (in px). + * @default 20 + */ + itemMarkWidth: PropTypes.number, + /** + * Style applied to legend labels. + * @default theme.typography.subtitle1 + */ + labelStyle: PropTypes.object, + /** + * Space between the mark and the label (in px). + * @default 5 + */ + markGap: PropTypes.number, + /** + * Callback fired when a legend item is clicked. + * @param {React.MouseEvent} event The click event. + * @param {SeriesLegendItemContext} legendItem The legend item data. + * @param {number} index The index of the clicked legend item. + * @default undefined + */ + onItemClick: PropTypes.func, + /** + * Legend padding (in px). + * Can either be a single number, or an object with top, left, bottom, right properties. + * @default 10 + */ + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), /** * The position of the legend. */ diff --git a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx index 84cf4d8f4be94..16f4c1c8ea4d6 100644 --- a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx @@ -141,7 +141,6 @@ DefaultChartsLegend.propTypes = { maxValue: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), minValue: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), seriesId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - type: PropTypes.oneOf(['piecewiseColor', 'series']).isRequired, }), ).isRequired, } as any; diff --git a/packages/x-charts/src/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index 94235ce0c79d6..8f937ecf3c492 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -253,6 +253,21 @@ LineChart.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, + itemGap: PropTypes.number, + itemMarkHeight: PropTypes.number, + itemMarkWidth: PropTypes.number, + labelStyle: PropTypes.object, + markGap: PropTypes.number, + onItemClick: PropTypes.func, + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, diff --git a/packages/x-charts/src/PieChart/PieChart.tsx b/packages/x-charts/src/PieChart/PieChart.tsx index 51fe9e0d87a31..ff6d44b1ec9eb 100644 --- a/packages/x-charts/src/PieChart/PieChart.tsx +++ b/packages/x-charts/src/PieChart/PieChart.tsx @@ -278,6 +278,21 @@ PieChart.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, + itemGap: PropTypes.number, + itemMarkHeight: PropTypes.number, + itemMarkWidth: PropTypes.number, + labelStyle: PropTypes.object, + markGap: PropTypes.number, + onItemClick: PropTypes.func, + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index d8ae6735b52b7..7fc8d6bb3bcf1 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -228,6 +228,21 @@ ScatterChart.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, + itemGap: PropTypes.number, + itemMarkHeight: PropTypes.number, + itemMarkWidth: PropTypes.number, + labelStyle: PropTypes.object, + markGap: PropTypes.number, + onItemClick: PropTypes.func, + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, diff --git a/scripts/x-charts-pro.exports.json b/scripts/x-charts-pro.exports.json index b4aba91475fb0..5a6002d4f4486 100644 --- a/scripts/x-charts-pro.exports.json +++ b/scripts/x-charts-pro.exports.json @@ -85,6 +85,7 @@ { "name": "ChartsLegendClasses", "kind": "Interface" }, { "name": "ChartsLegendClassKey", "kind": "TypeAlias" }, { "name": "ChartsLegendProps", "kind": "Interface" }, + { "name": "ChartsLegendPropsBase", "kind": "TypeAlias" }, { "name": "ChartsLegendSlotProps", "kind": "Interface" }, { "name": "ChartsLegendSlots", "kind": "Interface" }, { "name": "ChartsOnAxisClickHandler", "kind": "Function" }, diff --git a/scripts/x-charts.exports.json b/scripts/x-charts.exports.json index 0db09b39d5bdd..77e4e3e29edc7 100644 --- a/scripts/x-charts.exports.json +++ b/scripts/x-charts.exports.json @@ -83,6 +83,7 @@ { "name": "ChartsLegendClasses", "kind": "Interface" }, { "name": "ChartsLegendClassKey", "kind": "TypeAlias" }, { "name": "ChartsLegendProps", "kind": "Interface" }, + { "name": "ChartsLegendPropsBase", "kind": "TypeAlias" }, { "name": "ChartsLegendSlotProps", "kind": "Interface" }, { "name": "ChartsLegendSlots", "kind": "Interface" }, { "name": "ChartsOnAxisClickHandler", "kind": "Function" }, From acc7843621ab9c8cb5a90be587f9ffe058b24464 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 29 Aug 2024 20:37:56 +0200 Subject: [PATCH 16/25] remove spilled typings --- docs/pages/x/api/charts/charts-legend.json | 12 ----- docs/pages/x/api/charts/pie-chart.json | 2 +- .../charts/charts-legend/charts-legend.json | 8 ---- .../src/ScatterChartPro/ScatterChartPro.tsx | 14 ------ packages/x-charts/src/BarChart/BarChart.tsx | 14 ------ .../src/ChartsLegend/ChartsLegend.tsx | 45 ++----------------- packages/x-charts/src/LineChart/LineChart.tsx | 14 ------ packages/x-charts/src/PieChart/PieChart.tsx | 14 ------ .../src/ScatterChart/ScatterChart.tsx | 14 ------ 9 files changed, 4 insertions(+), 133 deletions(-) diff --git a/docs/pages/x/api/charts/charts-legend.json b/docs/pages/x/api/charts/charts-legend.json index 5abdc1852b6a8..0b85a6e8605e1 100644 --- a/docs/pages/x/api/charts/charts-legend.json +++ b/docs/pages/x/api/charts/charts-legend.json @@ -3,11 +3,6 @@ "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "direction": { "type": { "name": "enum", "description": "'column'
| 'row'" } }, "hidden": { "type": { "name": "bool" }, "default": "false" }, - "itemGap": { "type": { "name": "number" }, "default": "10" }, - "itemMarkHeight": { "type": { "name": "number" }, "default": "20" }, - "itemMarkWidth": { "type": { "name": "number" }, "default": "20" }, - "labelStyle": { "type": { "name": "object" }, "default": "theme.typography.subtitle1" }, - "markGap": { "type": { "name": "number" }, "default": "5" }, "onItemClick": { "type": { "name": "func" }, "default": "undefined", @@ -16,13 +11,6 @@ "describedArgs": ["event", "legendItem", "index"] } }, - "padding": { - "type": { - "name": "union", - "description": "number
| { bottom?: number, left?: number, right?: number, top?: number }" - }, - "default": "10" - }, "position": { "type": { "name": "shape", diff --git a/docs/pages/x/api/charts/pie-chart.json b/docs/pages/x/api/charts/pie-chart.json index dfb20738cb2a4..fe001ecaa12c9 100644 --- a/docs/pages/x/api/charts/pie-chart.json +++ b/docs/pages/x/api/charts/pie-chart.json @@ -39,7 +39,7 @@ "legend": { "type": { "name": "shape", - "description": "{ classes?: object, direction?: 'column'
| 'row', hidden?: bool, itemGap?: number, itemMarkHeight?: number, itemMarkWidth?: number, labelStyle?: object, markGap?: number, onItemClick?: func, padding?: number
| { bottom?: number, left?: number, right?: number, top?: number }, position?: { horizontal: 'left'
| 'middle'
| 'right', vertical: 'bottom'
| 'middle'
| 'top' }, slotProps?: object, slots?: object }" + "description": "{ classes?: object, direction?: 'column'
| 'row', hidden?: bool, onItemClick?: func, position?: { horizontal: 'left'
| 'middle'
| 'right', vertical: 'bottom'
| 'middle'
| 'top' }, slotProps?: object, slots?: object }" }, "default": "{ direction: 'column', position: { vertical: 'middle', horizontal: 'right' } }", "deprecated": true, diff --git a/docs/translations/api-docs/charts/charts-legend/charts-legend.json b/docs/translations/api-docs/charts/charts-legend/charts-legend.json index 697f19e692d3b..cf031ce748237 100644 --- a/docs/translations/api-docs/charts/charts-legend/charts-legend.json +++ b/docs/translations/api-docs/charts/charts-legend/charts-legend.json @@ -6,11 +6,6 @@ "description": "The direction of the legend layout. The default depends on the chart." }, "hidden": { "description": "Set to true to hide the legend." }, - "itemGap": { "description": "Space between two legend items (in px)." }, - "itemMarkHeight": { "description": "Height of the item mark (in px)." }, - "itemMarkWidth": { "description": "Width of the item mark (in px)." }, - "labelStyle": { "description": "Style applied to legend labels." }, - "markGap": { "description": "Space between the mark and the label (in px)." }, "onItemClick": { "description": "Callback fired when a legend item is clicked.", "typeDescriptions": { @@ -19,9 +14,6 @@ "index": "The index of the clicked legend item." } }, - "padding": { - "description": "Legend padding (in px). Can either be a single number, or an object with top, left, bottom, right properties." - }, "position": { "description": "The position of the legend." }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." } diff --git a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx index 5c086e242dc2d..31cb8eb53ef8f 100644 --- a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx +++ b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx @@ -147,21 +147,7 @@ ScatterChartPro.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, - itemGap: PropTypes.number, - itemMarkHeight: PropTypes.number, - itemMarkWidth: PropTypes.number, - labelStyle: PropTypes.object, - markGap: PropTypes.number, onItemClick: PropTypes.func, - padding: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.shape({ - bottom: PropTypes.number, - left: PropTypes.number, - right: PropTypes.number, - top: PropTypes.number, - }), - ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index 5e5929c6d8cec..695b94d935639 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -232,21 +232,7 @@ BarChart.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, - itemGap: PropTypes.number, - itemMarkHeight: PropTypes.number, - itemMarkWidth: PropTypes.number, - labelStyle: PropTypes.object, - markGap: PropTypes.number, onItemClick: PropTypes.func, - padding: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.shape({ - bottom: PropTypes.number, - left: PropTypes.number, - right: PropTypes.number, - top: PropTypes.number, - }), - ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx index 104cfa8b452cb..2c37579b58818 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx @@ -11,9 +11,9 @@ import { useDrawingArea } from '../hooks'; import { useSeries } from '../hooks/useSeries'; import { LegendPlacement } from './legend.types'; -export type ChartsLegendPropsBase = Omit< - LegendRendererProps, - keyof LegendPlacement | 'contextBuilder' | 'series' | 'seriesToDisplay' | 'drawingArea' +export type ChartsLegendPropsBase = Pick< + Omit, + 'classes' | 'hidden' | 'onItemClick' > & LegendPlacement; @@ -114,31 +114,6 @@ ChartsLegend.propTypes = { * @default false */ hidden: PropTypes.bool, - /** - * Space between two legend items (in px). - * @default 10 - */ - itemGap: PropTypes.number, - /** - * Height of the item mark (in px). - * @default 20 - */ - itemMarkHeight: PropTypes.number, - /** - * Width of the item mark (in px). - * @default 20 - */ - itemMarkWidth: PropTypes.number, - /** - * Style applied to legend labels. - * @default theme.typography.subtitle1 - */ - labelStyle: PropTypes.object, - /** - * Space between the mark and the label (in px). - * @default 5 - */ - markGap: PropTypes.number, /** * Callback fired when a legend item is clicked. * @param {React.MouseEvent} event The click event. @@ -147,20 +122,6 @@ ChartsLegend.propTypes = { * @default undefined */ onItemClick: PropTypes.func, - /** - * Legend padding (in px). - * Can either be a single number, or an object with top, left, bottom, right properties. - * @default 10 - */ - padding: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.shape({ - bottom: PropTypes.number, - left: PropTypes.number, - right: PropTypes.number, - top: PropTypes.number, - }), - ]), /** * The position of the legend. */ diff --git a/packages/x-charts/src/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index 8f937ecf3c492..31b290380441a 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -253,21 +253,7 @@ LineChart.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, - itemGap: PropTypes.number, - itemMarkHeight: PropTypes.number, - itemMarkWidth: PropTypes.number, - labelStyle: PropTypes.object, - markGap: PropTypes.number, onItemClick: PropTypes.func, - padding: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.shape({ - bottom: PropTypes.number, - left: PropTypes.number, - right: PropTypes.number, - top: PropTypes.number, - }), - ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, diff --git a/packages/x-charts/src/PieChart/PieChart.tsx b/packages/x-charts/src/PieChart/PieChart.tsx index ff6d44b1ec9eb..06e6012662b87 100644 --- a/packages/x-charts/src/PieChart/PieChart.tsx +++ b/packages/x-charts/src/PieChart/PieChart.tsx @@ -278,21 +278,7 @@ PieChart.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, - itemGap: PropTypes.number, - itemMarkHeight: PropTypes.number, - itemMarkWidth: PropTypes.number, - labelStyle: PropTypes.object, - markGap: PropTypes.number, onItemClick: PropTypes.func, - padding: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.shape({ - bottom: PropTypes.number, - left: PropTypes.number, - right: PropTypes.number, - top: PropTypes.number, - }), - ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index 7fc8d6bb3bcf1..a863f9e70e206 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -228,21 +228,7 @@ ScatterChart.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, - itemGap: PropTypes.number, - itemMarkHeight: PropTypes.number, - itemMarkWidth: PropTypes.number, - labelStyle: PropTypes.object, - markGap: PropTypes.number, onItemClick: PropTypes.func, - padding: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.shape({ - bottom: PropTypes.number, - left: PropTypes.number, - right: PropTypes.number, - top: PropTypes.number, - }), - ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, From 9e669e51480fd8e08cca0a15705d70cc28f106d2 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 29 Aug 2024 21:04:45 +0200 Subject: [PATCH 17/25] Fix doc generation --- docs/pages/x/api/charts/bar-chart-pro.json | 17 +- docs/pages/x/api/charts/charts-legend.json | 12 + docs/pages/x/api/charts/line-chart-pro.json | 17 +- docs/pages/x/api/charts/pie-chart.json | 2 +- .../charts/bar-chart-pro/bar-chart-pro.json | 7 +- .../charts/charts-legend/charts-legend.json | 8 + .../charts/line-chart-pro/line-chart-pro.json | 7 +- .../src/BarChartPro/BarChartPro.tsx | 93 ++-- .../src/LineChartPro/LineChartPro.tsx | 402 +++++++++++++++++- .../src/ScatterChartPro/ScatterChartPro.tsx | 14 + packages/x-charts/src/BarChart/BarChart.tsx | 14 + .../src/ChartsLegend/ChartsLegend.tsx | 45 +- packages/x-charts/src/LineChart/LineChart.tsx | 14 + packages/x-charts/src/PieChart/PieChart.tsx | 14 + .../src/ScatterChart/ScatterChart.tsx | 14 + 15 files changed, 604 insertions(+), 76 deletions(-) diff --git a/docs/pages/x/api/charts/bar-chart-pro.json b/docs/pages/x/api/charts/bar-chart-pro.json index 141bd308bd168..8cc679f15c36f 100644 --- a/docs/pages/x/api/charts/bar-chart-pro.json +++ b/docs/pages/x/api/charts/bar-chart-pro.json @@ -73,6 +73,13 @@ "describedArgs": ["event", "barItemIdentifier"] } }, + "onZoomChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(zoomData: Array) => void", + "describedArgs": ["zoomData"] + } + }, "rightAxis": { "type": { "name": "union", "description": "object
| string" }, "default": "null" @@ -99,13 +106,19 @@ "xAxis": { "type": { "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?: 'bottom'
| 'top', 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, zoom?: { maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }
| bool }>" + "description": "Array<{ 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?: 'bottom'
| 'top', reverse?: bool, scaleType?: 'band'
| 'linear'
| 'log'
| 'point'
| 'pow'
| 'sqrt'
| 'time'
| 'utc', slotProps?: object, slots?: object, stroke?: string, sx?: Array<func
| object
| bool>
| func
| object, 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, zoom?: { filterMode?: 'discard'
| 'keep', maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }
| bool }>" } }, "yAxis": { "type": { "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, zoom?: { maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }
| bool }>" + "description": "Array<{ 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, sx?: Array<func
| object
| bool>
| func
| object, 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, zoom?: { filterMode?: 'discard'
| 'keep', maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }
| bool }>" + } + }, + "zoom": { + "type": { + "name": "arrayOf", + "description": "Array<{ axisId: number
| string, end: number, start: number }>" } } }, diff --git a/docs/pages/x/api/charts/charts-legend.json b/docs/pages/x/api/charts/charts-legend.json index 0b85a6e8605e1..5abdc1852b6a8 100644 --- a/docs/pages/x/api/charts/charts-legend.json +++ b/docs/pages/x/api/charts/charts-legend.json @@ -3,6 +3,11 @@ "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "direction": { "type": { "name": "enum", "description": "'column'
| 'row'" } }, "hidden": { "type": { "name": "bool" }, "default": "false" }, + "itemGap": { "type": { "name": "number" }, "default": "10" }, + "itemMarkHeight": { "type": { "name": "number" }, "default": "20" }, + "itemMarkWidth": { "type": { "name": "number" }, "default": "20" }, + "labelStyle": { "type": { "name": "object" }, "default": "theme.typography.subtitle1" }, + "markGap": { "type": { "name": "number" }, "default": "5" }, "onItemClick": { "type": { "name": "func" }, "default": "undefined", @@ -11,6 +16,13 @@ "describedArgs": ["event", "legendItem", "index"] } }, + "padding": { + "type": { + "name": "union", + "description": "number
| { bottom?: number, left?: number, right?: number, top?: number }" + }, + "default": "10" + }, "position": { "type": { "name": "shape", diff --git a/docs/pages/x/api/charts/line-chart-pro.json b/docs/pages/x/api/charts/line-chart-pro.json index 6b2c4e32e0460..9737b36e65cc9 100644 --- a/docs/pages/x/api/charts/line-chart-pro.json +++ b/docs/pages/x/api/charts/line-chart-pro.json @@ -65,6 +65,13 @@ }, "onLineClick": { "type": { "name": "func" } }, "onMarkClick": { "type": { "name": "func" } }, + "onZoomChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(zoomData: Array) => void", + "describedArgs": ["zoomData"] + } + }, "rightAxis": { "type": { "name": "union", "description": "object
| string" }, "default": "null" @@ -92,13 +99,19 @@ "xAxis": { "type": { "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?: 'bottom'
| 'top', 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, zoom?: { maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }
| bool }>" + "description": "Array<{ 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?: 'bottom'
| 'top', reverse?: bool, scaleType?: 'band'
| 'linear'
| 'log'
| 'point'
| 'pow'
| 'sqrt'
| 'time'
| 'utc', slotProps?: object, slots?: object, stroke?: string, sx?: Array<func
| object
| bool>
| func
| object, 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, zoom?: { filterMode?: 'discard'
| 'keep', maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }
| bool }>" } }, "yAxis": { "type": { "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, zoom?: { maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }
| bool }>" + "description": "Array<{ 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, sx?: Array<func
| object
| bool>
| func
| object, 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, zoom?: { filterMode?: 'discard'
| 'keep', maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }
| bool }>" + } + }, + "zoom": { + "type": { + "name": "arrayOf", + "description": "Array<{ axisId: number
| string, end: number, start: number }>" } } }, diff --git a/docs/pages/x/api/charts/pie-chart.json b/docs/pages/x/api/charts/pie-chart.json index fe001ecaa12c9..dfb20738cb2a4 100644 --- a/docs/pages/x/api/charts/pie-chart.json +++ b/docs/pages/x/api/charts/pie-chart.json @@ -39,7 +39,7 @@ "legend": { "type": { "name": "shape", - "description": "{ classes?: object, direction?: 'column'
| 'row', hidden?: bool, onItemClick?: func, position?: { horizontal: 'left'
| 'middle'
| 'right', vertical: 'bottom'
| 'middle'
| 'top' }, slotProps?: object, slots?: object }" + "description": "{ classes?: object, direction?: 'column'
| 'row', hidden?: bool, itemGap?: number, itemMarkHeight?: number, itemMarkWidth?: number, labelStyle?: object, markGap?: number, onItemClick?: func, padding?: number
| { bottom?: number, left?: number, right?: number, top?: number }, position?: { horizontal: 'left'
| 'middle'
| 'right', vertical: 'bottom'
| 'middle'
| 'top' }, slotProps?: object, slots?: object }" }, "default": "{ direction: 'column', position: { vertical: 'middle', horizontal: 'right' } }", "deprecated": true, diff --git a/docs/translations/api-docs/charts/bar-chart-pro/bar-chart-pro.json b/docs/translations/api-docs/charts/bar-chart-pro/bar-chart-pro.json index 48e64539542e8..58fc1a173e710 100644 --- a/docs/translations/api-docs/charts/bar-chart-pro/bar-chart-pro.json +++ b/docs/translations/api-docs/charts/bar-chart-pro/bar-chart-pro.json @@ -52,6 +52,10 @@ "barItemIdentifier": "The bar item identifier." } }, + "onZoomChange": { + "description": "Callback fired when the zoom has changed.", + "typeDescriptions": { "zoomData": "Updated zoom data." } + }, "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." }, @@ -76,7 +80,8 @@ }, "yAxis": { "description": "The configuration of the y-axes. If not provided, a default axis config is used. An array of
AxisConfig objects." - } + }, + "zoom": { "description": "The list of zoom data related to each axis." } }, "classDescriptions": {} } diff --git a/docs/translations/api-docs/charts/charts-legend/charts-legend.json b/docs/translations/api-docs/charts/charts-legend/charts-legend.json index cf031ce748237..697f19e692d3b 100644 --- a/docs/translations/api-docs/charts/charts-legend/charts-legend.json +++ b/docs/translations/api-docs/charts/charts-legend/charts-legend.json @@ -6,6 +6,11 @@ "description": "The direction of the legend layout. The default depends on the chart." }, "hidden": { "description": "Set to true to hide the legend." }, + "itemGap": { "description": "Space between two legend items (in px)." }, + "itemMarkHeight": { "description": "Height of the item mark (in px)." }, + "itemMarkWidth": { "description": "Width of the item mark (in px)." }, + "labelStyle": { "description": "Style applied to legend labels." }, + "markGap": { "description": "Space between the mark and the label (in px)." }, "onItemClick": { "description": "Callback fired when a legend item is clicked.", "typeDescriptions": { @@ -14,6 +19,9 @@ "index": "The index of the clicked legend item." } }, + "padding": { + "description": "Legend padding (in px). Can either be a single number, or an object with top, left, bottom, right properties." + }, "position": { "description": "The position of the legend." }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." } diff --git a/docs/translations/api-docs/charts/line-chart-pro/line-chart-pro.json b/docs/translations/api-docs/charts/line-chart-pro/line-chart-pro.json index a262e0ac15bf2..bc67c9eba65b4 100644 --- a/docs/translations/api-docs/charts/line-chart-pro/line-chart-pro.json +++ b/docs/translations/api-docs/charts/line-chart-pro/line-chart-pro.json @@ -46,6 +46,10 @@ }, "onLineClick": { "description": "Callback fired when a line element is clicked." }, "onMarkClick": { "description": "Callback fired when a mark element is clicked." }, + "onZoomChange": { + "description": "Callback fired when the zoom has changed.", + "typeDescriptions": { "zoomData": "Updated zoom data." } + }, "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." }, @@ -70,7 +74,8 @@ }, "yAxis": { "description": "The configuration of the y-axes. If not provided, a default axis config is used. An array of AxisConfig objects." - } + }, + "zoom": { "description": "The list of zoom data related to each axis." } }, "classDescriptions": {} } diff --git a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx index ef8624363755d..ebf8d6a00fa8c 100644 --- a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx +++ b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx @@ -17,6 +17,12 @@ import { ZoomSetup } from '../context/ZoomProvider/ZoomSetup'; import { useZoom } from '../context/ZoomProvider/useZoom'; import { ZoomProps } from '../context/ZoomProvider'; +function BarChartPlotZoom(props: BarPlotProps) { + const { isInteracting } = useZoom(); + + return ; +} + export interface BarChartProProps extends BarChartProps, ZoomProps {} /** @@ -159,6 +165,21 @@ BarChartPro.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, + itemGap: PropTypes.number, + itemMarkHeight: PropTypes.number, + itemMarkWidth: PropTypes.number, + labelStyle: PropTypes.object, + markGap: PropTypes.number, + onItemClick: PropTypes.func, + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, @@ -202,6 +223,12 @@ BarChartPro.propTypes = { * @param {BarItemIdentifier} barItemIdentifier The bar item identifier. */ onItemClick: PropTypes.func, + /** + * Callback fired when the zoom has changed. + * + * @param {ZoomData[]} zoomData Updated zoom data. + */ + onZoomChange: PropTypes.func, /** * Indicate which axis to display the right of the charts. * Can be a string (the id of the axis) or an object `ChartsYAxisProps`. @@ -269,7 +296,6 @@ BarChartPro.propTypes = { */ xAxis: PropTypes.arrayOf( PropTypes.shape({ - axisId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), classes: PropTypes.object, colorMap: PropTypes.oneOfType([ PropTypes.shape({ @@ -316,6 +342,11 @@ BarChartPro.propTypes = { slotProps: PropTypes.object, slots: PropTypes.object, stroke: PropTypes.string, + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), tickFontSize: PropTypes.number, tickInterval: PropTypes.oneOfType([ PropTypes.oneOf(['auto']), @@ -333,6 +364,7 @@ BarChartPro.propTypes = { valueFormatter: PropTypes.func, zoom: PropTypes.oneOfType([ PropTypes.shape({ + filterMode: PropTypes.oneOf(['discard', 'keep']), maxEnd: PropTypes.number, maxSpan: PropTypes.number, minSpan: PropTypes.number, @@ -351,7 +383,6 @@ BarChartPro.propTypes = { */ yAxis: PropTypes.arrayOf( PropTypes.shape({ - axisId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), classes: PropTypes.object, colorMap: PropTypes.oneOfType([ PropTypes.shape({ @@ -398,6 +429,11 @@ BarChartPro.propTypes = { slotProps: PropTypes.object, slots: PropTypes.object, stroke: PropTypes.string, + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), tickFontSize: PropTypes.number, tickInterval: PropTypes.oneOfType([ PropTypes.oneOf(['auto']), @@ -415,6 +451,7 @@ BarChartPro.propTypes = { valueFormatter: PropTypes.func, zoom: PropTypes.oneOfType([ PropTypes.shape({ + filterMode: PropTypes.oneOf(['discard', 'keep']), maxEnd: PropTypes.number, maxSpan: PropTypes.number, minSpan: PropTypes.number, @@ -426,52 +463,16 @@ BarChartPro.propTypes = { ]), }), ), -} as any; - -function BarChartPlotZoom(props: BarPlotProps) { - const { isInteracting } = useZoom(); - - return ; -} - -BarChartPlotZoom.propTypes = { - // ----------------------------- Warning -------------------------------- - // | These PropTypes are generated from the TypeScript type definitions | - // | To update them edit the TypeScript types and run "pnpm proptypes" | - // ---------------------------------------------------------------------- /** - * If provided, the function will be used to format the label of the bar. - * It can be set to 'value' to display the current value. - * @param {BarItem} item The item to format. - * @param {BarLabelContext} context data about the bar. - * @returns {string} The formatted label. + * The list of zoom data related to each axis. */ - barLabel: PropTypes.oneOfType([PropTypes.oneOf(['value']), PropTypes.func]), - /** - * Defines the border radius of the bar element. - */ - borderRadius: PropTypes.number, - /** - * Callback fired when a bar item is clicked. - * @param {React.MouseEvent} event The event source of the callback. - * @param {BarItemIdentifier} barItemIdentifier The bar item identifier. - */ - onItemClick: PropTypes.func, - /** - * If `true`, animations are skipped. - * @default false - */ - skipAnimation: PropTypes.bool, - /** - * The props used for each component slot. - * @default {} - */ - slotProps: PropTypes.object, - /** - * Overridable component slots. - * @default {} - */ - slots: PropTypes.object, + zoom: PropTypes.arrayOf( + PropTypes.shape({ + axisId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, + end: PropTypes.number.isRequired, + start: PropTypes.number.isRequired, + }), + ), } as any; export { BarChartPro }; diff --git a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx index 8075680e6bc4f..685ecc68d4c21 100644 --- a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx +++ b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx @@ -25,6 +25,21 @@ import { ZoomSetup } from '../context/ZoomProvider/ZoomSetup'; import { useZoom } from '../context/ZoomProvider/useZoom'; import { ZoomProps } from '../context/ZoomProvider'; +function LinePlotZoom(props: LinePlotProps) { + const { isInteracting } = useZoom(); + return ; +} + +function AreaPlotZoom(props: AreaPlotProps) { + const { isInteracting } = useZoom(); + return ; +} + +function MarkPlotZoom(props: MarkPlotProps) { + const { isInteracting } = useZoom(); + return ; +} + export interface LineChartProProps extends LineChartProps, ZoomProps {} /** @@ -437,11 +452,6 @@ LineChartPro.propTypes = { ), } as any; -function MarkPlotZoom(props: MarkPlotProps) { - const { isInteracting } = useZoom(); - return ; -} - MarkPlotZoom.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | @@ -470,11 +480,6 @@ MarkPlotZoom.propTypes = { slots: PropTypes.object, } as any; -function LinePlotZoom(props: LinePlotProps) { - const { isInteracting } = useZoom(); - return ; -} - LinePlotZoom.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | @@ -503,22 +508,160 @@ LinePlotZoom.propTypes = { slots: PropTypes.object, } as any; -function AreaPlotZoom(props: AreaPlotProps) { - const { isInteracting } = useZoom(); - return ; -} - -AreaPlotZoom.propTypes = { +LineChartPro.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "pnpm proptypes" | // ---------------------------------------------------------------------- /** - * Callback fired when a line area item is clicked. - * @param {React.MouseEvent} event The event source of the callback. - * @param {LineItemIdentifier} lineItemIdentifier The line item identifier. + * The configuration of axes highlight. + * @see See {@link https://mui.com/x/react-charts/tooltip/#highlights highlight docs} for more details. + * @default { x: 'line' } */ - onItemClick: PropTypes.func, + axisHighlight: PropTypes.shape({ + x: PropTypes.oneOf(['band', 'line', 'none']), + y: PropTypes.oneOf(['band', 'line', 'none']), + }), + /** + * Indicate which axis to display the bottom of the charts. + * Can be a string (the id of the axis) or an object `ChartsXAxisProps`. + * @default xAxisIds[0] The id of the first provided axis + */ + bottomAxis: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), + 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, + /** + * If `true`, render the line highlight item. + */ + disableLineItemHighlight: PropTypes.bool, + /** + * Option to display a cartesian grid in the background. + */ + grid: PropTypes.shape({ + horizontal: PropTypes.bool, + vertical: PropTypes.bool, + }), + /** + * The height of the chart in px. If not defined, it takes the height of the parent element. + */ + height: PropTypes.number, + /** + * The item currently highlighted. Turns highlighting into a controlled prop. + */ + highlightedItem: PropTypes.shape({ + dataIndex: PropTypes.number, + seriesId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + }), + /** + * Indicate which axis to display the left of the charts. + * Can be a string (the id of the axis) or an object `ChartsYAxisProps`. + * @default yAxisIds[0] The id of the first provided axis + */ + leftAxis: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), + /** + * @deprecated Consider using `slotProps.legend` instead. + */ + legend: PropTypes.shape({ + classes: PropTypes.object, + direction: PropTypes.oneOf(['column', 'row']), + hidden: PropTypes.bool, + itemGap: PropTypes.number, + itemMarkHeight: PropTypes.number, + itemMarkWidth: PropTypes.number, + labelStyle: PropTypes.object, + markGap: PropTypes.number, + onItemClick: PropTypes.func, + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), + position: PropTypes.shape({ + horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, + vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, + }), + slotProps: PropTypes.object, + slots: PropTypes.object, + }), + /** + * If `true`, a loading overlay is displayed. + * @default false + */ + loading: PropTypes.bool, + /** + * 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, + }), + /** + * Callback fired when an area element is clicked. + */ + onAreaClick: PropTypes.func, + /** + * The function called for onClick events. + * The second argument contains information about all line/bar elements at the current mouse position. + * @param {MouseEvent} event The mouse event recorded on the `` element. + * @param {null | AxisData} data The data about the clicked axis and items associated with it. + */ + onAxisClick: PropTypes.func, + /** + * The callback fired when the highlighted item changes. + * + * @param {HighlightItemData | null} highlightedItem The newly highlighted item. + */ + onHighlightChange: PropTypes.func, + /** + * Callback fired when a line element is clicked. + */ + onLineClick: PropTypes.func, + /** + * Callback fired when a mark element is clicked. + */ + onMarkClick: PropTypes.func, + /** + * Callback fired when the zoom has changed. + * + * @param {ZoomData[]} zoomData Updated zoom data. + */ + onZoomChange: PropTypes.func, + /** + * Indicate which axis to display the right of the charts. + * Can be a string (the id of the axis) or an object `ChartsYAxisProps`. + * @default null + */ + rightAxis: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), + /** + * The series to display in the line chart. + * An array of [[LineSeriesType]] objects. + */ + series: PropTypes.arrayOf(PropTypes.object).isRequired, /** * If `true`, animations are skipped. * @default false @@ -534,6 +677,225 @@ AreaPlotZoom.propTypes = { * @default {} */ slots: PropTypes.object, + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + title: PropTypes.string, + /** + * The configuration of the tooltip. + * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. + * @default { trigger: 'item' } + */ + tooltip: PropTypes.shape({ + axisContent: PropTypes.elementType, + classes: PropTypes.object, + itemContent: PropTypes.elementType, + slotProps: PropTypes.object, + slots: PropTypes.object, + trigger: PropTypes.oneOf(['axis', 'item', 'none']), + }), + /** + * Indicate which axis to display the top of the charts. + * Can be a string (the id of the axis) or an object `ChartsXAxisProps`. + * @default null + */ + topAxis: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), + viewBox: PropTypes.shape({ + height: PropTypes.number, + width: PropTypes.number, + x: PropTypes.number, + y: PropTypes.number, + }), + /** + * The width of the chart in px. If not defined, it takes the width of the parent element. + */ + width: PropTypes.number, + /** + * 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({ + 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), + 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, + 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, + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + 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, + zoom: PropTypes.oneOfType([ + PropTypes.shape({ + filterMode: PropTypes.oneOf(['discard', 'keep']), + maxEnd: PropTypes.number, + maxSpan: PropTypes.number, + minSpan: PropTypes.number, + minStart: PropTypes.number, + panning: PropTypes.bool, + step: PropTypes.number, + }), + PropTypes.bool, + ]), + }), + ), + /** + * 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({ + 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), + 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, + 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, + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + 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, + zoom: PropTypes.oneOfType([ + PropTypes.shape({ + filterMode: PropTypes.oneOf(['discard', 'keep']), + maxEnd: PropTypes.number, + maxSpan: PropTypes.number, + minSpan: PropTypes.number, + minStart: PropTypes.number, + panning: PropTypes.bool, + step: PropTypes.number, + }), + PropTypes.bool, + ]), + }), + ), + /** + * The list of zoom data related to each axis. + */ + zoom: PropTypes.arrayOf( + PropTypes.shape({ + axisId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, + end: PropTypes.number.isRequired, + start: PropTypes.number.isRequired, + }), + ), } as any; export { LineChartPro }; diff --git a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx index 31cb8eb53ef8f..5c086e242dc2d 100644 --- a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx +++ b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx @@ -147,7 +147,21 @@ ScatterChartPro.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, + itemGap: PropTypes.number, + itemMarkHeight: PropTypes.number, + itemMarkWidth: PropTypes.number, + labelStyle: PropTypes.object, + markGap: PropTypes.number, onItemClick: PropTypes.func, + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index 695b94d935639..5e5929c6d8cec 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -232,7 +232,21 @@ BarChart.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, + itemGap: PropTypes.number, + itemMarkHeight: PropTypes.number, + itemMarkWidth: PropTypes.number, + labelStyle: PropTypes.object, + markGap: PropTypes.number, onItemClick: PropTypes.func, + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx index 2c37579b58818..104cfa8b452cb 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx @@ -11,9 +11,9 @@ import { useDrawingArea } from '../hooks'; import { useSeries } from '../hooks/useSeries'; import { LegendPlacement } from './legend.types'; -export type ChartsLegendPropsBase = Pick< - Omit, - 'classes' | 'hidden' | 'onItemClick' +export type ChartsLegendPropsBase = Omit< + LegendRendererProps, + keyof LegendPlacement | 'contextBuilder' | 'series' | 'seriesToDisplay' | 'drawingArea' > & LegendPlacement; @@ -114,6 +114,31 @@ ChartsLegend.propTypes = { * @default false */ hidden: PropTypes.bool, + /** + * Space between two legend items (in px). + * @default 10 + */ + itemGap: PropTypes.number, + /** + * Height of the item mark (in px). + * @default 20 + */ + itemMarkHeight: PropTypes.number, + /** + * Width of the item mark (in px). + * @default 20 + */ + itemMarkWidth: PropTypes.number, + /** + * Style applied to legend labels. + * @default theme.typography.subtitle1 + */ + labelStyle: PropTypes.object, + /** + * Space between the mark and the label (in px). + * @default 5 + */ + markGap: PropTypes.number, /** * Callback fired when a legend item is clicked. * @param {React.MouseEvent} event The click event. @@ -122,6 +147,20 @@ ChartsLegend.propTypes = { * @default undefined */ onItemClick: PropTypes.func, + /** + * Legend padding (in px). + * Can either be a single number, or an object with top, left, bottom, right properties. + * @default 10 + */ + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), /** * The position of the legend. */ diff --git a/packages/x-charts/src/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index 31b290380441a..8f937ecf3c492 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -253,7 +253,21 @@ LineChart.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, + itemGap: PropTypes.number, + itemMarkHeight: PropTypes.number, + itemMarkWidth: PropTypes.number, + labelStyle: PropTypes.object, + markGap: PropTypes.number, onItemClick: PropTypes.func, + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, diff --git a/packages/x-charts/src/PieChart/PieChart.tsx b/packages/x-charts/src/PieChart/PieChart.tsx index 06e6012662b87..ff6d44b1ec9eb 100644 --- a/packages/x-charts/src/PieChart/PieChart.tsx +++ b/packages/x-charts/src/PieChart/PieChart.tsx @@ -278,7 +278,21 @@ PieChart.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, + itemGap: PropTypes.number, + itemMarkHeight: PropTypes.number, + itemMarkWidth: PropTypes.number, + labelStyle: PropTypes.object, + markGap: PropTypes.number, onItemClick: PropTypes.func, + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index a863f9e70e206..7fc8d6bb3bcf1 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -228,7 +228,21 @@ ScatterChart.propTypes = { classes: PropTypes.object, direction: PropTypes.oneOf(['column', 'row']), hidden: PropTypes.bool, + itemGap: PropTypes.number, + itemMarkHeight: PropTypes.number, + itemMarkWidth: PropTypes.number, + labelStyle: PropTypes.object, + markGap: PropTypes.number, onItemClick: PropTypes.func, + padding: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.shape({ + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + top: PropTypes.number, + }), + ]), position: PropTypes.shape({ horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, From 98bd4508648823e6dc5f7caa13dd38eb1928cbb0 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 29 Aug 2024 21:11:48 +0200 Subject: [PATCH 18/25] Fix order --- packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx index 685ecc68d4c21..d2d52b416c8a2 100644 --- a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx +++ b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx @@ -25,14 +25,14 @@ import { ZoomSetup } from '../context/ZoomProvider/ZoomSetup'; import { useZoom } from '../context/ZoomProvider/useZoom'; import { ZoomProps } from '../context/ZoomProvider'; -function LinePlotZoom(props: LinePlotProps) { +function AreaPlotZoom(props: AreaPlotProps) { const { isInteracting } = useZoom(); - return ; + return ; } -function AreaPlotZoom(props: AreaPlotProps) { +function LinePlotZoom(props: LinePlotProps) { const { isInteracting } = useZoom(); - return ; + return ; } function MarkPlotZoom(props: MarkPlotProps) { From 73197d5e430c5620459b297cb01b75c0a0bc33f5 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 29 Aug 2024 21:55:16 +0200 Subject: [PATCH 19/25] Remove need to pass context builder --- .../src/ChartsLegend/DefaultChartsLegend.tsx | 10 +++++++--- packages/x-charts/src/ChartsLegend/LegendPerItem.tsx | 12 +++--------- .../src/ChartsLegend/PiecewiseColorLegend.tsx | 9 +++++++-- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx index 16f4c1c8ea4d6..5ac263e174b0d 100644 --- a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx @@ -15,7 +15,7 @@ const seriesContextBuilder = (context: LegendItemConfig): SeriesLegendItemContex }) as const; export interface LegendRendererProps - extends Omit { + extends Omit { series: FormattedSeries; seriesToDisplay: LegendPerItemProps['itemsToDisplay']; /** @@ -37,13 +37,17 @@ export interface LegendRendererProps } function DefaultChartsLegend(props: LegendRendererProps) { - const { drawingArea, seriesToDisplay, ...other } = props; + const { drawingArea, seriesToDisplay, onItemClick, ...other } = props; return ( onItemClick(e, seriesContextBuilder(seriesToDisplay[i]), i) + : undefined + } /> ); } diff --git a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx index 1122da33637e0..0ee44596b52e8 100644 --- a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx +++ b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx @@ -5,7 +5,7 @@ import { DrawingArea } from '../context/DrawingProvider'; import { ChartsTextStyle } from '../ChartsText'; import { CardinalDirections } from '../models/layout'; import { getWordsByLines } from '../internals/getWordsByLines'; -import { GetItemSpaceType, LegendItemConfig, LegendItemContext } from './chartsLegend.types'; +import { GetItemSpaceType, LegendItemConfig } from './chartsLegend.types'; import { legendItemPlacements } from './legendItemsPlacement'; import { useDrawingArea } from '../hooks/useDrawingArea'; import { AnchorPosition, Direction, LegendPlacement } from './legend.types'; @@ -74,12 +74,7 @@ export interface LegendPerItemProps * @default false */ hidden?: boolean; - contextBuilder: (context: LegendItemConfig) => LegendItemContext; - onItemClick?: ( - event: React.MouseEvent, - legendItem: any, - index: number, - ) => void; + onItemClick?: (event: React.MouseEvent, index: number) => void; } /** @@ -122,7 +117,6 @@ export function LegendPerItem(props: LegendPerItemProps) { padding: paddingProps = 10, labelStyle: inLabelStyle, onItemClick, - contextBuilder, } = props; const theme = useTheme(); const drawingArea = useDrawingArea(); @@ -221,7 +215,7 @@ export function LegendPerItem(props: LegendPerItemProps) { markGap={markGap} labelStyle={labelStyle} classes={classes} - onClick={(e) => onItemClick?.(e, contextBuilder(item), i)} + onClick={onItemClick ? (e) => onItemClick(e, i) : undefined} /> ))} diff --git a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx index 95b06f608c8fe..5b6eaeb8c0bda 100644 --- a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx @@ -19,7 +19,7 @@ function defaultLabelFormatter(params: PiecewiseLabelFormatterParams) { export interface PiecewiseColorLegendProps extends ColorLegendSelector, - Omit { + Omit { /** * Hide the first item of the legend, corresponding to the [-infinity, min] piece. * @default false @@ -66,6 +66,7 @@ function PiecewiseColorLegend(props: PiecewiseColorLegendProps) { hideFirst, hideLast, labelFormatter = defaultLabelFormatter, + onItemClick, ...other } = props; @@ -118,7 +119,11 @@ function PiecewiseColorLegend(props: PiecewiseColorLegendProps) { onItemClick(e, piecewiseColorContextBuilder(itemsToDisplay[i]), i) + : undefined + } /> ); } From 2f8793752c64c5a0fc9910ae3636770a50f81b5f Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Mon, 2 Sep 2024 17:05:56 +0200 Subject: [PATCH 20/25] Remove hidden from piecewise --- docs/pages/x/api/charts/piecewise-color-legend.json | 1 - .../piecewise-color-legend/piecewise-color-legend.json | 1 - packages/x-charts/src/ChartsLegend/LegendPerItem.tsx | 5 ----- packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx | 5 ----- 4 files changed, 12 deletions(-) diff --git a/docs/pages/x/api/charts/piecewise-color-legend.json b/docs/pages/x/api/charts/piecewise-color-legend.json index 75feb96aaf546..28b485ad9374e 100644 --- a/docs/pages/x/api/charts/piecewise-color-legend.json +++ b/docs/pages/x/api/charts/piecewise-color-legend.json @@ -20,7 +20,6 @@ "default": "The first axis item." }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "hidden": { "type": { "name": "bool" }, "default": "false" }, "hideFirst": { "type": { "name": "bool" }, "default": "false" }, "hideLast": { "type": { "name": "bool" }, "default": "false" }, "itemGap": { "type": { "name": "number" }, "default": "10" }, diff --git a/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json b/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json index a804d3089d3cb..eb233fb379f1f 100644 --- a/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json +++ b/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json @@ -11,7 +11,6 @@ "direction": { "description": "The direction of the legend layout. The default depends on the chart." }, - "hidden": { "description": "Set to true to hide the legend." }, "hideFirst": { "description": "Hide the first item of the legend, corresponding to the [-infinity, min] piece." }, diff --git a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx index 8c4dfd03bf69b..d8e8be1bf6cbd 100644 --- a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx +++ b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx @@ -69,11 +69,6 @@ export interface LegendPerItemProps * @default 10 */ padding?: number | Partial>; - /** - * Set to true to hide the legend. - * @default false - */ - hidden?: boolean; onItemClick?: (event: React.MouseEvent, index: number) => void; } diff --git a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx index 5b6eaeb8c0bda..999f9314abb30 100644 --- a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx @@ -152,11 +152,6 @@ PiecewiseColorLegend.propTypes = { * The default depends on the chart. */ direction: PropTypes.oneOf(['column', 'row']).isRequired, - /** - * Set to true to hide the legend. - * @default false - */ - hidden: PropTypes.bool, /** * Hide the first item of the legend, corresponding to the [-infinity, min] piece. * @default false From c9452f9145b1a902c747cc172d4dd64241d9c552 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Mon, 2 Sep 2024 19:45:10 +0200 Subject: [PATCH 21/25] Revert name change --- packages/x-charts/src/BarChart/legend.ts | 4 ++-- packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx | 4 ++-- packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx | 4 ++-- packages/x-charts/src/ChartsLegend/LegendPerItem.tsx | 4 ++-- packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx | 4 ++-- packages/x-charts/src/ChartsLegend/chartsLegend.types.ts | 4 ++-- packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts | 4 ++-- packages/x-charts/src/LineChart/legend.ts | 4 ++-- packages/x-charts/src/PieChart/legend.ts | 4 ++-- packages/x-charts/src/ScatterChart/legend.ts | 4 ++-- .../src/context/PluginProvider/SeriesFormatter.types.ts | 4 ++-- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/x-charts/src/BarChart/legend.ts b/packages/x-charts/src/BarChart/legend.ts index 6f1ba3d8c86bd..e2ee7ae8c7e92 100644 --- a/packages/x-charts/src/BarChart/legend.ts +++ b/packages/x-charts/src/BarChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItemConfig } from '../ChartsLegend/chartsLegend.types'; +import { LegendItemParams } from '../ChartsLegend/chartsLegend.types'; import { LegendGetter } from '../context/PluginProvider'; import { getLabel } from '../internals/getLabel'; @@ -19,7 +19,7 @@ const legendGetter: LegendGetter<'bar'> = (params) => { }); return acc; - }, [] as LegendItemConfig[]); + }, [] as LegendItemParams[]); }; export default legendGetter; diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx index 85a13d0673eae..51d8b151fc572 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx @@ -2,10 +2,10 @@ import * as React from 'react'; import clsx from 'clsx'; import { useRtl } from '@mui/system/RtlProvider'; import { ChartsText, ChartsTextStyle } from '../ChartsText'; -import { LegendItemConfig } from './chartsLegend.types'; +import { LegendItemParams } from './chartsLegend.types'; import { ChartsLegendClasses } from './chartsLegendClasses'; -export interface ChartsLegendItemProps extends LegendItemConfig { +export interface ChartsLegendItemProps extends LegendItemParams { positionY: number; label: string; positionX: number; diff --git a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx index bac0c2f2a7f71..b789313b215e3 100644 --- a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx @@ -3,9 +3,9 @@ import PropTypes from 'prop-types'; import { FormattedSeries } from '../context/SeriesProvider'; import { LegendPerItem, LegendPerItemProps } from './LegendPerItem'; import { DrawingArea } from '../context/DrawingProvider'; -import { LegendItemConfig, SeriesLegendItemContext } from './chartsLegend.types'; +import { LegendItemParams, SeriesLegendItemContext } from './chartsLegend.types'; -const seriesContextBuilder = (context: LegendItemConfig): SeriesLegendItemContext => +const seriesContextBuilder = (context: LegendItemParams): SeriesLegendItemContext => ({ type: 'series', color: context.color, diff --git a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx index d8e8be1bf6cbd..ce4d5e863d335 100644 --- a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx +++ b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx @@ -5,7 +5,7 @@ import { DrawingArea } from '../context/DrawingProvider'; import { ChartsTextStyle } from '../ChartsText'; import { CardinalDirections } from '../models/layout'; import { getWordsByLines } from '../internals/getWordsByLines'; -import { GetItemSpaceType, LegendItemConfig } from './chartsLegend.types'; +import { GetItemSpaceType, LegendItemParams } from './chartsLegend.types'; import { legendItemPlacements } from './legendItemsPlacement'; import { useDrawingArea } from '../hooks/useDrawingArea'; import { AnchorPosition, Direction, LegendPlacement } from './legend.types'; @@ -33,7 +33,7 @@ export interface LegendPerItemProps /** * The ordered array of item to display in the legend. */ - itemsToDisplay: LegendItemConfig[]; + itemsToDisplay: LegendItemParams[]; /** * Override or extend the styles applied to the component. */ diff --git a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx index 999f9314abb30..7565990ab912a 100644 --- a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx @@ -5,7 +5,7 @@ import { useAxis } from './useAxis'; import { ColorLegendSelector, PiecewiseLabelFormatterParams } from './legend.types'; import { LegendPerItem, LegendPerItemProps } from './LegendPerItem'; import { notNull } from '../internals/notNull'; -import { LegendItemConfig, PiecewiseColorLegendItemContext } from './chartsLegend.types'; +import { LegendItemParams, PiecewiseColorLegendItemContext } from './chartsLegend.types'; function defaultLabelFormatter(params: PiecewiseLabelFormatterParams) { if (params.min === null) { @@ -50,7 +50,7 @@ export interface PiecewiseColorLegendProps ) => void; } -const piecewiseColorContextBuilder = (context: LegendItemConfig): PiecewiseColorLegendItemContext => +const piecewiseColorContextBuilder = (context: LegendItemParams): PiecewiseColorLegendItemContext => ({ type: 'piecewiseColor', color: context.color, diff --git a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts index ed5ad0391ae55..aae01465d0b89 100644 --- a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts +++ b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts @@ -13,7 +13,7 @@ interface LegendItemContextBase { label: string; } -export interface LegendItemConfig +export interface LegendItemParams extends Partial>, Partial>, LegendItemContextBase { @@ -62,7 +62,7 @@ export interface PiecewiseColorLegendItemContext extends LegendItemContextBase { export type LegendItemContext = SeriesLegendItemContext | PiecewiseColorLegendItemContext; -export interface LegendItemWithPosition extends LegendItemConfig { +export interface LegendItemWithPosition extends LegendItemParams { positionX: number; positionY: number; innerHeight: number; diff --git a/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts b/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts index ffaf941e67c49..f482e3b9a244c 100644 --- a/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts +++ b/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts @@ -1,8 +1,8 @@ import { ChartsTextStyle } from '../ChartsText'; -import { GetItemSpaceType, LegendItemConfig, LegendItemWithPosition } from './chartsLegend.types'; +import { GetItemSpaceType, LegendItemParams, LegendItemWithPosition } from './chartsLegend.types'; export function legendItemPlacements( - itemsToDisplay: LegendItemConfig[], + itemsToDisplay: LegendItemParams[], getItemSpace: GetItemSpaceType, labelStyle: ChartsTextStyle, direction: string, diff --git a/packages/x-charts/src/LineChart/legend.ts b/packages/x-charts/src/LineChart/legend.ts index d32d368540ea8..28d3ae4165461 100644 --- a/packages/x-charts/src/LineChart/legend.ts +++ b/packages/x-charts/src/LineChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItemConfig } from '../ChartsLegend/chartsLegend.types'; +import { LegendItemParams } from '../ChartsLegend/chartsLegend.types'; import { getLabel } from '../internals/getLabel'; import { LegendGetter } from '../context/PluginProvider'; @@ -18,7 +18,7 @@ const legendGetter: LegendGetter<'line'> = (params) => { label: formattedLabel, }); return acc; - }, [] as LegendItemConfig[]); + }, [] as LegendItemParams[]); }; export default legendGetter; diff --git a/packages/x-charts/src/PieChart/legend.ts b/packages/x-charts/src/PieChart/legend.ts index f01bf4e728241..5ba715ad26a21 100644 --- a/packages/x-charts/src/PieChart/legend.ts +++ b/packages/x-charts/src/PieChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItemConfig } from '../ChartsLegend/chartsLegend.types'; +import { LegendItemParams } from '../ChartsLegend/chartsLegend.types'; import { getLabel } from '../internals/getLabel'; import { LegendGetter } from '../context/PluginProvider'; @@ -20,7 +20,7 @@ const legendGetter: LegendGetter<'pie'> = (params) => { }); }); return acc; - }, [] as LegendItemConfig[]); + }, [] as LegendItemParams[]); }; export default legendGetter; diff --git a/packages/x-charts/src/ScatterChart/legend.ts b/packages/x-charts/src/ScatterChart/legend.ts index a466d2c8dd8cb..6a113642caf2b 100644 --- a/packages/x-charts/src/ScatterChart/legend.ts +++ b/packages/x-charts/src/ScatterChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItemConfig } from '../ChartsLegend/chartsLegend.types'; +import { LegendItemParams } from '../ChartsLegend/chartsLegend.types'; import { getLabel } from '../internals/getLabel'; import { LegendGetter } from '../context/PluginProvider'; @@ -18,7 +18,7 @@ const legendGetter: LegendGetter<'scatter'> = (params) => { label: formattedLabel, }); return acc; - }, [] as LegendItemConfig[]); + }, [] as LegendItemParams[]); }; export default legendGetter; diff --git a/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts b/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts index cfa7eceb624b0..6462da81a53b8 100644 --- a/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts +++ b/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts @@ -6,7 +6,7 @@ import type { } from '../../models/seriesType/config'; import type { SeriesId } from '../../models/seriesType/common'; import type { StackingGroupsType } from '../../internals/stackSeries'; -import type { LegendItemConfig } from '../../ChartsLegend/chartsLegend.types'; +import type { LegendItemParams } from '../../ChartsLegend/chartsLegend.types'; export type SeriesFormatterParams = { series: Record; @@ -29,7 +29,7 @@ export type SeriesFormatter = ( export type LegendGetter = ( series: SeriesFormatterResult, -) => LegendItemConfig[]; +) => LegendItemParams[]; export type SeriesFormatterConfig = { // TODO replace the function type by Formatter From 1e0fe2c79dd7f96e337a1851fe93f73db29bd395 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 4 Sep 2024 10:55:21 +0200 Subject: [PATCH 22/25] Remove default undefined --- docs/pages/x/api/charts/charts-legend.json | 1 - docs/pages/x/api/charts/default-charts-legend.json | 1 - docs/pages/x/api/charts/piecewise-color-legend.json | 1 - packages/x-charts/src/ChartsLegend/ChartsLegend.tsx | 1 - packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx | 2 -- packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx | 2 -- 6 files changed, 8 deletions(-) diff --git a/docs/pages/x/api/charts/charts-legend.json b/docs/pages/x/api/charts/charts-legend.json index 5abdc1852b6a8..8e58410c7fd64 100644 --- a/docs/pages/x/api/charts/charts-legend.json +++ b/docs/pages/x/api/charts/charts-legend.json @@ -10,7 +10,6 @@ "markGap": { "type": { "name": "number" }, "default": "5" }, "onItemClick": { "type": { "name": "func" }, - "default": "undefined", "signature": { "type": "function(event: React.MouseEvent, legendItem: SeriesLegendItemContext, index: number) => void", "describedArgs": ["event", "legendItem", "index"] diff --git a/docs/pages/x/api/charts/default-charts-legend.json b/docs/pages/x/api/charts/default-charts-legend.json index 1cb15587029bb..1c55aa4c7626f 100644 --- a/docs/pages/x/api/charts/default-charts-legend.json +++ b/docs/pages/x/api/charts/default-charts-legend.json @@ -20,7 +20,6 @@ "markGap": { "type": { "name": "number" }, "default": "5" }, "onItemClick": { "type": { "name": "func" }, - "default": "undefined", "signature": { "type": "function(event: React.MouseEvent, legendItem: SeriesLegendItemContext, index: number) => void", "describedArgs": ["event", "legendItem", "index"] diff --git a/docs/pages/x/api/charts/piecewise-color-legend.json b/docs/pages/x/api/charts/piecewise-color-legend.json index 28b485ad9374e..18c41729f90c5 100644 --- a/docs/pages/x/api/charts/piecewise-color-legend.json +++ b/docs/pages/x/api/charts/piecewise-color-legend.json @@ -37,7 +37,6 @@ "markGap": { "type": { "name": "number" }, "default": "5" }, "onItemClick": { "type": { "name": "func" }, - "default": "undefined", "signature": { "type": "function(event: React.MouseEvent, legendItem: PiecewiseColorLegendItemContext, index: number) => void", "describedArgs": ["event", "legendItem", "index"] diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx index 8d4128808053a..9bdaa53a48523 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx @@ -144,7 +144,6 @@ ChartsLegend.propTypes = { * @param {React.MouseEvent} event The click event. * @param {SeriesLegendItemContext} legendItem The legend item data. * @param {number} index The index of the clicked legend item. - * @default undefined */ onItemClick: PropTypes.func, /** diff --git a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx index b789313b215e3..2c2cd74c94d00 100644 --- a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx @@ -27,7 +27,6 @@ export interface LegendRendererProps * @param {React.MouseEvent} event The click event. * @param {SeriesLegendItemContext} legendItem The legend item data. * @param {number} index The index of the clicked legend item. - * @default undefined */ onItemClick?: ( event: React.MouseEvent, @@ -121,7 +120,6 @@ DefaultChartsLegend.propTypes = { * @param {React.MouseEvent} event The click event. * @param {SeriesLegendItemContext} legendItem The legend item data. * @param {number} index The index of the clicked legend item. - * @default undefined */ onItemClick: PropTypes.func, /** diff --git a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx index 7565990ab912a..22d3b689ce347 100644 --- a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx @@ -41,7 +41,6 @@ export interface PiecewiseColorLegendProps * @param {React.MouseEvent} event The click event. * @param {PiecewiseColorLegendItemContext} legendItem The legend item data. * @param {number} index The index of the clicked legend item. - * @default undefined */ onItemClick?: ( event: React.MouseEvent, @@ -198,7 +197,6 @@ PiecewiseColorLegend.propTypes = { * @param {React.MouseEvent} event The click event. * @param {PiecewiseColorLegendItemContext} legendItem The legend item data. * @param {number} index The index of the clicked legend item. - * @default undefined */ onItemClick: PropTypes.func, /** From d17ced2d1449fae5014a37b98e564eec8ad8c158 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 4 Sep 2024 10:55:30 +0200 Subject: [PATCH 23/25] Remove pie type ref --- packages/x-charts/src/ChartsLegend/chartsLegend.types.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts index aae01465d0b89..a1ef919c2a0bf 100644 --- a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts +++ b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts @@ -29,7 +29,6 @@ export interface SeriesLegendItemContext extends LegendItemContextBase { * The type of the legend item * - `series` is used for series legend item * - `piecewiseColor` is used for piecewise color legend item - * - `pie` is used for pie legend item */ type: 'series'; /** @@ -47,7 +46,6 @@ export interface PiecewiseColorLegendItemContext extends LegendItemContextBase { * The type of the legend item * - `series` is used for series legend item * - `piecewiseColor` is used for piecewise color legend item - * - `pie` is used for pie legend item */ type: 'piecewiseColor'; /** From ec96652dd0cae86dd5ac217746a93bf7e05b95a3 Mon Sep 17 00:00:00 2001 From: Jose C Quintas Jr Date: Wed, 4 Sep 2024 11:01:28 +0200 Subject: [PATCH 24/25] Apply suggestions from code review Co-authored-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Signed-off-by: Jose C Quintas Jr --- docs/data/charts/legend/legend.md | 6 +++--- packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/data/charts/legend/legend.md b/docs/data/charts/legend/legend.md index 8557dd708c939..208df12e253d7 100644 --- a/docs/data/charts/legend/legend.md +++ b/docs/data/charts/legend/legend.md @@ -115,17 +115,17 @@ labelFormatter = ({ min, max, formattedMin, formattedMax }) => string | null; ## Click event You can pass an `onItemClick` function to the `ChartsLegend` or `PiecewiseColorLegend` components to handle click events. - They both provide the following signature. ```js const clickHandler = ( - event, // The mouse event. + event, // The click event. context, // An object that identifies the clicked item. index, // The index of the clicked item. ) => {}; ``` -The `context` object contains different properties depending on the legend type. Click the legend items to see their content. +The `context` object contains different properties depending on the legend type. +Click the legend items to see their content. {{"demo": "LegendClickNoSnap.js"}} diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx index 51d8b151fc572..bf8521339daab 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx @@ -75,7 +75,7 @@ function ChartsLegendItem(props: ChartsLegendItemProps) { style={{ pointerEvents: 'none' }} /> Date: Thu, 5 Sep 2024 12:04:28 +0200 Subject: [PATCH 25/25] Make itemid optional --- packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx | 3 ++- packages/x-charts/src/ChartsLegend/chartsLegend.types.ts | 4 ++-- packages/x-charts/src/PieChart/legend.ts | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx index 2c2cd74c94d00..755a91d651b80 100644 --- a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx @@ -11,7 +11,7 @@ const seriesContextBuilder = (context: LegendItemParams): SeriesLegendItemContex color: context.color, label: context.label, seriesId: context.seriesId!, - itemId: context.id, + itemId: context.itemId, }) as const; export interface LegendRendererProps @@ -148,6 +148,7 @@ DefaultChartsLegend.propTypes = { PropTypes.shape({ color: PropTypes.string.isRequired, id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, + itemId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), label: PropTypes.string.isRequired, maxValue: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), minValue: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), diff --git a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts index a1ef919c2a0bf..a898c70aefbc6 100644 --- a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts +++ b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts @@ -14,7 +14,7 @@ interface LegendItemContextBase { } export interface LegendItemParams - extends Partial>, + extends Partial>, Partial>, LegendItemContextBase { /** @@ -38,7 +38,7 @@ export interface SeriesLegendItemContext extends LegendItemContextBase { /** * The identifier of the pie item */ - itemId: PieItemId; + itemId?: PieItemId; } export interface PiecewiseColorLegendItemContext extends LegendItemContextBase { diff --git a/packages/x-charts/src/PieChart/legend.ts b/packages/x-charts/src/PieChart/legend.ts index 5ba715ad26a21..4d39cdd7235e7 100644 --- a/packages/x-charts/src/PieChart/legend.ts +++ b/packages/x-charts/src/PieChart/legend.ts @@ -17,6 +17,7 @@ const legendGetter: LegendGetter<'pie'> = (params) => { seriesId, color: item.color, label: formattedLabel, + itemId: item.id, }); }); return acc;