From 9265cad5f4eead1d684f0723aed8a34b8864ecf4 Mon Sep 17 00:00:00 2001 From: "P. Esteves" Date: Wed, 31 Jan 2024 14:27:32 +0000 Subject: [PATCH 01/35] [DataGrid] Fix row reorder with cell selection (#11783) --- .../src/hooks/features/cellSelection/useGridCellSelection.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/grid/x-data-grid-premium/src/hooks/features/cellSelection/useGridCellSelection.ts b/packages/grid/x-data-grid-premium/src/hooks/features/cellSelection/useGridCellSelection.ts index 7d3d888d5d265..5877bfe51094c 100644 --- a/packages/grid/x-data-grid-premium/src/hooks/features/cellSelection/useGridCellSelection.ts +++ b/packages/grid/x-data-grid-premium/src/hooks/features/cellSelection/useGridCellSelection.ts @@ -22,6 +22,7 @@ import { gridClasses, gridFocusCellSelector, GridCellParams, + GRID_REORDER_COL_DEF, } from '@mui/x-data-grid-pro'; import { gridCellSelectionStateSelector } from './gridCellSelectionSelector'; import { GridCellSelectionApi } from './gridCellSelectionInterfaces'; @@ -221,6 +222,10 @@ export const useGridCellSelection = ( return; } + if (params.field === GRID_REORDER_COL_DEF.field) { + return; + } + const focusedCell = gridFocusCellSelector(apiRef); if (hasClickedValidCellForRangeSelection(params) && event.shiftKey && focusedCell) { event.preventDefault(); From 14fb94a875364f922fc471531374c0d2ed59b659 Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Wed, 31 Jan 2024 14:40:54 -0300 Subject: [PATCH 02/35] [docs] Add a general uplift to the changelog page (#11396) Signed-off-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Co-authored-by: alexandre Co-authored-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Co-authored-by: Jose Rodolfo Freitas --- docs/data/whats-new/WhatsNewLayoutNoSnap.js | 289 ------------- docs/data/whats-new/WhatsNewLayoutNoSnap.tsx | 297 -------------- .../WhatsNewLayoutNoSnap.tsx.preview | 7 - docs/data/whats-new/whats-new.md | 4 +- docs/src/modules/components/WhatsNewLayout.js | 381 ++++++++++++++++++ 5 files changed, 383 insertions(+), 595 deletions(-) delete mode 100644 docs/data/whats-new/WhatsNewLayoutNoSnap.js delete mode 100644 docs/data/whats-new/WhatsNewLayoutNoSnap.tsx delete mode 100644 docs/data/whats-new/WhatsNewLayoutNoSnap.tsx.preview create mode 100644 docs/src/modules/components/WhatsNewLayout.js diff --git a/docs/data/whats-new/WhatsNewLayoutNoSnap.js b/docs/data/whats-new/WhatsNewLayoutNoSnap.js deleted file mode 100644 index 58d0f9b2c82e2..0000000000000 --- a/docs/data/whats-new/WhatsNewLayoutNoSnap.js +++ /dev/null @@ -1,289 +0,0 @@ -import * as React from 'react'; -import Link from '@mui/material/Link'; -import List from '@mui/material/List'; -import ListItem from '@mui/material/ListItem'; -import Box from '@mui/material/Box'; -import Grid from '@mui/material/Grid'; -import Card from '@mui/material/Card'; -import CardActions from '@mui/material/CardActions'; -import CardContent from '@mui/material/CardContent'; -import Button from '@mui/material/Button'; -import Typography from '@mui/material/Typography'; -import { alpha } from '@mui/material/styles'; - -const blogs = [ - { - title: 'MUI X v6.18.x', - description: - 'New stable components, polished features, better performance, and more.', - announcementDate: 'Monday, Nov 13, 2023', - url: 'https://mui.com/blog/mui-x-end-v6-features/', - highlightList: [ - { - title: 'Charts - stable version', - url: 'https://mui.com/blog/mui-x-end-v6-features/#charts', - }, - { - title: 'Tree View - stable version', - url: 'https://mui.com/blog/mui-x-end-v6-features/#tree-view', - }, - { - title: 'Clearable date and time fields', - url: 'https://mui.com/blog/mui-x-end-v6-features/#clearable-field', - }, - { - title: 'Customization playgrounds for Date and Time Pickers', - url: 'https://mui.com/blog/mui-x-end-v6-features/#customization-playgrounds', - }, - { - title: 'Data Grid column autosizing', - url: 'https://mui.com/blog/mui-x-end-v6-features/#column-autosizing', - }, - { - title: 'Sparklines on Data Grid ', - url: 'https://mui.com/blog/mui-x-end-v6-features/#sparkline-as-a-column-type', - }, - ], - }, - { - title: 'MUI X v6.11.0', - description: 'A roundup of all new features since v6.0.0.', - announcementDate: 'Monday, Aug 14, 2023', - url: 'https://mui.com/blog/mui-x-mid-v6-features/', - highlightList: [ - { - title: 'Support for timezone on Date and Time Pickers', - url: 'https://mui.com/blog/mui-x-mid-v6-features/#support-for-time-zones', - }, - { - title: 'Digital Clock', - url: 'https://mui.com/blog/mui-x-mid-v6-features/#digital-clock', - }, - { - title: 'Filters on Data Grid column headers', - url: 'https://mui.com/blog/mui-x-mid-v6-features/#filter-on-column-headers', - }, - { - title: 'Copy and Paste on Data Grid', - url: 'https://mui.com/blog/mui-x-mid-v6-features/#copy-and-paste', - }, - { - title: 'Charts Alpha 🧪', - url: 'https://mui.com/blog/mui-x-mid-v6-features/#charts-alpha-version', - }, - { - title: 'TreeView migration from lab', - url: 'https://mui.com/blog/mui-x-mid-v6-features/#tree-view-is-moving-to-mui-x', - }, - ], - }, - { - title: 'MUI X v6.0.0', - description: - 'A new major is available, with many new features and improvements.', - announcementDate: 'Monday, Mar 06, 2023', - url: 'https://mui.com/blog/mui-x-v6/', - highlightList: [ - { - title: 'Date and time fields', - url: 'https://mui.com/blog/mui-x-v6/#fields-the-new-default-input-gt-for-pickers', - }, - { - title: 'Date Range shortcuts', - url: 'https://mui.com/blog/mui-x-v6/#shortcuts-for-picking-specific-dates-in-a-calendar', - }, - { - title: 'Improved layout customization', - url: 'https://mui.com/blog/mui-x-v6/#improved-layout-customization', - }, - { - title: 'Edit ranges with drag and drop', - url: 'https://mui.com/blog/mui-x-v6/#edit-date-ranges-with-drag-and-drop', - }, - { - title: 'New Column menu', - url: 'https://mui.com/blog/mui-x-v6/#improved-column-menu', - }, - { - title: 'ApiRef in community', - url: 'https://mui.com/blog/mui-x-v6/#apiref-moved-to-the-mit-community-version', - }, - { - title: 'Cell selection', - url: 'https://mui.com/blog/mui-x-v6/#cell-selection', - }, - ], - }, - { - title: 'Date Pickers v5.0.0', - description: - 'After some months of polishing in pre-releases, the Date Pickers finally get a stable.', - announcementDate: 'Monday, Sep 22, 2022', - url: 'https://mui.com/blog/date-pickers-stable-v5/', - highlightList: [ - { - title: 'Better APIs', - url: 'https://mui.com/blog/date-pickers-stable-v5/#better-apis-and-improved-customization', - }, - { - title: 'Easier customization', - url: 'https://mui.com/blog/date-pickers-stable-v5/#better-apis-and-improved-customization', - }, - { - title: 'Integrated localization', - url: 'https://mui.com/blog/date-pickers-stable-v5/#integrated-localization', - }, - ], - }, - { - title: 'Data Grid v5.15', - description: - 'This version brings an amazing set of new supported use cases with the Data Grid Premium.', - announcementDate: 'Monday, Aug 12, 2022', - url: 'https://mui.com/blog/aggregation-functions/', - highlightList: [ - { - title: 'Aggregation in summary rows and row groups', - url: 'https://mui.com/blog/aggregation-functions/#wait-what-is-an-aggregation-function', - }, - { - title: 'Row pinning', - url: 'https://mui.com/blog/aggregation-functions/#row-pinning', - }, - ], - }, - { - title: 'New Premium plan', - description: - 'Premium plan announcement, including the most advanced features for data analysis and management.', - announcementDate: 'Thursday, May 12, 2022', - url: 'https://mui.com/blog/premium-plan-release/', - highlightList: [ - { title: 'Row Grouping', url: '/x/react-data-grid/row-grouping/' }, - { title: 'Excel export', url: '/x/react-data-grid/export/#exported-rows' }, - ], - }, - { - title: 'MUI X v5.0.0', - description: 'A new virtualization engine, and improvements in several APIs.', - announcementDate: 'Monday, Nov 22, 2021', - url: 'https://mui.com/blog/mui-x-v5/', - highlightList: [ - { - title: 'New virtualization engine', - url: 'https://mui.com/blog/mui-x-v5/#a-new-virtualization-engine', - }, - { - title: 'Improved state management', - url: 'https://mui.com/blog/mui-x-v5/#improved-state-management', - }, - { - title: 'Simplified style customization', - url: 'https://mui.com/blog/mui-x-v5/#simplified-style-customization', - }, - ], - }, -]; - -function BlogCard(props) { - return ( - - theme.palette.mode === 'dark' - ? 'rgba(0, 27, 55, 0.2)' - : `${alpha(theme.palette.grey[50], 0.4)}`, - borderColor: 'divider', - [`& .MuiTypography-root`]: { - fontFamily: 'IBM Plex Sans', - }, - }} - component="article" - variant="outlined" - > - - - - {props.blog.announcementDate} - - - {props.blog.title} - - - - - - {props.blog.description} - - - - {props.blog.highlightList.map((item) => ( - - - {item.title} - - - ))} - - - - - - - - ); -} - -export default function WhatsNewLayoutNoSnap() { - return ( - - {blogs.map((blog) => ( - - - - ))} - - ); -} diff --git a/docs/data/whats-new/WhatsNewLayoutNoSnap.tsx b/docs/data/whats-new/WhatsNewLayoutNoSnap.tsx deleted file mode 100644 index 3e293bb688652..0000000000000 --- a/docs/data/whats-new/WhatsNewLayoutNoSnap.tsx +++ /dev/null @@ -1,297 +0,0 @@ -import * as React from 'react'; -import Link from '@mui/material/Link'; -import List from '@mui/material/List'; -import ListItem from '@mui/material/ListItem'; -import Box from '@mui/material/Box'; -import Grid from '@mui/material/Grid'; -import Card from '@mui/material/Card'; -import CardActions from '@mui/material/CardActions'; -import CardContent from '@mui/material/CardContent'; -import Button from '@mui/material/Button'; -import Typography from '@mui/material/Typography'; -import { alpha } from '@mui/material/styles'; - -type Blog = { - title: string; - announcementDate: string; - description: string; - url: string; - highlightList: { title: string; url: string }[]; -}; - -const blogs: Blog[] = [ - { - title: 'MUI X v6.18.x', - description: - 'New stable components, polished features, better performance, and more.', - announcementDate: 'Monday, Nov 13, 2023', - url: 'https://mui.com/blog/mui-x-end-v6-features/', - highlightList: [ - { - title: 'Charts - stable version', - url: 'https://mui.com/blog/mui-x-end-v6-features/#charts', - }, - { - title: 'Tree View - stable version', - url: 'https://mui.com/blog/mui-x-end-v6-features/#tree-view', - }, - { - title: 'Clearable date and time fields', - url: 'https://mui.com/blog/mui-x-end-v6-features/#clearable-field', - }, - { - title: 'Customization playgrounds for Date and Time Pickers', - url: 'https://mui.com/blog/mui-x-end-v6-features/#customization-playgrounds', - }, - { - title: 'Data Grid column autosizing', - url: 'https://mui.com/blog/mui-x-end-v6-features/#column-autosizing', - }, - { - title: 'Sparklines on Data Grid ', - url: 'https://mui.com/blog/mui-x-end-v6-features/#sparkline-as-a-column-type', - }, - ], - }, - { - title: 'MUI X v6.11.0', - description: 'A roundup of all new features since v6.0.0.', - announcementDate: 'Monday, Aug 14, 2023', - url: 'https://mui.com/blog/mui-x-mid-v6-features/', - highlightList: [ - { - title: 'Support for timezone on Date and Time Pickers', - url: 'https://mui.com/blog/mui-x-mid-v6-features/#support-for-time-zones', - }, - { - title: 'Digital Clock', - url: 'https://mui.com/blog/mui-x-mid-v6-features/#digital-clock', - }, - { - title: 'Filters on Data Grid column headers', - url: 'https://mui.com/blog/mui-x-mid-v6-features/#filter-on-column-headers', - }, - { - title: 'Copy and Paste on Data Grid', - url: 'https://mui.com/blog/mui-x-mid-v6-features/#copy-and-paste', - }, - { - title: 'Charts Alpha 🧪', - url: 'https://mui.com/blog/mui-x-mid-v6-features/#charts-alpha-version', - }, - { - title: 'TreeView migration from lab', - url: 'https://mui.com/blog/mui-x-mid-v6-features/#tree-view-is-moving-to-mui-x', - }, - ], - }, - { - title: 'MUI X v6.0.0', - description: - 'A new major is available, with many new features and improvements.', - announcementDate: 'Monday, Mar 06, 2023', - url: 'https://mui.com/blog/mui-x-v6/', - highlightList: [ - { - title: 'Date and time fields', - url: 'https://mui.com/blog/mui-x-v6/#fields-the-new-default-input-gt-for-pickers', - }, - { - title: 'Date Range shortcuts', - url: 'https://mui.com/blog/mui-x-v6/#shortcuts-for-picking-specific-dates-in-a-calendar', - }, - { - title: 'Improved layout customization', - url: 'https://mui.com/blog/mui-x-v6/#improved-layout-customization', - }, - { - title: 'Edit ranges with drag and drop', - url: 'https://mui.com/blog/mui-x-v6/#edit-date-ranges-with-drag-and-drop', - }, - { - title: 'New Column menu', - url: 'https://mui.com/blog/mui-x-v6/#improved-column-menu', - }, - { - title: 'ApiRef in community', - url: 'https://mui.com/blog/mui-x-v6/#apiref-moved-to-the-mit-community-version', - }, - { - title: 'Cell selection', - url: 'https://mui.com/blog/mui-x-v6/#cell-selection', - }, - ], - }, - { - title: 'Date Pickers v5.0.0', - description: - 'After some months of polishing in pre-releases, the Date Pickers finally get a stable.', - announcementDate: 'Monday, Sep 22, 2022', - url: 'https://mui.com/blog/date-pickers-stable-v5/', - highlightList: [ - { - title: 'Better APIs', - url: 'https://mui.com/blog/date-pickers-stable-v5/#better-apis-and-improved-customization', - }, - { - title: 'Easier customization', - url: 'https://mui.com/blog/date-pickers-stable-v5/#better-apis-and-improved-customization', - }, - { - title: 'Integrated localization', - url: 'https://mui.com/blog/date-pickers-stable-v5/#integrated-localization', - }, - ], - }, - { - title: 'Data Grid v5.15', - description: - 'This version brings an amazing set of new supported use cases with the Data Grid Premium.', - announcementDate: 'Monday, Aug 12, 2022', - url: 'https://mui.com/blog/aggregation-functions/', - highlightList: [ - { - title: 'Aggregation in summary rows and row groups', - url: 'https://mui.com/blog/aggregation-functions/#wait-what-is-an-aggregation-function', - }, - { - title: 'Row pinning', - url: 'https://mui.com/blog/aggregation-functions/#row-pinning', - }, - ], - }, - { - title: 'New Premium plan', - description: - 'Premium plan announcement, including the most advanced features for data analysis and management.', - announcementDate: 'Thursday, May 12, 2022', - url: 'https://mui.com/blog/premium-plan-release/', - highlightList: [ - { title: 'Row Grouping', url: '/x/react-data-grid/row-grouping/' }, - { title: 'Excel export', url: '/x/react-data-grid/export/#exported-rows' }, - ], - }, - { - title: 'MUI X v5.0.0', - description: 'A new virtualization engine, and improvements in several APIs.', - announcementDate: 'Monday, Nov 22, 2021', - url: 'https://mui.com/blog/mui-x-v5/', - highlightList: [ - { - title: 'New virtualization engine', - url: 'https://mui.com/blog/mui-x-v5/#a-new-virtualization-engine', - }, - { - title: 'Improved state management', - url: 'https://mui.com/blog/mui-x-v5/#improved-state-management', - }, - { - title: 'Simplified style customization', - url: 'https://mui.com/blog/mui-x-v5/#simplified-style-customization', - }, - ], - }, -]; - -function BlogCard(props: { blog: Blog }) { - return ( - - theme.palette.mode === 'dark' - ? 'rgba(0, 27, 55, 0.2)' - : `${alpha(theme.palette.grey[50], 0.4)}`, - borderColor: 'divider', - [`& .MuiTypography-root`]: { - fontFamily: 'IBM Plex Sans', - }, - }} - component="article" - variant="outlined" - > - - - - {props.blog.announcementDate} - - - {props.blog.title} - - - - - - {props.blog.description} - - - - {props.blog.highlightList.map((item) => ( - - - {item.title} - - - ))} - - - - - - - - ); -} - -export default function WhatsNewLayoutNoSnap() { - return ( - - {blogs.map((blog) => ( - - - - ))} - - ); -} diff --git a/docs/data/whats-new/WhatsNewLayoutNoSnap.tsx.preview b/docs/data/whats-new/WhatsNewLayoutNoSnap.tsx.preview deleted file mode 100644 index b701ffab9b3b5..0000000000000 --- a/docs/data/whats-new/WhatsNewLayoutNoSnap.tsx.preview +++ /dev/null @@ -1,7 +0,0 @@ - - {blogs.map((blog) => ( - - - - ))} - \ No newline at end of file diff --git a/docs/data/whats-new/whats-new.md b/docs/data/whats-new/whats-new.md index 50f506e6dc227..4564264752179 100644 --- a/docs/data/whats-new/whats-new.md +++ b/docs/data/whats-new/whats-new.md @@ -1,5 +1,5 @@ # What's new in MUI X -

Discover what's new in the latest versions.

+

Discover all the latest new features and other highlights.

-{{"demo": "WhatsNewLayoutNoSnap.js", "hideToolbar": true, "bg": "inline"}} +{{"component": "modules/components/WhatsNewLayout.js"}} diff --git a/docs/src/modules/components/WhatsNewLayout.js b/docs/src/modules/components/WhatsNewLayout.js new file mode 100644 index 0000000000000..d274e3fa4a40e --- /dev/null +++ b/docs/src/modules/components/WhatsNewLayout.js @@ -0,0 +1,381 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import Link from '@mui/material/Link'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import Box from '@mui/material/Box'; +import Card from '@mui/material/Card'; +import Divider from '@mui/material/Divider'; +import Button from '@mui/material/Button'; +import Typography from '@mui/material/Typography'; +import Timeline from '@mui/lab/Timeline'; +import TimelineItem from '@mui/lab/TimelineItem'; +import TimelineSeparator from '@mui/lab/TimelineSeparator'; +import TimelineConnector from '@mui/lab/TimelineConnector'; +import TimelineContent from '@mui/lab/TimelineContent'; +import TimelineDot from '@mui/lab/TimelineDot'; +import TimelineOppositeContent from '@mui/lab/TimelineOppositeContent'; + +const entries = [ + { + title: 'MUI X v6.18.x', + description: 'New stable components, polished features, better performance, and more.', + date: new Date(2023, 10, 13), + url: 'https://mui.com/blog/mui-x-end-v6-features/', + highlightList: [ + { + title: 'Charts goes stable!', + url: 'https://mui.com/blog/mui-x-end-v6-features/#charts', + }, + { + title: 'Tree View goes stable!', + url: 'https://mui.com/blog/mui-x-end-v6-features/#tree-view', + }, + { + title: 'Clearable Date and Time fields', + url: 'https://mui.com/blog/mui-x-end-v6-features/#clearable-field', + }, + { + title: 'Customization playgrounds for Date and Time Pickers', + url: 'https://mui.com/blog/mui-x-end-v6-features/#customization-playgrounds', + }, + { + title: 'Data Grid column autosizing', + url: 'https://mui.com/blog/mui-x-end-v6-features/#column-autosizing', + }, + { + title: 'Sparkline Charts on the Data Grid ', + url: 'https://mui.com/blog/mui-x-end-v6-features/#sparkline-as-a-column-type', + }, + ], + }, + { + title: 'MUI X v6.11.0', + description: 'A roundup of all new features since v6.0.0.', + date: new Date(2023, 7, 14), + url: 'https://mui.com/blog/mui-x-mid-v6-features/', + highlightList: [ + { + title: 'Support for timezone on Date and Time Pickers', + url: 'https://mui.com/blog/mui-x-mid-v6-features/#support-for-time-zones', + }, + { + title: 'Digital Clock', + url: 'https://mui.com/blog/mui-x-mid-v6-features/#digital-clock', + }, + { + title: 'Data Grid: Column header filters', + url: 'https://mui.com/blog/mui-x-mid-v6-features/#filter-on-column-headers', + }, + { + title: 'Data Grid: Copy and paste', + url: 'https://mui.com/blog/mui-x-mid-v6-features/#copy-and-paste', + }, + { + title: 'Charts move to Alpha 🧪', + url: 'https://mui.com/blog/mui-x-mid-v6-features/#charts-alpha-version', + }, + { + title: 'TreeView migration from the lab', + url: 'https://mui.com/blog/mui-x-mid-v6-features/#tree-view-is-moving-to-mui-x', + }, + ], + }, + { + title: 'MUI X v6.0.0', + description: 'A new major is available, with many new features and improvements.', + date: new Date(2023, 2, 6), + url: 'https://mui.com/blog/mui-x-v6/', + highlightList: [ + { + title: 'Date and Time Pickers', + url: 'https://mui.com/blog/mui-x-v6/#fields-the-new-default-input-gt-for-pickers', + }, + { + title: 'Date Range shortcuts', + url: 'https://mui.com/blog/mui-x-v6/#shortcuts-for-picking-specific-dates-in-a-calendar', + }, + { + title: 'Improved layout customization', + url: 'https://mui.com/blog/mui-x-v6/#improved-layout-customization', + }, + { + title: 'Edit ranges with drag and drop', + url: 'https://mui.com/blog/mui-x-v6/#edit-date-ranges-with-drag-and-drop', + }, + { + title: 'New Column menu', + url: 'https://mui.com/blog/mui-x-v6/#improved-column-menu', + }, + { + title: 'ApiRef in the community version', + url: 'https://mui.com/blog/mui-x-v6/#apiref-moved-to-the-mit-community-version', + }, + { + title: 'Cell selection', + url: 'https://mui.com/blog/mui-x-v6/#cell-selection', + }, + ], + }, + { + title: 'Date Pickers v5.0.0', + description: + 'After some months of polishing in pre-releases, the Date Pickers finally get a stable.', + date: new Date(2022, 8, 22), + url: 'https://mui.com/blog/date-pickers-stable-v5/', + highlightList: [ + { + title: 'Better APIs', + url: 'https://mui.com/blog/date-pickers-stable-v5/#better-apis-and-improved-customization', + }, + { + title: 'Easier customization', + url: 'https://mui.com/blog/date-pickers-stable-v5/#better-apis-and-improved-customization', + }, + { + title: 'Integrated localization', + url: 'https://mui.com/blog/date-pickers-stable-v5/#integrated-localization', + }, + ], + }, + { + title: 'Data Grid v5.15', + description: + 'This version brings an amazing set of new supported use cases with the Data Grid Premium.', + date: new Date(2022, 7, 12), + url: 'https://mui.com/blog/aggregation-functions/', + highlightList: [ + { + title: 'Aggregation in summary rows and row groups', + url: 'https://mui.com/blog/aggregation-functions/#wait-what-is-an-aggregation-function', + }, + { + title: 'Row pinning', + url: 'https://mui.com/blog/aggregation-functions/#row-pinning', + }, + ], + }, + { + title: 'New Premium plan', + description: + 'Premium plan announcement, including the most advanced features for data analysis and management.', + date: new Date(2022, 4, 12), + url: 'https://mui.com/blog/premium-plan-release/', + highlightList: [ + { title: 'Row Grouping', url: '/x/react-data-grid/row-grouping/' }, + { title: 'Excel export', url: '/x/react-data-grid/export/#exported-rows' }, + ], + }, + { + title: 'MUI X v5.0.0', + description: 'A new Data Grid virtualization engine, and improvements in several APIs.', + date: new Date(2021, 10, 22), + url: 'https://mui.com/blog/mui-x-v5/', + highlightList: [ + { + title: 'New virtualization engine', + url: 'https://mui.com/blog/mui-x-v5/#a-new-virtualization-engine', + }, + { + title: 'Improved state management', + url: 'https://mui.com/blog/mui-x-v5/#improved-state-management', + }, + { + title: 'Simplified style customization', + url: 'https://mui.com/blog/mui-x-v5/#simplified-style-customization', + }, + ], + }, +]; + +function BlogCard({ entry }) { + return ( + + ({ + p: 2.5, + display: 'flex', + flexDirection: { xs: 'column', sm: 'row' }, + justifyContent: 'space-between', + alignItems: 'center', + gap: 3, + background: `${(theme.vars || theme).palette.gradients.linearSubtle}`, + // TODO: Allow to use theme.applyDarkStyles + '.mode-dark &': { + bgcolor: 'primaryDark.900', + background: `${(theme.vars || theme).palette.gradients.linearSubtle}`, + }, + })} + > +
+ + {entry.date.toLocaleDateString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', + })} + + + {entry.title} + + + {entry.description} + +
+ +
+ + + {entry.highlightList.map((item) => ( + + + {item.title} + + + ))} + +
+ ); +} + +BlogCard.propTypes = { + entry: PropTypes.any, +}; + +export default function WhatsNewLayout() { + return ( +
+ + {entries.map((entry) => ( + + + {entry.date.toLocaleDateString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', + })} + + + + + + + + + + + ))} + +
+ ); +} From 5db3711d5081bf2366c9c940b93fc103126e9398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rodolfo=20Freitas?= Date: Wed, 31 Jan 2024 17:05:57 -0300 Subject: [PATCH 03/35] [docs] Update whats new page with "v7 Beta blogpost" content (#11879) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Rodolfo Freitas Co-authored-by: Michel Engelen <32863416+michelengelen@users.noreply.github.com> --- docs/src/modules/components/WhatsNewLayout.js | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/src/modules/components/WhatsNewLayout.js b/docs/src/modules/components/WhatsNewLayout.js index d274e3fa4a40e..f77d437456ac6 100644 --- a/docs/src/modules/components/WhatsNewLayout.js +++ b/docs/src/modules/components/WhatsNewLayout.js @@ -17,6 +17,35 @@ import TimelineDot from '@mui/lab/TimelineDot'; import TimelineOppositeContent from '@mui/lab/TimelineOppositeContent'; const entries = [ + { + title: 'MUI X v7.0.0-beta.0', + description: + 'Featuring new components and multiple enhancements for both developers and end-users.', + date: new Date(2024, 0, 29), + url: 'https://mui.com/blog/mui-x-v7-beta/', + highlightList: [ + { + title: 'Data Grid - Sticky headers', + url: 'https://mui.com/blog/mui-x-v7-beta/#sticky-headers', + }, + { + title: 'Data Grid - Columns management panel', + url: 'https://mui.com/blog/mui-x-v7-beta/#improved-columns-panel-design', + }, + { + title: 'Rich Tree View', + url: 'https://mui.com/blog/mui-x-v7-beta/#richtreeview', + }, + { + title: 'Date Time Range Picker', + url: 'https://mui.com/blog/mui-x-v7-beta/#date-time-range-picker', + }, + { + title: 'Charts - Reference line ', + url: 'https://mui.com/blog/mui-x-v7-beta/#reference-line', + }, + ], + }, { title: 'MUI X v6.18.x', description: 'New stable components, polished features, better performance, and more.', From 9d3515174c564c5b7aab705b7ed149726329e1df Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:31:30 +0100 Subject: [PATCH 04/35] [charts] Add `onClick` support (#11411) Signed-off-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> --- docs/data/charts-component-api-pages.ts | 4 + docs/data/charts/bars/BarClickNoSnap.js | 96 +++++++++++++ docs/data/charts/bars/bars.md | 44 +++++- docs/data/charts/lines/LineClickNoSnap.js | 102 ++++++++++++++ docs/data/charts/lines/lines.md | 47 ++++++- docs/data/charts/pie/PieClickNoSnap.js | 97 +++++++++++++ docs/data/charts/pie/pie.md | 14 ++ .../data/charts/scatter/ScatterClickNoSnap.js | 121 +++++++++++++++++ docs/data/charts/scatter/scatter.md | 18 +++ docs/data/charts/tooltip/tooltip.md | 4 +- docs/pages/x/api/charts/area-plot.json | 7 + docs/pages/x/api/charts/bar-chart.json | 14 ++ docs/pages/x/api/charts/bar-plot.json | 7 + .../charts/charts-on-axis-click-handler.js | 23 ++++ .../charts/charts-on-axis-click-handler.json | 22 +++ .../x/api/charts/charts-voronoi-handler.json | 11 +- docs/pages/x/api/charts/line-chart.json | 7 + docs/pages/x/api/charts/line-plot.json | 7 + docs/pages/x/api/charts/mark-plot.json | 7 + docs/pages/x/api/charts/pie-arc-plot.json | 2 +- docs/pages/x/api/charts/pie-plot.json | 2 +- docs/pages/x/api/charts/scatter-chart.json | 7 + docs/pages/x/api/charts/scatter-plot.json | 7 + docs/pages/x/api/charts/scatter.json | 10 +- .../api-docs/charts/area-plot/area-plot.json | 7 + .../api-docs/charts/bar-chart/bar-chart.json | 14 ++ .../api-docs/charts/bar-plot/bar-plot.json | 7 + .../charts-on-axis-click-handler.json | 13 ++ .../charts-voronoi-handler.json | 7 + .../charts/line-chart/line-chart.json | 7 + .../api-docs/charts/line-plot/line-plot.json | 7 + .../api-docs/charts/mark-plot/mark-plot.json | 7 + .../charts/pie-arc-plot/pie-arc-plot.json | 2 +- .../api-docs/charts/pie-plot/pie-plot.json | 2 +- .../charts/scatter-chart/scatter-chart.json | 7 + .../charts/scatter-plot/scatter-plot.json | 7 + .../api-docs/charts/scatter/scatter.json | 14 +- packages/x-charts/src/BarChart/BarChart.tsx | 35 ++++- packages/x-charts/src/BarChart/BarElement.tsx | 3 + packages/x-charts/src/BarChart/BarPlot.tsx | 25 +++- .../ChartsOnAxisClickHandler.tsx | 90 ++++++++++++ .../src/ChartsOnAxisClickHandler/index.tsx | 1 + .../ChartsVoronoiHandler.tsx | 128 +++++++++++++----- .../x-charts/src/LineChart/AreaElement.tsx | 17 ++- packages/x-charts/src/LineChart/AreaPlot.tsx | 22 ++- packages/x-charts/src/LineChart/LineChart.tsx | 57 ++++++-- .../x-charts/src/LineChart/LineElement.tsx | 16 ++- .../src/LineChart/LineHighlightElement.tsx | 3 +- packages/x-charts/src/LineChart/LinePlot.tsx | 22 ++- .../x-charts/src/LineChart/MarkElement.tsx | 3 + packages/x-charts/src/LineChart/MarkPlot.tsx | 23 +++- packages/x-charts/src/PieChart/PieArcPlot.tsx | 10 +- packages/x-charts/src/PieChart/PieChart.tsx | 9 +- packages/x-charts/src/PieChart/PiePlot.tsx | 8 +- .../x-charts/src/ScatterChart/Scatter.tsx | 31 ++++- .../src/ScatterChart/ScatterChart.tsx | 36 ++++- .../x-charts/src/ScatterChart/ScatterPlot.tsx | 11 +- .../src/context/InteractionProvider.tsx | 2 +- packages/x-charts/src/index.ts | 1 + scripts/x-charts.exports.json | 2 + 60 files changed, 1243 insertions(+), 93 deletions(-) create mode 100644 docs/data/charts/bars/BarClickNoSnap.js create mode 100644 docs/data/charts/lines/LineClickNoSnap.js create mode 100644 docs/data/charts/pie/PieClickNoSnap.js create mode 100644 docs/data/charts/scatter/ScatterClickNoSnap.js create mode 100644 docs/pages/x/api/charts/charts-on-axis-click-handler.js create mode 100644 docs/pages/x/api/charts/charts-on-axis-click-handler.json create mode 100644 docs/translations/api-docs/charts/charts-on-axis-click-handler/charts-on-axis-click-handler.json create mode 100644 packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx create mode 100644 packages/x-charts/src/ChartsOnAxisClickHandler/index.tsx diff --git a/docs/data/charts-component-api-pages.ts b/docs/data/charts-component-api-pages.ts index b2a117fef59bc..b3b304429fd1a 100644 --- a/docs/data/charts-component-api-pages.ts +++ b/docs/data/charts-component-api-pages.ts @@ -57,6 +57,10 @@ const apiPages: MuiPage[] = [ pathname: '/x/api/charts/charts-legend', title: 'ChartsLegend', }, + { + pathname: '/x/api/charts/charts-on-axis-click-handler', + title: 'ChartsOnAxisClickHandler', + }, { pathname: '/x/api/charts/charts-reference-line', title: 'ChartsReferenceLine', diff --git a/docs/data/charts/bars/BarClickNoSnap.js b/docs/data/charts/bars/BarClickNoSnap.js new file mode 100644 index 0000000000000..da4a899c22abc --- /dev/null +++ b/docs/data/charts/bars/BarClickNoSnap.js @@ -0,0 +1,96 @@ +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 { BarChart } from '@mui/x-charts/BarChart'; + +import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; + +const barChartsParams = { + series: [ + { + id: 'series-1', + data: [3, 4, 1, 6, 5], + label: 'A', + stack: 'total', + highlightScope: { + highlighted: 'item', + }, + }, + { + id: 'series-2', + data: [4, 3, 1, 5, 8], + label: 'B', + stack: 'total', + highlightScope: { + highlighted: 'item', + }, + }, + { + id: 'series-3', + data: [4, 2, 5, 4, 1], + label: 'C', + highlightScope: { + highlighted: 'item', + }, + }, + ], + xAxis: [{ data: ['0', '3', '6', '9', '12'], scaleType: 'band', id: 'axis1' }], + height: 400, +}; + +export default function BarClickNoSnap() { + const [itemData, setItemData] = React.useState(); + const [axisData, setAxisData] = React.useState(); + + return ( + + + setItemData(d)} + onAxisClick={(event, d) => setAxisData(d)} + /> + + + + + Click on the chart + { + setItemData(null); + setAxisData(null); + }} + > + + + + + + + ); +} diff --git a/docs/data/charts/bars/bars.md b/docs/data/charts/bars/bars.md index 2603d5f2d1b0b..1fe2616864e39 100644 --- a/docs/data/charts/bars/bars.md +++ b/docs/data/charts/bars/bars.md @@ -1,7 +1,7 @@ --- title: React Bar chart productId: x-charts -components: BarChart, BarElement, BarPlot +components: BarChart, BarElement, BarPlot, ChartsOnAxisClickHandler --- # Charts - Bars @@ -64,6 +64,48 @@ If you're using [composition](/x/react-charts/composition/), you should set the {{"demo": "HorizontalBars.js"}} +## Click event + +Bar charts provides two click handlers: + +- `onItemClick` for click on a specific bar. +- `onAxisClick` for a click anywhere in the chart + +They both provide the following signature. + +```js +const clickHandler = ( + event, // The mouse event. + params, // An object that identifies the clicked elements. +) => {}; +``` + +{{"demo": "BarClickNoSnap.js"}} + +:::info +Their is a slight difference between the `event` of `onItemClick` and `onAxisClick`: + +- For `onItemClick` it's a React synthetic mouse event emitted by the bar component. +- For `onAxisClick` it's a native mouse event emitted by the svg component. + +::: + +### Composition + +If you're using composition, you can get those click event as follow. +Notice that the `onAxisClick` will handle both bar and line series if you mix them. + +```jsx +import ChartsOnAxisClickHandler from '@mui/x-charts/ChartsOnAxisClickHandler'; +// ... + + + {/* ... */} + + +; +``` + ## Animation To skip animation at the creation and update of your chart, you can use the `skipAnimation` prop. diff --git a/docs/data/charts/lines/LineClickNoSnap.js b/docs/data/charts/lines/LineClickNoSnap.js new file mode 100644 index 0000000000000..f60adf5623891 --- /dev/null +++ b/docs/data/charts/lines/LineClickNoSnap.js @@ -0,0 +1,102 @@ +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 { LineChart } from '@mui/x-charts/LineChart'; + +import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; + +const lineChartsParams = { + series: [ + { + id: 'series-1', + data: [3, 4, 1, 6, 5], + label: 'A', + area: true, + stack: 'total', + highlightScope: { + highlighted: 'item', + }, + }, + { + id: 'series-2', + data: [4, 3, 1, 5, 8], + label: 'B', + area: true, + stack: 'total', + highlightScope: { + highlighted: 'item', + }, + }, + { + id: 'series-3', + data: [4, 2, 5, 4, 1], + label: 'C', + area: true, + stack: 'total', + highlightScope: { + highlighted: 'item', + }, + }, + ], + xAxis: [{ data: [0, 3, 6, 9, 12], scaleType: 'linear', id: 'axis1' }], + height: 400, +}; + +export default function LineClickNoSnap() { + const [itemData, setItemData] = React.useState(); + const [axisData, setAxisData] = React.useState(); + + return ( + + + setItemData(d)} + onMarkClick={(event, d) => setItemData(d)} + onLineClick={(event, d) => setItemData(d)} + onAxisClick={(event, d) => setAxisData(d)} + /> + + + + + Click on the chart + { + setItemData(null); + setAxisData(null); + }} + > + + + + + + + ); +} diff --git a/docs/data/charts/lines/lines.md b/docs/data/charts/lines/lines.md index 37a1250e87f8a..72b117a8e159c 100644 --- a/docs/data/charts/lines/lines.md +++ b/docs/data/charts/lines/lines.md @@ -1,7 +1,7 @@ --- title: React Line chart productId: x-charts -components: LineChart, LineElement, LineHighlightElement, LineHighlightPlot, LinePlot, MarkElement, MarkPlot, AreaElement, AreaPlot, AnimatedLine, AnimatedArea +components: LineChart, LineElement, LineHighlightElement, LineHighlightPlot, LinePlot, MarkElement, MarkPlot, AreaElement, AreaPlot, AnimatedLine, AnimatedArea, ChartsOnAxisClickHandler --- # Charts - Lines @@ -91,6 +91,51 @@ However, it cannot extrapolate the curve before the first non-null data point or {{"demo": "ConnectNulls.js"}} +## Click event + +Line charts provides multiple click handlers: + +- `onAreaClick` for click on a specific area. +- `onLineClick` for click on a specific line. +- `onMarkClick` for click on a specific mark. +- `onAxisClick` for a click anywhere in the chart + +They all provide the following signature. + +```js +const clickHandler = ( + event, // The mouse event. + params, // An object that identifies the clicked elements. +) => {}; +``` + +{{"demo": "LineClickNoSnap.js"}} + +:::info +Their is a slight difference between the `event` of `onAxisClick` and the others: + +- For `onAxisClick` it's a native mouse event emitted by the svg component. +- For others, it's a React synthetic mouse event emitted by the area, line, or mark component. + +::: + +### Composition + +If you're using composition, you can get those click event as follow. +Notice that the `onAxisClick` will handle both bar and line series if you mix them. + +```jsx +import ChartsOnAxisClickHandler from '@mui/x-charts/ChartsOnAxisClickHandler'; +// ... + + + {/* ... */} + + + +; +``` + ## Styling ### Interpolation diff --git a/docs/data/charts/pie/PieClickNoSnap.js b/docs/data/charts/pie/PieClickNoSnap.js new file mode 100644 index 0000000000000..9e20f6c90adf2 --- /dev/null +++ b/docs/data/charts/pie/PieClickNoSnap.js @@ -0,0 +1,97 @@ +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 { PieChart } from '@mui/x-charts/PieChart'; + +import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; + +const data1 = [ + { label: 'Group A', value: 400 }, + { label: 'Group B', value: 300 }, + { label: 'Group C', value: 300 }, + { label: 'Group D', value: 200 }, +]; + +const data2 = [ + { label: 'A1', value: 100 }, + { label: 'A2', value: 300 }, + { label: 'B1', value: 100 }, + { label: 'B2', value: 80 }, + { label: 'B3', value: 40 }, + { label: 'B4', value: 30 }, + { label: 'B5', value: 50 }, + { label: 'C1', value: 100 }, + { label: 'C2', value: 200 }, + { label: 'D1', value: 150 }, + { label: 'D2', value: 50 }, +]; +const series = [ + { + innerRadius: 0, + outerRadius: 80, + id: 'series-1', + data: data1, + }, + { + innerRadius: 100, + outerRadius: 120, + id: 'series-2', + data: data2, + }, +]; + +export default function PieClickNoSnap() { + const [itemData, setItemData] = React.useState(); + + return ( + + + setItemData(d)} + />{' '} + + + + + Click on the chart + { + setItemData(null); + }} + > + + + + + + + ); +} diff --git a/docs/data/charts/pie/pie.md b/docs/data/charts/pie/pie.md index e0126a44cfae9..9c2237e68c873 100644 --- a/docs/data/charts/pie/pie.md +++ b/docs/data/charts/pie/pie.md @@ -91,6 +91,20 @@ This value can be negative to reduce arc size. {{"demo": "PieActiveArc.js"}} +## Click event + +Pie Chart provides an `onItemClick` handler for handling clicks on specific pie arcs. +It has the following signature. + +```js +const onItemClick = ( + event, // The mouse event. + params, // An object that identifies the clicked element. +) => {}; +``` + +{{"demo": "PieClickNoSnap.js"}} + ## Animation To skip animation at the creation and update of your chart you can use the `skipAnimation` prop. diff --git a/docs/data/charts/scatter/ScatterClickNoSnap.js b/docs/data/charts/scatter/ScatterClickNoSnap.js new file mode 100644 index 0000000000000..decb628cb1fac --- /dev/null +++ b/docs/data/charts/scatter/ScatterClickNoSnap.js @@ -0,0 +1,121 @@ +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 { ScatterChart } from '@mui/x-charts/ScatterChart'; + +import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; + +const scatterChartsParams = { + series: [ + { + id: 'series-1', + data: [ + { x: 6.5e-2, y: -1.3, id: 0 }, + { x: -2.1, y: -7.0e-1, id: 1 }, + { x: -7.6e-1, y: -6.7e-1, id: 2 }, + { x: -1.5e-2, y: -2.0e-1, id: 3 }, + { x: -1.4, y: -9.9e-1, id: 4 }, + { x: -1.1, y: -1.5, id: 5 }, + { x: -7.0e-1, y: -2.7e-1, id: 6 }, + { x: -5.1e-1, y: -8.8e-1, id: 7 }, + { x: -4.0e-3, y: -1.4, id: 8 }, + { x: -1.3, y: -2.2, id: 9 }, + ], + label: 'A', + highlightScope: { + highlighted: 'item', + }, + }, + { + id: 'series-2', + data: [ + { x: 1.8, y: -1.7e-2, id: 0 }, + { x: 7.1e-1, y: 2.6e-1, id: 1 }, + { x: -1.2, y: 9.8e-1, id: 2 }, + { x: 2.0, y: -2.0e-1, id: 3 }, + { x: 9.4e-1, y: -2.7e-1, id: 4 }, + { x: -4.8e-1, y: -1.6e-1, id: 5 }, + { x: -1.5, y: 1.1, id: 6 }, + { x: 1.3, y: 3.4e-1, id: 7 }, + { x: -4.2e-1, y: 1.0e-1, id: 8 }, + { x: 5.4e-2, y: 4.0e-1, id: 9 }, + ], + label: 'B', + highlightScope: { + highlighted: 'item', + }, + }, + ], + height: 400, +}; + +export default function ScatterClickNoSnap() { + const [data, setData] = React.useState(); + + const { axis, item, ...other } = data ?? {}; + const dataDisplayed = data && { + ...(item + ? { + item: { + dataIndex: item.dataIndex, + series: { + id: item.series.id, + toReplace: '', + }, + }, + } + : undefined), + ...(axis ? { axis } : undefined), + ...other, + }; + return ( + + + setData(d)} + /> + + + + Click on the chart + { + setData(null); + }} + > + + + + + + + ); +} diff --git a/docs/data/charts/scatter/scatter.md b/docs/data/charts/scatter/scatter.md index c66ad53e6079a..084fbed789b85 100644 --- a/docs/data/charts/scatter/scatter.md +++ b/docs/data/charts/scatter/scatter.md @@ -33,6 +33,24 @@ To use this feature with composition, add the `ChartsVoronoiHandler`. ``` +## Click event + +Scatter Chart provides an `onItemClick` handler for handling clicks on specific scatter items. +It has the following signature. + +```js +const onItemClick = ( + event, // The mouse event. + params, // An object that identifies the clicked elements. +) => {}; +``` + +{{"demo": "ScatterClickNoSnap.js"}} + +If `disableVoronoi=true`, users need to click precisely on the scatter element, and the mouse event will come from this element. + +Otherwise, the click behavior will be the same as defined in the [interaction section](#interaction) and the mouse event will come from the svg component. + ## Styling ### CSS 🚧 diff --git a/docs/data/charts/tooltip/tooltip.md b/docs/data/charts/tooltip/tooltip.md index c126bf0f45e29..3837e7e8196ef 100644 --- a/docs/data/charts/tooltip/tooltip.md +++ b/docs/data/charts/tooltip/tooltip.md @@ -11,7 +11,7 @@ components: ChartsAxisTooltipContent, ChartsItemTooltipContent, ChartsTooltip, D In all charts components, you can pass props to the tooltip by using `tooltip={{...}}`. If you are using composition, you can add the `` component and pass props directly. -## Interactions +## Tooltip trigger The tooltip can be triggered by two kinds of events: @@ -86,7 +86,7 @@ It will remove the header showing the x-axis value from the tooltip. If you're using composition, by default, the axis will be listening for mouse events to get its current x/y values. If you don't need it, you can disable those listeners with the `disableAxisListener` prop. -You need those listeners if you are using [axes highlight](/x/react-charts/tooltip/#highlighting-axis) or you have a tooltip [triggered by axis](/x/react-charts/tooltip/#interactions). +You need those listeners if you are using [axes highlight](/x/react-charts/tooltip/#highlighting-axis) or you have a tooltip [triggered by axis](/x/react-charts/tooltip/#tooltip-trigger). ```jsx diff --git a/docs/pages/x/api/charts/area-plot.json b/docs/pages/x/api/charts/area-plot.json index 30c6fa3f2ce3c..e70a4110d61af 100644 --- a/docs/pages/x/api/charts/area-plot.json +++ b/docs/pages/x/api/charts/area-plot.json @@ -1,5 +1,12 @@ { "props": { + "onItemClick": { + "type": { "name": "func" }, + "signature": { + "type": "function(event: React.MouseEvent, lineItemIdentifier: LineItemIdentifier) => void", + "describedArgs": ["event", "lineItemIdentifier"] + } + }, "skipAnimation": { "type": { "name": "bool" }, "default": "false" }, "slotProps": { "type": { "name": "object" }, "default": "{}" }, "slots": { diff --git a/docs/pages/x/api/charts/bar-chart.json b/docs/pages/x/api/charts/bar-chart.json index c95a8d55fe689..ee0ee516ffb94 100644 --- a/docs/pages/x/api/charts/bar-chart.json +++ b/docs/pages/x/api/charts/bar-chart.json @@ -34,6 +34,20 @@ }, "default": "object Depends on the charts type." }, + "onAxisClick": { + "type": { "name": "func" }, + "signature": { + "type": "function(event: MouseEvent, data: null | AxisData) => void", + "describedArgs": ["event", "data"] + } + }, + "onItemClick": { + "type": { "name": "func" }, + "signature": { + "type": "function(event: React.MouseEvent, barItemIdentifier: BarItemIdentifier) => void", + "describedArgs": ["event", "barItemIdentifier"] + } + }, "rightAxis": { "type": { "name": "union", diff --git a/docs/pages/x/api/charts/bar-plot.json b/docs/pages/x/api/charts/bar-plot.json index bebcdf0a429d0..200f09808221c 100644 --- a/docs/pages/x/api/charts/bar-plot.json +++ b/docs/pages/x/api/charts/bar-plot.json @@ -1,5 +1,12 @@ { "props": { + "onItemClick": { + "type": { "name": "func" }, + "signature": { + "type": "function(event: React.MouseEvent, barItemIdentifier: BarItemIdentifier) => void", + "describedArgs": ["event", "barItemIdentifier"] + } + }, "skipAnimation": { "type": { "name": "bool" }, "default": "false" }, "slotProps": { "type": { "name": "object" }, "default": "{}" }, "slots": { diff --git a/docs/pages/x/api/charts/charts-on-axis-click-handler.js b/docs/pages/x/api/charts/charts-on-axis-click-handler.js new file mode 100644 index 0000000000000..261a76d5960ca --- /dev/null +++ b/docs/pages/x/api/charts/charts-on-axis-click-handler.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import ApiPage from 'docs/src/modules/components/ApiPage'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './charts-on-axis-click-handler.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ; +} + +Page.getInitialProps = () => { + const req = require.context( + 'docsx/translations/api-docs/charts/charts-on-axis-click-handler', + false, + /\.\/charts-on-axis-click-handler.*.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/x/api/charts/charts-on-axis-click-handler.json b/docs/pages/x/api/charts/charts-on-axis-click-handler.json new file mode 100644 index 0000000000000..92638d4ee5d01 --- /dev/null +++ b/docs/pages/x/api/charts/charts-on-axis-click-handler.json @@ -0,0 +1,22 @@ +{ + "props": { + "onAxisClick": { + "type": { "name": "func" }, + "signature": { + "type": "function(event: MouseEvent, data: null | AxisData) => void", + "describedArgs": ["event", "data"] + } + } + }, + "name": "ChartsOnAxisClickHandler", + "imports": [ + "import { ChartsOnAxisClickHandler } from '@mui/x-charts/ChartsOnAxisClickHandler';", + "import { ChartsOnAxisClickHandler } from '@mui/x-charts';" + ], + "classes": [], + "muiName": "MuiChartsOnAxisClickHandler", + "filename": "/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx", + "inheritance": null, + "demos": "", + "cssComponent": false +} diff --git a/docs/pages/x/api/charts/charts-voronoi-handler.json b/docs/pages/x/api/charts/charts-voronoi-handler.json index 72ada4aeea80f..891187ec2bbb7 100644 --- a/docs/pages/x/api/charts/charts-voronoi-handler.json +++ b/docs/pages/x/api/charts/charts-voronoi-handler.json @@ -1,5 +1,14 @@ { - "props": { "voronoiMaxRadius": { "type": { "name": "number" }, "default": "undefined" } }, + "props": { + "onItemClick": { + "type": { "name": "func" }, + "signature": { + "type": "function(event: MouseEvent, scatterItemIdentifier: ScatterItemIdentifier) => void", + "describedArgs": ["event", "scatterItemIdentifier"] + } + }, + "voronoiMaxRadius": { "type": { "name": "number" }, "default": "undefined" } + }, "name": "ChartsVoronoiHandler", "imports": [ "import { ChartsVoronoiHandler } from '@mui/x-charts/ChartsVoronoiHandler';", diff --git a/docs/pages/x/api/charts/line-chart.json b/docs/pages/x/api/charts/line-chart.json index 1ae374f7c5e72..b8fc2abd5917d 100644 --- a/docs/pages/x/api/charts/line-chart.json +++ b/docs/pages/x/api/charts/line-chart.json @@ -36,6 +36,13 @@ }, "default": "object Depends on the charts type." }, + "onAxisClick": { + "type": { "name": "func" }, + "signature": { + "type": "function(event: MouseEvent, data: null | AxisData) => void", + "describedArgs": ["event", "data"] + } + }, "rightAxis": { "type": { "name": "union", diff --git a/docs/pages/x/api/charts/line-plot.json b/docs/pages/x/api/charts/line-plot.json index 695302fba7fa5..b42395b5ed14e 100644 --- a/docs/pages/x/api/charts/line-plot.json +++ b/docs/pages/x/api/charts/line-plot.json @@ -1,5 +1,12 @@ { "props": { + "onItemClick": { + "type": { "name": "func" }, + "signature": { + "type": "function(event: React.MouseEvent, lineItemIdentifier: LineItemIdentifier) => void", + "describedArgs": ["event", "lineItemIdentifier"] + } + }, "skipAnimation": { "type": { "name": "bool" }, "default": "false" }, "slotProps": { "type": { "name": "object" }, "default": "{}" }, "slots": { diff --git a/docs/pages/x/api/charts/mark-plot.json b/docs/pages/x/api/charts/mark-plot.json index e334cc78e61d5..bd8e81555f56a 100644 --- a/docs/pages/x/api/charts/mark-plot.json +++ b/docs/pages/x/api/charts/mark-plot.json @@ -1,5 +1,12 @@ { "props": { + "onItemClick": { + "type": { "name": "func" }, + "signature": { + "type": "function(event: React.MouseEvent, lineItemIdentifier: LineItemIdentifier) => void", + "describedArgs": ["event", "lineItemIdentifier"] + } + }, "skipAnimation": { "type": { "name": "bool" }, "default": "false" }, "slotProps": { "type": { "name": "object" }, "default": "{}" }, "slots": { diff --git a/docs/pages/x/api/charts/pie-arc-plot.json b/docs/pages/x/api/charts/pie-arc-plot.json index bb73132ab4353..2b52c04ea36a5 100644 --- a/docs/pages/x/api/charts/pie-arc-plot.json +++ b/docs/pages/x/api/charts/pie-arc-plot.json @@ -20,7 +20,7 @@ } }, "innerRadius": { "type": { "name": "number" }, "default": "0" }, - "onClick": { + "onItemClick": { "type": { "name": "func" }, "signature": { "type": "function(event: React.MouseEvent, pieItemIdentifier: PieItemIdentifier, item: DefaultizedPieValueType) => void", diff --git a/docs/pages/x/api/charts/pie-plot.json b/docs/pages/x/api/charts/pie-plot.json index 21d97bf5c3030..4d098050997e0 100644 --- a/docs/pages/x/api/charts/pie-plot.json +++ b/docs/pages/x/api/charts/pie-plot.json @@ -1,6 +1,6 @@ { "props": { - "onClick": { + "onItemClick": { "type": { "name": "func" }, "signature": { "type": "function(event: React.MouseEvent, pieItemIdentifier: PieItemIdentifier, item: DefaultizedPieValueType) => void", diff --git a/docs/pages/x/api/charts/scatter-chart.json b/docs/pages/x/api/charts/scatter-chart.json index 624f957f297cc..d223d3f4c85bb 100644 --- a/docs/pages/x/api/charts/scatter-chart.json +++ b/docs/pages/x/api/charts/scatter-chart.json @@ -29,6 +29,13 @@ }, "default": "object Depends on the charts type." }, + "onItemClick": { + "type": { "name": "func" }, + "signature": { + "type": "function(event: MouseEvent, scatterItemIdentifier: ScatterItemIdentifier) => void", + "describedArgs": ["event", "scatterItemIdentifier"] + } + }, "rightAxis": { "type": { "name": "union", diff --git a/docs/pages/x/api/charts/scatter-plot.json b/docs/pages/x/api/charts/scatter-plot.json index eb293b3b005da..06c717e800fe6 100644 --- a/docs/pages/x/api/charts/scatter-plot.json +++ b/docs/pages/x/api/charts/scatter-plot.json @@ -1,5 +1,12 @@ { "props": { + "onItemClick": { + "type": { "name": "func" }, + "signature": { + "type": "function(event: MouseEvent, scatterItemIdentifier: ScatterItemIdentifier) => void", + "describedArgs": ["event", "scatterItemIdentifier"] + } + }, "slotProps": { "type": { "name": "object" }, "default": "{}" }, "slots": { "type": { "name": "object" }, diff --git a/docs/pages/x/api/charts/scatter.json b/docs/pages/x/api/charts/scatter.json index fb41b85894338..258a927ce8261 100644 --- a/docs/pages/x/api/charts/scatter.json +++ b/docs/pages/x/api/charts/scatter.json @@ -1,5 +1,13 @@ { - "props": {}, + "props": { + "onItemClick": { + "type": { "name": "func" }, + "signature": { + "type": "function(event: MouseEvent, scatterItemIdentifier: ScatterItemIdentifier) => void", + "describedArgs": ["event", "scatterItemIdentifier"] + } + } + }, "name": "Scatter", "imports": [ "import { Scatter } from '@mui/x-charts/ScatterChart';", diff --git a/docs/translations/api-docs/charts/area-plot/area-plot.json b/docs/translations/api-docs/charts/area-plot/area-plot.json index 44b71c6c124ce..20909993d298d 100644 --- a/docs/translations/api-docs/charts/area-plot/area-plot.json +++ b/docs/translations/api-docs/charts/area-plot/area-plot.json @@ -1,6 +1,13 @@ { "componentDescription": "", "propDescriptions": { + "onItemClick": { + "description": "Callback fired when a line area item is clicked.", + "typeDescriptions": { + "event": "The event source of the callback.", + "lineItemIdentifier": "The line item identifier." + } + }, "skipAnimation": { "description": "If true, animations are skipped." }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." } diff --git a/docs/translations/api-docs/charts/bar-chart/bar-chart.json b/docs/translations/api-docs/charts/bar-chart/bar-chart.json index 52c7ccee6d9e5..82d7351d03891 100644 --- a/docs/translations/api-docs/charts/bar-chart/bar-chart.json +++ b/docs/translations/api-docs/charts/bar-chart/bar-chart.json @@ -23,6 +23,20 @@ "margin": { "description": "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." }, + "onAxisClick": { + "description": "The function called for onClick events. The second argument contains information about all line/bar elements at the current mouse position.", + "typeDescriptions": { + "event": "The mouse event recorded on the <svg/> element.", + "data": "The data about the clicked axis and items associated with it." + } + }, + "onItemClick": { + "description": "Callback fired when a bar item is clicked.", + "typeDescriptions": { + "event": "The event source of the callback.", + "barItemIdentifier": "The bar item identifier." + } + }, "rightAxis": { "description": "Indicate which axis to display the right of the charts. Can be a string (the id of the axis) or an object ChartsYAxisProps." }, diff --git a/docs/translations/api-docs/charts/bar-plot/bar-plot.json b/docs/translations/api-docs/charts/bar-plot/bar-plot.json index b84aa3efd86ae..509120eaefd28 100644 --- a/docs/translations/api-docs/charts/bar-plot/bar-plot.json +++ b/docs/translations/api-docs/charts/bar-plot/bar-plot.json @@ -1,6 +1,13 @@ { "componentDescription": "", "propDescriptions": { + "onItemClick": { + "description": "Callback fired when a bar item is clicked.", + "typeDescriptions": { + "event": "The event source of the callback.", + "barItemIdentifier": "The bar item identifier." + } + }, "skipAnimation": { "description": "If true, animations are skipped." }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." } diff --git a/docs/translations/api-docs/charts/charts-on-axis-click-handler/charts-on-axis-click-handler.json b/docs/translations/api-docs/charts/charts-on-axis-click-handler/charts-on-axis-click-handler.json new file mode 100644 index 0000000000000..f9129ff20bdec --- /dev/null +++ b/docs/translations/api-docs/charts/charts-on-axis-click-handler/charts-on-axis-click-handler.json @@ -0,0 +1,13 @@ +{ + "componentDescription": "", + "propDescriptions": { + "onAxisClick": { + "description": "The function called for onClick events. The second argument contains information about all line/bar elements at the current mouse position.", + "typeDescriptions": { + "event": "The mouse event recorded on the <svg/> element.", + "data": "The data about the clicked axis and items associated with it." + } + } + }, + "classDescriptions": {} +} diff --git a/docs/translations/api-docs/charts/charts-voronoi-handler/charts-voronoi-handler.json b/docs/translations/api-docs/charts/charts-voronoi-handler/charts-voronoi-handler.json index 92bf65e12a76e..1e277962d2f42 100644 --- a/docs/translations/api-docs/charts/charts-voronoi-handler/charts-voronoi-handler.json +++ b/docs/translations/api-docs/charts/charts-voronoi-handler/charts-voronoi-handler.json @@ -1,6 +1,13 @@ { "componentDescription": "", "propDescriptions": { + "onItemClick": { + "description": "Callback fired when clicking on a scatter item.", + "typeDescriptions": { + "event": "Mouse event catched at the svg level", + "scatterItemIdentifier": "Identify whihc item got clicked" + } + }, "voronoiMaxRadius": { "description": "Defines the maximal distance between a scatter point and the pointer that triggers the interaction. If undefined, the radius is assumed to be infinite." } diff --git a/docs/translations/api-docs/charts/line-chart/line-chart.json b/docs/translations/api-docs/charts/line-chart/line-chart.json index a6d9fe50d903f..444ba852a39c8 100644 --- a/docs/translations/api-docs/charts/line-chart/line-chart.json +++ b/docs/translations/api-docs/charts/line-chart/line-chart.json @@ -26,6 +26,13 @@ "margin": { "description": "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." }, + "onAxisClick": { + "description": "The function called for onClick events. The second argument contains information about all line/bar elements at the current mouse position.", + "typeDescriptions": { + "event": "The mouse event recorded on the <svg/> element.", + "data": "The data about the clicked axis and items associated with it." + } + }, "rightAxis": { "description": "Indicate which axis to display the right of the charts. Can be a string (the id of the axis) or an object ChartsYAxisProps." }, diff --git a/docs/translations/api-docs/charts/line-plot/line-plot.json b/docs/translations/api-docs/charts/line-plot/line-plot.json index 32105cc21e585..85bdfcd68a9a4 100644 --- a/docs/translations/api-docs/charts/line-plot/line-plot.json +++ b/docs/translations/api-docs/charts/line-plot/line-plot.json @@ -1,6 +1,13 @@ { "componentDescription": "", "propDescriptions": { + "onItemClick": { + "description": "Callback fired when a line item is clicked.", + "typeDescriptions": { + "event": "The event source of the callback.", + "lineItemIdentifier": "The line item identifier." + } + }, "skipAnimation": { "description": "If true, animations are skipped." }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." } diff --git a/docs/translations/api-docs/charts/mark-plot/mark-plot.json b/docs/translations/api-docs/charts/mark-plot/mark-plot.json index c338ac1652e53..521be58519194 100644 --- a/docs/translations/api-docs/charts/mark-plot/mark-plot.json +++ b/docs/translations/api-docs/charts/mark-plot/mark-plot.json @@ -1,6 +1,13 @@ { "componentDescription": "", "propDescriptions": { + "onItemClick": { + "description": "Callback fired when a line mark item is clicked.", + "typeDescriptions": { + "event": "The event source of the callback.", + "lineItemIdentifier": "The line mark item identifier." + } + }, "skipAnimation": { "description": "If true, animations are skipped." }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." } diff --git a/docs/translations/api-docs/charts/pie-arc-plot/pie-arc-plot.json b/docs/translations/api-docs/charts/pie-arc-plot/pie-arc-plot.json index 58bfec3d2112b..72d44f2ee1d9d 100644 --- a/docs/translations/api-docs/charts/pie-arc-plot/pie-arc-plot.json +++ b/docs/translations/api-docs/charts/pie-arc-plot/pie-arc-plot.json @@ -12,7 +12,7 @@ "innerRadius": { "description": "The radius between circle center and the begining of the arc." }, - "onClick": { + "onItemClick": { "description": "Callback fired when a pie item is clicked.", "typeDescriptions": { "event": "The event source of the callback.", diff --git a/docs/translations/api-docs/charts/pie-plot/pie-plot.json b/docs/translations/api-docs/charts/pie-plot/pie-plot.json index bf05960bf8799..2fe4ec8dec4cd 100644 --- a/docs/translations/api-docs/charts/pie-plot/pie-plot.json +++ b/docs/translations/api-docs/charts/pie-plot/pie-plot.json @@ -1,7 +1,7 @@ { "componentDescription": "", "propDescriptions": { - "onClick": { + "onItemClick": { "description": "Callback fired when a pie item is clicked.", "typeDescriptions": { "event": "The event source of the callback.", diff --git a/docs/translations/api-docs/charts/scatter-chart/scatter-chart.json b/docs/translations/api-docs/charts/scatter-chart/scatter-chart.json index d23370f5a9a79..0922311d29506 100644 --- a/docs/translations/api-docs/charts/scatter-chart/scatter-chart.json +++ b/docs/translations/api-docs/charts/scatter-chart/scatter-chart.json @@ -23,6 +23,13 @@ "margin": { "description": "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." }, + "onItemClick": { + "description": "Callback fired when clicking on a scatter item.", + "typeDescriptions": { + "event": "The mouse event recorded on the <svg/> element if using Voronoi cells. Or the Mouse event from the scatter element, when disableVoronoi=true.", + "scatterItemIdentifier": "The scatter item identifier." + } + }, "rightAxis": { "description": "Indicate which axis to display the right of the charts. Can be a string (the id of the axis) or an object ChartsYAxisProps." }, diff --git a/docs/translations/api-docs/charts/scatter-plot/scatter-plot.json b/docs/translations/api-docs/charts/scatter-plot/scatter-plot.json index f2d38cfd30736..6d95fc6a93fb3 100644 --- a/docs/translations/api-docs/charts/scatter-plot/scatter-plot.json +++ b/docs/translations/api-docs/charts/scatter-plot/scatter-plot.json @@ -1,6 +1,13 @@ { "componentDescription": "", "propDescriptions": { + "onItemClick": { + "description": "Callback fired when clicking on a scatter item.", + "typeDescriptions": { + "event": "Mouse event recorded on the <svg/> element.", + "scatterItemIdentifier": "The scatter item identifier." + } + }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." } }, diff --git a/docs/translations/api-docs/charts/scatter/scatter.json b/docs/translations/api-docs/charts/scatter/scatter.json index f93d4cbd8c798..512086dda520e 100644 --- a/docs/translations/api-docs/charts/scatter/scatter.json +++ b/docs/translations/api-docs/charts/scatter/scatter.json @@ -1 +1,13 @@ -{ "componentDescription": "", "propDescriptions": {}, "classDescriptions": {} } +{ + "componentDescription": "", + "propDescriptions": { + "onItemClick": { + "description": "Callback fired when clicking on a scatter item.", + "typeDescriptions": { + "event": "Mouse event recorded on the <svg/> element.", + "scatterItemIdentifier": "The scatter item identifier." + } + } + }, + "classDescriptions": {} +} diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index b83f033fdcdd9..3a1756447225c 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -25,6 +25,10 @@ import { import { ChartsAxisHighlight, ChartsAxisHighlightProps } from '../ChartsAxisHighlight'; import { ChartsClipPath } from '../ChartsClipPath'; import { ChartsAxisSlots, ChartsAxisSlotProps } from '../models/axis'; +import { + ChartsOnAxisClickHandler, + ChartsOnAxisClickHandlerProps, +} from '../ChartsOnAxisClickHandler'; export interface BarChartSlots extends ChartsAxisSlots, @@ -40,7 +44,8 @@ export interface BarChartSlotProps export interface BarChartProps extends Omit, Omit, - Pick { + Omit, + ChartsOnAxisClickHandlerProps { series: MakeOptional[]; tooltip?: ChartsTooltipProps; /** @@ -99,6 +104,8 @@ const BarChart = React.forwardRef(function BarChart(props: BarChartProps, ref) { rightAxis, bottomAxis, skipAnimation, + onItemClick, + onAxisClick, children, slots, slotProps, @@ -146,11 +153,20 @@ const BarChart = React.forwardRef(function BarChart(props: BarChartProps, ref) { dataset={dataset} sx={sx} disableAxisListener={ - tooltip?.trigger !== 'axis' && axisHighlight?.x === 'none' && axisHighlight?.y === 'none' + tooltip?.trigger !== 'axis' && + axisHighlight?.x === 'none' && + axisHighlight?.y === 'none' && + !onAxisClick } > + {onAxisClick && } - + ` element. + * @param {null | AxisData} data The data about the clicked axis and items associated with it. + */ + onAxisClick: PropTypes.func, + /** + * 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, /** * Indicate which axis to display the right of the charts. * Can be a string (the id of the axis) or an object `ChartsYAxisProps`. diff --git a/packages/x-charts/src/BarChart/BarElement.tsx b/packages/x-charts/src/BarChart/BarElement.tsx index df1a0dfe483ea..be10fbc3f29f4 100644 --- a/packages/x-charts/src/BarChart/BarElement.tsx +++ b/packages/x-charts/src/BarChart/BarElement.tsx @@ -95,6 +95,7 @@ function BarElement(props: BarElementProps) { slots, slotProps, style, + onClick, ...other } = props; const getInteractionItemProps = useInteractionItemProps(highlightScope); @@ -128,6 +129,8 @@ function BarElement(props: BarElementProps) { ...getInteractionItemProps({ type: 'bar', seriesId: id, dataIndex }), style, className: classes.root, + onClick, + cursor: onClick ? 'pointer' : 'unset', }, ownerState, }); diff --git a/packages/x-charts/src/BarChart/BarPlot.tsx b/packages/x-charts/src/BarChart/BarPlot.tsx index d421de7eddd16..304d6f1dd45bc 100644 --- a/packages/x-charts/src/BarChart/BarPlot.tsx +++ b/packages/x-charts/src/BarChart/BarPlot.tsx @@ -7,7 +7,7 @@ import { BarElement, BarElementProps } from './BarElement'; import { isBandScaleConfig } from '../models/axis'; import { FormatterResult } from '../models/seriesType/config'; import { HighlightScope } from '../context/HighlightProvider'; -import { BarSeriesType } from '../models'; +import { BarItemIdentifier, BarSeriesType } from '../models'; import { DEFAULT_X_AXIS_KEY, DEFAULT_Y_AXIS_KEY } from '../constants'; /** @@ -56,6 +56,15 @@ export interface BarPlotProps extends Pick} event The event source of the callback. + * @param {BarItemIdentifier} barItemIdentifier The bar item identifier. + */ + onItemClick?: ( + event: React.MouseEvent, + barItemIdentifier: BarItemIdentifier, + ) => void; } interface CompletedBarData { @@ -216,7 +225,7 @@ const getInStyle = ({ x, width, y, height }: CompletedBarData) => ({ */ function BarPlot(props: BarPlotProps) { const completedData = useAggregatedData(); - const { skipAnimation, ...other } = props; + const { skipAnimation, onItemClick, ...other } = props; const transition = useTransition(completedData, { keys: (bar) => `${bar.seriesId}-${bar.dataIndex}`, @@ -235,6 +244,12 @@ function BarPlot(props: BarPlotProps) { highlightScope={highlightScope} color={color} {...other} + onClick={ + onItemClick && + ((event) => { + onItemClick(event, { type: 'bar', seriesId, dataIndex }); + }) + } style={style} /> ))} @@ -247,6 +262,12 @@ BarPlot.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * 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 diff --git a/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx b/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx new file mode 100644 index 0000000000000..3deca39d1810a --- /dev/null +++ b/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx @@ -0,0 +1,90 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { SVGContext } from '../context/DrawingProvider'; +import { InteractionContext } from '../context/InteractionProvider'; +import { CartesianContext } from '../context/CartesianContextProvider'; +import { SeriesContext } from '../context/SeriesContextProvider'; + +type AxisData = { + dataIndex: number; + axisValue?: number | Date | string; + seriesValues: Record; +}; + +export interface ChartsOnAxisClickHandlerProps { + /** + * 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?: (event: MouseEvent, data: null | AxisData) => void; +} + +function ChartsOnAxisClickHandler(props: ChartsOnAxisClickHandlerProps) { + const { onAxisClick } = props; + + const svgRef = React.useContext(SVGContext); + const series = React.useContext(SeriesContext); + const { axis } = React.useContext(InteractionContext); + const { xAxisIds, xAxis, yAxisIds, yAxis } = React.useContext(CartesianContext); + + React.useEffect(() => { + const element = svgRef.current; + if (element === null || !onAxisClick) { + return () => {}; + } + + const handleMouseClick = (event: MouseEvent) => { + event.preventDefault(); + + const isXaxis = (axis.x && axis.x.index) !== undefined; + const USED_AXIS_ID = isXaxis ? xAxisIds[0] : yAxisIds[0]; + const dataIndex = isXaxis ? axis.x && axis.x.index : axis.y && axis.y.index; + + if (dataIndex == null) { + return; + } + + const seriesValues: Record = {}; + + Object.keys(series) + .filter((seriesType): seriesType is 'bar' | 'line' => ['bar', 'line'].includes(seriesType)) + .forEach((seriesType) => { + series[seriesType]?.seriesOrder.forEach((seriesId) => { + const seriesItem = series[seriesType]!.series[seriesId]; + const axisKey = isXaxis ? seriesItem.xAxisKey : seriesItem.yAxisKey; + if (axisKey === undefined || axisKey === USED_AXIS_ID) { + seriesValues[seriesId] = seriesItem.data[dataIndex]; + } + }); + }); + const axisValue = (isXaxis ? xAxis : yAxis)[USED_AXIS_ID].data?.[dataIndex]; + onAxisClick(event, { dataIndex, axisValue, seriesValues }); + }; + + element.addEventListener('click', handleMouseClick); + return () => { + element.removeEventListener('click', handleMouseClick); + }; + }, [axis.x, axis.y, onAxisClick, series, svgRef, xAxis, xAxisIds, yAxis, yAxisIds]); + + // eslint-disable-next-line react/jsx-no-useless-fragment + return ; +} + +ChartsOnAxisClickHandler.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "yarn proptypes" | + // ---------------------------------------------------------------------- + /** + * 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, +} as any; + +export { ChartsOnAxisClickHandler }; diff --git a/packages/x-charts/src/ChartsOnAxisClickHandler/index.tsx b/packages/x-charts/src/ChartsOnAxisClickHandler/index.tsx new file mode 100644 index 0000000000000..2e389601bf677 --- /dev/null +++ b/packages/x-charts/src/ChartsOnAxisClickHandler/index.tsx @@ -0,0 +1 @@ +export * from './ChartsOnAxisClickHandler'; diff --git a/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx b/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx index 3018ce60c6d04..73225bce43c7b 100644 --- a/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx +++ b/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx @@ -8,6 +8,7 @@ import { SVGContext, DrawingContext } from '../context/DrawingProvider'; import { SeriesContext } from '../context/SeriesContextProvider'; import { getValueToPositionMapper } from '../hooks/useScale'; import { getSVGPoint } from '../internals/utils'; +import { ScatterItemIdentifier } from '../models'; export type ChartsVoronoiHandlerProps = { /** @@ -16,10 +17,16 @@ export type ChartsVoronoiHandlerProps = { * @default undefined */ voronoiMaxRadius?: number | undefined; + /** + * Callback fired when clicking on a scatter item. + * @param {MouseEvent} event Mouse event catched at the svg level + * @param {ScatterItemIdentifier} scatterItemIdentifier Identify whihc item got clicked + */ + onItemClick?: (event: MouseEvent, scatterItemIdentifier: ScatterItemIdentifier) => void; }; function ChartsVoronoiHandler(props: ChartsVoronoiHandlerProps) { - const { voronoiMaxRadius } = props; + const { voronoiMaxRadius, onItemClick } = props; const svgRef = React.useContext(SVGContext); const { width, height, top, left } = React.useContext(DrawingContext); const { xAxis, yAxis, xAxisIds, yAxisIds } = React.useContext(CartesianContext); @@ -41,6 +48,8 @@ function ChartsVoronoiHandler(props: ChartsVoronoiHandlerProps) { }, [dispatch]); useEnhancedEffect(() => { + // This effect generate and store the Delaunay object that's used to map coordinate to closest point. + if (seriesOrder === undefined || series === undefined) { // If there is no scatter chart series return; @@ -74,66 +83,107 @@ function ChartsVoronoiHandler(props: ChartsVoronoiHandlerProps) { return undefined; } - const handleMouseOut = () => { - dispatch({ type: 'exitChart' }); - }; - // TODO: A perf optimisation of voronoi could be to use the last point as the intial point for the next search. - const handleMouseMove = (event: MouseEvent) => { + function getClosestPoint( + event: MouseEvent, + ): + | { seriesId: string; dataIndex: number } + | 'outside-chart' + | 'outside-voronoi-max-radius' + | 'no-point-found' { // Get mouse coordinate in global SVG space const svgPoint = getSVGPoint(svgRef.current!, event); const outsideX = svgPoint.x < left || svgPoint.x > left + width; const outsideY = svgPoint.y < top || svgPoint.y > top + height; if (outsideX || outsideY) { - dispatch({ type: 'exitChart' }); - return; + return 'outside-chart'; } if (!voronoiRef.current.delauney) { - return; + return 'no-point-found'; } const closestPointIndex = voronoiRef.current.delauney?.find(svgPoint.x, svgPoint.y); - if (closestPointIndex !== undefined) { - const seriesId = Object.keys(voronoiRef.current).find((id) => { - if (id === 'delauney') { - return false; - } - return ( - 2 * closestPointIndex >= voronoiRef.current[id].startIndex && - 2 * closestPointIndex < voronoiRef.current[id].endIndex - ); - }); - if (seriesId === undefined) { - return; + if (closestPointIndex === undefined) { + return 'no-point-found'; + } + + const seriesId = Object.keys(voronoiRef.current).find((id) => { + if (id === 'delauney') { + return false; } + return ( + 2 * closestPointIndex >= voronoiRef.current[id].startIndex && + 2 * closestPointIndex < voronoiRef.current[id].endIndex + ); + }); + if (seriesId === undefined) { + return 'no-point-found'; + } - const dataIndex = (2 * closestPointIndex - voronoiRef.current[seriesId].startIndex) / 2; - - if (voronoiMaxRadius !== undefined) { - const pointX = voronoiRef.current.delauney.points[2 * closestPointIndex]; - const pointY = voronoiRef.current.delauney.points[2 * closestPointIndex + 1]; - const dist2 = (pointX - svgPoint.x) ** 2 + (pointY - svgPoint.y) ** 2; - if (dist2 > voronoiMaxRadius ** 2) { - // The closest point is too far to be considered. - dispatch({ type: 'leaveItem', data: { type: 'scatter', seriesId, dataIndex } }); - return; - } + const dataIndex = (2 * closestPointIndex - voronoiRef.current[seriesId].startIndex) / 2; + + if (voronoiMaxRadius !== undefined) { + const pointX = voronoiRef.current.delauney.points[2 * closestPointIndex]; + const pointY = voronoiRef.current.delauney.points[2 * closestPointIndex + 1]; + const dist2 = (pointX - svgPoint.x) ** 2 + (pointY - svgPoint.y) ** 2; + if (dist2 > voronoiMaxRadius ** 2) { + // The closest point is too far to be considered. + return 'outside-voronoi-max-radius'; } - dispatch({ type: 'enterItem', data: { type: 'scatter', seriesId, dataIndex } }); } + return { seriesId, dataIndex }; + } + + const handleMouseOut = () => { + dispatch({ type: 'exitChart' }); + }; + + const handleMouseMove = (event: MouseEvent) => { + const closestPoint = getClosestPoint(event); + + if (closestPoint === 'outside-chart') { + dispatch({ type: 'exitChart' }); + return; + } + + if (closestPoint === 'outside-voronoi-max-radius' || closestPoint === 'no-point-found') { + dispatch({ type: 'leaveItem', data: { type: 'scatter' } }); + return; + } + + const { seriesId, dataIndex } = closestPoint; + dispatch({ type: 'enterItem', data: { type: 'scatter', seriesId, dataIndex } }); + }; + + const handleMouseClick = (event: MouseEvent) => { + if (!onItemClick) { + return; + } + const closestPoint = getClosestPoint(event); + + if (typeof closestPoint === 'string') { + // No point fond for any reason + return; + } + + const { seriesId, dataIndex } = closestPoint; + onItemClick(event, { type: 'scatter', seriesId, dataIndex }); }; element.addEventListener('mouseout', handleMouseOut); element.addEventListener('mousemove', handleMouseMove); - + element.addEventListener('click', handleMouseClick); return () => { element.removeEventListener('mouseout', handleMouseOut); element.removeEventListener('mousemove', handleMouseMove); + element.removeEventListener('click', handleMouseClick); }; - }, [svgRef, dispatch, left, width, top, height, yAxis, xAxis, voronoiMaxRadius]); - return ; // Workaround to fix docs scripts + }, [svgRef, dispatch, left, width, top, height, yAxis, xAxis, voronoiMaxRadius, onItemClick]); + + // eslint-disable-next-line react/jsx-no-useless-fragment + return ; } ChartsVoronoiHandler.propTypes = { @@ -141,6 +191,12 @@ ChartsVoronoiHandler.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * Callback fired when clicking on a scatter item. + * @param {MouseEvent} event Mouse event catched at the svg level + * @param {ScatterItemIdentifier} scatterItemIdentifier Identify whihc item got clicked + */ + onItemClick: PropTypes.func, /** * Defines the maximal distance between a scatter point and the pointer that triggers the interaction. * If `undefined`, the radius is assumed to be infinite. diff --git a/packages/x-charts/src/LineChart/AreaElement.tsx b/packages/x-charts/src/LineChart/AreaElement.tsx index d8819b94cefe4..1c9ed001bfac4 100644 --- a/packages/x-charts/src/LineChart/AreaElement.tsx +++ b/packages/x-charts/src/LineChart/AreaElement.tsx @@ -65,7 +65,8 @@ export interface AreaElementSlotProps { export interface AreaElementProps extends Omit, - Pick { + Pick, + Omit, 'color' | 'id'> { d: string; highlightScope?: Partial; /** @@ -91,7 +92,17 @@ export interface AreaElementProps * - [AreaElement API](https://mui.com/x/api/charts/area-element/) */ function AreaElement(props: AreaElementProps) { - const { id, classes: innerClasses, color, highlightScope, slots, slotProps, ...other } = props; + const { + id, + classes: innerClasses, + color, + highlightScope, + slots, + slotProps, + onClick, + ...other + } = props; + const getInteractionItemProps = useInteractionItemProps(highlightScope); const { item } = React.useContext(InteractionContext); @@ -117,6 +128,8 @@ function AreaElement(props: AreaElementProps) { ...other, ...getInteractionItemProps({ type: 'line', seriesId: id }), className: classes.root, + onClick, + cursor: onClick ? 'pointer' : 'unset', }, ownerState, }); diff --git a/packages/x-charts/src/LineChart/AreaPlot.tsx b/packages/x-charts/src/LineChart/AreaPlot.tsx index 8d4446ba7ff7a..f441e340e1183 100644 --- a/packages/x-charts/src/LineChart/AreaPlot.tsx +++ b/packages/x-charts/src/LineChart/AreaPlot.tsx @@ -12,6 +12,7 @@ import { import { getValueToPositionMapper } from '../hooks/useScale'; import getCurveFactory from '../internals/getCurve'; import { DEFAULT_X_AXIS_KEY } from '../constants'; +import { LineItemIdentifier } from '../models/seriesType/line'; export interface AreaPlotSlots extends AreaElementSlots {} @@ -19,7 +20,17 @@ export interface AreaPlotSlotProps extends AreaElementSlotProps {} export interface AreaPlotProps extends React.SVGAttributes, - Pick {} + Pick { + /** + * 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. + */ + onItemClick?: ( + event: React.MouseEvent, + lineItemIdentifier: LineItemIdentifier, + ) => void; +} const useAggregatedData = () => { const seriesData = React.useContext(SeriesContext).line; @@ -100,7 +111,7 @@ const useAggregatedData = () => { * - [AreaPlot API](https://mui.com/x/api/charts/area-plot/) */ function AreaPlot(props: AreaPlotProps) { - const { slots, slotProps, skipAnimation, ...other } = props; + const { slots, slotProps, onItemClick, skipAnimation, ...other } = props; const completedData = useAggregatedData(); @@ -119,6 +130,7 @@ function AreaPlot(props: AreaPlotProps) { highlightScope={highlightScope} slots={slots} slotProps={slotProps} + onClick={onItemClick && ((event) => onItemClick(event, { type: 'line', seriesId }))} skipAnimation={skipAnimation} /> ), @@ -132,6 +144,12 @@ AreaPlot.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn 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. + */ + onItemClick: PropTypes.func, /** * If `true`, animations are skipped. * @default false diff --git a/packages/x-charts/src/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index 2e0d71190d8ee..b6b4558689417 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -1,13 +1,13 @@ import * as React from 'react'; import useId from '@mui/utils/useId'; import PropTypes from 'prop-types'; -import { AreaPlot, AreaPlotSlotProps, AreaPlotSlots } from './AreaPlot'; -import { LinePlot, LinePlotSlotProps, LinePlotSlots } from './LinePlot'; +import { AreaPlot, AreaPlotProps, AreaPlotSlotProps, AreaPlotSlots } from './AreaPlot'; +import { LinePlot, LinePlotProps, LinePlotSlotProps, LinePlotSlots } from './LinePlot'; import { ResponsiveChartContainer, ResponsiveChartContainerProps, } from '../ResponsiveChartContainer'; -import { MarkPlot, MarkPlotSlotProps, MarkPlotSlots } from './MarkPlot'; +import { MarkPlot, MarkPlotProps, MarkPlotSlotProps, MarkPlotSlots } from './MarkPlot'; import { ChartsAxis, ChartsAxisProps } from '../ChartsAxis/ChartsAxis'; import { LineSeriesType } from '../models/seriesType/line'; import { MakeOptional } from '../models/helpers'; @@ -32,6 +32,10 @@ import { LineHighlightPlotSlots, LineHighlightPlotSlotProps, } from './LineHighlightPlot'; +import { + ChartsOnAxisClickHandler, + ChartsOnAxisClickHandlerProps, +} from '../ChartsOnAxisClickHandler'; export interface LineChartSlots extends ChartsAxisSlots, @@ -52,7 +56,8 @@ export interface LineChartSlotProps export interface LineChartProps extends Omit, - Omit { + Omit, + ChartsOnAxisClickHandlerProps { series: MakeOptional[]; tooltip?: ChartsTooltipProps; /** @@ -82,6 +87,9 @@ export interface LineChartProps * @default {} */ slotProps?: LineChartSlotProps; + onAreaClick?: AreaPlotProps['onItemClick']; + onLineClick?: LinePlotProps['onItemClick']; + onMarkClick?: MarkPlotProps['onItemClick']; /** * If `true`, animations are skipped. * @default false @@ -111,6 +119,10 @@ const LineChart = React.forwardRef(function LineChart(props: LineChartProps, ref dataset, sx, tooltip, + onAxisClick, + onAreaClick, + onLineClick, + onMarkClick, axisHighlight = { x: 'line' }, disableLineItemHighlight, legend, @@ -155,12 +167,26 @@ const LineChart = React.forwardRef(function LineChart(props: LineChartProps, ref dataset={dataset} sx={sx} disableAxisListener={ - tooltip?.trigger !== 'axis' && axisHighlight?.x === 'none' && axisHighlight?.y === 'none' + tooltip?.trigger !== 'axis' && + axisHighlight?.x === 'none' && + axisHighlight?.y === 'none' && + !onAxisClick } > + {onAxisClick && } - - + + - + @@ -319,6 +350,16 @@ LineChart.propTypes = { right: PropTypes.number, top: PropTypes.number, }), + 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, + onLineClick: PropTypes.func, + onMarkClick: 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`. diff --git a/packages/x-charts/src/LineChart/LineElement.tsx b/packages/x-charts/src/LineChart/LineElement.tsx index a03e2486c81c6..e5d2e21c6ecd5 100644 --- a/packages/x-charts/src/LineChart/LineElement.tsx +++ b/packages/x-charts/src/LineChart/LineElement.tsx @@ -65,7 +65,8 @@ export interface LineElementSlotProps { export interface LineElementProps extends Omit, - Pick { + Pick, + Omit, 'color' | 'id'> { d: string; highlightScope?: Partial; /** @@ -91,7 +92,16 @@ export interface LineElementProps * - [LineElement API](https://mui.com/x/api/charts/line-element/) */ function LineElement(props: LineElementProps) { - const { id, classes: innerClasses, color, highlightScope, slots, slotProps, ...other } = props; + const { + id, + classes: innerClasses, + color, + highlightScope, + slots, + slotProps, + onClick, + ...other + } = props; const getInteractionItemProps = useInteractionItemProps(highlightScope); const { item } = React.useContext(InteractionContext); @@ -117,6 +127,8 @@ function LineElement(props: LineElementProps) { ...other, ...getInteractionItemProps({ type: 'line', seriesId: id }), className: classes.root, + onClick, + cursor: onClick ? 'pointer' : 'unset', }, ownerState, }); diff --git a/packages/x-charts/src/LineChart/LineHighlightElement.tsx b/packages/x-charts/src/LineChart/LineHighlightElement.tsx index 987b9d5425b77..0fb858781aa14 100644 --- a/packages/x-charts/src/LineChart/LineHighlightElement.tsx +++ b/packages/x-charts/src/LineChart/LineHighlightElement.tsx @@ -75,12 +75,13 @@ function LineHighlightElement(props: LineHighlightElementProps) { return ( ); } diff --git a/packages/x-charts/src/LineChart/LinePlot.tsx b/packages/x-charts/src/LineChart/LinePlot.tsx index 1d180d423a323..885f3cc3ee0cc 100644 --- a/packages/x-charts/src/LineChart/LinePlot.tsx +++ b/packages/x-charts/src/LineChart/LinePlot.tsx @@ -12,6 +12,7 @@ import { import { getValueToPositionMapper } from '../hooks/useScale'; import getCurveFactory from '../internals/getCurve'; import { DEFAULT_X_AXIS_KEY } from '../constants'; +import { LineItemIdentifier } from '../models/seriesType/line'; export interface LinePlotSlots extends LineElementSlots {} @@ -19,7 +20,17 @@ export interface LinePlotSlotProps extends LineElementSlotProps {} export interface LinePlotProps extends React.SVGAttributes, - Pick {} + Pick { + /** + * Callback fired when a line item is clicked. + * @param {React.MouseEvent} event The event source of the callback. + * @param {LineItemIdentifier} lineItemIdentifier The line item identifier. + */ + onItemClick?: ( + event: React.MouseEvent, + lineItemIdentifier: LineItemIdentifier, + ) => void; +} const useAggregatedData = () => { const seriesData = React.useContext(SeriesContext).line; @@ -97,7 +108,7 @@ const useAggregatedData = () => { * - [LinePlot API](https://mui.com/x/api/charts/line-plot/) */ function LinePlot(props: LinePlotProps) { - const { slots, slotProps, skipAnimation, ...other } = props; + const { slots, slotProps, skipAnimation, onItemClick, ...other } = props; const completedData = useAggregatedData(); @@ -114,6 +125,7 @@ function LinePlot(props: LinePlotProps) { skipAnimation={skipAnimation} slots={slots} slotProps={slotProps} + onClick={onItemClick && ((event) => onItemClick(event, { type: 'line', seriesId }))} /> ); })} @@ -126,6 +138,12 @@ LinePlot.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * Callback fired when a line item is clicked. + * @param {React.MouseEvent} event The event source of the callback. + * @param {LineItemIdentifier} lineItemIdentifier The line item identifier. + */ + onItemClick: PropTypes.func, /** * If `true`, animations are skipped. * @default false diff --git a/packages/x-charts/src/LineChart/MarkElement.tsx b/packages/x-charts/src/LineChart/MarkElement.tsx index de78d5b1e8d8e..81a1dc09afaf8 100644 --- a/packages/x-charts/src/LineChart/MarkElement.tsx +++ b/packages/x-charts/src/LineChart/MarkElement.tsx @@ -121,6 +121,7 @@ function MarkElement(props: MarkElementProps) { shape, dataIndex, highlightScope, + onClick, skipAnimation, ...other } = props; @@ -155,6 +156,8 @@ function MarkElement(props: MarkElementProps) { ownerState={ownerState} className={classes.root} d={d3Symbol(d3SymbolsFill[getSymbol(shape)])()!} + onClick={onClick} + cursor={onClick ? 'pointer' : 'unset'} {...getInteractionItemProps({ type: 'line', seriesId: id, dataIndex })} /> ); diff --git a/packages/x-charts/src/LineChart/MarkPlot.tsx b/packages/x-charts/src/LineChart/MarkPlot.tsx index 69baf3061cbdf..59a78bbb4ab26 100644 --- a/packages/x-charts/src/LineChart/MarkPlot.tsx +++ b/packages/x-charts/src/LineChart/MarkPlot.tsx @@ -5,6 +5,7 @@ import { CartesianContext } from '../context/CartesianContextProvider'; import { MarkElement, MarkElementProps } from './MarkElement'; import { getValueToPositionMapper } from '../hooks/useScale'; import { DEFAULT_X_AXIS_KEY } from '../constants'; +import { LineItemIdentifier } from '../models/seriesType/line'; import { DrawingContext } from '../context/DrawingProvider'; import { cleanId } from '../internals/utils'; @@ -29,6 +30,15 @@ export interface MarkPlotProps * @default {} */ slotProps?: MarkPlotSlotProps; + /** + * Callback fired when a line mark item is clicked. + * @param {React.MouseEvent} event The event source of the callback. + * @param {LineItemIdentifier} lineItemIdentifier The line mark item identifier. + */ + onItemClick?: ( + event: React.MouseEvent, + lineItemIdentifier: LineItemIdentifier, + ) => void; } /** @@ -42,7 +52,7 @@ export interface MarkPlotProps * - [MarkPlot API](https://mui.com/x/api/charts/mark-plot/) */ function MarkPlot(props: MarkPlotProps) { - const { slots, slotProps, skipAnimation, ...other } = props; + const { slots, slotProps, skipAnimation, onItemClick, ...other } = props; const seriesData = React.useContext(SeriesContext).line; const axisData = React.useContext(CartesianContext); @@ -148,6 +158,11 @@ function MarkPlot(props: MarkPlotProps) { y={y!} // Don't know why TS doesn't get from the filter that y can't be null highlightScope={series[seriesId].highlightScope} skipAnimation={skipAnimation} + onClick={ + onItemClick && + ((event) => + onItemClick(event, { type: 'line', seriesId, dataIndex: index })) + } {...slotProps?.mark} /> ); @@ -165,6 +180,12 @@ MarkPlot.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * Callback fired when a line mark item is clicked. + * @param {React.MouseEvent} event The event source of the callback. + * @param {LineItemIdentifier} lineItemIdentifier The line mark item identifier. + */ + onItemClick: PropTypes.func, /** * If `true`, animations are skipped. * @default false diff --git a/packages/x-charts/src/PieChart/PieArcPlot.tsx b/packages/x-charts/src/PieChart/PieArcPlot.tsx index 1db0508cc4175..b8c29b427bb81 100644 --- a/packages/x-charts/src/PieChart/PieArcPlot.tsx +++ b/packages/x-charts/src/PieChart/PieArcPlot.tsx @@ -50,7 +50,7 @@ export interface PieArcPlotProps * @param {PieItemIdentifier} pieItemIdentifier The pie item identifier. * @param {DefaultizedPieValueType} item The pie item. */ - onClick?: ( + onItemClick?: ( event: React.MouseEvent, pieItemIdentifier: PieItemIdentifier, item: DefaultizedPieValueType, @@ -75,7 +75,7 @@ function PieArcPlot(props: PieArcPlotProps) { highlighted, faded = { additionalRadius: -5 }, data, - onClick, + onItemClick, skipAnimation, ...other } = props; @@ -136,9 +136,9 @@ function PieArcPlot(props: PieArcPlotProps) { isFaded={item.isFaded} isHighlighted={item.isHighlighted} onClick={ - onClick && + onItemClick && ((event) => { - onClick(event, { type: 'pie', seriesId: id, dataIndex: index }, item); + onItemClick(event, { type: 'pie', seriesId: id, dataIndex: index }, item); }) } {...slotProps?.pieArc} @@ -219,7 +219,7 @@ PieArcPlot.propTypes = { * @param {PieItemIdentifier} pieItemIdentifier The pie item identifier. * @param {DefaultizedPieValueType} item The pie item. */ - onClick: PropTypes.func, + onItemClick: PropTypes.func, /** * The radius between circle center and the end of the arc. */ diff --git a/packages/x-charts/src/PieChart/PieChart.tsx b/packages/x-charts/src/PieChart/PieChart.tsx index cb0cd54077d67..c3b5946b003b0 100644 --- a/packages/x-charts/src/PieChart/PieChart.tsx +++ b/packages/x-charts/src/PieChart/PieChart.tsx @@ -65,8 +65,7 @@ export interface PieChartProps * @deprecated Consider using `slotProps.legend` instead. */ legend?: ChartsLegendProps; - onClick?: PiePlotProps['onClick']; - + onItemClick?: PiePlotProps['onItemClick']; slots?: PieChartSlots; /** * The props used for each component slot. @@ -108,7 +107,7 @@ function PieChart(props: PieChartProps) { children, slots, slotProps, - onClick, + onItemClick, } = props; const margin = { ...defaultMargin, ...marginProps }; @@ -147,7 +146,7 @@ function PieChart(props: PieChartProps) { @@ -284,7 +283,7 @@ PieChart.propTypes = { right: PropTypes.number, top: PropTypes.number, }), - onClick: PropTypes.func, + onItemClick: 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`. diff --git a/packages/x-charts/src/PieChart/PiePlot.tsx b/packages/x-charts/src/PieChart/PiePlot.tsx index 198ef8accc157..3352b3ed5c331 100644 --- a/packages/x-charts/src/PieChart/PiePlot.tsx +++ b/packages/x-charts/src/PieChart/PiePlot.tsx @@ -10,7 +10,7 @@ export interface PiePlotSlots extends PieArcPlotSlots, PieArcLabelPlotSlots {} export interface PiePlotSlotProps extends PieArcPlotSlotProps, PieArcLabelPlotSlotProps {} -export interface PiePlotProps extends Pick { +export interface PiePlotProps extends Pick { /** * Overridable component slots. * @default {} @@ -40,7 +40,7 @@ export interface PiePlotProps extends Pick @@ -154,7 +154,7 @@ PiePlot.propTypes = { * @param {PieItemIdentifier} pieItemIdentifier The pie item identifier. * @param {DefaultizedPieValueType} item The pie item. */ - onClick: PropTypes.func, + onItemClick: PropTypes.func, /** * If `true`, animations are skipped. * @default false diff --git a/packages/x-charts/src/ScatterChart/Scatter.tsx b/packages/x-charts/src/ScatterChart/Scatter.tsx index 75ea2af883541..0b5fdd0689337 100644 --- a/packages/x-charts/src/ScatterChart/Scatter.tsx +++ b/packages/x-charts/src/ScatterChart/Scatter.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { DefaultizedScatterSeriesType } from '../models/seriesType/scatter'; +import { DefaultizedScatterSeriesType, ScatterItemIdentifier } from '../models/seriesType/scatter'; import { getValueToPositionMapper } from '../hooks/useScale'; import { getIsFaded, @@ -17,6 +17,15 @@ export interface ScatterProps { yScale: D3Scale; markerSize: number; color: string; + /** + * Callback fired when clicking on a scatter item. + * @param {MouseEvent} event Mouse event recorded on the `` element. + * @param {ScatterItemIdentifier} scatterItemIdentifier The scatter item identifier. + */ + onItemClick?: ( + event: React.MouseEvent, + scatterItemIdentifier: ScatterItemIdentifier, + ) => void; } /** @@ -30,7 +39,7 @@ export interface ScatterProps { * - [Scatter API](https://mui.com/x/api/charts/scatter/) */ function Scatter(props: ScatterProps) { - const { series, xScale, yScale, color, markerSize } = props; + const { series, xScale, yScale, color, markerSize, onItemClick } = props; const highlightScope: HighlightScope = React.useMemo( () => ({ highlighted: 'item', faded: 'global', ...series.highlightScope }), @@ -57,6 +66,7 @@ function Scatter(props: ScatterProps) { x: number; y: number; id: string | number; + dataIndex: number; isHighlighted: boolean; isFaded: boolean; interactionProps: ReturnType; @@ -81,6 +91,7 @@ function Scatter(props: ScatterProps) { isFaded: !isHighlighted && getIsFaded(item, pointCtx, highlightScope), interactionProps: getInteractionItemProps(pointCtx), id: scatterPoint.id, + dataIndex: i, }); } } @@ -99,6 +110,16 @@ function Scatter(props: ScatterProps) { transform={`translate(${dataPoint.x}, ${dataPoint.y})`} fill={color} opacity={(dataPoint.isFaded && 0.3) || 1} + onClick={ + onItemClick && + ((event) => + onItemClick(event, { + type: 'scatter', + seriesId: series.id, + dataIndex: dataPoint.dataIndex, + })) + } + cursor={onItemClick ? 'pointer' : 'unset'} {...dataPoint.interactionProps} /> ))} @@ -113,6 +134,12 @@ Scatter.propTypes = { // ---------------------------------------------------------------------- color: PropTypes.string.isRequired, markerSize: PropTypes.number.isRequired, + /** + * Callback fired when clicking on a scatter item. + * @param {MouseEvent} event Mouse event recorded on the `` element. + * @param {ScatterItemIdentifier} scatterItemIdentifier The scatter item identifier. + */ + onItemClick: PropTypes.func, series: PropTypes.object.isRequired, xScale: PropTypes.func.isRequired, yScale: PropTypes.func.isRequired, diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index 0b718d98ee695..5b59407db17c7 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -1,6 +1,11 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { ScatterPlot, ScatterPlotSlotProps, ScatterPlotSlots } from './ScatterPlot'; +import { + ScatterPlot, + ScatterPlotProps, + ScatterPlotSlotProps, + ScatterPlotSlots, +} from './ScatterPlot'; import { ResponsiveChartContainer, ResponsiveChartContainerProps, @@ -41,7 +46,7 @@ export interface ScatterChartSlotProps export interface ScatterChartProps extends Omit, Omit, - ChartsVoronoiHandlerProps { + Omit { series: MakeOptional[]; tooltip?: ChartsTooltipProps; axisHighlight?: ChartsAxisHighlightProps; @@ -64,6 +69,12 @@ export interface ScatterChartProps * @default {} */ slotProps?: ScatterChartSlotProps; + /** + * Callback fired when clicking on a scatter item. + * @param {MouseEvent} event The mouse event recorded on the `` element if using Voronoi cells. Or the Mouse event from the scatter element, when `disableVoronoi=true`. + * @param {ScatterItemIdentifier} scatterItemIdentifier The scatter item identifier. + */ + onItemClick?: ScatterPlotProps['onItemClick'] | ChartsVoronoiHandlerProps['onItemClick']; } /** @@ -95,6 +106,7 @@ const ScatterChart = React.forwardRef(function ScatterChart(props: ScatterChartP leftAxis, rightAxis, bottomAxis, + onItemClick, children, slots, slotProps, @@ -111,7 +123,13 @@ const ScatterChart = React.forwardRef(function ScatterChart(props: ScatterChartP yAxis={yAxis} sx={sx} > - {!disableVoronoi && } + {!disableVoronoi && ( + + )} + - + @@ -260,6 +282,12 @@ ScatterChart.propTypes = { right: PropTypes.number, top: PropTypes.number, }), + /** + * Callback fired when clicking on a scatter item. + * @param {MouseEvent} event The mouse event recorded on the `` element if using Voronoi cells. Or the Mouse event from the scatter element, when `disableVoronoi=true`. + * @param {ScatterItemIdentifier} scatterItemIdentifier The scatter item identifier. + */ + onItemClick: 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`. diff --git a/packages/x-charts/src/ScatterChart/ScatterPlot.tsx b/packages/x-charts/src/ScatterChart/ScatterPlot.tsx index 2c27f9d15b622..4f82984741031 100644 --- a/packages/x-charts/src/ScatterChart/ScatterPlot.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterPlot.tsx @@ -12,7 +12,7 @@ export interface ScatterPlotSlotProps { scatter?: Partial; } -export interface ScatterPlotProps { +export interface ScatterPlotProps extends Pick { /** * Overridable component slots. * @default {} @@ -36,7 +36,7 @@ export interface ScatterPlotProps { * - [ScatterPlot API](https://mui.com/x/api/charts/scatter-plot/) */ function ScatterPlot(props: ScatterPlotProps) { - const { slots, slotProps } = props; + const { slots, slotProps, onItemClick } = props; const seriesData = React.useContext(SeriesContext).scatter; const axisData = React.useContext(CartesianContext); @@ -65,6 +65,7 @@ function ScatterPlot(props: ScatterPlotProps) { color={color} markerSize={markerSize ?? 4} series={series[seriesId]} + onItemClick={onItemClick} {...slotProps?.scatter} /> ); @@ -78,6 +79,12 @@ ScatterPlot.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * Callback fired when clicking on a scatter item. + * @param {MouseEvent} event Mouse event recorded on the `` element. + * @param {ScatterItemIdentifier} scatterItemIdentifier The scatter item identifier. + */ + onItemClick: PropTypes.func, /** * The props used for each component slot. * @default {} diff --git a/packages/x-charts/src/context/InteractionProvider.tsx b/packages/x-charts/src/context/InteractionProvider.tsx index a8c3f75d37fe9..0e478d13a09a2 100644 --- a/packages/x-charts/src/context/InteractionProvider.tsx +++ b/packages/x-charts/src/context/InteractionProvider.tsx @@ -25,7 +25,7 @@ type InteractionActions = } | { type: 'leaveItem'; - data: ItemInteractionData; + data: Partial>; } | { type: 'exitChart'; diff --git a/packages/x-charts/src/index.ts b/packages/x-charts/src/index.ts index cc46bd9eb7334..750a9107003e6 100644 --- a/packages/x-charts/src/index.ts +++ b/packages/x-charts/src/index.ts @@ -13,6 +13,7 @@ export * from './ChartsTooltip'; export * from './ChartsLegend'; export * from './ChartsAxisHighlight'; export * from './ChartsVoronoiHandler'; +export * from './ChartsOnAxisClickHandler'; export * from './BarChart'; export * from './LineChart'; export * from './PieChart'; diff --git a/scripts/x-charts.exports.json b/scripts/x-charts.exports.json index 49a150ddaa4b9..e22243740e686 100644 --- a/scripts/x-charts.exports.json +++ b/scripts/x-charts.exports.json @@ -73,6 +73,8 @@ { "name": "ChartsLegendRootOwnerState", "kind": "TypeAlias" }, { "name": "ChartsLegendSlotProps", "kind": "Interface" }, { "name": "ChartsLegendSlots", "kind": "Interface" }, + { "name": "ChartsOnAxisClickHandler", "kind": "Function" }, + { "name": "ChartsOnAxisClickHandlerProps", "kind": "Interface" }, { "name": "ChartsPieSorting", "kind": "TypeAlias" }, { "name": "ChartsReferenceLine", "kind": "Function" }, { "name": "ChartsReferenceLineClasses", "kind": "Interface" }, From 04fafeb634066f6a0070070e778f504eb2f10b14 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Date: Thu, 1 Feb 2024 13:28:27 +0100 Subject: [PATCH 05/35] bump monorepo (#11897) --- docs/package.json | 12 +- package.json | 6 +- .../grid/x-data-grid-generator/package.json | 2 +- .../grid/x-data-grid-premium/package.json | 4 +- packages/grid/x-data-grid-pro/package.json | 4 +- packages/grid/x-data-grid/package.json | 4 +- packages/x-charts/package.json | 6 +- packages/x-date-pickers-pro/package.json | 6 +- packages/x-date-pickers/package.json | 6 +- packages/x-license-pro/package.json | 2 +- packages/x-tree-view/package.json | 6 +- yarn.lock | 158 +++++++++--------- 12 files changed, 108 insertions(+), 108 deletions(-) diff --git a/docs/package.json b/docs/package.json index 6568e6136eeba..602319a2772a5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -27,12 +27,12 @@ "@emotion/react": "^11.11.3", "@emotion/server": "^11.11.0", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.15.6", - "@mui/joy": "^5.0.0-beta.24", - "@mui/lab": "^5.0.0-alpha.162", - "@mui/material": "^5.15.6", - "@mui/styles": "^5.15.6", - "@mui/utils": "^5.15.6", + "@mui/icons-material": "^5.15.7", + "@mui/joy": "^5.0.0-beta.25", + "@mui/lab": "^5.0.0-alpha.163", + "@mui/material": "^5.15.7", + "@mui/styles": "^5.15.7", + "@mui/utils": "^5.15.7", "@react-spring/web": "^9.7.3", "@trendmicro/react-interpolate": "^0.5.5", "@types/lodash": "^4.14.202", diff --git a/package.json b/package.json index 279364aaa3fbb..5d46619e78196 100644 --- a/package.json +++ b/package.json @@ -84,10 +84,10 @@ "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@mnajdova/enzyme-adapter-react-18": "^0.2.0", - "@mui/icons-material": "^5.15.6", - "@mui/material": "^5.15.6", + "@mui/icons-material": "^5.15.7", + "@mui/material": "^5.15.7", "@mui/monorepo": "https://github.com/mui/material-ui.git#master", - "@mui/utils": "^5.15.6", + "@mui/utils": "^5.15.7", "@next/eslint-plugin-next": "14.0.4", "@octokit/plugin-retry": "^6.0.1", "@octokit/rest": "^20.0.2", diff --git a/packages/grid/x-data-grid-generator/package.json b/packages/grid/x-data-grid-generator/package.json index 90c4bbfc26bd7..e263a77b43c9d 100644 --- a/packages/grid/x-data-grid-generator/package.json +++ b/packages/grid/x-data-grid-generator/package.json @@ -34,7 +34,7 @@ }, "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/base": "^5.0.0-beta.33", + "@mui/base": "^5.0.0-beta.34", "@mui/x-data-grid-premium": "7.0.0-beta.0", "chance": "^1.1.11", "clsx": "^2.1.0", diff --git a/packages/grid/x-data-grid-premium/package.json b/packages/grid/x-data-grid-premium/package.json index a2c2b531db695..a7b4750b49135 100644 --- a/packages/grid/x-data-grid-premium/package.json +++ b/packages/grid/x-data-grid-premium/package.json @@ -44,8 +44,8 @@ }, "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/system": "^5.15.6", - "@mui/utils": "^5.15.6", + "@mui/system": "^5.15.7", + "@mui/utils": "^5.15.7", "@mui/x-data-grid": "7.0.0-beta.0", "@mui/x-data-grid-pro": "7.0.0-beta.0", "@mui/x-license-pro": "7.0.0-beta.0", diff --git a/packages/grid/x-data-grid-pro/package.json b/packages/grid/x-data-grid-pro/package.json index 6e4ffcf65dc7b..7d3adb5cb7af1 100644 --- a/packages/grid/x-data-grid-pro/package.json +++ b/packages/grid/x-data-grid-pro/package.json @@ -44,8 +44,8 @@ }, "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/system": "^5.15.6", - "@mui/utils": "^5.15.6", + "@mui/system": "^5.15.7", + "@mui/utils": "^5.15.7", "@mui/x-data-grid": "7.0.0-beta.0", "@mui/x-license-pro": "7.0.0-beta.0", "@types/format-util": "^1.0.4", diff --git a/packages/grid/x-data-grid/package.json b/packages/grid/x-data-grid/package.json index ba2eeb5264344..ee2ae2b86543c 100644 --- a/packages/grid/x-data-grid/package.json +++ b/packages/grid/x-data-grid/package.json @@ -48,8 +48,8 @@ }, "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/system": "^5.15.6", - "@mui/utils": "^5.15.6", + "@mui/system": "^5.15.7", + "@mui/utils": "^5.15.7", "clsx": "^2.1.0", "prop-types": "^15.8.1", "reselect": "^4.1.8" diff --git a/packages/x-charts/package.json b/packages/x-charts/package.json index 5ed752020b0f2..441fb68c82a19 100644 --- a/packages/x-charts/package.json +++ b/packages/x-charts/package.json @@ -40,9 +40,9 @@ }, "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/base": "^5.0.0-beta.33", - "@mui/system": "^5.15.6", - "@mui/utils": "^5.15.6", + "@mui/base": "^5.0.0-beta.34", + "@mui/system": "^5.15.7", + "@mui/utils": "^5.15.7", "@react-spring/rafz": "^9.7.3", "@react-spring/web": "^9.7.3", "clsx": "^2.1.0", diff --git a/packages/x-date-pickers-pro/package.json b/packages/x-date-pickers-pro/package.json index a0290c6382e46..94a902cf856ec 100644 --- a/packages/x-date-pickers-pro/package.json +++ b/packages/x-date-pickers-pro/package.json @@ -43,9 +43,9 @@ }, "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/base": "^5.0.0-beta.33", - "@mui/system": "^5.15.6", - "@mui/utils": "^5.15.6", + "@mui/base": "^5.0.0-beta.34", + "@mui/system": "^5.15.7", + "@mui/utils": "^5.15.7", "@mui/x-date-pickers": "7.0.0-beta.0", "@mui/x-license-pro": "7.0.0-beta.0", "clsx": "^2.1.0", diff --git a/packages/x-date-pickers/package.json b/packages/x-date-pickers/package.json index 66513995ed30d..3130ca36a46a5 100644 --- a/packages/x-date-pickers/package.json +++ b/packages/x-date-pickers/package.json @@ -46,9 +46,9 @@ }, "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/base": "^5.0.0-beta.33", - "@mui/system": "^5.15.6", - "@mui/utils": "^5.15.6", + "@mui/base": "^5.0.0-beta.34", + "@mui/system": "^5.15.7", + "@mui/utils": "^5.15.7", "@types/react-transition-group": "^4.4.10", "clsx": "^2.1.0", "prop-types": "^15.8.1", diff --git a/packages/x-license-pro/package.json b/packages/x-license-pro/package.json index 239c2994cc858..a5af0141425c0 100644 --- a/packages/x-license-pro/package.json +++ b/packages/x-license-pro/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.15.6" + "@mui/utils": "^5.15.7" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0" diff --git a/packages/x-tree-view/package.json b/packages/x-tree-view/package.json index 1cf6e981ef448..be02940081368 100644 --- a/packages/x-tree-view/package.json +++ b/packages/x-tree-view/package.json @@ -44,9 +44,9 @@ }, "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/base": "^5.0.0-beta.33", - "@mui/system": "^5.15.6", - "@mui/utils": "^5.15.6", + "@mui/base": "^5.0.0-beta.34", + "@mui/system": "^5.15.7", + "@mui/utils": "^5.15.7", "@types/react-transition-group": "^4.4.10", "clsx": "^2.1.0", "prop-types": "^15.8.1", diff --git a/yarn.lock b/yarn.lock index 3db928c8d825f..1d61768874dcd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1286,7 +1286,7 @@ core-js "^2.6.12" regenerator-runtime "^0.14.0" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.8", "@babel/runtime@^7.23.9", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.9", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.23.9" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7" integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw== @@ -1560,7 +1560,7 @@ "@floating-ui/core" "^1.6.0" "@floating-ui/utils" "^0.2.1" -"@floating-ui/react-dom@^2.0.6": +"@floating-ui/react-dom@^2.0.8": version "2.0.8" resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.8.tgz#afc24f9756d1b433e1fe0d047c24bd4d9cefaa5d" integrity sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw== @@ -1796,69 +1796,69 @@ react-test-renderer "^18.0.0" semver "^5.7.0" -"@mui/base@5.0.0-beta.33", "@mui/base@^5.0.0-beta.33": - version "5.0.0-beta.33" - resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.33.tgz#fbb844e2d840d47dd7a48850a03152aed2381d10" - integrity sha512-WcSpoJUw/UYHXpvgtl4HyMar2Ar97illUpqiS/X1gtSBp6sdDW6kB2BJ9OlVQ+Kk/RL2GDp/WHA9sbjAYV35ow== +"@mui/base@5.0.0-beta.34", "@mui/base@^5.0.0-beta.34": + version "5.0.0-beta.34" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.34.tgz#44b0f203250a6e3b2d810f37c9720d114182abd0" + integrity sha512-e2mbTGTtReD/y5RFwnhkl1Tgl3XwgJhY040IlfkTVaU9f5LWrVhEnpRsYXu3B1CtLrwiWs4cu7aMHV9yRd4jpw== dependencies: - "@babel/runtime" "^7.23.8" - "@floating-ui/react-dom" "^2.0.6" + "@babel/runtime" "^7.23.9" + "@floating-ui/react-dom" "^2.0.8" "@mui/types" "^7.2.13" - "@mui/utils" "^5.15.6" + "@mui/utils" "^5.15.7" "@popperjs/core" "^2.11.8" clsx "^2.1.0" prop-types "^15.8.1" -"@mui/core-downloads-tracker@^5.15.6": - version "5.15.6" - resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.6.tgz#9b82ba86d5a0fe55e9479b68dd5068943cc3835b" - integrity sha512-0aoWS4qvk1uzm9JBs83oQmIMIQeTBUeqqu8u+3uo2tMznrB5fIKqQVCbCgq+4Tm4jG+5F7dIvnjvQ2aV7UKtdw== +"@mui/core-downloads-tracker@^5.15.7": + version "5.15.7" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.7.tgz#78a0e98ecbd84906bf7339f780e8f41c5d505754" + integrity sha512-AuF+Wo2Mp/edaO6vJnWjg+gj4tzEz5ChMZnAQpc22DXpSvM8ddgGcZvM7D7F99pIBoSv8ub+Iz0viL+yuGVmhg== -"@mui/icons-material@^5.15.6": - version "5.15.6" - resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.15.6.tgz#6958232bef48972fcbafd5f69e6079a9be5951f1" - integrity sha512-GnkxMtlhs+8ieHLmCytg00ew0vMOiXGFCw8Ra9nxMsBjBqnrOI5gmXqUm+sGggeEU/HG8HyeqC1MX/IxOBJHzA== +"@mui/icons-material@^5.15.7": + version "5.15.7" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.15.7.tgz#6b1cc370894f505b756fa1aa1cbd25b5890d54d5" + integrity sha512-EDAc8TVJGIA/imAvR3u4nANl2W5h3QeHieu2gK7Ypez/nIA55p08tHjf8UrMXEpxCAvfZO6piY9S9uaxETdicA== dependencies: - "@babel/runtime" "^7.23.8" + "@babel/runtime" "^7.23.9" -"@mui/joy@^5.0.0-beta.24": - version "5.0.0-beta.24" - resolved "https://registry.yarnpkg.com/@mui/joy/-/joy-5.0.0-beta.24.tgz#5210c4cde618d7452a2fd8129b155dc0e1616f9b" - integrity sha512-cKlIW56GsKKo9cVm+6pzNS+s4ch3r/SX/Zq5DA10I/TSuW9O5ptIOqeSs+WYpkyAzIoPkCpEXCPR/vGHpOt6MA== +"@mui/joy@^5.0.0-beta.25": + version "5.0.0-beta.25" + resolved "https://registry.yarnpkg.com/@mui/joy/-/joy-5.0.0-beta.25.tgz#e1c0d620b27b928c66f87248fdb489cdee0b104f" + integrity sha512-7OF+np0h92GSVjwu1EyKRAjEsTJfP1F3RTIrtKH+XlzP/GYvZ68TiRen7sya0creQzGsc4NRJU3aEnvEX691Mg== dependencies: - "@babel/runtime" "^7.23.8" - "@mui/base" "5.0.0-beta.33" - "@mui/core-downloads-tracker" "^5.15.6" - "@mui/system" "^5.15.6" + "@babel/runtime" "^7.23.9" + "@mui/base" "5.0.0-beta.34" + "@mui/core-downloads-tracker" "^5.15.7" + "@mui/system" "^5.15.7" "@mui/types" "^7.2.13" - "@mui/utils" "^5.15.6" + "@mui/utils" "^5.15.7" clsx "^2.1.0" prop-types "^15.8.1" -"@mui/lab@^5.0.0-alpha.162": - version "5.0.0-alpha.162" - resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.162.tgz#f7b4ddef46f796760a1f667f444060b3984fb3ab" - integrity sha512-nSdlhq1YVozKXn6mtItWmnU9b/gQ708RSWG6C+M/Y096MlQ7Mz1gdNWOEwcGw2HaNoNgDvuG0+0HKARAMIMaLg== +"@mui/lab@^5.0.0-alpha.163": + version "5.0.0-alpha.163" + resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.163.tgz#e25969a3e9188da7d76aa3c9047422df98662fe7" + integrity sha512-ieOX3LFBln78jgNsBca0JUX+zAC2p6/u2P9b7rU9eZIr0AK44b5Qr8gDOWI1JfJtib4kxLGd1Msasrbxy5cMSQ== dependencies: - "@babel/runtime" "^7.23.8" - "@mui/base" "5.0.0-beta.33" - "@mui/system" "^5.15.6" + "@babel/runtime" "^7.23.9" + "@mui/base" "5.0.0-beta.34" + "@mui/system" "^5.15.7" "@mui/types" "^7.2.13" - "@mui/utils" "^5.15.6" + "@mui/utils" "^5.15.7" clsx "^2.1.0" prop-types "^15.8.1" -"@mui/material@^5.15.6": - version "5.15.6" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.15.6.tgz#e32944ae4e01f85b314bc26e4cbbb700d598f30c" - integrity sha512-rw7bDdpi2kzfmcDN78lHp8swArJ5sBCKsn+4G3IpGfu44ycyWAWX0VdlvkjcR9Yrws2KIm7c+8niXpWHUDbWoA== +"@mui/material@^5.15.7": + version "5.15.7" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.15.7.tgz#8496d8a2b9f0409a0f82b93f819a48f6f82bc12f" + integrity sha512-l6+AiKZH3iOJmZCnlpel8ghYQe9Lq0BEuKP8fGj3g5xz4arO9GydqYAtLPMvuHKtArj8lJGNuT2yHYxmejincA== dependencies: - "@babel/runtime" "^7.23.8" - "@mui/base" "5.0.0-beta.33" - "@mui/core-downloads-tracker" "^5.15.6" - "@mui/system" "^5.15.6" + "@babel/runtime" "^7.23.9" + "@mui/base" "5.0.0-beta.34" + "@mui/core-downloads-tracker" "^5.15.7" + "@mui/system" "^5.15.7" "@mui/types" "^7.2.13" - "@mui/utils" "^5.15.6" + "@mui/utils" "^5.15.7" "@types/react-transition-group" "^4.4.10" clsx "^2.1.0" csstype "^3.1.2" @@ -1867,42 +1867,42 @@ react-transition-group "^4.4.5" "@mui/monorepo@https://github.com/mui/material-ui.git#master": - version "5.15.6" - resolved "https://github.com/mui/material-ui.git#b63fb955e6cfab340fdc3597fbb399493d39d81d" + version "5.15.7" + resolved "https://github.com/mui/material-ui.git#19ff6ada02dafa827531653801a3b657d58047ba" dependencies: "@googleapis/sheets" "^5.0.5" "@slack/bolt" "^3.17.1" - google-auth-library "^9.4.2" + google-auth-library "^9.5.0" -"@mui/private-theming@^5.15.6": - version "5.15.6" - resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.15.6.tgz#224819694ed76df041b1257256152a45d1fd733d" - integrity sha512-ZBX9E6VNUSscUOtU8uU462VvpvBS7eFl5VfxAzTRVQBHflzL+5KtnGrebgf6Nd6cdvxa1o0OomiaxSKoN2XDmg== +"@mui/private-theming@^5.15.7": + version "5.15.7" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.15.7.tgz#a1b2aeac22ac2b71cd18f7ac61bb10dd6adfe173" + integrity sha512-bcEeeXm7GyQCQvN9dwo8htGv8/6tP05p0i02Z7GXm5EoDPlBcqTNGugsjNLoGq6B0SsdyanjJGw0Jw00o1yAOA== dependencies: - "@babel/runtime" "^7.23.8" - "@mui/utils" "^5.15.6" + "@babel/runtime" "^7.23.9" + "@mui/utils" "^5.15.7" prop-types "^15.8.1" -"@mui/styled-engine@^5.15.6": - version "5.15.6" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.15.6.tgz#3f4a8804de6ddeee17cb52ec92225686f423398a" - integrity sha512-KAn8P8xP/WigFKMlEYUpU9z2o7jJnv0BG28Qu1dhNQVutsLVIFdRf5Nb+0ijp2qgtcmygQ0FtfRuXv5LYetZTg== +"@mui/styled-engine@^5.15.7": + version "5.15.7" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.15.7.tgz#011fd98d57af927b1a744efc0186089bd0add57b" + integrity sha512-ixSdslOjK1kzdGcxqj7O3d14By/LPQ7EWknsViQ8RaeT863EAQemS+zvUJDTcOpkfJh6q6gPnYMIb2TJCs9eWA== dependencies: - "@babel/runtime" "^7.23.8" + "@babel/runtime" "^7.23.9" "@emotion/cache" "^11.11.0" csstype "^3.1.2" prop-types "^15.8.1" -"@mui/styles@^5.15.6": - version "5.15.6" - resolved "https://registry.yarnpkg.com/@mui/styles/-/styles-5.15.6.tgz#128529bf50e7055974e48e51e9bf67fc8e143fcf" - integrity sha512-5WYJ4KjJ4eMEgWcqY8lPr1hbte5mw7/zVgB7IjonoyIEnG9JPKbT/ma4QW5Rm3q/dUxmpngrRdh60fZPIhQpfw== +"@mui/styles@^5.15.7": + version "5.15.7" + resolved "https://registry.yarnpkg.com/@mui/styles/-/styles-5.15.7.tgz#f73d4967c51aaa8aca8edd84b3829a8edf4e9c3f" + integrity sha512-3F/ZIPyVLz5mlc6fZRSdfj8i3JBn+lPrXikFJ5NlK2n23cXZSEYe14hpbYRCflxumPNnvSjkYnGc/RvBgb5ZAQ== dependencies: - "@babel/runtime" "^7.23.8" + "@babel/runtime" "^7.23.9" "@emotion/hash" "^0.9.1" - "@mui/private-theming" "^5.15.6" + "@mui/private-theming" "^5.15.7" "@mui/types" "^7.2.13" - "@mui/utils" "^5.15.6" + "@mui/utils" "^5.15.7" clsx "^2.1.0" csstype "^3.1.2" hoist-non-react-statics "^3.3.2" @@ -1916,16 +1916,16 @@ jss-plugin-vendor-prefixer "^10.10.0" prop-types "^15.8.1" -"@mui/system@^5.15.6": - version "5.15.6" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.15.6.tgz#d278adb09d57ee21f4eef2f6bc335bf9bd062fca" - integrity sha512-J01D//u8IfXvaEHMBQX5aO2l7Q+P15nt96c4NskX7yp5/+UuZP8XCQJhtBtLuj+M2LLyXHYGmCPeblsmmscP2Q== +"@mui/system@^5.15.7": + version "5.15.7" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.15.7.tgz#5ded95c14c78e0a2b5cb9a8643c6fc05c621be7f" + integrity sha512-9alZ4/dLxsTwUOdqakgzxiL5YW6ntqj0CfzWImgWnBMTZhgGcPsbYpBLniNkkk7/jptma4/bykWXHwju/ls/pg== dependencies: - "@babel/runtime" "^7.23.8" - "@mui/private-theming" "^5.15.6" - "@mui/styled-engine" "^5.15.6" + "@babel/runtime" "^7.23.9" + "@mui/private-theming" "^5.15.7" + "@mui/styled-engine" "^5.15.7" "@mui/types" "^7.2.13" - "@mui/utils" "^5.15.6" + "@mui/utils" "^5.15.7" clsx "^2.1.0" csstype "^3.1.2" prop-types "^15.8.1" @@ -1935,12 +1935,12 @@ resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.13.tgz#d1584912942f9dc042441ecc2d1452be39c666b8" integrity sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g== -"@mui/utils@^5.15.6": - version "5.15.6" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.15.6.tgz#bbcc302b8e83e360a87230afe3ed8fc99e29fae9" - integrity sha512-qfEhf+zfU9aQdbzo1qrSWlbPQhH1nCgeYgwhOVnj9Bn39shJQitEnXpSQpSNag8+uty5Od6PxmlNKPTnPySRKA== +"@mui/utils@^5.15.7": + version "5.15.7" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.15.7.tgz#a71e08c4a2f5ba9c8a07106083ebf1b4c864ebb1" + integrity sha512-8qhsxQRNV6aEOjjSk6YQIYJxkF5klhj8oG1FEEU4z6HV78TjNqRxMP08QGcdsibEbez+nihAaz6vu83b4XqbAg== dependencies: - "@babel/runtime" "^7.23.8" + "@babel/runtime" "^7.23.9" "@types/prop-types" "^15.7.11" prop-types "^15.8.1" react-is "^18.2.0" @@ -7951,7 +7951,7 @@ gm@^1.25.0: cross-spawn "^4.0.0" debug "^3.1.0" -google-auth-library@^9.0.0, google-auth-library@^9.4.2: +google-auth-library@^9.0.0, google-auth-library@^9.5.0: version "9.6.0" resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-9.6.0.tgz#47a20aad0a358e9798c2adc489a89f1938e9c3ff" integrity sha512-bM/buCwCeYZjmnzGstwREu3BsnbmnuI064ZGur0NmHyXUxubWMJTCO9kxsyy4T6jdzacHJY3XQWHxX4D4Mc+EA== From 8bca35fb19db7f03ad239f19a620ef951f2aaf70 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Date: Thu, 1 Feb 2024 13:38:58 +0100 Subject: [PATCH 06/35] [charts] Fix Tooltip crash with out of range lines (#11898) --- packages/x-charts/src/BarChart/formatter.ts | 4 +-- .../ChartsAxisTooltipContent.tsx | 29 ++++++++----------- .../DefaultChartsAxisTooltipContent.tsx | 7 +++-- packages/x-charts/src/ChartsTooltip/utils.tsx | 16 +++++++++- packages/x-charts/src/LineChart/formatter.ts | 4 +-- 5 files changed, 33 insertions(+), 27 deletions(-) diff --git a/packages/x-charts/src/BarChart/formatter.ts b/packages/x-charts/src/BarChart/formatter.ts index 2c7d571fb0772..e7cc322ad8142 100644 --- a/packages/x-charts/src/BarChart/formatter.ts +++ b/packages/x-charts/src/BarChart/formatter.ts @@ -86,9 +86,7 @@ const formatter: Formatter<'bar'> = (params, dataset) => { return { seriesOrder, stackingGroups, - series: defaultizeValueFormatter(completedSeries, (v) => - v === null ? '' : v.toLocaleString(), - ), + series: defaultizeValueFormatter(completedSeries, (v) => (v == null ? '' : v.toLocaleString())), }; }; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx index 102bb42989ea0..1ea6324818568 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx @@ -5,14 +5,11 @@ import { useSlotProps } from '@mui/base/utils'; import { AxisInteractionData } from '../context/InteractionProvider'; import { SeriesContext } from '../context/SeriesContextProvider'; import { CartesianContext } from '../context/CartesianContextProvider'; -import { - CartesianChartSeriesType, - ChartSeriesDefaultized, - ChartSeriesType, -} from '../models/seriesType/config'; +import { ChartSeriesDefaultized, ChartSeriesType } from '../models/seriesType/config'; import { AxisDefaultized } from '../models/axis'; import { ChartsTooltipClasses } from './chartsTooltipClasses'; import { DefaultChartsAxisTooltipContent } from './DefaultChartsAxisTooltipContent'; +import { isCartesianSeriesType } from './utils'; export type ChartsAxisContentProps = { /** @@ -63,19 +60,17 @@ function ChartsAxisTooltipContent(props: { const relevantSeries = React.useMemo(() => { const rep: any[] = []; - ( - Object.keys(series).filter((seriesType) => - ['bar', 'line', 'scatter'].includes(seriesType), - ) as CartesianChartSeriesType[] - ).forEach((seriesType) => { - series[seriesType]!.seriesOrder.forEach((seriesId) => { - const item = series[seriesType]!.series[seriesId]; - const axisKey = isXaxis ? item.xAxisKey : item.yAxisKey; - if (axisKey === undefined || axisKey === USED_AXIS_ID) { - rep.push(series[seriesType]!.series[seriesId]); - } + Object.keys(series) + .filter(isCartesianSeriesType) + .forEach((seriesType) => { + series[seriesType]!.seriesOrder.forEach((seriesId) => { + const item = series[seriesType]!.series[seriesId]; + const axisKey = isXaxis ? item.xAxisKey : item.yAxisKey; + if (axisKey === undefined || axisKey === USED_AXIS_ID) { + rep.push(series[seriesType]!.series[seriesId]); + } + }); }); - }); return rep; }, [USED_AXIS_ID, isXaxis, series]); diff --git a/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx index 9a708be0ee29f..e02e09e773cf7 100644 --- a/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx @@ -2,7 +2,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import Typography from '@mui/material/Typography'; -import { ChartSeriesDefaultized } from '../models/seriesType/config'; import { ChartsTooltipCell, ChartsTooltipPaper, @@ -11,6 +10,7 @@ import { ChartsTooltipRow, } from './ChartsTooltipTable'; import type { ChartsAxisContentProps } from './ChartsAxisTooltipContent'; +import { isCartesianSeries } from './utils'; function DefaultChartsAxisTooltipContent(props: ChartsAxisContentProps) { const { series, axis, dataIndex, axisValue, sx, classes } = props; @@ -33,8 +33,9 @@ function DefaultChartsAxisTooltipContent(props: ChartsAxisContentProps) { )} - {series.map(({ color, id, label, valueFormatter, data }: ChartSeriesDefaultized) => { - const formattedValue = valueFormatter(data[dataIndex]); + {series.filter(isCartesianSeries).map(({ color, id, label, valueFormatter, data }) => { + // @ts-ignore + const formattedValue = valueFormatter(data[dataIndex] ?? null); if (formattedValue == null) { return null; } diff --git a/packages/x-charts/src/ChartsTooltip/utils.tsx b/packages/x-charts/src/ChartsTooltip/utils.tsx index a0f8f6addb4bb..0b59e3106002c 100644 --- a/packages/x-charts/src/ChartsTooltip/utils.tsx +++ b/packages/x-charts/src/ChartsTooltip/utils.tsx @@ -1,7 +1,11 @@ import * as React from 'react'; import { AxisInteractionData, ItemInteractionData } from '../context/InteractionProvider'; import { SVGContext } from '../context/DrawingProvider'; -import { ChartSeriesType } from '../models/seriesType/config'; +import { + CartesianChartSeriesType, + ChartSeriesDefaultized, + ChartSeriesType, +} from '../models/seriesType/config'; export function generateVirtualElement(mousePosition: { x: number; y: number } | null) { if (mousePosition === null) { @@ -85,3 +89,13 @@ export function getTooltipHasData( return hasAxisXData || hasAxisYData; } + +export function isCartesianSeriesType(seriesType: string): seriesType is CartesianChartSeriesType { + return ['bar', 'line', 'scatter'].includes(seriesType); +} + +export function isCartesianSeries( + series: ChartSeriesDefaultized, +): series is ChartSeriesDefaultized { + return isCartesianSeriesType(series.type); +} diff --git a/packages/x-charts/src/LineChart/formatter.ts b/packages/x-charts/src/LineChart/formatter.ts index 7734671d42053..d041eff126794 100644 --- a/packages/x-charts/src/LineChart/formatter.ts +++ b/packages/x-charts/src/LineChart/formatter.ts @@ -83,9 +83,7 @@ const formatter: Formatter<'line'> = (params, dataset) => { return { seriesOrder, stackingGroups, - series: defaultizeValueFormatter(completedSeries, (v) => - v === null ? '' : v.toLocaleString(), - ), + series: defaultizeValueFormatter(completedSeries, (v) => (v == null ? '' : v.toLocaleString())), }; }; From 0c7c6747d9ee3740954460c2f759f3f923e7efce Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskii Date: Thu, 1 Feb 2024 14:48:21 +0100 Subject: [PATCH 07/35] [DataGrid] Change `GridColDef` methods signatures (#11573) --- .../AggregationColDefAggregable.js | 2 +- .../AggregationColDefAggregable.tsx | 2 +- .../AggregationColDefNonAggregable.js | 2 +- .../AggregationColDefNonAggregable.tsx | 2 +- .../aggregation/AggregationControlled.js | 2 +- .../aggregation/AggregationControlled.tsx | 2 +- .../aggregation/AggregationCustomFunction.js | 2 +- .../aggregation/AggregationCustomFunction.tsx | 2 +- .../aggregation/AggregationFiltering.js | 2 +- .../aggregation/AggregationFiltering.tsx | 2 +- .../AggregationGetAggregationPosition.js | 2 +- .../AggregationGetAggregationPosition.tsx | 2 +- .../aggregation/AggregationInitialState.js | 2 +- .../aggregation/AggregationInitialState.tsx | 2 +- .../AggregationMultipleRowFields.js | 8 +- .../AggregationMultipleRowFields.tsx | 12 +- .../AggregationRemoveFunctionAllColumns.js | 2 +- .../AggregationRemoveFunctionAllColumns.tsx | 2 +- .../AggregationRemoveFunctionOneColumn.js | 2 +- .../AggregationRemoveFunctionOneColumn.tsx | 2 +- .../aggregation/AggregationRowGrouping.js | 2 +- .../aggregation/AggregationRowGrouping.tsx | 2 +- .../aggregation/AggregationTreeData.js | 24 ++-- .../aggregation/AggregationTreeData.tsx | 26 ++-- .../aggregation/AggregationValueFormatter.js | 2 +- .../aggregation/AggregationValueFormatter.tsx | 2 +- .../data/data-grid/aggregation/aggregation.md | 2 +- .../column-definition/ValueFormatterGrid.js | 14 +- .../column-definition/ValueFormatterGrid.tsx | 16 +-- .../column-definition/ValueGetterGrid.js | 22 +-- .../column-definition/ValueGetterGrid.tsx | 27 ++-- .../column-definition/column-definition.md | 16 +-- .../column-spanning/ColumnSpanningDerived.js | 20 +-- .../column-spanning/ColumnSpanningDerived.tsx | 28 ++-- .../column-spanning/ColumnSpanningFunction.js | 8 +- .../ColumnSpanningFunction.tsx | 8 +- .../custom-columns/CustomColumnTypesGrid.js | 2 +- .../custom-columns/CustomColumnTypesGrid.tsx | 2 +- .../custom-columns/EditingWithDatePickers.js | 20 +-- .../custom-columns/EditingWithDatePickers.tsx | 20 +-- .../custom-columns/SparklineColumn.js | 6 +- .../custom-columns/SparklineColumn.tsx | 11 +- .../custom-columns/custom-columns.md | 2 +- .../editing/ValueParserSetterGrid.js | 36 ++--- .../editing/ValueParserSetterGrid.tsx | 41 +++--- docs/data/data-grid/editing/editing.md | 8 +- .../data-grid/events/CatalogOfEventsNoSnap.js | 2 +- docs/data/data-grid/export/export.md | 2 +- .../filtering/QuickFilteringDiacritics.js | 2 +- .../filtering/QuickFilteringDiacritics.tsx | 2 +- .../data-grid/localization/DataGridRTL.js | 2 +- .../data-grid/localization/DataGridRTL.tsx | 2 +- .../master-detail/BasicDetailPanels.js | 4 +- .../master-detail/BasicDetailPanels.tsx | 6 +- .../master-detail/DetailPanelAutoHeight.js | 4 +- .../master-detail/DetailPanelAutoHeight.tsx | 6 +- .../master-detail/FullWidthDetailPanel.js | 6 +- .../master-detail/FullWidthDetailPanel.tsx | 6 +- docs/data/data-grid/overview/DataGridDemo.js | 3 +- docs/data/data-grid/overview/DataGridDemo.tsx | 7 +- ...RowGroupingCustomGroupingColDefCallback.js | 5 +- ...owGroupingCustomGroupingColDefCallback.tsx | 7 +- .../RowGroupingGroupingValueGetter.js | 8 +- .../RowGroupingGroupingValueGetter.tsx | 10 +- .../data-grid/row-grouping/row-grouping.md | 2 +- .../sorting/ExtendedSortComparator.js | 9 +- .../sorting/ExtendedSortComparator.tsx | 10 +- .../sorting/FullyCustomSortComparator.js | 2 +- .../sorting/FullyCustomSortComparator.tsx | 2 +- .../StylingAllCellsButAggregation.js | 2 +- .../StylingAllCellsButAggregation.tsx | 2 +- docs/data/data-grid/style/StylingAllCells.js | 6 +- docs/data/data-grid/style/StylingAllCells.tsx | 6 +- .../tree-data/TreeDataCustomGroupingColumn.js | 4 +- .../TreeDataCustomGroupingColumn.tsx | 8 +- .../data-grid/tree-data/TreeDataWithGap.js | 8 +- .../data-grid/tree-data/TreeDataWithGap.tsx | 19 ++- .../migration-data-grid-v6.md | 82 +++++++++++ .../x/api/data-grid/grid-actions-col-def.md | 14 +- docs/pages/x/api/data-grid/grid-col-def.md | 14 +- .../data-grid/grid-single-select-col-def.md | 14 +- .../src/columns/commodities.columns.tsx | 10 +- .../src/columns/employees.columns.tsx | 10 +- .../src/hooks/useMovieData.ts | 2 +- .../src/hooks/useQuery.ts | 6 +- .../useDataGridPremiumComponent.tsx | 2 +- .../aggregation/wrapColumnWithAggregation.tsx | 27 ++-- .../clipboard/useGridClipboardImport.ts | 8 +- .../export/serializer/excelSerializer.ts | 14 +- .../rowGrouping/createGroupingColDef.tsx | 35 +++-- .../rowGrouping/gridRowGroupingUtils.ts | 18 +-- .../useGridRowGroupingPreProcessors.ts | 2 +- .../src/models/gridGroupingValueGetter.ts | 12 ++ .../models/gridGroupingValueGetterParams.ts | 38 ----- .../src/models/gridPastedValueParser.ts | 13 ++ .../x-data-grid-premium/src/models/index.ts | 3 +- .../src/tests/DataGridPremium.spec.tsx | 8 +- .../aggregation.DataGridPremium.test.tsx | 6 +- .../tests/clipboard.DataGridPremium.test.tsx | 20 +-- .../rowGrouping.DataGridPremium.test.tsx | 47 ++++--- .../src/typeOverloads/modules.ts | 13 +- .../DataGridPro/useDataGridProComponent.tsx | 2 +- .../gridDetailPanelToggleColDef.tsx | 9 +- .../treeData/gridTreeDataGroupColDef.ts | 9 +- .../src/tests/DataGridPro.spec.tsx | 8 +- .../tests/cellEditing.DataGridPro.test.tsx | 16 ++- .../tests/columnSpanning.DataGridPro.test.tsx | 18 +-- .../src/tests/events.DataGridPro.test.tsx | 4 +- .../src/tests/export.DataGridPro.test.tsx | 2 +- .../src/tests/rowEditing.DataGridPro.test.tsx | 31 +++-- .../statePersistence.DataGridPro.test.tsx | 2 +- .../src/tests/treeData.DataGridPro.test.tsx | 2 +- .../src/DataGrid/useDataGridComponent.tsx | 2 +- .../src/colDef/gridBooleanColDef.tsx | 11 +- .../colDef/gridCheckboxSelectionColDef.tsx | 7 +- .../x-data-grid/src/colDef/gridDateColDef.ts | 22 +-- .../src/colDef/gridNumericColDef.ts | 2 +- .../src/colDef/gridSingleSelectColDef.tsx | 12 +- .../src/components/cell/GridEditInputCell.tsx | 2 +- .../features/columns/useGridColumnSpanning.ts | 4 +- .../features/editing/useGridCellEditing.ts | 6 +- .../features/editing/useGridRowEditing.ts | 7 +- .../hooks/features/filter/gridFilterUtils.ts | 4 +- .../hooks/features/rows/useGridParamsApi.ts | 77 ++--------- .../src/models/colDef/gridColDef.ts | 70 +++++++--- .../x-data-grid/src/models/colDef/index.ts | 5 + .../src/models/params/gridCellParams.ts | 32 ----- .../x-data-grid/src/tests/DataGrid.spec.tsx | 32 ++--- .../src/tests/cells.DataGrid.test.tsx | 14 +- .../tests/columnSpanning.DataGrid.test.tsx | 40 +++--- .../src/tests/columns.DataGrid.test.tsx | 10 +- .../x-data-grid/src/tests/columns.spec.tsx | 130 ++++++++++++++++++ .../src/tests/filtering.DataGrid.test.tsx | 6 +- .../src/tests/layout.DataGrid.test.tsx | 2 +- .../tests/quickFiltering.DataGrid.test.tsx | 4 +- scripts/x-data-grid-premium.exports.json | 14 +- scripts/x-data-grid-pro.exports.json | 11 +- scripts/x-data-grid.exports.json | 11 +- 138 files changed, 914 insertions(+), 731 deletions(-) create mode 100644 packages/grid/x-data-grid-premium/src/models/gridGroupingValueGetter.ts delete mode 100644 packages/grid/x-data-grid-premium/src/models/gridGroupingValueGetterParams.ts create mode 100644 packages/grid/x-data-grid-premium/src/models/gridPastedValueParser.ts diff --git a/docs/data/data-grid/aggregation/AggregationColDefAggregable.js b/docs/data/data-grid/aggregation/AggregationColDefAggregable.js index dbdfe5da56988..e23410c8e7818 100644 --- a/docs/data/data-grid/aggregation/AggregationColDefAggregable.js +++ b/docs/data/data-grid/aggregation/AggregationColDefAggregable.js @@ -23,7 +23,7 @@ const COLUMNS = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationColDefAggregable.tsx b/docs/data/data-grid/aggregation/AggregationColDefAggregable.tsx index 61b3d5d6cf36e..d67e44cacd711 100644 --- a/docs/data/data-grid/aggregation/AggregationColDefAggregable.tsx +++ b/docs/data/data-grid/aggregation/AggregationColDefAggregable.tsx @@ -23,7 +23,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationColDefNonAggregable.js b/docs/data/data-grid/aggregation/AggregationColDefNonAggregable.js index 43b88020a1aad..b68f392842cf4 100644 --- a/docs/data/data-grid/aggregation/AggregationColDefNonAggregable.js +++ b/docs/data/data-grid/aggregation/AggregationColDefNonAggregable.js @@ -23,7 +23,7 @@ const COLUMNS = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationColDefNonAggregable.tsx b/docs/data/data-grid/aggregation/AggregationColDefNonAggregable.tsx index ecc1b1407e1c5..e9facc9195e00 100644 --- a/docs/data/data-grid/aggregation/AggregationColDefNonAggregable.tsx +++ b/docs/data/data-grid/aggregation/AggregationColDefNonAggregable.tsx @@ -23,7 +23,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationControlled.js b/docs/data/data-grid/aggregation/AggregationControlled.js index ea05bd5793108..dd4f26158ebe9 100644 --- a/docs/data/data-grid/aggregation/AggregationControlled.js +++ b/docs/data/data-grid/aggregation/AggregationControlled.js @@ -17,7 +17,7 @@ const COLUMNS = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationControlled.tsx b/docs/data/data-grid/aggregation/AggregationControlled.tsx index 9bf1e433d3070..66b4ef4370af0 100644 --- a/docs/data/data-grid/aggregation/AggregationControlled.tsx +++ b/docs/data/data-grid/aggregation/AggregationControlled.tsx @@ -21,7 +21,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationCustomFunction.js b/docs/data/data-grid/aggregation/AggregationCustomFunction.js index 25bda31c3cfc4..7691e12ef11f6 100644 --- a/docs/data/data-grid/aggregation/AggregationCustomFunction.js +++ b/docs/data/data-grid/aggregation/AggregationCustomFunction.js @@ -31,7 +31,7 @@ const COLUMNS = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationCustomFunction.tsx b/docs/data/data-grid/aggregation/AggregationCustomFunction.tsx index 044cd70bf6c8e..979ba2b313ab6 100644 --- a/docs/data/data-grid/aggregation/AggregationCustomFunction.tsx +++ b/docs/data/data-grid/aggregation/AggregationCustomFunction.tsx @@ -33,7 +33,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationFiltering.js b/docs/data/data-grid/aggregation/AggregationFiltering.js index 66f67462935bd..44d2db771d0e4 100644 --- a/docs/data/data-grid/aggregation/AggregationFiltering.js +++ b/docs/data/data-grid/aggregation/AggregationFiltering.js @@ -17,7 +17,7 @@ const COLUMNS = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationFiltering.tsx b/docs/data/data-grid/aggregation/AggregationFiltering.tsx index d6dbeaddd85d5..9b4e63676084b 100644 --- a/docs/data/data-grid/aggregation/AggregationFiltering.tsx +++ b/docs/data/data-grid/aggregation/AggregationFiltering.tsx @@ -17,7 +17,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationGetAggregationPosition.js b/docs/data/data-grid/aggregation/AggregationGetAggregationPosition.js index c982b38c0e4cf..a3ee72b9c6443 100644 --- a/docs/data/data-grid/aggregation/AggregationGetAggregationPosition.js +++ b/docs/data/data-grid/aggregation/AggregationGetAggregationPosition.js @@ -31,7 +31,7 @@ const COLUMNS = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationGetAggregationPosition.tsx b/docs/data/data-grid/aggregation/AggregationGetAggregationPosition.tsx index 286e46bab22d6..a7b8766ec1bb4 100644 --- a/docs/data/data-grid/aggregation/AggregationGetAggregationPosition.tsx +++ b/docs/data/data-grid/aggregation/AggregationGetAggregationPosition.tsx @@ -32,7 +32,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationInitialState.js b/docs/data/data-grid/aggregation/AggregationInitialState.js index 93057744fa732..68ce37b2c22f3 100644 --- a/docs/data/data-grid/aggregation/AggregationInitialState.js +++ b/docs/data/data-grid/aggregation/AggregationInitialState.js @@ -17,7 +17,7 @@ const COLUMNS = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationInitialState.tsx b/docs/data/data-grid/aggregation/AggregationInitialState.tsx index 7f6dcf5bd509a..403388b35dfff 100644 --- a/docs/data/data-grid/aggregation/AggregationInitialState.tsx +++ b/docs/data/data-grid/aggregation/AggregationInitialState.tsx @@ -17,7 +17,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationMultipleRowFields.js b/docs/data/data-grid/aggregation/AggregationMultipleRowFields.js index 9432c00a61c74..1ef1ec469957b 100644 --- a/docs/data/data-grid/aggregation/AggregationMultipleRowFields.js +++ b/docs/data/data-grid/aggregation/AggregationMultipleRowFields.js @@ -31,13 +31,13 @@ const COLUMNS = [ type: 'number', width: 70, groupable: false, - valueGetter: ({ row }) => { + valueGetter: (value, row) => { if (!row.gross || !row.budget) { return null; } return calculateProfit(row.gross, row.budget); }, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return null; } @@ -50,7 +50,7 @@ const COLUMNS = [ type: 'number', minWidth: 140, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } @@ -63,7 +63,7 @@ const COLUMNS = [ type: 'number', minWidth: 140, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationMultipleRowFields.tsx b/docs/data/data-grid/aggregation/AggregationMultipleRowFields.tsx index 099439992db7e..07896dfa7290f 100644 --- a/docs/data/data-grid/aggregation/AggregationMultipleRowFields.tsx +++ b/docs/data/data-grid/aggregation/AggregationMultipleRowFields.tsx @@ -7,7 +7,7 @@ import { useGridApiRef, useKeepGroupedColumnsHidden, } from '@mui/x-data-grid-premium'; -import { useMovieData } from '@mui/x-data-grid-generator'; +import { useMovieData, Movie } from '@mui/x-data-grid-generator'; const currencyFormatter = new Intl.NumberFormat('en-US', { style: 'currency', @@ -20,7 +20,7 @@ function calculateProfit(gross: number, budget: number) { return (gross - budget) / budget; } -const COLUMNS: GridColDef[] = [ +const COLUMNS: GridColDef[] = [ { field: 'title', headerName: 'Title', width: 200, groupable: false }, { field: 'company', @@ -33,13 +33,13 @@ const COLUMNS: GridColDef[] = [ type: 'number', width: 70, groupable: false, - valueGetter: ({ row }) => { + valueGetter: (value, row) => { if (!row.gross || !row.budget) { return null; } return calculateProfit(row.gross, row.budget); }, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return null; } @@ -52,7 +52,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', minWidth: 140, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } @@ -65,7 +65,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', minWidth: 140, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationRemoveFunctionAllColumns.js b/docs/data/data-grid/aggregation/AggregationRemoveFunctionAllColumns.js index fee7e52de356c..b742e996f35c5 100644 --- a/docs/data/data-grid/aggregation/AggregationRemoveFunctionAllColumns.js +++ b/docs/data/data-grid/aggregation/AggregationRemoveFunctionAllColumns.js @@ -20,7 +20,7 @@ const COLUMNS = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationRemoveFunctionAllColumns.tsx b/docs/data/data-grid/aggregation/AggregationRemoveFunctionAllColumns.tsx index 64ab72e7df4ac..4e7d017f270c2 100644 --- a/docs/data/data-grid/aggregation/AggregationRemoveFunctionAllColumns.tsx +++ b/docs/data/data-grid/aggregation/AggregationRemoveFunctionAllColumns.tsx @@ -21,7 +21,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationRemoveFunctionOneColumn.js b/docs/data/data-grid/aggregation/AggregationRemoveFunctionOneColumn.js index a251fe9a9cf0f..31aeef25b95d4 100644 --- a/docs/data/data-grid/aggregation/AggregationRemoveFunctionOneColumn.js +++ b/docs/data/data-grid/aggregation/AggregationRemoveFunctionOneColumn.js @@ -17,7 +17,7 @@ const COLUMNS = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationRemoveFunctionOneColumn.tsx b/docs/data/data-grid/aggregation/AggregationRemoveFunctionOneColumn.tsx index 3584dad91db66..eef15e64a31bf 100644 --- a/docs/data/data-grid/aggregation/AggregationRemoveFunctionOneColumn.tsx +++ b/docs/data/data-grid/aggregation/AggregationRemoveFunctionOneColumn.tsx @@ -17,7 +17,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationRowGrouping.js b/docs/data/data-grid/aggregation/AggregationRowGrouping.js index 60406b087f723..34dbd8ad7c2da 100644 --- a/docs/data/data-grid/aggregation/AggregationRowGrouping.js +++ b/docs/data/data-grid/aggregation/AggregationRowGrouping.js @@ -26,7 +26,7 @@ const COLUMNS = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationRowGrouping.tsx b/docs/data/data-grid/aggregation/AggregationRowGrouping.tsx index 6d7feee5bedff..4a2a996e49234 100644 --- a/docs/data/data-grid/aggregation/AggregationRowGrouping.tsx +++ b/docs/data/data-grid/aggregation/AggregationRowGrouping.tsx @@ -27,7 +27,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationTreeData.js b/docs/data/data-grid/aggregation/AggregationTreeData.js index f13b2c299d342..460f64c2a2ee7 100644 --- a/docs/data/data-grid/aggregation/AggregationTreeData.js +++ b/docs/data/data-grid/aggregation/AggregationTreeData.js @@ -89,23 +89,23 @@ const columns = [ field: 'size', headerName: 'Size', type: 'number', - valueFormatter: (params) => { - if (params.value == null) { + valueFormatter: (value) => { + if (value == null) { return ''; } - if (params.value < 100) { - return `${params.value} b`; + if (value < 100) { + return `${value} b`; } - if (params.value < 1_000_000) { - return `${Math.floor(params.value / 100) / 10} Kb`; + if (value < 1_000_000) { + return `${Math.floor(value / 100) / 10} Kb`; } - if (params.value < 1_000_000_000) { - return `${Math.floor(params.value / 100_000) / 10} Mb`; + if (value < 1_000_000_000) { + return `${Math.floor(value / 100_000) / 10} Mb`; } - return `${Math.floor(params.value / 100_000_000) / 10} Gb`; + return `${Math.floor(value / 100_000_000) / 10} Gb`; }, }, { @@ -113,12 +113,12 @@ const columns = [ headerName: 'Last modification', type: 'dateTime', width: 200, - valueGetter: (params) => { - if (params.value == null) { + valueGetter: (value) => { + if (value == null) { return null; } - return new Date(params.value); + return new Date(value); }, }, ]; diff --git a/docs/data/data-grid/aggregation/AggregationTreeData.tsx b/docs/data/data-grid/aggregation/AggregationTreeData.tsx index 78c6456f21f39..b5caa5a5a1854 100644 --- a/docs/data/data-grid/aggregation/AggregationTreeData.tsx +++ b/docs/data/data-grid/aggregation/AggregationTreeData.tsx @@ -95,28 +95,28 @@ const rows: GridRowsProp = [ }, ]; -const columns: GridColDef[] = [ +const columns: GridColDef[] = [ { field: 'size', headerName: 'Size', type: 'number', - valueFormatter: (params) => { - if (params.value == null) { + valueFormatter: (value) => { + if (value == null) { return ''; } - if (params.value < 100) { - return `${params.value} b`; + if (value < 100) { + return `${value} b`; } - if (params.value < 1_000_000) { - return `${Math.floor(params.value / 100) / 10} Kb`; + if (value < 1_000_000) { + return `${Math.floor(value / 100) / 10} Kb`; } - if (params.value < 1_000_000_000) { - return `${Math.floor(params.value / 100_000) / 10} Mb`; + if (value < 1_000_000_000) { + return `${Math.floor(value / 100_000) / 10} Mb`; } - return `${Math.floor(params.value / 100_000_000) / 10} Gb`; + return `${Math.floor(value / 100_000_000) / 10} Gb`; }, }, { @@ -124,12 +124,12 @@ const columns: GridColDef[] = [ headerName: 'Last modification', type: 'dateTime', width: 200, - valueGetter: (params) => { - if (params.value == null) { + valueGetter: (value) => { + if (value == null) { return null; } - return new Date(params.value); + return new Date(value); }, }, ]; diff --git a/docs/data/data-grid/aggregation/AggregationValueFormatter.js b/docs/data/data-grid/aggregation/AggregationValueFormatter.js index 568eee480b7cf..955a77b5ec8a2 100644 --- a/docs/data/data-grid/aggregation/AggregationValueFormatter.js +++ b/docs/data/data-grid/aggregation/AggregationValueFormatter.js @@ -25,7 +25,7 @@ const COLUMNS = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/AggregationValueFormatter.tsx b/docs/data/data-grid/aggregation/AggregationValueFormatter.tsx index 10e92d96373a2..1a3f4c5a1c2f9 100644 --- a/docs/data/data-grid/aggregation/AggregationValueFormatter.tsx +++ b/docs/data/data-grid/aggregation/AggregationValueFormatter.tsx @@ -27,7 +27,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return value; } diff --git a/docs/data/data-grid/aggregation/aggregation.md b/docs/data/data-grid/aggregation/aggregation.md index f86b89c8f5f2e..0dad0c32852c2 100644 --- a/docs/data/data-grid/aggregation/aggregation.md +++ b/docs/data/data-grid/aggregation/aggregation.md @@ -228,7 +228,7 @@ In the example below, the values in the `profit` column are derived from the `gr { field: 'profit', type: 'number', - valueGetter: ({ row }) => { + valueGetter: (value, row) => { if (!row.gross || !row.budget) { return null; } diff --git a/docs/data/data-grid/column-definition/ValueFormatterGrid.js b/docs/data/data-grid/column-definition/ValueFormatterGrid.js index f9fd6b171f2e6..4699cc8792f6d 100644 --- a/docs/data/data-grid/column-definition/ValueFormatterGrid.js +++ b/docs/data/data-grid/column-definition/ValueFormatterGrid.js @@ -27,17 +27,17 @@ export default function ValueFormatterGrid() { field: 'taxRate', headerName: 'Tax Rate', width: 150, - valueGetter: (params) => { - if (!params.value) { - return params.value; + valueGetter: (value) => { + if (!value) { + return value; } - return params.value * 100; + return value * 100; }, - valueFormatter: (params) => { - if (params.value == null) { + valueFormatter: (value) => { + if (value == null) { return ''; } - return `${params.value.toLocaleString()} %`; + return `${value.toLocaleString()} %`; }, }, ]} diff --git a/docs/data/data-grid/column-definition/ValueFormatterGrid.tsx b/docs/data/data-grid/column-definition/ValueFormatterGrid.tsx index 24a4e6049fc05..fe540c044cc6a 100644 --- a/docs/data/data-grid/column-definition/ValueFormatterGrid.tsx +++ b/docs/data/data-grid/column-definition/ValueFormatterGrid.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { DataGrid, GridValueFormatterParams } from '@mui/x-data-grid'; +import { DataGrid } from '@mui/x-data-grid'; const rows = [ { @@ -27,17 +27,17 @@ export default function ValueFormatterGrid() { field: 'taxRate', headerName: 'Tax Rate', width: 150, - valueGetter: (params) => { - if (!params.value) { - return params.value; + valueGetter: (value) => { + if (!value) { + return value; } - return params.value * 100; + return value * 100; }, - valueFormatter: (params: GridValueFormatterParams) => { - if (params.value == null) { + valueFormatter: (value?: number) => { + if (value == null) { return ''; } - return `${params.value.toLocaleString()} %`; + return `${value.toLocaleString()} %`; }, }, ]} diff --git a/docs/data/data-grid/column-definition/ValueGetterGrid.js b/docs/data/data-grid/column-definition/ValueGetterGrid.js index 4e45d2d764d58..498e2c4d91a96 100644 --- a/docs/data/data-grid/column-definition/ValueGetterGrid.js +++ b/docs/data/data-grid/column-definition/ValueGetterGrid.js @@ -2,9 +2,17 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import { DataGrid } from '@mui/x-data-grid'; -function getFullName(params) { - return `${params.row.firstName || ''} ${params.row.lastName || ''}`; -} +const rows = [ + { id: 1, lastName: 'Snow', firstName: 'Jon' }, + { id: 2, lastName: 'Lannister', firstName: 'Cersei' }, + { id: 3, lastName: 'Lannister', firstName: 'Jaime' }, + { id: 4, lastName: 'Stark', firstName: 'Arya' }, + { id: 5, lastName: 'Targaryen', firstName: 'Daenerys' }, +]; + +const getFullName = (value, row) => { + return `${row.firstName || ''} ${row.lastName || ''}`; +}; const columns = [ { field: 'firstName', headerName: 'First name', width: 130 }, @@ -17,14 +25,6 @@ const columns = [ }, ]; -const rows = [ - { id: 1, lastName: 'Snow', firstName: 'Jon' }, - { id: 2, lastName: 'Lannister', firstName: 'Cersei' }, - { id: 3, lastName: 'Lannister', firstName: 'Jaime' }, - { id: 4, lastName: 'Stark', firstName: 'Arya' }, - { id: 5, lastName: 'Targaryen', firstName: 'Daenerys' }, -]; - export default function ValueGetterGrid() { return ( diff --git a/docs/data/data-grid/column-definition/ValueGetterGrid.tsx b/docs/data/data-grid/column-definition/ValueGetterGrid.tsx index 8035a20486b95..cc4e1ea77c5c5 100644 --- a/docs/data/data-grid/column-definition/ValueGetterGrid.tsx +++ b/docs/data/data-grid/column-definition/ValueGetterGrid.tsx @@ -1,10 +1,21 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid'; +import { DataGrid, GridColDef, GridValueGetter } from '@mui/x-data-grid'; -function getFullName(params: GridValueGetterParams) { - return `${params.row.firstName || ''} ${params.row.lastName || ''}`; -} +const rows = [ + { id: 1, lastName: 'Snow', firstName: 'Jon' }, + { id: 2, lastName: 'Lannister', firstName: 'Cersei' }, + { id: 3, lastName: 'Lannister', firstName: 'Jaime' }, + { id: 4, lastName: 'Stark', firstName: 'Arya' }, + { id: 5, lastName: 'Targaryen', firstName: 'Daenerys' }, +]; + +const getFullName: GridValueGetter<(typeof rows)[number], unknown> = ( + value, + row, +) => { + return `${row.firstName || ''} ${row.lastName || ''}`; +}; const columns: GridColDef[] = [ { field: 'firstName', headerName: 'First name', width: 130 }, @@ -17,14 +28,6 @@ const columns: GridColDef[] = [ }, ]; -const rows = [ - { id: 1, lastName: 'Snow', firstName: 'Jon' }, - { id: 2, lastName: 'Lannister', firstName: 'Cersei' }, - { id: 3, lastName: 'Lannister', firstName: 'Jaime' }, - { id: 4, lastName: 'Stark', firstName: 'Arya' }, - { id: 5, lastName: 'Targaryen', firstName: 'Daenerys' }, -]; - export default function ValueGetterGrid() { return ( diff --git a/docs/data/data-grid/column-definition/column-definition.md b/docs/data/data-grid/column-definition/column-definition.md index 59e42a9ac1028..dc73721a1e571 100644 --- a/docs/data/data-grid/column-definition/column-definition.md +++ b/docs/data/data-grid/column-definition/column-definition.md @@ -42,12 +42,12 @@ You can use the `valueGetter` attribute of `GridColDef` to: const columns: GridColDef[] = [ { field: 'taxRate', - valueGetter: (params) => { - if (!params.value) { - return params.value; + valueGetter: (value) => { + if (!value) { + return value; } // Convert the decimal value to a percentage - return params.value * 100; + return value * 100; }, }, ]; @@ -59,8 +59,8 @@ You can use the `valueGetter` attribute of `GridColDef` to: const columns: GridColDef[] = [ { field: 'fullName', - valueGetter: (params) => { - return `${params.row.firstName || ''} ${params.row.lastName || ''}`; + valueGetter: (value, row) => { + return `${row.firstName || ''} ${row.lastName || ''}`; }, }, ]; @@ -72,7 +72,7 @@ You can use the `valueGetter` attribute of `GridColDef` to: const columns: GridColDef[] = [ { field: 'profit', - valueGetter: ({ row }) => { + valueGetter: (value, row) => { if (!row.gross || !row.costs) { return null; } @@ -240,7 +240,7 @@ If for any reason, your data type is not the correct one, you can use `valueGett { field: 'lastLogin', type: 'dateTime', - valueGetter: ({ value }) => value && new Date(value), + valueGetter: (value) => value && new Date(value), } ``` diff --git a/docs/data/data-grid/column-spanning/ColumnSpanningDerived.js b/docs/data/data-grid/column-spanning/ColumnSpanningDerived.js index 960cceabb0409..a79a2cb56f110 100644 --- a/docs/data/data-grid/column-spanning/ColumnSpanningDerived.js +++ b/docs/data/data-grid/column-spanning/ColumnSpanningDerived.js @@ -66,8 +66,8 @@ const slotColumnCommonFields = { hideable: false, minWidth: 140, cellClassName: (params) => params.value, - colSpan: ({ row, field, value }) => { - const index = Number(field); + colSpan: (value, row, column) => { + const index = Number(column.field); let colSpan = 1; for (let i = index + 1; i < row.slots.length; i += 1) { const nextValue = row.slots[i]; @@ -89,49 +89,49 @@ const columns = [ { field: '0', headerName: slotTimesLookup[0], - valueGetter: ({ row }) => row.slots[0], + valueGetter: (value, row) => row.slots[0], ...slotColumnCommonFields, }, { field: '1', headerName: slotTimesLookup[1], - valueGetter: ({ row }) => row.slots[1], + valueGetter: (value, row) => row.slots[1], ...slotColumnCommonFields, }, { field: '2', headerName: slotTimesLookup[2], - valueGetter: ({ row }) => row.slots[2], + valueGetter: (value, row) => row.slots[2], ...slotColumnCommonFields, }, { field: '3', headerName: slotTimesLookup[3], - valueGetter: ({ row }) => row.slots[3], + valueGetter: (value, row) => row.slots[3], ...slotColumnCommonFields, }, { field: '4', headerName: slotTimesLookup[4], - valueGetter: ({ row }) => row.slots[4], + valueGetter: (value, row) => row.slots[4], ...slotColumnCommonFields, }, { field: '5', headerName: slotTimesLookup[5], - valueGetter: ({ row }) => row.slots[5], + valueGetter: (value, row) => row.slots[5], ...slotColumnCommonFields, }, { field: '6', headerName: slotTimesLookup[6], - valueGetter: ({ row }) => row.slots[6], + valueGetter: (value, row) => row.slots[6], ...slotColumnCommonFields, }, { field: '7', headerName: slotTimesLookup[7], - valueGetter: ({ row }) => row.slots[7], + valueGetter: (value, row) => row.slots[7], ...slotColumnCommonFields, }, ]; diff --git a/docs/data/data-grid/column-spanning/ColumnSpanningDerived.tsx b/docs/data/data-grid/column-spanning/ColumnSpanningDerived.tsx index a34476e2811c0..653671f61040f 100644 --- a/docs/data/data-grid/column-spanning/ColumnSpanningDerived.tsx +++ b/docs/data/data-grid/column-spanning/ColumnSpanningDerived.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import { DataGridPro, GridColDef, GridCellParams } from '@mui/x-data-grid-pro'; +import { DataGridPro, GridColDef } from '@mui/x-data-grid-pro'; const slotTimesLookup = { 0: '09:00 - 10:00', @@ -22,7 +22,9 @@ type Subject = | 'Music' | 'Dance'; -const rows: Array<{ id: number; day: string; slots: Array }> = [ +type Row = { id: number; day: string; slots: Array }; + +const rows: Array = [ { id: 1, day: 'Monday', @@ -75,8 +77,8 @@ const slotColumnCommonFields: Partial = { hideable: false, minWidth: 140, cellClassName: (params) => params.value, - colSpan: ({ row, field, value }: GridCellParams) => { - const index = Number(field); + colSpan: (value, row, column) => { + const index = Number(column.field); let colSpan = 1; for (let i = index + 1; i < row.slots.length; i += 1) { const nextValue = row.slots[i]; @@ -90,7 +92,7 @@ const slotColumnCommonFields: Partial = { }, }; -const columns: GridColDef[] = [ +const columns: GridColDef[] = [ { field: 'day', headerName: 'Day', @@ -98,49 +100,49 @@ const columns: GridColDef[] = [ { field: '0', headerName: slotTimesLookup[0], - valueGetter: ({ row }) => row.slots[0], + valueGetter: (value, row) => row.slots[0], ...slotColumnCommonFields, }, { field: '1', headerName: slotTimesLookup[1], - valueGetter: ({ row }) => row.slots[1], + valueGetter: (value, row) => row.slots[1], ...slotColumnCommonFields, }, { field: '2', headerName: slotTimesLookup[2], - valueGetter: ({ row }) => row.slots[2], + valueGetter: (value, row) => row.slots[2], ...slotColumnCommonFields, }, { field: '3', headerName: slotTimesLookup[3], - valueGetter: ({ row }) => row.slots[3], + valueGetter: (value, row) => row.slots[3], ...slotColumnCommonFields, }, { field: '4', headerName: slotTimesLookup[4], - valueGetter: ({ row }) => row.slots[4], + valueGetter: (value, row) => row.slots[4], ...slotColumnCommonFields, }, { field: '5', headerName: slotTimesLookup[5], - valueGetter: ({ row }) => row.slots[5], + valueGetter: (value, row) => row.slots[5], ...slotColumnCommonFields, }, { field: '6', headerName: slotTimesLookup[6], - valueGetter: ({ row }) => row.slots[6], + valueGetter: (value, row) => row.slots[6], ...slotColumnCommonFields, }, { field: '7', headerName: slotTimesLookup[7], - valueGetter: ({ row }) => row.slots[7], + valueGetter: (value, row) => row.slots[7], ...slotColumnCommonFields, }, ]; diff --git a/docs/data/data-grid/column-spanning/ColumnSpanningFunction.js b/docs/data/data-grid/column-spanning/ColumnSpanningFunction.js index d1e7ab69fb180..80ff992b970be 100644 --- a/docs/data/data-grid/column-spanning/ColumnSpanningFunction.js +++ b/docs/data/data-grid/column-spanning/ColumnSpanningFunction.js @@ -27,7 +27,7 @@ const columns = [ headerName: 'Item/Description', ...baseColumnOptions, flex: 3, - colSpan: ({ row }) => { + colSpan: (value, row) => { if (row.id === 'SUBTOTAL' || row.id === 'TOTAL') { return 3; } @@ -36,7 +36,7 @@ const columns = [ } return undefined; }, - valueGetter: ({ value, row }) => { + valueGetter: (value, row) => { if (row.id === 'SUBTOTAL' || row.id === 'TAX' || row.id === 'TOTAL') { return row.label; } @@ -55,7 +55,7 @@ const columns = [ headerName: 'Price', flex: 1, ...baseColumnOptions, - valueGetter: ({ row, value }) => { + valueGetter: (value, row) => { if (row.id === 'TAX') { return `${row.taxRate}%`; } @@ -67,7 +67,7 @@ const columns = [ headerName: 'Total', flex: 1, ...baseColumnOptions, - valueGetter: ({ row }) => { + valueGetter: (value, row) => { if (row.id === 'SUBTOTAL') { return row.subtotal; } diff --git a/docs/data/data-grid/column-spanning/ColumnSpanningFunction.tsx b/docs/data/data-grid/column-spanning/ColumnSpanningFunction.tsx index beda4fc1074b4..5f5dcac599db4 100644 --- a/docs/data/data-grid/column-spanning/ColumnSpanningFunction.tsx +++ b/docs/data/data-grid/column-spanning/ColumnSpanningFunction.tsx @@ -50,7 +50,7 @@ const columns: GridColDef[] = [ headerName: 'Item/Description', ...baseColumnOptions, flex: 3, - colSpan: ({ row }) => { + colSpan: (value, row) => { if (row.id === 'SUBTOTAL' || row.id === 'TOTAL') { return 3; } @@ -59,7 +59,7 @@ const columns: GridColDef[] = [ } return undefined; }, - valueGetter: ({ value, row }) => { + valueGetter: (value, row) => { if (row.id === 'SUBTOTAL' || row.id === 'TAX' || row.id === 'TOTAL') { return row.label; } @@ -78,7 +78,7 @@ const columns: GridColDef[] = [ headerName: 'Price', flex: 1, ...baseColumnOptions, - valueGetter: ({ row, value }) => { + valueGetter: (value, row) => { if (row.id === 'TAX') { return `${row.taxRate}%`; } @@ -90,7 +90,7 @@ const columns: GridColDef[] = [ headerName: 'Total', flex: 1, ...baseColumnOptions, - valueGetter: ({ row }) => { + valueGetter: (value, row) => { if (row.id === 'SUBTOTAL') { return row.subtotal; } diff --git a/docs/data/data-grid/custom-columns/CustomColumnTypesGrid.js b/docs/data/data-grid/custom-columns/CustomColumnTypesGrid.js index 3b54134e2d274..589e12759a599 100644 --- a/docs/data/data-grid/custom-columns/CustomColumnTypesGrid.js +++ b/docs/data/data-grid/custom-columns/CustomColumnTypesGrid.js @@ -32,7 +32,7 @@ const currencyFormatter = new Intl.NumberFormat('en-US', { const usdPrice = { type: 'number', width: 130, - valueFormatter: ({ value }) => currencyFormatter.format(value), + valueFormatter: (value) => currencyFormatter.format(value), cellClassName: 'font-tabular-nums', }; diff --git a/docs/data/data-grid/custom-columns/CustomColumnTypesGrid.tsx b/docs/data/data-grid/custom-columns/CustomColumnTypesGrid.tsx index 1dd2525169c6a..82e558130be7b 100644 --- a/docs/data/data-grid/custom-columns/CustomColumnTypesGrid.tsx +++ b/docs/data/data-grid/custom-columns/CustomColumnTypesGrid.tsx @@ -32,7 +32,7 @@ const currencyFormatter = new Intl.NumberFormat('en-US', { const usdPrice: GridColTypeDef = { type: 'number', width: 130, - valueFormatter: ({ value }) => currencyFormatter.format(value), + valueFormatter: (value) => currencyFormatter.format(value), cellClassName: 'font-tabular-nums', }; diff --git a/docs/data/data-grid/custom-columns/EditingWithDatePickers.js b/docs/data/data-grid/custom-columns/EditingWithDatePickers.js index 3278ebe5189bf..69bdb8343d583 100644 --- a/docs/data/data-grid/custom-columns/EditingWithDatePickers.js +++ b/docs/data/data-grid/custom-columns/EditingWithDatePickers.js @@ -36,12 +36,12 @@ const dateColumnType = { InputComponent: GridFilterDateInput, InputComponentProps: { showTime: false }, })), - valueFormatter: (params) => { - if (typeof params.value === 'string') { - return params.value; + valueFormatter: (value) => { + if (typeof value === 'string') { + return value; } - if (params.value) { - return dateAdapter.format(params.value, 'keyboardDate'); + if (value) { + return dateAdapter.format(value, 'keyboardDate'); } return ''; }, @@ -122,12 +122,12 @@ const dateTimeColumnType = { InputComponent: GridFilterDateInput, InputComponentProps: { showTime: true }, })), - valueFormatter: (params) => { - if (typeof params.value === 'string') { - return params.value; + valueFormatter: (value) => { + if (typeof value === 'string') { + return value; } - if (params.value) { - return dateAdapter.format(params.value, 'keyboardDateTime'); + if (value) { + return dateAdapter.format(value, 'keyboardDateTime'); } return ''; }, diff --git a/docs/data/data-grid/custom-columns/EditingWithDatePickers.tsx b/docs/data/data-grid/custom-columns/EditingWithDatePickers.tsx index d51f0fea6b871..4f8f4803dd6c5 100644 --- a/docs/data/data-grid/custom-columns/EditingWithDatePickers.tsx +++ b/docs/data/data-grid/custom-columns/EditingWithDatePickers.tsx @@ -42,12 +42,12 @@ const dateColumnType: GridColTypeDef = { InputComponent: GridFilterDateInput, InputComponentProps: { showTime: false }, })), - valueFormatter: (params) => { - if (typeof params.value === 'string') { - return params.value; + valueFormatter: (value) => { + if (typeof value === 'string') { + return value; } - if (params.value) { - return dateAdapter.format(params.value, 'keyboardDate'); + if (value) { + return dateAdapter.format(value, 'keyboardDate'); } return ''; }, @@ -137,12 +137,12 @@ const dateTimeColumnType: GridColTypeDef = { InputComponent: GridFilterDateInput, InputComponentProps: { showTime: true }, })), - valueFormatter: (params) => { - if (typeof params.value === 'string') { - return params.value; + valueFormatter: (value) => { + if (typeof value === 'string') { + return value; } - if (params.value) { - return dateAdapter.format(params.value, 'keyboardDateTime'); + if (value) { + return dateAdapter.format(value, 'keyboardDateTime'); } return ''; }, diff --git a/docs/data/data-grid/custom-columns/SparklineColumn.js b/docs/data/data-grid/custom-columns/SparklineColumn.js index 0150cac14f838..3b6eb6b9016b6 100644 --- a/docs/data/data-grid/custom-columns/SparklineColumn.js +++ b/docs/data/data-grid/custom-columns/SparklineColumn.js @@ -41,14 +41,14 @@ const columns = [ headerName: 'Monthly DLs (bar)', renderCell: (params) => , width: 150, - valueGetter: (params) => params.row.monthlyDownloads, + valueGetter: (value, row) => row.monthlyDownloads, }, { field: 'lastMonthDownloads', headerName: 'Last month DLs', type: 'number', - valueGetter: (params) => - params.row.monthlyDownloads[params.row.monthlyDownloads.length - 1], + valueGetter: (value, row) => + row.monthlyDownloads[row.monthlyDownloads.length - 1], width: 150, }, ]; diff --git a/docs/data/data-grid/custom-columns/SparklineColumn.tsx b/docs/data/data-grid/custom-columns/SparklineColumn.tsx index 7e268946d24b5..b643d30d037d6 100644 --- a/docs/data/data-grid/custom-columns/SparklineColumn.tsx +++ b/docs/data/data-grid/custom-columns/SparklineColumn.tsx @@ -2,7 +2,6 @@ import * as React from 'react'; import { DataGrid, GridColDef, - GridRowsProp, GridColTypeDef, GridRenderCellParams, GRID_STRING_COL_DEF, @@ -40,7 +39,7 @@ const sparklineColumnType: GridColTypeDef = { renderCell: (params) => , }; -const columns: GridColDef[] = [ +const columns: GridColDef<(typeof rows)[number]>[] = [ { field: 'name', headerName: 'Package name', width: 180 }, { field: 'monthlyDownloads', @@ -54,14 +53,14 @@ const columns: GridColDef[] = [ headerName: 'Monthly DLs (bar)', renderCell: (params) => , width: 150, - valueGetter: (params) => params.row.monthlyDownloads, + valueGetter: (value, row) => row.monthlyDownloads, }, { field: 'lastMonthDownloads', headerName: 'Last month DLs', type: 'number', - valueGetter: (params) => - params.row.monthlyDownloads[params.row.monthlyDownloads.length - 1], + valueGetter: (value, row) => + row.monthlyDownloads[row.monthlyDownloads.length - 1], width: 150, }, ]; @@ -74,7 +73,7 @@ export default function SparklineColumn() { ); } -const rows: GridRowsProp = [ +const rows = [ { name: 'react-datepicker', monthlyDownloads: [ diff --git a/docs/data/data-grid/custom-columns/custom-columns.md b/docs/data/data-grid/custom-columns/custom-columns.md index 6c002afb4b0c3..118a6905b663a 100644 --- a/docs/data/data-grid/custom-columns/custom-columns.md +++ b/docs/data/data-grid/custom-columns/custom-columns.md @@ -10,7 +10,7 @@ The demo below defines a new column type: `usdPrice` that extends the native `nu const usdPrice: GridColTypeDef = { type: 'number', width: 130, - valueFormatter: ({ value }) => valueFormatter.format(Number(value)), + valueFormatter: (value) => valueFormatter.format(Number(value)), cellClassName: 'font-tabular-nums', }; ``` diff --git a/docs/data/data-grid/editing/ValueParserSetterGrid.js b/docs/data/data-grid/editing/ValueParserSetterGrid.js index f7686a31037f2..0dd07cf48e5cc 100644 --- a/docs/data/data-grid/editing/ValueParserSetterGrid.js +++ b/docs/data/data-grid/editing/ValueParserSetterGrid.js @@ -1,21 +1,17 @@ import * as React from 'react'; import { DataGrid } from '@mui/x-data-grid'; -function getFullName(params) { - return `${params.row.firstName || ''} ${params.row.lastName || ''}`; -} - -function setFullName(params) { - const [firstName, lastName] = params.value.toString().split(' '); - return { ...params.row, firstName, lastName }; -} +const setFullName = (value, row) => { + const [firstName, lastName] = value.toString().split(' '); + return { ...row, firstName, lastName }; +}; -function parseFullName(value) { +const parseFullName = (value) => { return String(value) .split(' ') .map((str) => (str.length > 0 ? str[0].toUpperCase() + str.slice(1) : '')) .join(' '); -} +}; export default function ValueParserSetterGrid() { return ( @@ -25,6 +21,18 @@ export default function ValueParserSetterGrid() { ); } +const defaultRows = [ + { id: 1, lastName: 'Snow', firstName: 'Jon' }, + { id: 2, lastName: 'Lannister', firstName: 'Cersei' }, + { id: 3, lastName: 'Lannister', firstName: 'Jaime' }, + { id: 4, lastName: 'Stark', firstName: 'Arya' }, + { id: 5, lastName: 'Targaryen', firstName: 'Daenerys' }, +]; + +const getFullName = (value, row) => { + return `${row.firstName || ''} ${row.lastName || ''}`; +}; + const columns = [ { field: 'firstName', headerName: 'First name', width: 130, editable: true }, { field: 'lastName', headerName: 'Last name', width: 130, editable: true }, @@ -39,11 +47,3 @@ const columns = [ sortComparator: (v1, v2) => v1.toString().localeCompare(v2.toString()), }, ]; - -const defaultRows = [ - { id: 1, lastName: 'Snow', firstName: 'Jon' }, - { id: 2, lastName: 'Lannister', firstName: 'Cersei' }, - { id: 3, lastName: 'Lannister', firstName: 'Jaime' }, - { id: 4, lastName: 'Stark', firstName: 'Arya' }, - { id: 5, lastName: 'Targaryen', firstName: 'Daenerys' }, -]; diff --git a/docs/data/data-grid/editing/ValueParserSetterGrid.tsx b/docs/data/data-grid/editing/ValueParserSetterGrid.tsx index 6b2658657840b..4ced3f4c3560f 100644 --- a/docs/data/data-grid/editing/ValueParserSetterGrid.tsx +++ b/docs/data/data-grid/editing/ValueParserSetterGrid.tsx @@ -2,25 +2,24 @@ import * as React from 'react'; import { DataGrid, GridColDef, - GridValueGetterParams, - GridValueSetterParams, + GridValueGetter, + GridValueSetter, + GridValueParser, } from '@mui/x-data-grid'; -function getFullName(params: GridValueGetterParams) { - return `${params.row.firstName || ''} ${params.row.lastName || ''}`; -} +type Row = (typeof defaultRows)[number]; -function setFullName(params: GridValueSetterParams) { - const [firstName, lastName] = params.value!.toString().split(' '); - return { ...params.row, firstName, lastName }; -} +const setFullName: GridValueSetter = (value, row) => { + const [firstName, lastName] = value!.toString().split(' '); + return { ...row, firstName, lastName }; +}; -function parseFullName(value: any) { +const parseFullName: GridValueParser = (value) => { return String(value) .split(' ') .map((str) => (str.length > 0 ? str[0].toUpperCase() + str.slice(1) : '')) .join(' '); -} +}; export default function ValueParserSetterGrid() { return ( @@ -30,6 +29,18 @@ export default function ValueParserSetterGrid() { ); } +const defaultRows = [ + { id: 1, lastName: 'Snow', firstName: 'Jon' }, + { id: 2, lastName: 'Lannister', firstName: 'Cersei' }, + { id: 3, lastName: 'Lannister', firstName: 'Jaime' }, + { id: 4, lastName: 'Stark', firstName: 'Arya' }, + { id: 5, lastName: 'Targaryen', firstName: 'Daenerys' }, +]; + +const getFullName: GridValueGetter = (value, row) => { + return `${row.firstName || ''} ${row.lastName || ''}`; +}; + const columns: GridColDef[] = [ { field: 'firstName', headerName: 'First name', width: 130, editable: true }, { field: 'lastName', headerName: 'Last name', width: 130, editable: true }, @@ -44,11 +55,3 @@ const columns: GridColDef[] = [ sortComparator: (v1, v2) => v1!.toString().localeCompare(v2!.toString()), }, ]; - -const defaultRows = [ - { id: 1, lastName: 'Snow', firstName: 'Jon' }, - { id: 2, lastName: 'Lannister', firstName: 'Cersei' }, - { id: 3, lastName: 'Lannister', firstName: 'Jaime' }, - { id: 4, lastName: 'Stark', firstName: 'Arya' }, - { id: 5, lastName: 'Targaryen', firstName: 'Daenerys' }, -]; diff --git a/docs/data/data-grid/editing/editing.md b/docs/data/data-grid/editing/editing.md index ae28abf66188d..2e74600d3fc90 100644 --- a/docs/data/data-grid/editing/editing.md +++ b/docs/data/data-grid/editing/editing.md @@ -212,7 +212,7 @@ You can use the `valueParser` property in the column definition to modify the va ```tsx const columns: GridColDef[] = [ { - valueParser: (value: any, params: GridCellParams) => { + valueParser: (value, row, column, apiRef) => { return value.toLowerCase(); }, }, @@ -227,9 +227,9 @@ If you are already using a `valueGetter` to extract the value from a nested obje ```tsx const columns: GridColDef[] = [ { - valueSetter: (params: GridValueSetterParams) => { - const [firstName, lastName] = params.value!.toString().split(' '); - return { ...params.row, firstName, lastName }; + valueSetter: (value, row) => { + const [firstName, lastName] = value!.toString().split(' '); + return { ...row, firstName, lastName }; }, }, ]; diff --git a/docs/data/data-grid/events/CatalogOfEventsNoSnap.js b/docs/data/data-grid/events/CatalogOfEventsNoSnap.js index af7348a2d469d..a8961cf3d97bd 100644 --- a/docs/data/data-grid/events/CatalogOfEventsNoSnap.js +++ b/docs/data/data-grid/events/CatalogOfEventsNoSnap.js @@ -82,7 +82,7 @@ const COLUMNS = [ headerName: 'Available on', width: 100, align: 'center', - valueGetter: ({ row }) => { + valueGetter: (value, row) => { if (row.projects.includes('x-data-grid')) { return 'x-data-grid'; } diff --git a/docs/data/data-grid/export/export.md b/docs/data/data-grid/export/export.md index 1056d3cc9518a..41145286c6f07 100644 --- a/docs/data/data-grid/export/export.md +++ b/docs/data/data-grid/export/export.md @@ -122,7 +122,7 @@ You can provide a [`valueFormatter`](/x/react-data-grid/column-definition/#value columns={[ { field: 'progress', - valueFormatter: ({ value }) => `${value * 100}%`, + valueFormatter: (value) => `${value * 100}%`, renderCell: ({ value }) => , }, ]} diff --git a/docs/data/data-grid/filtering/QuickFilteringDiacritics.js b/docs/data/data-grid/filtering/QuickFilteringDiacritics.js index 72466794f2003..a5562cff2a684 100644 --- a/docs/data/data-grid/filtering/QuickFilteringDiacritics.js +++ b/docs/data/data-grid/filtering/QuickFilteringDiacritics.js @@ -19,7 +19,7 @@ const columns = [ field: 'date', type: 'date', width: 150, - valueFormatter: (params) => dateFormatter.format(params.value), + valueFormatter: (value) => dateFormatter.format(value), }, { field: 'singleSelect', diff --git a/docs/data/data-grid/filtering/QuickFilteringDiacritics.tsx b/docs/data/data-grid/filtering/QuickFilteringDiacritics.tsx index 26197a90dbad9..c54fb2e0a141b 100644 --- a/docs/data/data-grid/filtering/QuickFilteringDiacritics.tsx +++ b/docs/data/data-grid/filtering/QuickFilteringDiacritics.tsx @@ -23,7 +23,7 @@ const columns: GridColDef[] = [ field: 'date', type: 'date', width: 150, - valueFormatter: (params) => dateFormatter.format(params.value), + valueFormatter: (value) => dateFormatter.format(value), }, { field: 'singleSelect', diff --git a/docs/data/data-grid/localization/DataGridRTL.js b/docs/data/data-grid/localization/DataGridRTL.js index abd88d606147c..e5b06bc23c837 100644 --- a/docs/data/data-grid/localization/DataGridRTL.js +++ b/docs/data/data-grid/localization/DataGridRTL.js @@ -27,7 +27,7 @@ const columns = [ { field: 'age', headerName: 'عمر', - valueGetter: (params) => `${params.value} سنوات`, + valueGetter: (value) => `${value} سنوات`, width: 150, }, { diff --git a/docs/data/data-grid/localization/DataGridRTL.tsx b/docs/data/data-grid/localization/DataGridRTL.tsx index df697849b2d07..bd14585f52558 100644 --- a/docs/data/data-grid/localization/DataGridRTL.tsx +++ b/docs/data/data-grid/localization/DataGridRTL.tsx @@ -27,7 +27,7 @@ const columns: GridColDef[] = [ { field: 'age', headerName: 'عمر', - valueGetter: (params) => `${params.value} سنوات`, + valueGetter: (value) => `${value} سنوات`, width: 150, }, { diff --git a/docs/data/data-grid/master-detail/BasicDetailPanels.js b/docs/data/data-grid/master-detail/BasicDetailPanels.js index 27441b5dc3956..20da411552c06 100644 --- a/docs/data/data-grid/master-detail/BasicDetailPanels.js +++ b/docs/data/data-grid/master-detail/BasicDetailPanels.js @@ -61,7 +61,7 @@ function DetailPanelContent({ row: rowProp }) { field: 'total', headerName: 'Total', type: 'number', - valueGetter: ({ row }) => row.quantity * row.unitPrice, + valueGetter: (value, row) => row.quantity * row.unitPrice, }, ]} rows={rowProp.products} @@ -83,7 +83,7 @@ const columns = [ field: 'total', type: 'number', headerName: 'Total', - valueGetter: ({ row }) => { + valueGetter: (value, row) => { const subtotal = row.products.reduce( (acc, product) => product.unitPrice * product.quantity, 0, diff --git a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx index 44f2287d995f7..b9c17508bd5b5 100644 --- a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx +++ b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx @@ -62,7 +62,7 @@ function DetailPanelContent({ row: rowProp }: { row: Customer }) { field: 'total', headerName: 'Total', type: 'number', - valueGetter: ({ row }) => row.quantity * row.unitPrice, + valueGetter: (value, row) => row.quantity * row.unitPrice, }, ]} rows={rowProp.products} @@ -75,7 +75,7 @@ function DetailPanelContent({ row: rowProp }: { row: Customer }) { ); } -const columns: GridColDef[] = [ +const columns: GridColDef<(typeof rows)[number]>[] = [ { field: 'id', headerName: 'Order ID' }, { field: 'customer', headerName: 'Customer', width: 200 }, { field: 'date', type: 'date', headerName: 'Placed at' }, @@ -84,7 +84,7 @@ const columns: GridColDef[] = [ field: 'total', type: 'number', headerName: 'Total', - valueGetter: ({ row }) => { + valueGetter: (value, row) => { const subtotal = row.products.reduce( (acc: number, product: any) => product.unitPrice * product.quantity, 0, diff --git a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js index 1b2979ef15af7..6819a2be2b18b 100644 --- a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js +++ b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js @@ -69,7 +69,7 @@ function DetailPanelContent({ row: rowProp }) { field: 'total', headerName: 'Total', type: 'number', - valueGetter: ({ row }) => row.quantity * row.unitPrice, + valueGetter: (value, row) => row.quantity * row.unitPrice, }, { field: 'actions', @@ -141,7 +141,7 @@ const columns = [ field: 'total', type: 'number', headerName: 'Total', - valueGetter: ({ row }) => { + valueGetter: (value, row) => { const subtotal = row.products.reduce( (acc, product) => product.unitPrice * product.quantity, 0, diff --git a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx index 477b12e3c9aa6..dfe9d815e169f 100644 --- a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx +++ b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx @@ -55,7 +55,7 @@ function DetailPanelContent({ row: rowProp }: { row: Customer }) { [apiRef, rowProp], ); - const columns = React.useMemo( + const columns = React.useMemo[]>( () => [ { field: 'name', headerName: 'Product', flex: 1, editable: true }, { @@ -71,7 +71,7 @@ function DetailPanelContent({ row: rowProp }: { row: Customer }) { field: 'total', headerName: 'Total', type: 'number', - valueGetter: ({ row }) => row.quantity * row.unitPrice, + valueGetter: (value, row) => row.quantity * row.unitPrice, }, { field: 'actions', @@ -144,7 +144,7 @@ const columns: GridColDef[] = [ field: 'total', type: 'number', headerName: 'Total', - valueGetter: ({ row }) => { + valueGetter: (value, row) => { const subtotal = row.products.reduce( (acc: number, product: any) => product.unitPrice * product.quantity, 0, diff --git a/docs/data/data-grid/master-detail/FullWidthDetailPanel.js b/docs/data/data-grid/master-detail/FullWidthDetailPanel.js index dd37ac623ca1e..16bd2837aba38 100644 --- a/docs/data/data-grid/master-detail/FullWidthDetailPanel.js +++ b/docs/data/data-grid/master-detail/FullWidthDetailPanel.js @@ -69,7 +69,7 @@ function DetailPanelContent({ row: rowProp }) { field: 'total', headerName: 'Total', type: 'number', - valueGetter: ({ row }) => row.quantity * row.unitPrice, + valueGetter: (value, row) => row.quantity * row.unitPrice, }, ]} rows={rowProp.products} @@ -92,13 +92,13 @@ const columns = [ { field: 'city', headerName: 'City', - valueGetter: ({ row }) => `${row.city}, ${row.country.label}`, + valueGetter: (value, row) => `${row.city}, ${row.country.label}`, }, { field: 'total', type: 'number', headerName: 'Total', - valueGetter: ({ row }) => { + valueGetter: (value, row) => { const subtotal = row.products.reduce( (acc, product) => product.unitPrice * product.quantity, 0, diff --git a/docs/data/data-grid/master-detail/FullWidthDetailPanel.tsx b/docs/data/data-grid/master-detail/FullWidthDetailPanel.tsx index 70edba0e00b1e..d2910a6214d20 100644 --- a/docs/data/data-grid/master-detail/FullWidthDetailPanel.tsx +++ b/docs/data/data-grid/master-detail/FullWidthDetailPanel.tsx @@ -71,7 +71,7 @@ function DetailPanelContent({ row: rowProp }: { row: Customer }) { field: 'total', headerName: 'Total', type: 'number', - valueGetter: ({ row }) => row.quantity * row.unitPrice, + valueGetter: (value, row) => row.quantity * row.unitPrice, }, ]} rows={rowProp.products} @@ -94,13 +94,13 @@ const columns: GridColDef[] = [ { field: 'city', headerName: 'City', - valueGetter: ({ row }) => `${row.city}, ${row.country.label}`, + valueGetter: (value, row) => `${row.city}, ${row.country.label}`, }, { field: 'total', type: 'number', headerName: 'Total', - valueGetter: ({ row }) => { + valueGetter: (value, row) => { const subtotal = row.products.reduce( (acc: number, product: any) => product.unitPrice * product.quantity, 0, diff --git a/docs/data/data-grid/overview/DataGridDemo.js b/docs/data/data-grid/overview/DataGridDemo.js index 7987b9fdb00fc..b9bffd9e02790 100644 --- a/docs/data/data-grid/overview/DataGridDemo.js +++ b/docs/data/data-grid/overview/DataGridDemo.js @@ -29,8 +29,7 @@ const columns = [ description: 'This column has a value getter and is not sortable.', sortable: false, width: 160, - valueGetter: (params) => - `${params.row.firstName || ''} ${params.row.lastName || ''}`, + valueGetter: (value, row) => `${row.firstName || ''} ${row.lastName || ''}`, }, ]; diff --git a/docs/data/data-grid/overview/DataGridDemo.tsx b/docs/data/data-grid/overview/DataGridDemo.tsx index 5e5f832862749..44a9499bfa196 100644 --- a/docs/data/data-grid/overview/DataGridDemo.tsx +++ b/docs/data/data-grid/overview/DataGridDemo.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid'; +import { DataGrid, GridColDef } from '@mui/x-data-grid'; -const columns: GridColDef[] = [ +const columns: GridColDef<(typeof rows)[number]>[] = [ { field: 'id', headerName: 'ID', width: 90 }, { field: 'firstName', @@ -29,8 +29,7 @@ const columns: GridColDef[] = [ description: 'This column has a value getter and is not sortable.', sortable: false, width: 160, - valueGetter: (params: GridValueGetterParams) => - `${params.row.firstName || ''} ${params.row.lastName || ''}`, + valueGetter: (value, row) => `${row.firstName || ''} ${row.lastName || ''}`, }, ]; diff --git a/docs/data/data-grid/row-grouping/RowGroupingCustomGroupingColDefCallback.js b/docs/data/data-grid/row-grouping/RowGroupingCustomGroupingColDefCallback.js index 6c6ad41c2bcd0..0d09526ce08d2 100644 --- a/docs/data/data-grid/row-grouping/RowGroupingCustomGroupingColDefCallback.js +++ b/docs/data/data-grid/row-grouping/RowGroupingCustomGroupingColDefCallback.js @@ -58,8 +58,9 @@ export default function RowGroupingCustomGroupingColDefCallback() { if (params.fields.includes('director')) { return { headerName: 'Director', - valueFormatter: (valueFormatterParams) => { - const rowNode = apiRef.current.getRowNode(valueFormatterParams.id); + valueFormatter: (value, row) => { + const rowId = apiRef.current.getRowId(row); + const rowNode = apiRef.current.getRowNode(rowId); if ( rowNode?.type === 'group' && rowNode?.groupingField === 'director' diff --git a/docs/data/data-grid/row-grouping/RowGroupingCustomGroupingColDefCallback.tsx b/docs/data/data-grid/row-grouping/RowGroupingCustomGroupingColDefCallback.tsx index d55e8a779683d..e8c4da9dab49f 100644 --- a/docs/data/data-grid/row-grouping/RowGroupingCustomGroupingColDefCallback.tsx +++ b/docs/data/data-grid/row-grouping/RowGroupingCustomGroupingColDefCallback.tsx @@ -59,10 +59,9 @@ export default function RowGroupingCustomGroupingColDefCallback() { if (params.fields.includes('director')) { return { headerName: 'Director', - valueFormatter: (valueFormatterParams) => { - const rowNode = apiRef.current.getRowNode( - valueFormatterParams.id!, - ); + valueFormatter: (value, row) => { + const rowId = apiRef.current.getRowId(row); + const rowNode = apiRef.current.getRowNode(rowId); if ( rowNode?.type === 'group' && rowNode?.groupingField === 'director' diff --git a/docs/data/data-grid/row-grouping/RowGroupingGroupingValueGetter.js b/docs/data/data-grid/row-grouping/RowGroupingGroupingValueGetter.js index 0516dad488d31..f07843101f27c 100644 --- a/docs/data/data-grid/row-grouping/RowGroupingGroupingValueGetter.js +++ b/docs/data/data-grid/row-grouping/RowGroupingGroupingValueGetter.js @@ -16,15 +16,15 @@ export default function RowGroupingGroupingValueGetter() { { field: 'composer', headerName: 'Composer', - valueGetter: (params) => params.value?.name, - groupingValueGetter: (params) => params.value.name, + valueGetter: (value) => value.name, + groupingValueGetter: (value) => value.name, width: 200, }, { field: 'decade', headerName: 'Decade', - valueGetter: (params) => Math.floor(params.row.year / 10) * 10, - groupingValueGetter: (params) => Math.floor(params.row.year / 10) * 10, + valueGetter: (value, row) => Math.floor(row.year / 10) * 10, + groupingValueGetter: (value, row) => Math.floor(row.year / 10) * 10, renderCell: (params) => { if (params.value == null) { return ''; diff --git a/docs/data/data-grid/row-grouping/RowGroupingGroupingValueGetter.tsx b/docs/data/data-grid/row-grouping/RowGroupingGroupingValueGetter.tsx index 2ed31822cf4c1..41b5f2b7ff6b7 100644 --- a/docs/data/data-grid/row-grouping/RowGroupingGroupingValueGetter.tsx +++ b/docs/data/data-grid/row-grouping/RowGroupingGroupingValueGetter.tsx @@ -17,15 +17,15 @@ export default function RowGroupingGroupingValueGetter() { { field: 'composer', headerName: 'Composer', - valueGetter: (params) => params.value?.name, - groupingValueGetter: (params) => params.value.name, + valueGetter: (value: { name: string }) => value.name, + groupingValueGetter: (value: { name: string }) => value.name, width: 200, - } as GridColDef, + } as GridColDef, { field: 'decade', headerName: 'Decade', - valueGetter: (params) => Math.floor(params.row.year / 10) * 10, - groupingValueGetter: (params) => Math.floor(params.row.year / 10) * 10, + valueGetter: (value, row) => Math.floor(row.year / 10) * 10, + groupingValueGetter: (value, row) => Math.floor(row.year / 10) * 10, renderCell: (params) => { if (params.value == null) { return ''; diff --git a/docs/data/data-grid/row-grouping/row-grouping.md b/docs/data/data-grid/row-grouping/row-grouping.md index de63e20f769f4..2935b2ad9861b 100644 --- a/docs/data/data-grid/row-grouping/row-grouping.md +++ b/docs/data/data-grid/row-grouping/row-grouping.md @@ -212,7 +212,7 @@ If your cell value is more complex, pass a `groupingValueGetter` property to the const columns: GridColDef[] = [ { field: 'composer', - groupingValueGetter: (params) => params.value.name, + groupingValueGetter: (value) => value.name, }, // ... ]; diff --git a/docs/data/data-grid/sorting/ExtendedSortComparator.js b/docs/data/data-grid/sorting/ExtendedSortComparator.js index 86acdc0d08ee6..705eb59585e86 100644 --- a/docs/data/data-grid/sorting/ExtendedSortComparator.js +++ b/docs/data/data-grid/sorting/ExtendedSortComparator.js @@ -37,12 +37,11 @@ export default function ExtendedSortComparator() { { field: 'nameAdmin', headerName: 'Name', - valueGetter: (params) => ({ - name: params.row.name, - isAdmin: params.row.isAdmin, + valueGetter: (value, row) => ({ + name: row.name, + isAdmin: row.isAdmin, }), - valueFormatter: (params) => { - const value = params.value; + valueFormatter: (value) => { if (value.isAdmin) { return `${value.name} (admin)`; } diff --git a/docs/data/data-grid/sorting/ExtendedSortComparator.tsx b/docs/data/data-grid/sorting/ExtendedSortComparator.tsx index ddeef60aeb359..5419a57b3eea9 100644 --- a/docs/data/data-grid/sorting/ExtendedSortComparator.tsx +++ b/docs/data/data-grid/sorting/ExtendedSortComparator.tsx @@ -2,7 +2,6 @@ import * as React from 'react'; import { GridColDef, DataGrid, - GridValueGetterParams, gridNumberComparator, gridStringOrNumberComparator, GridComparatorFn, @@ -50,12 +49,11 @@ export default function ExtendedSortComparator() { { field: 'nameAdmin', headerName: 'Name', - valueGetter: (params: GridValueGetterParams) => ({ - name: params.row.name, - isAdmin: params.row.isAdmin, + valueGetter: (value, row) => ({ + name: row.name, + isAdmin: row.isAdmin, }), - valueFormatter: (params) => { - const value = params.value as NameAdminCellValue; + valueFormatter: (value: NameAdminCellValue) => { if (value.isAdmin) { return `${value.name} (admin)`; } diff --git a/docs/data/data-grid/sorting/FullyCustomSortComparator.js b/docs/data/data-grid/sorting/FullyCustomSortComparator.js index ecd8c8a0112ab..be364bee8b75c 100644 --- a/docs/data/data-grid/sorting/FullyCustomSortComparator.js +++ b/docs/data/data-grid/sorting/FullyCustomSortComparator.js @@ -17,7 +17,7 @@ export default function FullyCustomSortComparator() { () => [ { field: 'dateCreatedCustom', - valueGetter: (params) => params.row.dateCreated, + valueGetter: (value, row) => row.dateCreated, headerName: 'Created on', width: 180, type: 'date', diff --git a/docs/data/data-grid/sorting/FullyCustomSortComparator.tsx b/docs/data/data-grid/sorting/FullyCustomSortComparator.tsx index 22a7ee7441606..1ffd85dad444b 100644 --- a/docs/data/data-grid/sorting/FullyCustomSortComparator.tsx +++ b/docs/data/data-grid/sorting/FullyCustomSortComparator.tsx @@ -18,7 +18,7 @@ export default function FullyCustomSortComparator() { () => [ { field: 'dateCreatedCustom', - valueGetter: (params) => params.row.dateCreated, + valueGetter: (value, row) => row.dateCreated, headerName: 'Created on', width: 180, type: 'date', diff --git a/docs/data/data-grid/style-recipes/StylingAllCellsButAggregation.js b/docs/data/data-grid/style-recipes/StylingAllCellsButAggregation.js index 4ed59c8b462b4..da7be87708494 100644 --- a/docs/data/data-grid/style-recipes/StylingAllCellsButAggregation.js +++ b/docs/data/data-grid/style-recipes/StylingAllCellsButAggregation.js @@ -3,7 +3,7 @@ import Box from '@mui/material/Box'; import { DataGridPremium, gridClasses } from '@mui/x-data-grid-premium'; // eliminate rounding errors in aggregation row -const valueFormatter = ({ value }) => `${Math.floor(value * 1000) / 1000} °C`; +const valueFormatter = (value) => `${Math.floor(value * 1000) / 1000} °C`; const columns = [ { field: 'city' }, diff --git a/docs/data/data-grid/style-recipes/StylingAllCellsButAggregation.tsx b/docs/data/data-grid/style-recipes/StylingAllCellsButAggregation.tsx index 5d0d5c0200c73..f26c378f9e606 100644 --- a/docs/data/data-grid/style-recipes/StylingAllCellsButAggregation.tsx +++ b/docs/data/data-grid/style-recipes/StylingAllCellsButAggregation.tsx @@ -8,7 +8,7 @@ import { } from '@mui/x-data-grid-premium'; // eliminate rounding errors in aggregation row -const valueFormatter: GridColDef['valueFormatter'] = ({ value }) => +const valueFormatter: GridColDef['valueFormatter'] = (value) => `${Math.floor(value * 1000) / 1000} °C`; const columns: GridColDef[] = [ diff --git a/docs/data/data-grid/style/StylingAllCells.js b/docs/data/data-grid/style/StylingAllCells.js index ebd925f7e3b8e..6760aea754cc5 100644 --- a/docs/data/data-grid/style/StylingAllCells.js +++ b/docs/data/data-grid/style/StylingAllCells.js @@ -4,9 +4,9 @@ import { DataGrid, gridClasses } from '@mui/x-data-grid'; const columns = [ { field: 'city' }, - { field: 'oct', type: 'number', valueFormatter: ({ value }) => `${value} °C` }, - { field: 'nov', type: 'number', valueFormatter: ({ value }) => `${value} °C` }, - { field: 'dec', type: 'number', valueFormatter: ({ value }) => `${value} °C` }, + { field: 'oct', type: 'number', valueFormatter: (value) => `${value} °C` }, + { field: 'nov', type: 'number', valueFormatter: (value) => `${value} °C` }, + { field: 'dec', type: 'number', valueFormatter: (value) => `${value} °C` }, ]; const rows = [ diff --git a/docs/data/data-grid/style/StylingAllCells.tsx b/docs/data/data-grid/style/StylingAllCells.tsx index ef089f4c9a6b6..08d1222d64f82 100644 --- a/docs/data/data-grid/style/StylingAllCells.tsx +++ b/docs/data/data-grid/style/StylingAllCells.tsx @@ -4,9 +4,9 @@ import { GridColDef, DataGrid, GridCellParams, gridClasses } from '@mui/x-data-g const columns: GridColDef[] = [ { field: 'city' }, - { field: 'oct', type: 'number', valueFormatter: ({ value }) => `${value} °C` }, - { field: 'nov', type: 'number', valueFormatter: ({ value }) => `${value} °C` }, - { field: 'dec', type: 'number', valueFormatter: ({ value }) => `${value} °C` }, + { field: 'oct', type: 'number', valueFormatter: (value) => `${value} °C` }, + { field: 'nov', type: 'number', valueFormatter: (value) => `${value} °C` }, + { field: 'dec', type: 'number', valueFormatter: (value) => `${value} °C` }, ]; const rows = [ diff --git a/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.js b/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.js index 1a7a7ff8ad46b..873711c2d23f8 100644 --- a/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.js +++ b/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.js @@ -146,8 +146,8 @@ const columns = [ { field: 'name', headerName: 'Name', - valueGetter: (params) => { - const hierarchy = params.row.hierarchy; + valueGetter: (value, row) => { + const hierarchy = row.hierarchy; return hierarchy[hierarchy.length - 1]; }, }, diff --git a/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.tsx b/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.tsx index ca3e81a973cf0..c69ba21dd243d 100644 --- a/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.tsx +++ b/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.tsx @@ -153,15 +153,15 @@ const rows: GridRowsProp = [ }, ]; -const columns: GridColDef[] = [ +const columns: GridColDef[] = [ { field: 'name', headerName: 'Name', - valueGetter: (params) => { - const hierarchy = params.row.hierarchy; + valueGetter: (value, row) => { + const hierarchy = row.hierarchy; return hierarchy[hierarchy.length - 1]; }, - } as GridColDef, + }, { field: 'jobTitle', headerName: 'Job Title', width: 200 }, { field: 'recruitmentDate', diff --git a/docs/data/data-grid/tree-data/TreeDataWithGap.js b/docs/data/data-grid/tree-data/TreeDataWithGap.js index e482cad77dcb7..4262567ee62a3 100644 --- a/docs/data/data-grid/tree-data/TreeDataWithGap.js +++ b/docs/data/data-grid/tree-data/TreeDataWithGap.js @@ -88,12 +88,14 @@ const columns = [ field: 'isAutoGenerated', headerName: 'Gap', type: 'boolean', - valueGetter: (params) => { - if (params.rowNode.type !== 'group') { + valueGetter: (value, row, column, apiRef) => { + const rowId = apiRef.current.getRowId(row); + const rowNode = apiRef.current.getRowNode(rowId); + if (rowNode?.type !== 'group') { return undefined; } - return params.rowNode.isAutoGenerated; + return rowNode.isAutoGenerated; }, }, ]; diff --git a/docs/data/data-grid/tree-data/TreeDataWithGap.tsx b/docs/data/data-grid/tree-data/TreeDataWithGap.tsx index a7a5d9bea0590..bc3e5e34b4d5e 100644 --- a/docs/data/data-grid/tree-data/TreeDataWithGap.tsx +++ b/docs/data/data-grid/tree-data/TreeDataWithGap.tsx @@ -1,12 +1,7 @@ import * as React from 'react'; -import { - DataGridPro, - GridColDef, - GridRowsProp, - DataGridProProps, -} from '@mui/x-data-grid-pro'; +import { DataGridPro, GridColDef, DataGridProProps } from '@mui/x-data-grid-pro'; -const rows: GridRowsProp = [ +const rows = [ { hierarchy: ['Sarah'], jobTitle: 'Head of Human Resources', @@ -81,7 +76,7 @@ const rows: GridRowsProp = [ }, ]; -const columns: GridColDef[] = [ +const columns: GridColDef<(typeof rows)[number]>[] = [ { field: 'jobTitle', headerName: 'Job Title', width: 200 }, { field: 'recruitmentDate', @@ -93,12 +88,14 @@ const columns: GridColDef[] = [ field: 'isAutoGenerated', headerName: 'Gap', type: 'boolean', - valueGetter: (params) => { - if (params.rowNode.type !== 'group') { + valueGetter: (value, row, column, apiRef) => { + const rowId = apiRef.current.getRowId(row); + const rowNode = apiRef.current.getRowNode(rowId); + if (rowNode?.type !== 'group') { return undefined; } - return params.rowNode.isAutoGenerated; + return rowNode.isAutoGenerated; }, }, ]; diff --git a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md index f7683fe808231..907ccdf3398a3 100644 --- a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md +++ b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md @@ -182,6 +182,88 @@ Here's the list of affected features, colDef flags and props to disable them and - `Show all` and `Hide all` buttons in the `ColumnsPanel` have been combined into one `Show/Hide All` checkbox in the new columns management component. The related props `disableShowAllButton` and `disableHideAllButton` have been replaced with a new prop `disableShowHideToggle`. +- The signature of `GridColDef['valueGetter']` has been changed for performance reasons: + + ```diff + - valueGetter: ({ value, row }) => value, + + valueGetter: (value, row, column, apiRef) => value, + ``` + + The `GridValueGetterParams` interface has been removed: + + ```diff + - const customValueGetter = (params: GridValueGetterParams) => params.row.budget; + + const customValueGetter: GridValueGetterFn = (value, row) => row.budget; + ``` + +- The signature of `GridColDef['valueFormatter']` has been changed for performance reasons: + + ```diff + - valueFormatter: ({ value }) => value, + + valueFormatter: (value, row, column, apiRef) => value, + ``` + + The `GridValueFormatterParams` interface has been removed: + + ```diff + - const gridDateFormatter = ({ value, field, id }: GridValueFormatterParams) => value.toLocaleDateString(); + + const gridDateFormatter: GridValueFormatter = (value: Date) => value.toLocaleDateString(); + ``` + +- The signature of `GridColDef['valueSetter']` has been changed for performance reasons: + + ```diff + - valueSetter: (params) => { + - const [firstName, lastName] = params.value!.toString().split(' '); + - return { ...params.row, firstName, lastName }; + - } + + valueSetter: (value, row) => { + + const [firstName, lastName] = value!.toString().split(' '); + + return { ...row, firstName, lastName }; + +} + ``` + + The `GridValueSetterParams` interface has been removed: + + ```diff + - const setFullName = (params: GridValueSetterParams) => { + - const [firstName, lastName] = params.value!.toString().split(' '); + - return { ...params.row, firstName, lastName }; + - }; + + const setFullName: GridValueSetter = (value, row) => { + + const [firstName, lastName] = value!.toString().split(' '); + + return { ...row, firstName, lastName }; + + } + ``` + +- The signature of `GridColDef['valueParser']` has been changed for performance reasons: + + ```diff + - valueParser: (value, params: GridCellParams) => value.toLowerCase(), + + valueParser: (value, row, column, apiRef) => value.toLowerCase(), + ``` + +- The signature of `GridColDef['colSpan']` has been changed for performance reasons: + + ```diff + - colSpan: ({ row, field, value }: GridCellParams) => (row.id === 'total' ? 2 : 1), + + colSpan: (value, row, column, apiRef) => (row.id === 'total' ? 2 : 1), + ``` + +- The signature of `GridColDef['pastedValueParser']` has been changed for performance reasons: + + ```diff + - pastedValueParser: (value, params) => new Date(value), + + pastedValueParser: (value, row, column, apiRef) => new Date(value), + ``` + +- The signature of `GridColDef['groupingValueGetter']` has been changed for performance reasons: + + ```diff + - groupingValueGetter: (params) => params.value.name, + + groupingValueGetter: (value: { name: string }) => value.name, + ``` + diff --git a/docs/pages/x/api/data-grid/grid-actions-col-def.md b/docs/pages/x/api/data-grid/grid-actions-col-def.md index af3663b0805c6..81fa4a45606ac 100644 --- a/docs/pages/x/api/data-grid/grid-actions-col-def.md +++ b/docs/pages/x/api/data-grid/grid-actions-col-def.md @@ -29,7 +29,7 @@ import { GridActionsColDef } from '@mui/x-data-grid'; | align? | GridAlignment | | Allows to align the column values in cells. | | availableAggregationFunctions? [](/x/introduction/licensing/#premium-plan) | string[] | | Limit the aggregation function usable on this column.
By default, the column will have all the aggregation functions that are compatible with its type. | | cellClassName? | GridCellClassNamePropType<R, V> | | Class name that will be added in cells for that column. | -| colSpan? | number \| ((params: GridCellParams<R, V, F>) => number \| undefined) | 1 | Number of columns a cell should span. | +| colSpan? | number \| GridColSpanFn<R, V, F> | 1 | Number of columns a cell should span. | | description? | string | | The description of the column rendered as tooltip if the column header name is not fully displayed. | | disableColumnMenu? | boolean | false | If `true`, the column menu is disabled for this column. | | disableExport? | boolean | false | If `true`, this column will not be included in exports. | @@ -42,7 +42,7 @@ import { GridActionsColDef } from '@mui/x-data-grid'; | getActions | (params: GridRowParams<R>) => React.ReactElement<GridActionsCellItemProps>[] | | Function that returns the actions to be shown. | | getApplyQuickFilterFn? | GetApplyQuickFilterFn<R, V> | | The callback that generates a filtering function for a given quick filter value.
This function can return `null` to skip filtering for this value and column. | | groupable? | boolean | true | If `true`, the rows can be grouped based on this column values (pro-plan only).
Only available in DataGridPremium. | -| groupingValueGetter? [](/x/introduction/licensing/#premium-plan) | (params: GridGroupingValueGetterParams<R, V>) => GridKeyValue \| null \| undefined | | Function that transforms a complex cell value into a key that be used for grouping the rows. | +| groupingValueGetter? [](/x/introduction/licensing/#premium-plan) | GridGroupingValueGetter<R> | | Function that transforms a complex cell value into a key that be used for grouping the rows. | | headerAlign? | GridAlignment | | Header cell element alignment. | | headerClassName? | GridColumnHeaderClassNamePropType | | Class name that will be added in the column header cell. | | headerName? | string | | The title of the column rendered in the column header cell. | @@ -50,7 +50,7 @@ import { GridActionsColDef } from '@mui/x-data-grid'; | hideSortIcons? | boolean | false | Toggle the visibility of the sort icons. | | maxWidth? | number | Infinity | Sets the maximum width of a column. | | minWidth? | number | 50 | Sets the minimum width of a column. | -| pastedValueParser? [](/x/introduction/licensing/#premium-plan) | (value: string, params: GridCellParams<R, V, F>) => V \| undefined | | Function that takes the clipboard-pasted value and converts it to a value used internally. | +| pastedValueParser? [](/x/introduction/licensing/#premium-plan) | GridPastedValueParser<R, V, F> | | Function that takes the clipboard-pasted value and converts it to a value used internally. | | pinnable? | boolean | true | If `false`, the menu items for column pinning menu will not be rendered.
Only available in DataGridPro. | | preProcessEditCellProps? | (params: GridPreProcessEditCellProps) => GridEditCellProps \| Promise<GridEditCellProps> | | Callback fired when the edit props of the cell changes.
It allows to process the props that saved into the state. | | renderCell? | (params: GridRenderCellParams<R, V, F>) => React.ReactNode | | Allows to override the component rendered as cell for this column. | @@ -62,8 +62,8 @@ import { GridActionsColDef } from '@mui/x-data-grid'; | sortComparator? | GridComparatorFn<V> | | A comparator function used to sort rows. | | sortingOrder? | GridSortDirection[] | | The order of the sorting sequence. | | type | 'actions' | 'actions' | The type of the column. | -| valueFormatter? | (params: GridValueFormatterParams<V>) => F | | Function that allows to apply a formatter before rendering its value. | -| valueGetter? | (params: GridValueGetterParams<R, any>) => V | | Function that allows to get a specific data instead of field to render in the cell. | -| valueParser? | (value: F \| undefined, params?: GridCellParams<R, V, F>) => V | | Function that takes the user-entered value and converts it to a value used internally. | -| valueSetter? | (params: GridValueSetterParams<R, V>) => R | | Function that allows to customize how the entered value is stored in the row.
It only works with cell/row editing. | +| valueFormatter? | GridValueFormatter<R, V, F> | | Function that allows to apply a formatter before rendering its value. | +| valueGetter? | GridValueGetter<R, V, F> | | Function that allows to get a specific data instead of field to render in the cell. | +| valueParser? | GridValueParser<R, V, F> | | Function that takes the user-entered value and converts it to a value used internally. | +| valueSetter? | GridValueSetter<R, V, F> | | Function that allows to customize how the entered value is stored in the row.
It only works with cell/row editing. | | width? | number | 100 | Set the width of the column. | diff --git a/docs/pages/x/api/data-grid/grid-col-def.md b/docs/pages/x/api/data-grid/grid-col-def.md index c05e09badc9cf..bee228483b219 100644 --- a/docs/pages/x/api/data-grid/grid-col-def.md +++ b/docs/pages/x/api/data-grid/grid-col-def.md @@ -29,7 +29,7 @@ import { GridColDef } from '@mui/x-data-grid'; | align? | GridAlignment | | Allows to align the column values in cells. | | availableAggregationFunctions? [](/x/introduction/licensing/#premium-plan) | string[] | | Limit the aggregation function usable on this column.
By default, the column will have all the aggregation functions that are compatible with its type. | | cellClassName? | GridCellClassNamePropType<R, V> | | Class name that will be added in cells for that column. | -| colSpan? | number \| ((params: GridCellParams<R, V, F>) => number \| undefined) | 1 | Number of columns a cell should span. | +| colSpan? | number \| GridColSpanFn<R, V, F> | 1 | Number of columns a cell should span. | | description? | string | | The description of the column rendered as tooltip if the column header name is not fully displayed. | | disableColumnMenu? | boolean | false | If `true`, the column menu is disabled for this column. | | disableExport? | boolean | false | If `true`, this column will not be included in exports. | @@ -41,7 +41,7 @@ import { GridColDef } from '@mui/x-data-grid'; | flex? | number | | If set, it indicates that a column has fluid width. Range [0, ∞). | | getApplyQuickFilterFn? | GetApplyQuickFilterFn<R, V> | | The callback that generates a filtering function for a given quick filter value.
This function can return `null` to skip filtering for this value and column. | | groupable? | boolean | true | If `true`, the rows can be grouped based on this column values (pro-plan only).
Only available in DataGridPremium. | -| groupingValueGetter? [](/x/introduction/licensing/#premium-plan) | (params: GridGroupingValueGetterParams<R, V>) => GridKeyValue \| null \| undefined | | Function that transforms a complex cell value into a key that be used for grouping the rows. | +| groupingValueGetter? [](/x/introduction/licensing/#premium-plan) | GridGroupingValueGetter<R> | | Function that transforms a complex cell value into a key that be used for grouping the rows. | | headerAlign? | GridAlignment | | Header cell element alignment. | | headerClassName? | GridColumnHeaderClassNamePropType | | Class name that will be added in the column header cell. | | headerName? | string | | The title of the column rendered in the column header cell. | @@ -49,7 +49,7 @@ import { GridColDef } from '@mui/x-data-grid'; | hideSortIcons? | boolean | false | Toggle the visibility of the sort icons. | | maxWidth? | number | Infinity | Sets the maximum width of a column. | | minWidth? | number | 50 | Sets the minimum width of a column. | -| pastedValueParser? [](/x/introduction/licensing/#premium-plan) | (value: string, params: GridCellParams<R, V, F>) => V \| undefined | | Function that takes the clipboard-pasted value and converts it to a value used internally. | +| pastedValueParser? [](/x/introduction/licensing/#premium-plan) | GridPastedValueParser<R, V, F> | | Function that takes the clipboard-pasted value and converts it to a value used internally. | | pinnable? | boolean | true | If `false`, the menu items for column pinning menu will not be rendered.
Only available in DataGridPro. | | preProcessEditCellProps? | (params: GridPreProcessEditCellProps) => GridEditCellProps \| Promise<GridEditCellProps> | | Callback fired when the edit props of the cell changes.
It allows to process the props that saved into the state. | | renderCell? | (params: GridRenderCellParams<R, V, F>) => React.ReactNode | | Allows to override the component rendered as cell for this column. | @@ -61,8 +61,8 @@ import { GridColDef } from '@mui/x-data-grid'; | sortComparator? | GridComparatorFn<V> | | A comparator function used to sort rows. | | sortingOrder? | GridSortDirection[] | | The order of the sorting sequence. | | type? | GridColType | 'singleSelect' | The type of the column. | -| valueFormatter? | (params: GridValueFormatterParams<V>) => F | | Function that allows to apply a formatter before rendering its value. | -| valueGetter? | (params: GridValueGetterParams<R, any>) => V | | Function that allows to get a specific data instead of field to render in the cell. | -| valueParser? | (value: F \| undefined, params?: GridCellParams<R, V, F>) => V | | Function that takes the user-entered value and converts it to a value used internally. | -| valueSetter? | (params: GridValueSetterParams<R, V>) => R | | Function that allows to customize how the entered value is stored in the row.
It only works with cell/row editing. | +| valueFormatter? | GridValueFormatter<R, V, F> | | Function that allows to apply a formatter before rendering its value. | +| valueGetter? | GridValueGetter<R, V, F> | | Function that allows to get a specific data instead of field to render in the cell. | +| valueParser? | GridValueParser<R, V, F> | | Function that takes the user-entered value and converts it to a value used internally. | +| valueSetter? | GridValueSetter<R, V, F> | | Function that allows to customize how the entered value is stored in the row.
It only works with cell/row editing. | | width? | number | 100 | Set the width of the column. | diff --git a/docs/pages/x/api/data-grid/grid-single-select-col-def.md b/docs/pages/x/api/data-grid/grid-single-select-col-def.md index 4b3ce7f21236d..5a20d68d5cdba 100644 --- a/docs/pages/x/api/data-grid/grid-single-select-col-def.md +++ b/docs/pages/x/api/data-grid/grid-single-select-col-def.md @@ -29,7 +29,7 @@ import { GridSingleSelectColDef } from '@mui/x-data-grid'; | align? | GridAlignment | | Allows to align the column values in cells. | | availableAggregationFunctions? [](/x/introduction/licensing/#premium-plan) | string[] | | Limit the aggregation function usable on this column.
By default, the column will have all the aggregation functions that are compatible with its type. | | cellClassName? | GridCellClassNamePropType<R, V> | | Class name that will be added in cells for that column. | -| colSpan? | number \| ((params: GridCellParams<R, V, F>) => number \| undefined) | 1 | Number of columns a cell should span. | +| colSpan? | number \| GridColSpanFn<R, V, F> | 1 | Number of columns a cell should span. | | description? | string | | The description of the column rendered as tooltip if the column header name is not fully displayed. | | disableColumnMenu? | boolean | false | If `true`, the column menu is disabled for this column. | | disableExport? | boolean | false | If `true`, this column will not be included in exports. | @@ -43,7 +43,7 @@ import { GridSingleSelectColDef } from '@mui/x-data-grid'; | getOptionLabel? | (value: ValueOptions) => string | | Used to determine the label displayed for a given value option. | | getOptionValue? | (value: ValueOptions) => any | | Used to determine the value used for a value option. | | groupable? | boolean | true | If `true`, the rows can be grouped based on this column values (pro-plan only).
Only available in DataGridPremium. | -| groupingValueGetter? [](/x/introduction/licensing/#premium-plan) | (params: GridGroupingValueGetterParams<R, V>) => GridKeyValue \| null \| undefined | | Function that transforms a complex cell value into a key that be used for grouping the rows. | +| groupingValueGetter? [](/x/introduction/licensing/#premium-plan) | GridGroupingValueGetter<R> | | Function that transforms a complex cell value into a key that be used for grouping the rows. | | headerAlign? | GridAlignment | | Header cell element alignment. | | headerClassName? | GridColumnHeaderClassNamePropType | | Class name that will be added in the column header cell. | | headerName? | string | | The title of the column rendered in the column header cell. | @@ -51,7 +51,7 @@ import { GridSingleSelectColDef } from '@mui/x-data-grid'; | hideSortIcons? | boolean | false | Toggle the visibility of the sort icons. | | maxWidth? | number | Infinity | Sets the maximum width of a column. | | minWidth? | number | 50 | Sets the minimum width of a column. | -| pastedValueParser? [](/x/introduction/licensing/#premium-plan) | (value: string, params: GridCellParams<R, V, F>) => V \| undefined | | Function that takes the clipboard-pasted value and converts it to a value used internally. | +| pastedValueParser? [](/x/introduction/licensing/#premium-plan) | GridPastedValueParser<R, V, F> | | Function that takes the clipboard-pasted value and converts it to a value used internally. | | pinnable? | boolean | true | If `false`, the menu items for column pinning menu will not be rendered.
Only available in DataGridPro. | | preProcessEditCellProps? | (params: GridPreProcessEditCellProps) => GridEditCellProps \| Promise<GridEditCellProps> | | Callback fired when the edit props of the cell changes.
It allows to process the props that saved into the state. | | renderCell? | (params: GridRenderCellParams<R, V, F>) => React.ReactNode | | Allows to override the component rendered as cell for this column. | @@ -63,9 +63,9 @@ import { GridSingleSelectColDef } from '@mui/x-data-grid'; | sortComparator? | GridComparatorFn<V> | | A comparator function used to sort rows. | | sortingOrder? | GridSortDirection[] | | The order of the sorting sequence. | | type | 'singleSelect' | 'singleSelect' | The type of the column. | -| valueFormatter? | (params: GridValueFormatterParams<V>) => F | | Function that allows to apply a formatter before rendering its value. | -| valueGetter? | (params: GridValueGetterParams<R, any>) => V | | Function that allows to get a specific data instead of field to render in the cell. | +| valueFormatter? | GridValueFormatter<R, V, F> | | Function that allows to apply a formatter before rendering its value. | +| valueGetter? | GridValueGetter<R, V, F> | | Function that allows to get a specific data instead of field to render in the cell. | | valueOptions? | Array<ValueOptions> \| ((params: GridValueOptionsParams<R>) => Array<ValueOptions>) | | To be used in combination with `type: 'singleSelect'`. This is an array (or a function returning an array) of the possible cell values and labels. | -| valueParser? | (value: F \| undefined, params?: GridCellParams<R, V, F>) => V | | Function that takes the user-entered value and converts it to a value used internally. | -| valueSetter? | (params: GridValueSetterParams<R, V>) => R | | Function that allows to customize how the entered value is stored in the row.
It only works with cell/row editing. | +| valueParser? | GridValueParser<R, V, F> | | Function that takes the user-entered value and converts it to a value used internally. | +| valueSetter? | GridValueSetter<R, V, F> | | Function that allows to customize how the entered value is stored in the row.
It only works with cell/row editing. | | width? | number | 100 | Set the width of the column. | diff --git a/packages/grid/x-data-grid-generator/src/columns/commodities.columns.tsx b/packages/grid/x-data-grid-generator/src/columns/commodities.columns.tsx index b112b5b6ec4ef..60c9f269b87f1 100644 --- a/packages/grid/x-data-grid-generator/src/columns/commodities.columns.tsx +++ b/packages/grid/x-data-grid-generator/src/columns/commodities.columns.tsx @@ -148,7 +148,7 @@ export const getCommodityColumns = (editable = false): GridColDefGenerator[] => { field: 'subTotal', headerName: 'Sub Total', - valueGetter: ({ row }) => + valueGetter: (value, row) => row.quantity == null || row.unitPrice == null ? null : row.quantity * row.unitPrice, type: 'number', width: 120, @@ -165,7 +165,7 @@ export const getCommodityColumns = (editable = false): GridColDefGenerator[] => { field: 'feeAmount', headerName: 'Fee Amount', - valueGetter: ({ row }) => + valueGetter: (value, row) => row.feeRate == null || row.quantity == null || row.unitPrice == null ? null : row.feeRate * row.quantity * row.unitPrice, @@ -184,7 +184,7 @@ export const getCommodityColumns = (editable = false): GridColDefGenerator[] => { field: 'totalPrice', headerName: 'Total in USD', - valueGetter: ({ row }) => + valueGetter: (value, row) => row.feeRate == null || row.quantity == null || row.unitPrice == null ? null : row.feeRate + row.quantity * row.unitPrice, @@ -249,8 +249,8 @@ export const getCommodityColumns = (editable = false): GridColDefGenerator[] => return value; }, - valueFormatter: ({ value }) => value?.label, - groupingValueGetter: (params) => params.value.code, + valueFormatter: (value: { label: string }) => value?.label, + groupingValueGetter: (value: { code: string }) => value.code, sortComparator: (v1, v2, param1, param2) => gridStringOrNumberComparator(v1.label, v2.label, param1, param2), editable, diff --git a/packages/grid/x-data-grid-generator/src/columns/employees.columns.tsx b/packages/grid/x-data-grid-generator/src/columns/employees.columns.tsx index 016f30539f599..7a448ca9e0073 100644 --- a/packages/grid/x-data-grid-generator/src/columns/employees.columns.tsx +++ b/packages/grid/x-data-grid-generator/src/columns/employees.columns.tsx @@ -40,10 +40,8 @@ export const getEmployeeColumns = (): GridColDefGenerator[] => [ headerName: 'Avatar', generateData: randomColor, renderCell: renderAvatar, - valueGetter: (params) => - params.row.name == null || params.row.avatar == null - ? null - : { name: params.row.name, color: params.row.avatar }, + valueGetter: (value, row) => + row.name == null || row.avatar == null ? null : { name: row.name, color: row.avatar }, sortable: false, filterable: false, groupable: false, @@ -114,7 +112,7 @@ export const getEmployeeColumns = (): GridColDefGenerator[] => [ headerName: 'Country', type: 'singleSelect', valueOptions: COUNTRY_ISO_OPTIONS_SORTED, - valueFormatter: ({ value }) => value?.label, + valueFormatter: (value: CountryIsoOption) => value?.label, generateData: randomCountry, renderCell: renderCountry, renderEditCell: renderEditCountry, @@ -166,7 +164,7 @@ export const getEmployeeColumns = (): GridColDefGenerator[] => [ headerName: 'Salary', generateData: () => randomInt(30000, 80000), type: 'number', - valueFormatter: ({ value }) => { + valueFormatter: (value?: number) => { if (!value || typeof value !== 'number') { return value; } diff --git a/packages/grid/x-data-grid-generator/src/hooks/useMovieData.ts b/packages/grid/x-data-grid-generator/src/hooks/useMovieData.ts index ba7d8e88aba0a..5ed7504920302 100644 --- a/packages/grid/x-data-grid-generator/src/hooks/useMovieData.ts +++ b/packages/grid/x-data-grid-generator/src/hooks/useMovieData.ts @@ -28,7 +28,7 @@ const COLUMNS: GridColDef[] = [ type: 'number', width: 150, groupable: false, - valueFormatter: ({ value }) => { + valueFormatter: (value) => { if (!value) { return ''; } diff --git a/packages/grid/x-data-grid-generator/src/hooks/useQuery.ts b/packages/grid/x-data-grid-generator/src/hooks/useQuery.ts index d864e2601a826..c888d14faa0e6 100644 --- a/packages/grid/x-data-grid-generator/src/hooks/useQuery.ts +++ b/packages/grid/x-data-grid-generator/src/hooks/useQuery.ts @@ -18,10 +18,10 @@ import { } from './useDemoData'; import { randomInt } from '../services/random-generator'; +const apiRef = {} as any; + const simplifiedValueGetter = (field: string, colDef: GridColDef) => (row: GridRowModel) => { - const params = { id: row.id, row, field, rowNode: {} }; - // @ts-ignore - return colDef.valueGetter?.(params) || row[field]; + return colDef.valueGetter?.(row[row.id] as never, row, colDef, apiRef) || row[field]; }; const getRowComparator = ( diff --git a/packages/grid/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx b/packages/grid/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx index 706c5f66d1dee..c1d5bf49973a6 100644 --- a/packages/grid/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx +++ b/packages/grid/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx @@ -147,7 +147,7 @@ export const useDataGridPremiumComponent = ( useGridRowPinning(apiRef, props); useGridColumns(apiRef, props); useGridRows(apiRef, props); - useGridParamsApi(apiRef, props); + useGridParamsApi(apiRef); useGridDetailPanel(apiRef, props); useGridColumnSpanning(apiRef); useGridColumnGrouping(apiRef, props); diff --git a/packages/grid/x-data-grid-premium/src/hooks/features/aggregation/wrapColumnWithAggregation.tsx b/packages/grid/x-data-grid-premium/src/hooks/features/aggregation/wrapColumnWithAggregation.tsx index 680a2d723a527..b7030fb5b9c08 100644 --- a/packages/grid/x-data-grid-premium/src/hooks/features/aggregation/wrapColumnWithAggregation.tsx +++ b/packages/grid/x-data-grid-premium/src/hooks/features/aggregation/wrapColumnWithAggregation.tsx @@ -45,17 +45,18 @@ const getAggregationValueWrappedValueGetter: ColumnPropertyWrapper<'valueGetter' value: valueGetter, getCellAggregationResult, }) => { - const wrappedValueGetter: GridBaseColDef['valueGetter'] = (params) => { - const cellAggregationResult = getCellAggregationResult(params.id, params.field); + const wrappedValueGetter: GridBaseColDef['valueGetter'] = (value, row, column, apiRef) => { + const rowId = apiRef.current.getRowId(row); + const cellAggregationResult = getCellAggregationResult(rowId, column.field); if (cellAggregationResult != null) { return cellAggregationResult?.value ?? null; } if (valueGetter) { - return valueGetter(params); + return valueGetter(value, row, column, apiRef); } - return params.row[params.field]; + return row[column.field]; }; return wrappedValueGetter; @@ -72,19 +73,25 @@ const getAggregationValueWrappedValueFormatter: ColumnPropertyWrapper<'valueForm return valueFormatter; } - const wrappedValueFormatter: GridBaseColDef['valueFormatter'] = (params) => { - if (params.id != null) { - const cellAggregationResult = getCellAggregationResult(params.id, params.field); + const wrappedValueFormatter: GridBaseColDef['valueFormatter'] = (value, row, column, apiRef) => { + const rowId = apiRef.current.getRowId(row); + if (rowId != null) { + const cellAggregationResult = getCellAggregationResult(rowId, column.field); if (cellAggregationResult != null) { - return aggregationRule.aggregationFunction.valueFormatter!(params); + return aggregationRule.aggregationFunction.valueFormatter?.({ + id: rowId, + field: column.field, + value, + api: apiRef.current, + }); } } if (valueFormatter) { - return valueFormatter(params); + return valueFormatter(value, row, column, apiRef); } - return params.value; + return value; }; return wrappedValueFormatter; diff --git a/packages/grid/x-data-grid-premium/src/hooks/features/clipboard/useGridClipboardImport.ts b/packages/grid/x-data-grid-premium/src/hooks/features/clipboard/useGridClipboardImport.ts index 13a5609086533..d42de85dd864f 100644 --- a/packages/grid/x-data-grid-premium/src/hooks/features/clipboard/useGridClipboardImport.ts +++ b/packages/grid/x-data-grid-premium/src/hooks/features/clipboard/useGridClipboardImport.ts @@ -130,14 +130,12 @@ class CellValueUpdater { return; } - const cellParams = apiRef.current.getCellParams(rowId, field); - let parsedValue = pastedCellValue; if (colDef.pastedValueParser) { - parsedValue = colDef.pastedValueParser(pastedCellValue, cellParams); + parsedValue = colDef.pastedValueParser(pastedCellValue, row, colDef, apiRef); } else if (colDef.valueParser) { - parsedValue = colDef.valueParser(parsedValue, cellParams); + parsedValue = colDef.valueParser(parsedValue, row, colDef, apiRef); } if (parsedValue === undefined) { @@ -146,7 +144,7 @@ class CellValueUpdater { let rowCopy = { ...row }; if (typeof colDef.valueSetter === 'function') { - rowCopy = colDef.valueSetter({ value: parsedValue, row: rowCopy }); + rowCopy = colDef.valueSetter(parsedValue, rowCopy, colDef, apiRef); } else { rowCopy[field] = parsedValue; } diff --git a/packages/grid/x-data-grid-premium/src/hooks/features/export/serializer/excelSerializer.ts b/packages/grid/x-data-grid-premium/src/hooks/features/export/serializer/excelSerializer.ts index 2cda4e8eedd7d..ba4439cc4da9f 100644 --- a/packages/grid/x-data-grid-premium/src/hooks/features/export/serializer/excelSerializer.ts +++ b/packages/grid/x-data-grid-premium/src/hooks/features/export/serializer/excelSerializer.ts @@ -2,11 +2,11 @@ import type * as Excel from 'exceljs'; import { GridRowId, GridColDef, - GridValueFormatterParams, GridApi, ValueOptions, GRID_DATE_COL_DEF, GRID_DATETIME_COL_DEF, + GridValidRowModel, } from '@mui/x-data-grid-pro'; import { buildWarning, @@ -35,6 +35,7 @@ const warnInvalidFormattedValue = buildWarning([ const getFormattedValueOptions = ( colDef: GridSingleSelectColDef, + row: GridValidRowModel, valueOptions: ValueOptions[], api: GridApi, ) => { @@ -49,8 +50,7 @@ const getFormattedValueOptions = ( return option; } - const params: GridValueFormatterParams = { field: colDef.field, api, value: option }; - return String(colDef.valueFormatter!(params)); + return String(colDef.valueFormatter!(option as never, row, colDef, { current: api })); }); } return valueOptionsFormatted.map((option) => @@ -111,7 +111,12 @@ export const serializeRow = ( row, field: cellParams.field, }); - const formattedValueOptions = getFormattedValueOptions(castColumn, valueOptions, api); + const formattedValueOptions = getFormattedValueOptions( + castColumn, + row, + valueOptions, + api, + ); dataValidation[castColumn.field] = { type: 'list', allowBlank: true, @@ -304,6 +309,7 @@ export async function getDataForValueOptionsSheet( const singleSelectColumn = column as GridSingleSelectColDef; const formattedValueOptions = getFormattedValueOptions( singleSelectColumn, + {}, singleSelectColumn.valueOptions as Array, api, ); diff --git a/packages/grid/x-data-grid-premium/src/hooks/features/rowGrouping/createGroupingColDef.tsx b/packages/grid/x-data-grid-premium/src/hooks/features/rowGrouping/createGroupingColDef.tsx index e15c252b29fcb..fd0573c80f842 100644 --- a/packages/grid/x-data-grid-premium/src/hooks/features/rowGrouping/createGroupingColDef.tsx +++ b/packages/grid/x-data-grid-premium/src/hooks/features/rowGrouping/createGroupingColDef.tsx @@ -6,6 +6,7 @@ import { GridRenderCellParams, GridGroupingColDefOverride, GridGroupNode, + GridTreeNodeWithRender, } from '@mui/x-data-grid-pro'; import { GridColumnRawLookup, isSingleSelectColDef } from '@mui/x-data-grid-pro/internals'; import { GridApiPremium } from '../../../models/gridApiPremium'; @@ -178,25 +179,23 @@ export const createGroupingColDefForOneGroupingCriteria = ({ return ''; }, - valueGetter: (params) => { - if ( - !params.rowNode || - params.rowNode.type === 'footer' || - params.rowNode.type === 'pinnedRow' - ) { + valueGetter: (value, row, column, apiRef) => { + const rowId = apiRef.current.getRowId(row); + const rowNode = apiRef.current.getRowNode(rowId); + if (!rowNode || rowNode.type === 'footer' || rowNode.type === 'pinnedRow') { return undefined; } - if (params.rowNode.type === 'leaf') { + if (rowNode.type === 'leaf') { if (leafColDef) { - return params.api.getCellValue(params.id, leafField!); + return apiRef.current.getCellValue(rowId, leafField!); } return undefined; } - if (params.rowNode.groupingField === groupingCriteria) { - return params.rowNode.groupingKey; + if (rowNode.groupingField === groupingCriteria) { + return rowNode.groupingKey; } return undefined; @@ -305,24 +304,22 @@ export const createGroupingColDefForAllGroupingCriteria = ({ /> ); }, - valueGetter: (params) => { - if ( - !params.rowNode || - params.rowNode.type === 'footer' || - params.rowNode.type === 'pinnedRow' - ) { + valueGetter: (value, row) => { + const rowId = apiRef.current.getRowId(row); + const rowNode = apiRef.current.getRowNode(rowId); + if (!rowNode || rowNode.type === 'footer' || rowNode.type === 'pinnedRow') { return undefined; } - if (params.rowNode.type === 'leaf') { + if (rowNode.type === 'leaf') { if (leafColDef) { - return params.api.getCellValue(params.id, leafField!); + return apiRef.current.getCellValue(rowId, leafField!); } return undefined; } - return params.rowNode.groupingKey; + return rowNode.groupingKey; }, }; diff --git a/packages/grid/x-data-grid-premium/src/hooks/features/rowGrouping/gridRowGroupingUtils.ts b/packages/grid/x-data-grid-premium/src/hooks/features/rowGrouping/gridRowGroupingUtils.ts index 64ca76ee5e549..361c76b069c51 100644 --- a/packages/grid/x-data-grid-premium/src/hooks/features/rowGrouping/gridRowGroupingUtils.ts +++ b/packages/grid/x-data-grid-premium/src/hooks/features/rowGrouping/gridRowGroupingUtils.ts @@ -17,7 +17,6 @@ import { GridColumnRawLookup, } from '@mui/x-data-grid-pro/internals'; import { DataGridPremiumProcessedProps } from '../../../models/dataGridPremiumProps'; -import { GridGroupingValueGetterParams } from '../../../models/gridGroupingValueGetterParams'; import { GridGroupingRule, GridGroupingRules, @@ -209,29 +208,18 @@ export const setStrategyAvailability = ( export const getCellGroupingCriteria = ({ row, - id, colDef, groupingRule, + apiRef, }: { row: GridRowModel; - id: GridRowId; colDef: GridColDef; groupingRule: GridGroupingRule; + apiRef: React.MutableRefObject; }) => { let key: GridKeyValue | null | undefined; if (groupingRule.groupingValueGetter) { - const groupingValueGetterParams: GridGroupingValueGetterParams = { - colDef, - field: groupingRule.field, - value: row[groupingRule.field], - id, - row, - rowNode: { - isAutoGenerated: false, - id, - }, - }; - key = groupingRule.groupingValueGetter(groupingValueGetterParams); + key = groupingRule.groupingValueGetter(row[groupingRule.field] as never, row, colDef, apiRef); } else { key = row[groupingRule.field] as GridKeyValue | null | undefined; } diff --git a/packages/grid/x-data-grid-premium/src/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.ts b/packages/grid/x-data-grid-premium/src/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.ts index f134c040d14e9..2fa403ec72d5e 100644 --- a/packages/grid/x-data-grid-premium/src/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.ts +++ b/packages/grid/x-data-grid-premium/src/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.ts @@ -153,9 +153,9 @@ export const useGridRowGroupingPreProcessors = ( .map((groupingRule) => getCellGroupingCriteria({ row, - id: rowId, groupingRule, colDef: columnsLookup[groupingRule.field], + apiRef, }), ) .filter((cell) => cell.key != null) as RowTreeBuilderGroupingCriterion[]; diff --git a/packages/grid/x-data-grid-premium/src/models/gridGroupingValueGetter.ts b/packages/grid/x-data-grid-premium/src/models/gridGroupingValueGetter.ts new file mode 100644 index 0000000000000..aaa20b7f73a13 --- /dev/null +++ b/packages/grid/x-data-grid-premium/src/models/gridGroupingValueGetter.ts @@ -0,0 +1,12 @@ +import { GridValidRowModel, GridColDef, GridKeyValue } from '@mui/x-data-grid-pro'; +import { GridApiPremium } from './gridApiPremium'; + +export type GridGroupingValueGetter< + R extends GridValidRowModel = GridValidRowModel, + TValue = never, +> = ( + value: TValue, + row: R, + column: GridColDef, + apiRef: React.MutableRefObject, +) => GridKeyValue | null | undefined; diff --git a/packages/grid/x-data-grid-premium/src/models/gridGroupingValueGetterParams.ts b/packages/grid/x-data-grid-premium/src/models/gridGroupingValueGetterParams.ts deleted file mode 100644 index 38ffa2e91df85..0000000000000 --- a/packages/grid/x-data-grid-premium/src/models/gridGroupingValueGetterParams.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { - GridRowId, - GridRowModel, - GridValidRowModel, - GridGroupNode, - GridColDef, -} from '@mui/x-data-grid-pro'; - -/** - * Parameters passed to `colDef.groupingValueGetter`. - */ -export interface GridGroupingValueGetterParams { - /** - * The grid row id. - */ - id: GridRowId; - /** - * The column field of the cell that triggered the event. - */ - field: string; - /** - * The cell value, does not take `valueGetter` into account. - */ - value: V; - /** - * The row model of the row that the current cell belongs to. - */ - row: GridRowModel; - /** - * The column of the row that the current cell belongs to. - */ - colDef: GridColDef; - /** - * The node of the row that the current cell belongs to. - * It only contains the information available before the actual grouping. - */ - rowNode: Pick; -} diff --git a/packages/grid/x-data-grid-premium/src/models/gridPastedValueParser.ts b/packages/grid/x-data-grid-premium/src/models/gridPastedValueParser.ts new file mode 100644 index 0000000000000..e20efa8a0c530 --- /dev/null +++ b/packages/grid/x-data-grid-premium/src/models/gridPastedValueParser.ts @@ -0,0 +1,13 @@ +import { GridColDef, GridValidRowModel } from '@mui/x-data-grid'; +import { GridApiPremium } from './gridApiPremium'; + +export type GridPastedValueParser< + R extends GridValidRowModel = GridValidRowModel, + V = any, + F = V, +> = ( + value: string, + row: R, + column: GridColDef, + apiRef: React.MutableRefObject, +) => V | undefined; diff --git a/packages/grid/x-data-grid-premium/src/models/index.ts b/packages/grid/x-data-grid-premium/src/models/index.ts index 03a21344b06bb..790f91cf4f468 100644 --- a/packages/grid/x-data-grid-premium/src/models/index.ts +++ b/packages/grid/x-data-grid-premium/src/models/index.ts @@ -1,3 +1,4 @@ -export * from './gridGroupingValueGetterParams'; +export * from './gridGroupingValueGetter'; export * from './gridPremiumIconSlotsComponent'; export * from './gridPremiumSlotsComponent'; +export * from './gridPastedValueParser'; diff --git a/packages/grid/x-data-grid-premium/src/tests/DataGridPremium.spec.tsx b/packages/grid/x-data-grid-premium/src/tests/DataGridPremium.spec.tsx index e7c53357b2e83..8f76012552efb 100644 --- a/packages/grid/x-data-grid-premium/src/tests/DataGridPremium.spec.tsx +++ b/packages/grid/x-data-grid-premium/src/tests/DataGridPremium.spec.tsx @@ -11,7 +11,7 @@ function ColumnPropTest() { { field: 'firstName', // @ts-expect-error - groupingValueGetter: (params) => params.row.lastName, + groupingValueGetter: (value, row) => row.lastName, }, ]} /> @@ -21,7 +21,7 @@ function ColumnPropTest() { columns={[ { field: 'firstName', - groupingValueGetter: (params) => params.row.firstName, + groupingValueGetter: (value, row) => row.firstName, }, ]} /> @@ -32,7 +32,7 @@ function ColumnPropTest() { { field: 'firstName', // @ts-expect-error - groupingValueGetter: (params) => params.row.lastName, + groupingValueGetter: (value, row) => row.lastName, }, ]} /> @@ -42,7 +42,7 @@ function ColumnPropTest() { columns={[ { field: 'firstName', - groupingValueGetter: (params) => params.row.firstName, + groupingValueGetter: (value, row) => row.firstName, }, ]} /> diff --git a/packages/grid/x-data-grid-premium/src/tests/aggregation.DataGridPremium.test.tsx b/packages/grid/x-data-grid-premium/src/tests/aggregation.DataGridPremium.test.tsx index 19bebd3b4e57b..a950d6f5d3824 100644 --- a/packages/grid/x-data-grid-premium/src/tests/aggregation.DataGridPremium.test.tsx +++ b/packages/grid/x-data-grid-premium/src/tests/aggregation.DataGridPremium.test.tsx @@ -130,7 +130,7 @@ describe(' - Aggregation', () => { { field: 'idBis', type: 'number', - valueGetter: (params) => params.row.id, + valueGetter: (valuem, row) => row.id, aggregable: false, }, ]} @@ -622,7 +622,7 @@ describe(' - Aggregation', () => { { field: 'id', type: 'number', - valueFormatter: (params) => `- ${params.value}`, + valueFormatter: (value) => `- ${value}`, }, ]} />, @@ -652,7 +652,7 @@ describe(' - Aggregation', () => { { field: 'id', type: 'number', - valueFormatter: (params) => `- ${params.value}`, + valueFormatter: (value) => `- ${value}`, }, ]} />, diff --git a/packages/grid/x-data-grid-premium/src/tests/clipboard.DataGridPremium.test.tsx b/packages/grid/x-data-grid-premium/src/tests/clipboard.DataGridPremium.test.tsx index ccf2a87d78f2f..a1aa7d15b88a6 100644 --- a/packages/grid/x-data-grid-premium/src/tests/clipboard.DataGridPremium.test.tsx +++ b/packages/grid/x-data-grid-premium/src/tests/clipboard.DataGridPremium.test.tsx @@ -471,17 +471,17 @@ describe(' - Clipboard', () => { it('should use valueSetter if the column has one', async () => { const processRowUpdateSpy = spy((newRow) => newRow); - const columns: GridColDef[] = [ + const columns: GridColDef<(typeof rows)[number]>[] = [ { field: 'firstName' }, { field: 'lastName' }, { field: 'fullName', - valueGetter: (params) => { - return `${params.row.firstName} ${params.row.lastName}`; + valueGetter: (value, row) => { + return `${row.firstName} ${row.lastName}`; }, - valueSetter: (params) => { - const [firstName, lastName] = params.value!.toString().split(' '); - return { ...params.row, firstName, lastName }; + valueSetter: (value, row) => { + const [firstName, lastName] = value!.toString().split(' '); + return { ...row, firstName, lastName }; }, editable: true, }, @@ -985,10 +985,10 @@ describe(' - Clipboard', () => { field: 'size', type: 'singleSelect', valueOptions: sizes, - valueGetter: (params) => params.value.size, - valueSetter: (params) => { - const value = sizes.find((option) => option.size === params.value); - return { ...params.row, size: value }; + valueGetter: (value: { size: number }) => value.size, + valueSetter: (value: string, row) => { + const size = sizes.find((option) => option.size === value); + return { ...row, size }; }, getOptionValue: (option: any) => option.size, getOptionLabel: (option: any) => option.size, diff --git a/packages/grid/x-data-grid-premium/src/tests/rowGrouping.DataGridPremium.test.tsx b/packages/grid/x-data-grid-premium/src/tests/rowGrouping.DataGridPremium.test.tsx index 854f9d3636138..1a9740d208265 100644 --- a/packages/grid/x-data-grid-premium/src/tests/rowGrouping.DataGridPremium.test.tsx +++ b/packages/grid/x-data-grid-premium/src/tests/rowGrouping.DataGridPremium.test.tsx @@ -22,7 +22,6 @@ import { getRowGroupingFieldFromGroupingCriteria, GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, GridApi, - GridGroupingValueGetterParams, GridPreferencePanelsValue, GridRowsProp, useGridApiRef, @@ -785,12 +784,12 @@ describe(' - Row grouping', () => { { field: 'id', type: 'number', - valueFormatter: (params) => { - if (params.value == null) { + valueFormatter: (value) => { + if (value == null) { return null; } - return `#${params.value}`; + return `#${value}`; }, }, { @@ -923,8 +922,9 @@ describe(' - Row grouping', () => { initialState={{ rowGrouping: { model: ['category1', 'category2'] } }} defaultGroupingExpansionDepth={1} groupingColDef={{ - valueFormatter: (params) => { - const node = apiRef.current.getRowNode(params.id!)!; + valueFormatter: (value, row) => { + const rowId = apiRef.current.getRowId(row); + const node = apiRef.current.getRowNode(rowId)!; if (node.type !== 'group') { return ''; } @@ -951,8 +951,9 @@ describe(' - Row grouping', () => { initialState={{ rowGrouping: { model: ['category1', 'category2'] } }} defaultGroupingExpansionDepth={1} groupingColDef={() => ({ - valueFormatter: (params) => { - const node = apiRef.current.getRowNode(params.id!)!; + valueFormatter: (value, row) => { + const rowId = apiRef.current.getRowId(row); + const node = apiRef.current.getRowNode(rowId)!; if (node.type !== 'group') { return ''; } @@ -1168,12 +1169,12 @@ describe(' - Row grouping', () => { { field: 'id', type: 'number', - valueFormatter: (params) => { - if (params.value == null) { + valueFormatter: (value) => { + if (value == null) { return null; } - return `#${params.value}`; + return `#${value}`; }, }, { @@ -1338,8 +1339,9 @@ describe(' - Row grouping', () => { rowGroupingColumnMode="multiple" defaultGroupingExpansionDepth={1} groupingColDef={{ - valueFormatter: (params) => { - const node = apiRef.current.getRowNode(params.id!)!; + valueFormatter: (value, row) => { + const rowId = apiRef.current.getRowId(row); + const node = apiRef.current.getRowNode(rowId)!; if (node.type !== 'group') { return ''; } @@ -1380,8 +1382,9 @@ describe(' - Row grouping', () => { } return { - valueFormatter: (params) => { - const node = apiRef.current.getRowNode(params.id!)!; + valueFormatter: (value, row) => { + const rowId = apiRef.current.getRowId(row); + const node = apiRef.current.getRowNode(rowId)!; if (node.type !== 'group') { return ''; } @@ -1503,7 +1506,7 @@ describe(' - Row grouping', () => { }, { field: 'category1', - groupingValueGetter: (params) => `groupingValue ${params.value}`, + groupingValueGetter: (value) => `groupingValue ${value}`, }, ]} initialState={{ rowGrouping: { model: ['category1'] } }} @@ -1531,7 +1534,7 @@ describe(' - Row grouping', () => { }, { field: 'modulo', - groupingValueGetter: (params) => params.row.id % 2, + groupingValueGetter: (value, row) => row.id % 2, }, ]} initialState={{ rowGrouping: { model: ['modulo'] } }} @@ -1545,7 +1548,7 @@ describe(' - Row grouping', () => { apiRef.current.updateColumns([ { field: 'modulo', - groupingValueGetter: (params) => params.row.id % 3, + groupingValueGetter: (value, row) => row.id % 3, }, ]), ); @@ -1563,7 +1566,7 @@ describe(' - Row grouping', () => { }, { field: 'category1', - valueGetter: (params) => `value ${params.row.category1}`, + valueGetter: (value, row) => `value ${row.category1}`, }, ]} initialState={{ rowGrouping: { model: ['category1'] } }} @@ -1586,9 +1589,9 @@ describe(' - Row grouping', () => { }, { field: 'category1', - valueGetter: (params) => `value ${params.row.category1}`, - groupingValueGetter: (params: GridGroupingValueGetterParams) => - `groupingValue ${params.row.category1}`, + valueGetter: (value, row) => `value ${row.category1}`, + groupingValueGetter: (value, row: { category1: string }) => + `groupingValue ${row.category1}`, }, ]} defaultGroupingExpansionDepth={-1} diff --git a/packages/grid/x-data-grid-premium/src/typeOverloads/modules.ts b/packages/grid/x-data-grid-premium/src/typeOverloads/modules.ts index 91b926ee9d793..c71fd5b99bc36 100644 --- a/packages/grid/x-data-grid-premium/src/typeOverloads/modules.ts +++ b/packages/grid/x-data-grid-premium/src/typeOverloads/modules.ts @@ -1,10 +1,10 @@ -import { GridCellParams, GridKeyValue, GridValidRowModel } from '@mui/x-data-grid-pro'; +import { GridValidRowModel } from '@mui/x-data-grid-pro'; import type { GridControlledStateEventLookupPro, GridApiCachesPro, GridEventLookupPro, } from '@mui/x-data-grid-pro/typeOverloads'; -import type { GridGroupingValueGetterParams } from '../models'; +import type { GridGroupingValueGetter, GridPastedValueParser } from '../models'; import type { GridRowGroupingModel, GridAggregationModel, @@ -58,19 +58,14 @@ export interface GridColDefPremium, - ) => GridKeyValue | null | undefined; + groupingValueGetter?: GridGroupingValueGetter; /** * Function that takes the clipboard-pasted value and converts it to a value used internally. - * @param {string} value The pasted value. - * @param {GridCellParams} params The cell params. * @returns {V} The converted value. */ - pastedValueParser?: (value: string, params: GridCellParams) => V | undefined; + pastedValueParser?: GridPastedValueParser; } // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/packages/grid/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx b/packages/grid/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx index 933153b306c11..b89f14923492f 100644 --- a/packages/grid/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx +++ b/packages/grid/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx @@ -133,7 +133,7 @@ export const useDataGridProComponent = ( useGridRowPinning(apiRef, props); useGridColumns(apiRef, props); useGridRows(apiRef, props); - useGridParamsApi(apiRef, props); + useGridParamsApi(apiRef); useGridDetailPanel(apiRef, props); useGridColumnSpanning(apiRef); useGridColumnGrouping(apiRef, props); diff --git a/packages/grid/x-data-grid-pro/src/hooks/features/detailPanel/gridDetailPanelToggleColDef.tsx b/packages/grid/x-data-grid-pro/src/hooks/features/detailPanel/gridDetailPanelToggleColDef.tsx index cd93bc204161e..ce3a18b882aa1 100644 --- a/packages/grid/x-data-grid-pro/src/hooks/features/detailPanel/gridDetailPanelToggleColDef.tsx +++ b/packages/grid/x-data-grid-pro/src/hooks/features/detailPanel/gridDetailPanelToggleColDef.tsx @@ -21,9 +21,12 @@ export const GRID_DETAIL_PANEL_TOGGLE_COL_DEF: GridColDef = { disableExport: true, align: 'left', width: 40, - valueGetter: (params) => { - const expandedRowIds = gridDetailPanelExpandedRowIdsSelector((params.api as GridApiPro).state); - return expandedRowIds.includes(params.id); + valueGetter: (value, row, column, apiRef) => { + const rowId = apiRef.current.getRowId(row); + const expandedRowIds = gridDetailPanelExpandedRowIdsSelector( + (apiRef.current as GridApiPro).state, + ); + return expandedRowIds.includes(rowId); }, renderCell: (params) => , renderHeader: () => null, diff --git a/packages/grid/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataGroupColDef.ts b/packages/grid/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataGroupColDef.ts index b7b20847e4557..4fe1addd677f4 100644 --- a/packages/grid/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataGroupColDef.ts +++ b/packages/grid/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataGroupColDef.ts @@ -12,10 +12,11 @@ export const GRID_TREE_DATA_GROUPING_COL_DEF: Omit - params.rowNode.type === 'group' || params.rowNode.type === 'leaf' - ? params.rowNode.groupingKey - : undefined, + valueGetter: (value, row, column, apiRef) => { + const rowId = apiRef.current.getRowId(row); + const rowNode = apiRef.current.getRowNode(rowId); + return rowNode?.type === 'group' || rowNode?.type === 'leaf' ? rowNode.groupingKey : undefined; + }, }; export const GRID_TREE_DATA_GROUPING_FIELD = '__tree_data_group__'; diff --git a/packages/grid/x-data-grid-pro/src/tests/DataGridPro.spec.tsx b/packages/grid/x-data-grid-pro/src/tests/DataGridPro.spec.tsx index 23cf358dbb1a5..381641537a0e1 100644 --- a/packages/grid/x-data-grid-pro/src/tests/DataGridPro.spec.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/DataGridPro.spec.tsx @@ -15,7 +15,7 @@ function ColumnPropTest() { { field: 'firstName', // @ts-expect-error - valueGetter: (params) => params.row.lastName, + valueGetter: (value, row) => row.lastName, }, ]} /> @@ -25,7 +25,7 @@ function ColumnPropTest() { columns={[ { field: 'firstName', - valueGetter: (params) => params.row.firstName, + valueGetter: (value, row) => row.firstName, }, ]} /> @@ -36,7 +36,7 @@ function ColumnPropTest() { { field: 'firstName', // @ts-expect-error - valueGetter: (params) => params.row.lastName, + valueGetter: (value, row) => row.lastName, }, ]} /> @@ -46,7 +46,7 @@ function ColumnPropTest() { columns={[ { field: 'firstName', - valueGetter: (params) => params.row.firstName, + valueGetter: (value, row) => row.firstName, }, ]} /> diff --git a/packages/grid/x-data-grid-pro/src/tests/cellEditing.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/cellEditing.DataGridPro.test.tsx index f601a5473bcce..d8f8c1505cd95 100644 --- a/packages/grid/x-data-grid-pro/src/tests/cellEditing.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/cellEditing.DataGridPro.test.tsx @@ -7,7 +7,7 @@ import { useGridApiRef, DataGridPro, GridRenderEditCellParams, - GridValueSetterParams, + GridValueSetter, GridPreProcessEditCellProps, GridCellProps, GridCellModes, @@ -107,10 +107,11 @@ describe(' - Cell editing', () => { }); it('should pass to renderEditCell the row with the value updated', async () => { - columnProps.valueSetter = ({ value, row }: GridValueSetterParams) => ({ + const valueSetter: GridValueSetter = (value: string, row) => ({ ...row, currencyPair: value.trim(), }); + columnProps.valueSetter = valueSetter; render(); act(() => apiRef.current.startCellEditMode({ id: 0, field: 'currencyPair' })); expect(renderEditCell.lastCall.args[0].row).to.deep.equal(defaultData.rows[0]); @@ -551,7 +552,10 @@ describe(' - Cell editing', () => { }); it('should pass the new value through the value setter before calling processRowUpdate', async () => { - columnProps.valueSetter = spy(({ value, row }) => ({ ...row, _currencyPair: value })); + columnProps.valueSetter = spy((value, row) => ({ + ...row, + _currencyPair: value, + })); const processRowUpdate = spy(() => new Promise(() => {})); render(); act(() => apiRef.current.startCellEditMode({ id: 0, field: 'currencyPair' })); @@ -564,10 +568,8 @@ describe(' - Cell editing', () => { currencyPair: 'USDGBP', _currencyPair: 'USD GBP', }); - expect(columnProps.valueSetter.lastCall.args[0]).to.deep.equal({ - value: 'USD GBP', - row: defaultData.rows[0], - }); + expect(columnProps.valueSetter.lastCall.args[0]).to.equal('USD GBP'); + expect(columnProps.valueSetter.lastCall.args[1]).to.deep.equal(defaultData.rows[0]); }); it('should move focus to the cell below when cellToFocusAfter=below', async () => { diff --git a/packages/grid/x-data-grid-pro/src/tests/columnSpanning.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/columnSpanning.DataGridPro.test.tsx index 06391336b3c80..ea6a2ad592826 100644 --- a/packages/grid/x-data-grid-pro/src/tests/columnSpanning.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/columnSpanning.DataGridPro.test.tsx @@ -79,9 +79,9 @@ describe(' - Column spanning', () => { describe('key navigation', () => { const columns: GridColDef[] = [ - { field: 'brand', colSpan: ({ row }) => (row.brand === 'Nike' ? 2 : 1) }, - { field: 'category', colSpan: ({ row }) => (row.brand === 'Adidas' ? 2 : 1) }, - { field: 'price', colSpan: ({ row }) => (row.brand === 'Puma' ? 2 : 1) }, + { field: 'brand', colSpan: (value, row) => (row.brand === 'Nike' ? 2 : 1) }, + { field: 'category', colSpan: (value, row) => (row.brand === 'Adidas' ? 2 : 1) }, + { field: 'price', colSpan: (value, row) => (row.brand === 'Puma' ? 2 : 1) }, { field: 'rating' }, ]; @@ -120,9 +120,9 @@ describe(' - Column spanning', () => { apiRef={apiRef} {...baselineProps} columns={[ - { field: 'brand', colSpan: ({ row }) => (row.brand === 'Nike' ? 2 : 1) }, - { field: 'category', colSpan: ({ row }) => (row.brand === 'Adidas' ? 2 : 1) }, - { field: 'price', colSpan: ({ row }) => (row.brand === 'Puma' ? 2 : 1) }, + { field: 'brand', colSpan: (value, row) => (row.brand === 'Nike' ? 2 : 1) }, + { field: 'category', colSpan: (value, row) => (row.brand === 'Adidas' ? 2 : 1) }, + { field: 'price', colSpan: (value, row) => (row.brand === 'Puma' ? 2 : 1) }, { field: 'rating' }, ]} disableVirtualization={isJSDOM} @@ -184,9 +184,9 @@ describe(' - Column spanning', () => { it('should apply `colSpan` correctly on GridApiRef setRows', () => { const columns: GridColDef[] = [ - { field: 'brand', colSpan: ({ row }) => (row.brand === 'Nike' ? 2 : 1) }, - { field: 'category', colSpan: ({ row }) => (row.brand === 'Adidas' ? 2 : 1) }, - { field: 'price', colSpan: ({ row }) => (row.brand === 'Puma' ? 2 : 1) }, + { field: 'brand', colSpan: (value, row) => (row.brand === 'Nike' ? 2 : 1) }, + { field: 'category', colSpan: (value, row) => (row.brand === 'Adidas' ? 2 : 1) }, + { field: 'price', colSpan: (value, row) => (row.brand === 'Puma' ? 2 : 1) }, { field: 'rating' }, ]; diff --git a/packages/grid/x-data-grid-pro/src/tests/events.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/events.DataGridPro.test.tsx index f596ed6ad2a16..62f2fde968c28 100644 --- a/packages/grid/x-data-grid-pro/src/tests/events.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/events.DataGridPro.test.tsx @@ -47,8 +47,8 @@ describe(' - Events params', () => { { field: 'age' }, { field: 'firstAge', - valueGetter: (params) => `${params.row.first}_${params.row.age}`, - valueFormatter: (params) => `${params.value} yrs`, + valueGetter: (value, row) => `${row.first}_${row.age}`, + valueFormatter: (value) => `${value} yrs`, }, ], }; diff --git a/packages/grid/x-data-grid-pro/src/tests/export.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/export.DataGridPro.test.tsx index 22ecc4d010f9b..a9868210ced84 100644 --- a/packages/grid/x-data-grid-pro/src/tests/export.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/export.DataGridPro.test.tsx @@ -112,7 +112,7 @@ describe(' - Export', () => { { field: 'brand', headerName: 'Brand', - valueFormatter: (params) => (params.value === 'Nike' ? 'Jordan' : params.value), + valueFormatter: (value) => (value === 'Nike' ? 'Jordan' : value), }, ]} rows={[ diff --git a/packages/grid/x-data-grid-pro/src/tests/rowEditing.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/rowEditing.DataGridPro.test.tsx index e6256208a2b6c..6904e424877cf 100644 --- a/packages/grid/x-data-grid-pro/src/tests/rowEditing.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/rowEditing.DataGridPro.test.tsx @@ -7,7 +7,7 @@ import { useGridApiRef, DataGridPro, GridRenderEditCellParams, - GridValueSetterParams, + GridValueSetter, GridPreProcessEditCellProps, GridRowModes, } from '@mui/x-data-grid-pro'; @@ -157,10 +157,11 @@ describe(' - Row editing', () => { }); it('should pass to renderEditCell the row with the values updated', async () => { - column1Props.valueSetter = ({ value, row }: GridValueSetterParams) => ({ + const valueSetter: GridValueSetter = (value, row) => ({ ...row, currencyPair: value.trim(), }); + column1Props.valueSetter = valueSetter; render(); act(() => apiRef.current.startRowEditMode({ id: 0 })); expect(renderEditCell1.lastCall.args[0].row).to.deep.equal(defaultData.rows[0]); @@ -610,8 +611,14 @@ describe(' - Row editing', () => { }); it('should pass the new value through all value setters before calling processRowUpdate', async () => { - column1Props.valueSetter = spy(({ value, row }) => ({ ...row, _currencyPair: value })); - column2Props.valueSetter = spy(({ value, row }) => ({ ...row, _price1M: value })); + column1Props.valueSetter = spy((value, row) => ({ + ...row, + _currencyPair: value, + })); + column2Props.valueSetter = spy((value, row) => ({ + ...row, + _price1M: value, + })); const processRowUpdate = spy((newRow) => newRow); render(); act(() => apiRef.current.startRowEditMode({ id: 0 })); @@ -627,13 +634,15 @@ describe(' - Row editing', () => { price1M: 1, _price1M: 1, }); - expect(column1Props.valueSetter.lastCall.args[0]).to.deep.equal({ - value: 'USD GBP', - row: defaultData.rows[0], - }); - expect(column2Props.valueSetter.lastCall.args[0]).to.deep.equal({ - value: 1, - row: { ...defaultData.rows[0], currencyPair: 'USDGBP', _currencyPair: 'USD GBP' }, // Ensure that the row contains the values from the previous setter + expect(column1Props.valueSetter.lastCall.args[0]).to.equal('USD GBP'); + expect(column1Props.valueSetter.lastCall.args[1]).to.deep.equal(defaultData.rows[0]); + + expect(column2Props.valueSetter.lastCall.args[0]).to.equal(1); + expect(column2Props.valueSetter.lastCall.args[1]).to.deep.equal({ + // Ensure that the row contains the values from the previous setter); + ...defaultData.rows[0], + currencyPair: 'USDGBP', + _currencyPair: 'USD GBP', }); }); diff --git a/packages/grid/x-data-grid-pro/src/tests/statePersistence.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/statePersistence.DataGridPro.test.tsx index f21003436f85e..69068db8f6f25 100644 --- a/packages/grid/x-data-grid-pro/src/tests/statePersistence.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/statePersistence.DataGridPro.test.tsx @@ -37,7 +37,7 @@ const columns: GridColDef[] = [ { field: 'idBis', type: 'number', - valueGetter: (params) => params.row.id, + valueGetter: (value, row) => row.id, }, { field: 'category', diff --git a/packages/grid/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx index 0e3fd7e32d15f..259c2f7a44092 100644 --- a/packages/grid/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx @@ -341,7 +341,7 @@ describe(' - Tree data', () => { it('should support valueFormatter', () => { render( `> ${value}` }} + groupingColDef={{ valueFormatter: (value) => `> ${value}` }} defaultGroupingExpansionDepth={-1} />, ); diff --git a/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx b/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx index 411f9d82b41c0..7de0ea67c93c6 100644 --- a/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx +++ b/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx @@ -88,7 +88,7 @@ export const useDataGridComponent = ( useGridRowSelection(apiRef, props); useGridColumns(apiRef, props); useGridRows(apiRef, props); - useGridParamsApi(apiRef, props); + useGridParamsApi(apiRef); useGridColumnSpanning(apiRef); useGridColumnGrouping(apiRef, props); useGridEditing(apiRef, props); diff --git a/packages/grid/x-data-grid/src/colDef/gridBooleanColDef.tsx b/packages/grid/x-data-grid/src/colDef/gridBooleanColDef.tsx index 7c2abdc9416e8..a032fc6451d9e 100644 --- a/packages/grid/x-data-grid/src/colDef/gridBooleanColDef.tsx +++ b/packages/grid/x-data-grid/src/colDef/gridBooleanColDef.tsx @@ -1,16 +1,15 @@ import { GRID_STRING_COL_DEF } from './gridStringColDef'; -import { GridColTypeDef } from '../models/colDef/gridColDef'; +import { GridColTypeDef, GridValueFormatter } from '../models/colDef/gridColDef'; import { renderBooleanCell } from '../components/cell/GridBooleanCell'; import { renderEditBooleanCell } from '../components/cell/GridEditBooleanCell'; import { gridNumberComparator } from '../hooks/features/sorting/gridSortingUtils'; import { getGridBooleanOperators } from './gridBooleanOperators'; -import { GridValueFormatterParams } from '../models/params/gridCellParams'; -function gridBooleanFormatter({ value, api }: GridValueFormatterParams) { +const gridBooleanFormatter: GridValueFormatter = (value, row, column, apiRef) => { return value - ? api.getLocaleText('booleanCellTrueLabel') - : api.getLocaleText('booleanCellFalseLabel'); -} + ? apiRef.current.getLocaleText('booleanCellTrueLabel') + : apiRef.current.getLocaleText('booleanCellFalseLabel'); +}; const stringToBoolean = (value: string) => { switch (value.toLowerCase().trim()) { diff --git a/packages/grid/x-data-grid/src/colDef/gridCheckboxSelectionColDef.tsx b/packages/grid/x-data-grid/src/colDef/gridCheckboxSelectionColDef.tsx index 5b6d1d78150fd..69ab4c9a5e344 100644 --- a/packages/grid/x-data-grid/src/colDef/gridCheckboxSelectionColDef.tsx +++ b/packages/grid/x-data-grid/src/colDef/gridCheckboxSelectionColDef.tsx @@ -21,9 +21,10 @@ export const GRID_CHECKBOX_SELECTION_COL_DEF: GridColDef = { disableReorder: true, disableExport: true, getApplyQuickFilterFn: undefined, - valueGetter: (params) => { - const selectionLookup = selectedIdsLookupSelector(params.api.state, params.api.instanceId); - return selectionLookup[params.id] !== undefined; + valueGetter: (value, row, column, apiRef) => { + const selectionLookup = selectedIdsLookupSelector(apiRef); + const rowId = apiRef.current.getRowId(row); + return selectionLookup[rowId] !== undefined; }, renderHeader: (params) => , renderCell: (params) => , diff --git a/packages/grid/x-data-grid/src/colDef/gridDateColDef.ts b/packages/grid/x-data-grid/src/colDef/gridDateColDef.ts index 46888646bec84..314c31869f6f3 100644 --- a/packages/grid/x-data-grid/src/colDef/gridDateColDef.ts +++ b/packages/grid/x-data-grid/src/colDef/gridDateColDef.ts @@ -1,9 +1,8 @@ import { gridDateComparator } from '../hooks/features/sorting/gridSortingUtils'; import { getGridDateOperators } from './gridDateOperators'; import { GRID_STRING_COL_DEF } from './gridStringColDef'; -import { GridColTypeDef } from '../models/colDef/gridColDef'; +import { GridColTypeDef, GridValueFormatter } from '../models/colDef/gridColDef'; import { renderEditDateCell } from '../components/cell/GridEditDateCell'; -import { GridValueFormatterParams } from '../models/params/gridCellParams'; function throwIfNotDateObject({ value, @@ -27,21 +26,28 @@ function throwIfNotDateObject({ } } -export function gridDateFormatter({ value, field, id }: GridValueFormatterParams) { +export const gridDateFormatter: GridValueFormatter = (value: Date, row, column, apiRef): string => { if (!value) { return ''; } - throwIfNotDateObject({ value, columnType: 'date', rowId: id, field }); + const rowId = apiRef.current.getRowId(row); + throwIfNotDateObject({ value, columnType: 'date', rowId, field: column.field }); return value.toLocaleDateString(); -} +}; -export function gridDateTimeFormatter({ value, field, id }: GridValueFormatterParams) { +export const gridDateTimeFormatter: GridValueFormatter = ( + value: Date, + row, + column, + apiRef, +): string => { if (!value) { return ''; } - throwIfNotDateObject({ value, columnType: 'dateTime', rowId: id, field }); + const rowId = apiRef.current.getRowId(row); + throwIfNotDateObject({ value, columnType: 'dateTime', rowId, field: column.field }); return value.toLocaleString(); -} +}; export const GRID_DATE_COL_DEF: GridColTypeDef = { ...GRID_STRING_COL_DEF, diff --git a/packages/grid/x-data-grid/src/colDef/gridNumericColDef.ts b/packages/grid/x-data-grid/src/colDef/gridNumericColDef.ts index cca2a740ff04a..1551315d19571 100644 --- a/packages/grid/x-data-grid/src/colDef/gridNumericColDef.ts +++ b/packages/grid/x-data-grid/src/colDef/gridNumericColDef.ts @@ -11,7 +11,7 @@ export const GRID_NUMERIC_COL_DEF: GridColTypeDef (value === '' ? null : Number(value)), - valueFormatter: ({ value }) => (isNumber(value) ? value.toLocaleString() : value || ''), + valueFormatter: (value?: number) => (isNumber(value) ? value.toLocaleString() : value || ''), filterOperators: getGridNumericOperators(), getApplyQuickFilterFn: getGridNumericQuickFilterFn, }; diff --git a/packages/grid/x-data-grid/src/colDef/gridSingleSelectColDef.tsx b/packages/grid/x-data-grid/src/colDef/gridSingleSelectColDef.tsx index 44f13cc779524..859e4f0a3525a 100644 --- a/packages/grid/x-data-grid/src/colDef/gridSingleSelectColDef.tsx +++ b/packages/grid/x-data-grid/src/colDef/gridSingleSelectColDef.tsx @@ -25,15 +25,15 @@ export const GRID_SINGLE_SELECT_COL_DEF: Omit = type: 'singleSelect', getOptionLabel: defaultGetOptionLabel, getOptionValue: defaultGetOptionValue, - valueFormatter(params) { - const { id, field, value, api } = params; - const colDef = params.api.getColumn(field); + valueFormatter(value, row, colDef, apiRef) { + // const { id, field, value, api } = params; + const rowId = apiRef.current.getRowId(row); if (!isSingleSelectColDef(colDef)) { return ''; } - const valueOptions = getValueOptions(colDef, { id, row: id ? api.getRow(id) : null }); + const valueOptions = getValueOptions(colDef, { id: rowId, row }); if (value == null) { return ''; } @@ -52,8 +52,8 @@ export const GRID_SINGLE_SELECT_COL_DEF: Omit = renderEditCell: renderEditSingleSelectCell, filterOperators: getGridSingleSelectOperators(), // @ts-ignore - pastedValueParser: (value, params) => { - const colDef = params.colDef as GridSingleSelectColDef; + pastedValueParser: (value, row, column) => { + const colDef = column as GridSingleSelectColDef; const valueOptions = getValueOptions(colDef) || []; const getOptionValue = (colDef as GridSingleSelectColDef).getOptionValue!; const valueOption = valueOptions.find((option) => { diff --git a/packages/grid/x-data-grid/src/components/cell/GridEditInputCell.tsx b/packages/grid/x-data-grid/src/components/cell/GridEditInputCell.tsx index 4dfad75a898f9..104f90d489cac 100644 --- a/packages/grid/x-data-grid/src/components/cell/GridEditInputCell.tsx +++ b/packages/grid/x-data-grid/src/components/cell/GridEditInputCell.tsx @@ -94,7 +94,7 @@ const GridEditInputCell = React.forwardRef { const column = apiRef.current.getColumn(field); if (column.valueSetter) { - rowUpdate = column.valueSetter({ - value: fieldProps.value, - row: rowUpdate, - }); + rowUpdate = column.valueSetter(fieldProps.value, rowUpdate, column, apiRef); } else { rowUpdate[field] = fieldProps.value; } diff --git a/packages/grid/x-data-grid/src/hooks/features/filter/gridFilterUtils.ts b/packages/grid/x-data-grid/src/hooks/features/filter/gridFilterUtils.ts index a62fb232a04bb..20d021178b453 100644 --- a/packages/grid/x-data-grid/src/hooks/features/filter/gridFilterUtils.ts +++ b/packages/grid/x-data-grid/src/hooks/features/filter/gridFilterUtils.ts @@ -172,8 +172,8 @@ const getFilterCallbackFromItem = ( if (column.valueParser) { const parser = column.valueParser; parsedValue = Array.isArray(filterItem.value) - ? filterItem.value?.map((x) => parser(x)) - : parser(filterItem.value); + ? filterItem.value?.map((x) => parser(x, undefined, column, apiRef)) + : parser(filterItem.value, undefined, column, apiRef); } else { parsedValue = filterItem.value; } diff --git a/packages/grid/x-data-grid/src/hooks/features/rows/useGridParamsApi.ts b/packages/grid/x-data-grid/src/hooks/features/rows/useGridParamsApi.ts index 9130fb075c6e6..ae7b518d64e8e 100644 --- a/packages/grid/x-data-grid/src/hooks/features/rows/useGridParamsApi.ts +++ b/packages/grid/x-data-grid/src/hooks/features/rows/useGridParamsApi.ts @@ -1,16 +1,13 @@ import * as React from 'react'; import { GridPrivateApiCommunity } from '../../../models/api/gridApiCommunity'; import { GridParamsApi } from '../../../models/api/gridParamsApi'; -import { GridRowId, GridTreeNodeWithRender } from '../../../models/gridRows'; -import { GridCellParams, GridValueGetterParams } from '../../../models/params/gridCellParams'; +import { GridCellParams } from '../../../models/params/gridCellParams'; import { GridRowParams } from '../../../models/params/gridRowParams'; -import { DataGridProcessedProps } from '../../../models/props/DataGridProps'; import { getGridCellElement, getGridColumnHeaderElement, getGridRowElement, } from '../../../utils/domUtils'; -import { GRID_ID_AUTOGENERATED } from './gridRowsUtils'; import { useGridApiMethod } from '../../utils/useGridApiMethod'; import { gridFocusCellSelector, gridTabIndexCellSelector } from '../focus/gridFocusStateSelector'; @@ -24,12 +21,7 @@ export class MissingRowIdError extends Error {} * TODO: Impossible priority - useGridEditing also needs to be after useGridParamsApi * TODO: Impossible priority - useGridFocus also needs to be after useGridParamsApi */ -export function useGridParamsApi( - apiRef: React.MutableRefObject, - props: Pick, -) { - const { getRowId } = props; - +export function useGridParamsApi(apiRef: React.MutableRefObject) { const getColumnHeaderParams = React.useCallback( (field) => ({ field, @@ -56,36 +48,6 @@ export function useGridParamsApi( [apiRef], ); - const getBaseCellParams = React.useCallback( - (id: GridRowId, field: string) => { - const row = apiRef.current.getRow(id); - const rowNode = apiRef.current.getRowNode(id); - - if (!row || !rowNode) { - throw new MissingRowIdError(`No row with id #${id} found`); - } - - const cellFocus = gridFocusCellSelector(apiRef); - const cellTabIndex = gridTabIndexCellSelector(apiRef); - - const params: GridValueGetterParams = { - id, - field, - row, - rowNode, - value: row[field], - colDef: apiRef.current.getColumn(field), - cellMode: apiRef.current.getCellMode(id, field), - api: apiRef.current, - hasFocus: cellFocus !== null && cellFocus.field === field && cellFocus.id === id, - tabIndex: cellTabIndex && cellTabIndex.field === field && cellTabIndex.id === id ? 0 : -1, - }; - - return params; - }, - [apiRef], - ); - const getCellParams = React.useCallback( (id, field) => { const colDef = apiRef.current.getColumn(field); @@ -114,12 +76,7 @@ export function useGridParamsApi( isEditable: false, }; if (colDef && colDef.valueFormatter) { - params.formattedValue = colDef.valueFormatter({ - id, - field: params.field, - value: params.value, - api: apiRef.current, - }); + params.formattedValue = colDef.valueFormatter(value as never, row, colDef, apiRef); } params.isEditable = colDef && apiRef.current.isCellEditable(params); @@ -142,24 +99,28 @@ export function useGridParamsApi( return rowModel[field]; } - return colDef.valueGetter(getBaseCellParams(id, field)); + const row = apiRef.current.getRow(id); + if (!row) { + throw new MissingRowIdError(`No row with id #${id} found`); + } + const value = row[colDef.field]; + return colDef.valueGetter(value as never, row, colDef, apiRef); }, - [apiRef, getBaseCellParams], + [apiRef], ); const getRowValue = React.useCallback( (row, colDef) => { - const id = - GRID_ID_AUTOGENERATED in row ? row[GRID_ID_AUTOGENERATED] : getRowId?.(row) ?? row.id; const field = colDef.field; if (!colDef || !colDef.valueGetter) { return row[field]; } - return colDef.valueGetter(getBaseCellParams(id, field)); + const value = row[colDef.field]; + return colDef.valueGetter(value as never, row, colDef, apiRef); }, - [getBaseCellParams, getRowId], + [apiRef], ); const getRowFormattedValue = React.useCallback( @@ -170,17 +131,9 @@ export function useGridParamsApi( return value; } - const id = (getRowId ? getRowId(row) : row.id) ?? row[GRID_ID_AUTOGENERATED]; - const field = colDef.field; - - return colDef.valueFormatter({ - id, - field, - value, - api: apiRef.current, - }); + return colDef.valueFormatter(value as never, row, colDef, apiRef); }, - [apiRef, getRowId, getRowValue], + [apiRef, getRowValue], ); const getColumnHeaderElement = React.useCallback( diff --git a/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts b/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts index f925f7d4714af..2f221d6d347fb 100644 --- a/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts +++ b/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts @@ -3,12 +3,8 @@ import { GridCellClassNamePropType } from '../gridCellClass'; import { GridColumnHeaderClassNamePropType } from '../gridColumnHeaderClass'; import type { GridFilterOperator } from '../gridFilterOperator'; import { - GridCellParams, GridRenderCellParams, GridRenderEditCellParams, - GridValueFormatterParams, - GridValueGetterParams, - GridValueSetterParams, GridPreProcessEditCellProps, } from '../params/gridCellParams'; import { GridColumnHeaderParams } from '../params/gridColumnHeaderParams'; @@ -45,6 +41,51 @@ export type GetApplyQuickFilterFn, ) => null | GridApplyQuickFilter; +export type GridValueGetter< + R extends GridValidRowModel = GridValidRowModel, + V = any, + F = V, + TValue = never, +> = ( + value: TValue, + row: R, + column: GridColDef, + apiRef: React.MutableRefObject, +) => V; + +export type GridValueFormatter< + R extends GridValidRowModel = GridValidRowModel, + V = any, + F = V, + TValue = never, +> = ( + value: TValue, + row: R, + column: GridColDef, + apiRef: React.MutableRefObject, +) => F; + +export type GridValueSetter = ( + value: V, + row: R, + column: GridColDef, + apiRef: React.MutableRefObject, +) => R; + +export type GridValueParser = ( + value: F | undefined, + row: R | undefined, + column: GridColDef, + apiRef: React.MutableRefObject, +) => V; + +export type GridColSpanFn = ( + value: V, + row: R, + column: GridColDef, + apiRef: React.MutableRefObject, +) => number | undefined; + /** * Column Definition base interface. */ @@ -134,34 +175,23 @@ export interface GridBaseColDef} params Object containing parameters for the getter. - * @returns {V} The cell value. */ - valueGetter?: (params: GridValueGetterParams) => V; + valueGetter?: GridValueGetter; /** * Function that allows to customize how the entered value is stored in the row. * It only works with cell/row editing. - * @template R, V - * @param {GridValueSetterParams} params Object containing parameters for the setter. * @returns {R} The row with the updated field. */ - valueSetter?: (params: GridValueSetterParams) => R; + valueSetter?: GridValueSetter; /** * Function that allows to apply a formatter before rendering its value. - * @template V, F - * @param {GridValueFormatterParams} params Object containing parameters for the formatter. - * @returns {F} The formatted value. */ - valueFormatter?: (params: GridValueFormatterParams) => F; + valueFormatter?: GridValueFormatter; /** * Function that takes the user-entered value and converts it to a value used internally. - * @template R, V, F - * @param {F | undefined} value The user-entered value. - * @param {GridCellParams} params The params when called before saving the value. * @returns {V} The converted value to use internally. */ - valueParser?: (value: F | undefined, params?: GridCellParams) => V; + valueParser?: GridValueParser; /** * Class name that will be added in cells for that column. */ @@ -245,7 +275,7 @@ export interface GridBaseColDef) => number | undefined); + colSpan?: number | GridColSpanFn; } /** diff --git a/packages/grid/x-data-grid/src/models/colDef/index.ts b/packages/grid/x-data-grid/src/models/colDef/index.ts index da8753ee10322..3b0ffa6535524 100644 --- a/packages/grid/x-data-grid/src/models/colDef/index.ts +++ b/packages/grid/x-data-grid/src/models/colDef/index.ts @@ -9,6 +9,11 @@ export type { GridSingleSelectColDef, GridActionsColDef, GetApplyQuickFilterFn, + GridValueGetter, + GridValueFormatter, + GridValueSetter, + GridValueParser, + GridColSpanFn, } from './gridColDef'; // Other types diff --git a/packages/grid/x-data-grid/src/models/params/gridCellParams.ts b/packages/grid/x-data-grid/src/models/params/gridCellParams.ts index 56d393921cb53..f0b18838440e1 100644 --- a/packages/grid/x-data-grid/src/models/params/gridCellParams.ts +++ b/packages/grid/x-data-grid/src/models/params/gridCellParams.ts @@ -108,38 +108,6 @@ export interface GridRenderEditCellParams< api: GridApiCommunity; } -/** - * Parameters passed to `colDef.valueGetter`. - */ -export interface GridValueGetterParams< - R extends GridValidRowModel = any, - V = any, - N extends GridTreeNodeWithRender = GridTreeNodeWithRender, -> extends Omit, 'formattedValue' | 'isEditable'> { - /** - * GridApi that let you manipulate the grid. - */ - api: GridApiCommunity; - /** - * The default value for the cell that the `valueGetter` is overriding. - */ - value: GridCellParams['value']; -} - -/** - * Object passed as parameter in the column [[GridColDef]] value setter callback. - */ -export interface GridValueSetterParams { - /** - * The new cell value. - */ - value: V; - /** - * The row that is being edited. - */ - row: R; -} - /** * Object passed as parameter in the column [[GridColDef]] value formatter callback. */ diff --git a/packages/grid/x-data-grid/src/tests/DataGrid.spec.tsx b/packages/grid/x-data-grid/src/tests/DataGrid.spec.tsx index 04037c69002f7..c82da0c7f74e6 100644 --- a/packages/grid/x-data-grid/src/tests/DataGrid.spec.tsx +++ b/packages/grid/x-data-grid/src/tests/DataGrid.spec.tsx @@ -79,12 +79,12 @@ function ColumnPropTest() { { field: 'firstName', // @ts-expect-error - valueGetter: (params) => params.row.lastName, + valueGetter: (value, row) => row.lastName, // @ts-expect-error - valueParser: (value, params) => params!.row.lastName, - valueSetter: (params) => { + valueParser: (value, row) => row!.lastName, + valueSetter: (value, row) => { // @ts-expect-error - const lastName = params.row.lastName; + const lastName = row.lastName; return {} as any; }, // @ts-expect-error @@ -98,10 +98,10 @@ function ColumnPropTest() { columns={[ { field: 'firstName', - valueGetter: (params) => params.row.firstName, - valueParser: (value, params) => params!.row.firstName, - valueSetter: (params) => { - const firstName = params.row.firstName; + valueGetter: (value, row) => row.firstName, + valueParser: (value, row) => row!.firstName, + valueSetter: (value, row) => { + const firstName = row.firstName; return {} as any; }, renderCell: (params) => params.row.firstName, @@ -115,12 +115,12 @@ function ColumnPropTest() { { field: 'firstName', // @ts-expect-error - valueGetter: (params) => params.row.lastName, + valueGetter: (value, row) => row.lastName, // @ts-expect-error - valueParser: (value, params) => params!.row.lastName, - valueSetter: (params) => { + valueParser: (value, row) => row!.lastName, + valueSetter: (value, row) => { // @ts-expect-error - const lastName = params.row.lastName; + const lastName = row.lastName; return {} as any; }, // @ts-expect-error @@ -134,10 +134,10 @@ function ColumnPropTest() { columns={[ { field: 'firstName', - valueGetter: (params) => params.row.firstName, - valueParser: (value, params) => params!.row.firstName, - valueSetter: (params) => { - const firstName = params.row.firstName; + valueGetter: (value, row) => row.firstName, + valueParser: (value, row) => row!.firstName, + valueSetter: (value, row) => { + const firstName = row.firstName; return {} as any; }, renderCell: (params) => params.row.firstName, diff --git a/packages/grid/x-data-grid/src/tests/cells.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/cells.DataGrid.test.tsx index b34cba0ec831b..263db67e04b85 100644 --- a/packages/grid/x-data-grid/src/tests/cells.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/cells.DataGrid.test.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { spy } from 'sinon'; import { createRenderer, fireEvent, userEvent } from '@mui-internal/test-utils'; import { expect } from 'chai'; -import { DataGrid } from '@mui/x-data-grid'; +import { DataGrid, GridValueFormatter } from '@mui/x-data-grid'; import { getCell } from 'test/utils/helperFn'; import { getBasicGridData } from '@mui/x-data-grid-generator'; @@ -145,7 +145,9 @@ describe(' - Cells', () => { }); it('should call the valueFormatter with the correct params', () => { - const valueFormatter = spy(({ value }) => (value ? 'Yes' : 'No')); + const valueFormatter = spy>((value) => + value ? 'Yes' : 'No', + ); render(
- Cells', () => {
, ); expect(getCell(0, 0)).to.have.text('Yes'); - expect(valueFormatter.lastCall.args[0]).to.have.keys('id', 'field', 'value', 'api'); - expect(valueFormatter.lastCall.args[0].id).to.equal(0); - expect(valueFormatter.lastCall.args[0].field).to.equal('isActive'); - expect(valueFormatter.lastCall.args[0].value).to.equal(true); + // expect(valueFormatter.lastCall.args[0]).to.have.keys('id', 'field', 'value', 'api'); + expect(valueFormatter.lastCall.args[0]).to.equal(true); + expect(valueFormatter.lastCall.args[1]).to.deep.equal({ id: 0, isActive: true }); + expect(valueFormatter.lastCall.args[2].field).to.equal('isActive'); }); it('should throw when focusing cell without updating the state', () => { diff --git a/packages/grid/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx index 36165bbcff92a..57f591f6f573b 100644 --- a/packages/grid/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx @@ -62,9 +62,9 @@ describe(' - Column spanning', () => { (row.brand === 'Nike' ? 2 : 1) }, - { field: 'category', colSpan: ({ row }) => (row.brand === 'Adidas' ? 2 : 1) }, - { field: 'price', colSpan: ({ row }) => (row.brand === 'Puma' ? 2 : 1) }, + { field: 'brand', colSpan: (value, row) => (row.brand === 'Nike' ? 2 : 1) }, + { field: 'category', colSpan: (value, row) => (row.brand === 'Adidas' ? 2 : 1) }, + { field: 'price', colSpan: (value, row) => (row.brand === 'Puma' ? 2 : 1) }, { field: 'rating' }, ]} disableVirtualization={isJSDOM} @@ -112,9 +112,9 @@ describe(' - Column spanning', () => { describe('key navigation', () => { const columns: GridColDef[] = [ - { field: 'brand', colSpan: ({ row }) => (row.brand === 'Nike' ? 2 : 1) }, - { field: 'category', colSpan: ({ row }) => (row.brand === 'Adidas' ? 2 : 1) }, - { field: 'price', colSpan: ({ row }) => (row.brand === 'Puma' ? 2 : 1) }, + { field: 'brand', colSpan: (value, row) => (row.brand === 'Nike' ? 2 : 1) }, + { field: 'category', colSpan: (value, row) => (row.brand === 'Adidas' ? 2 : 1) }, + { field: 'price', colSpan: (value, row) => (row.brand === 'Puma' ? 2 : 1) }, { field: 'rating' }, ]; @@ -307,7 +307,7 @@ describe(' - Column spanning', () => {
(row.brand === 'Adidas' ? 2 : 1) }, + { field: 'brand', colSpan: (value, row) => (row.brand === 'Adidas' ? 2 : 1) }, { field: 'category' }, { field: 'price' }, ]} @@ -370,7 +370,7 @@ describe(' - Column spanning', () => { (row.brand === 'Nike' ? 2 : 1) }, + { field: 'brand', colSpan: (value, row) => (row.brand === 'Nike' ? 2 : 1) }, { field: 'category' }, { field: 'price' }, { field: 'rating' }, @@ -492,9 +492,9 @@ describe(' - Column spanning', () => { (row.brand === 'Nike' ? 2 : 1) }, - { field: 'category', colSpan: ({ row }) => (row.brand === 'Adidas' ? 2 : 1) }, - { field: 'price', colSpan: ({ row }) => (row.brand === 'Puma' ? 2 : 1) }, + { field: 'brand', colSpan: (value, row) => (row.brand === 'Nike' ? 2 : 1) }, + { field: 'category', colSpan: (value, row) => (row.brand === 'Adidas' ? 2 : 1) }, + { field: 'price', colSpan: (value, row) => (row.brand === 'Puma' ? 2 : 1) }, { field: 'rating' }, ]} rows={[ @@ -571,9 +571,9 @@ describe(' - Column spanning', () => { (row.brand === 'Nike' ? 2 : 1) }, - { field: 'category', colSpan: ({ row }) => (row.brand === 'Adidas' ? 2 : 1) }, - { field: 'price', colSpan: ({ row }) => (row.brand === 'Puma' ? 2 : 1) }, + { field: 'brand', colSpan: (value, row) => (row.brand === 'Nike' ? 2 : 1) }, + { field: 'category', colSpan: (value, row) => (row.brand === 'Adidas' ? 2 : 1) }, + { field: 'price', colSpan: (value, row) => (row.brand === 'Puma' ? 2 : 1) }, { field: 'rating' }, ]} /> @@ -667,9 +667,9 @@ describe(' - Column spanning', () => { ]; const columns: GridColDef[] = [ - { field: 'brand', colSpan: ({ row }) => (row.brand === 'Nike' ? 2 : 1) }, - { field: 'category', colSpan: ({ row }) => (row.brand === 'Adidas' ? 2 : 1) }, - { field: 'price', colSpan: ({ row }) => (row.brand === 'Puma' ? 2 : 1) }, + { field: 'brand', colSpan: (value, row) => (row.brand === 'Nike' ? 2 : 1) }, + { field: 'category', colSpan: (value, row) => (row.brand === 'Adidas' ? 2 : 1) }, + { field: 'price', colSpan: (value, row) => (row.brand === 'Puma' ? 2 : 1) }, { field: 'rating' }, ]; @@ -732,7 +732,7 @@ describe(' - Column spanning', () => {
(value === '1-0' ? 3 : 1) }, + { field: 'col0', width: 100, colSpan: (value) => (value === '1-0' ? 3 : 1) }, { field: 'col1', width: 100 }, { field: 'col2', width: 100 }, { field: 'col3', width: 100 }, @@ -787,7 +787,7 @@ describe(' - Column spanning', () => {
(value === '1-0' ? 3 : 1) }, + { field: 'col0', width: 100, colSpan: (value) => (value === '1-0' ? 3 : 1) }, { field: 'col1', width: 100 }, { field: 'col2', width: 100 }, { field: 'col3', width: 100 }, @@ -855,7 +855,7 @@ describe(' - Column spanning', () => { pageSizeOptions={[3]} initialState={{ pagination: { paginationModel: { pageSize: 3 } } }} columns={[ - { field: 'col0', width: 100, colSpan: ({ value }) => (value === '4-0' ? 3 : 1) }, + { field: 'col0', width: 100, colSpan: (value) => (value === '4-0' ? 3 : 1) }, { field: 'col1', width: 100 }, { field: 'col2', width: 100 }, { field: 'col3', width: 100 }, diff --git a/packages/grid/x-data-grid/src/tests/columns.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/columns.DataGrid.test.tsx index 44db4a17cc263..20726bc89195c 100644 --- a/packages/grid/x-data-grid/src/tests/columns.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/columns.DataGrid.test.tsx @@ -75,7 +75,7 @@ describe(' - Columns', () => { it('should not persist valueFormatter on column type change', () => { const { setProps } = render( `$${value}` }]} + columns={[{ field: 'price', type: 'number', valueFormatter: (value) => `$${value}` }]} rows={[{ id: 0, price: 1 }]} />, ); @@ -93,8 +93,8 @@ describe(' - Columns', () => { field: 'id', type: 'string', width: 200, - valueFormatter: (params) => { - return `formatted: ${params.value}`; + valueFormatter: (value) => { + return `formatted: ${value}`; }, }, { field: 'idBis' }, @@ -110,8 +110,8 @@ describe(' - Columns', () => { field: 'id', type: 'number', width: 200, - valueFormatter: (params) => { - return `formatted: ${params.value}`; + valueFormatter: (value) => { + return `formatted: ${value}`; }, }, { field: 'idBis' }, diff --git a/packages/grid/x-data-grid/src/tests/columns.spec.tsx b/packages/grid/x-data-grid/src/tests/columns.spec.tsx index ac5a5ddc14235..63e214fa6022d 100644 --- a/packages/grid/x-data-grid/src/tests/columns.spec.tsx +++ b/packages/grid/x-data-grid/src/tests/columns.spec.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { DataGrid, GridRenderCellParams } from '@mui/x-data-grid'; +import type { Expect, Equal } from 'test/utils/typeUtils'; import { GridCellParams } from '../models/params/gridCellParams'; import { GridColDef, GridRowParams } from '../models'; @@ -156,3 +157,132 @@ const constEmptyRows = [] as const; function ConstProps() { return ; } + +function ValueGetter() { + const oldSignatureValueGetter: GridColDef[] = [ + { + field: 'brand', + valueGetter: (params) => { + type Test = Expect>; + return ''; + }, + }, + { + field: 'brand', + valueGetter: ({ value, row }) => { + type Tests = [Expect>, Expect>]; + return ''; + }, + }, + ]; + + const currentSignatureValueGetter: GridColDef[] = [ + { + field: 'brand', + valueGetter: (value) => { + type Test = Expect>; + return value; + }, + }, + { + field: 'brand', + valueGetter: (value: number) => { + type Test = Expect>; + return value; + }, + }, + { + field: 'brand', + valueGetter: (value: 'foo' | 'bar') => { + type Test = Expect>; + return value; + }, + }, + ]; +} + +function ValueFormatter() { + const oldSignatureValueFormatter: GridColDef[] = [ + { + field: 'brand', + valueFormatter: (params) => { + type Test = Expect>; + return ''; + }, + }, + { + field: 'brand', + valueFormatter: ({ value, row }) => { + type Tests = [Expect>, Expect>]; + return ''; + }, + }, + ]; + + const currentSignatureValueFormatter: GridColDef[] = [ + { + field: 'brand', + valueFormatter: (value) => { + type Test = Expect>; + return value; + }, + }, + { + field: 'brand', + valueFormatter: (value: number) => { + type Test = Expect>; + return value; + }, + }, + { + field: 'brand', + valueFormatter: (value: 'foo' | 'bar') => { + type Test = Expect>; + return value; + }, + }, + ]; +} + +function GroupingValueGetter() { + const oldSignatureGroupingValueGetter: GridColDef[] = [ + { + field: 'brand', + groupingValueGetter: (params) => { + type Test = Expect>; + return ''; + }, + }, + { + field: 'brand', + groupingValueGetter: ({ value, row }) => { + type Tests = [Expect>, Expect>]; + return ''; + }, + }, + ]; + + const currentSignatureGroupingValueGetter: GridColDef[] = [ + { + field: 'brand', + groupingValueGetter: (value) => { + type Test = Expect>; + return value; + }, + }, + { + field: 'brand', + groupingValueGetter: (value: number) => { + type Test = Expect>; + return value; + }, + }, + { + field: 'brand', + groupingValueGetter: (value: 'foo' | 'bar') => { + type Test = Expect>; + return value; + }, + }, + ]; +} diff --git a/packages/grid/x-data-grid/src/tests/filtering.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/filtering.DataGrid.test.tsx index ef87d1fa8ba4a..c69bb7331eca5 100644 --- a/packages/grid/x-data-grid/src/tests/filtering.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/filtering.DataGrid.test.tsx @@ -525,7 +525,7 @@ describe(' - Filter', () => { field: 'year', type: 'number', // Avoid the localization of the number to simplify the checks - valueFormatter: (params) => params.value, + valueFormatter: (value) => value, }, ]} />, @@ -650,7 +650,7 @@ describe(' - Filter', () => { field: 'date', type: 'date', // Avoid the localization of the date to simplify the checks - valueFormatter: ({ value }) => { + valueFormatter: (value?: Date | string) => { if (value === null) { return 'null'; } @@ -817,7 +817,7 @@ describe(' - Filter', () => { field: 'date', type: 'dateTime', // Avoid the localization of the date to simplify the checks - valueFormatter: ({ value }) => { + valueFormatter: (value?: Date | string) => { if (value === null) { return 'null'; } diff --git a/packages/grid/x-data-grid/src/tests/layout.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/layout.DataGrid.test.tsx index d0df981e57a96..52b7342ccb617 100644 --- a/packages/grid/x-data-grid/src/tests/layout.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/layout.DataGrid.test.tsx @@ -178,7 +178,7 @@ describe(' - Layout & warnings', () => { { field: 'lastName' }, { field: 'fullName', - valueGetter: (params) => `${params.row.firstName || ''} ${params.row.lastName || ''}`, + valueGetter: (value, row) => `${row.firstName || ''} ${row.lastName || ''}`, }, ]; diff --git a/packages/grid/x-data-grid/src/tests/quickFiltering.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/quickFiltering.DataGrid.test.tsx index 4075f42489e73..6c8bd95121ec1 100644 --- a/packages/grid/x-data-grid/src/tests/quickFiltering.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/quickFiltering.DataGrid.test.tsx @@ -422,7 +422,7 @@ describe(' - Quick filter', () => { { field: 'phone', type: 'string', - valueFormatter: ({ value }) => `+${value.slice(0, 2)} ${value.slice(2)}`, + valueFormatter: (value: string) => `+${value.slice(0, 2)} ${value.slice(2)}`, }, ]} />, @@ -534,7 +534,7 @@ describe(' - Quick filter', () => { field: 'year', type: 'number', // Avoid the localization of the number to simplify the checks - valueFormatter: (params) => params.value, + valueFormatter: (value) => value, }, ]} />, diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index 25b7aa594284b..287b954cc35ce 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -137,6 +137,7 @@ { "name": "GridClearIcon", "kind": "Variable" }, { "name": "GridCloseIcon", "kind": "Variable" }, { "name": "GridColDef", "kind": "TypeAlias" }, + { "name": "GridColSpanFn", "kind": "TypeAlias" }, { "name": "GridColType", "kind": "TypeAlias" }, { "name": "GridColTypeDef", "kind": "TypeAlias" }, { "name": "GridColumnApi", "kind": "Interface" }, @@ -238,8 +239,8 @@ { "name": "GridDataPinnedRowNode", "kind": "Interface" }, { "name": "gridDataRowIdsSelector", "kind": "Variable" }, { "name": "gridDateComparator", "kind": "Variable" }, - { "name": "gridDateFormatter", "kind": "Function" }, - { "name": "gridDateTimeFormatter", "kind": "Function" }, + { "name": "gridDateFormatter", "kind": "Variable" }, + { "name": "gridDateTimeFormatter", "kind": "Variable" }, { "name": "GridDeleteForeverIcon", "kind": "Variable" }, { "name": "GridDeleteIcon", "kind": "Variable" }, { "name": "GridDensity", "kind": "TypeAlias" }, @@ -356,7 +357,7 @@ { "name": "GridGroupingColDefOverrideParams", "kind": "Interface" }, { "name": "GridGroupingRule", "kind": "Interface" }, { "name": "GridGroupingRules", "kind": "TypeAlias" }, - { "name": "GridGroupingValueGetterParams", "kind": "Interface" }, + { "name": "GridGroupingValueGetter", "kind": "TypeAlias" }, { "name": "GridGroupNode", "kind": "TypeAlias" }, { "name": "GridGroupWorkIcon", "kind": "Variable" }, { "name": "GridHeader", "kind": "Function" }, @@ -417,6 +418,7 @@ { "name": "GridPanelWrapper", "kind": "Variable" }, { "name": "GridPanelWrapperProps", "kind": "Interface" }, { "name": "GridParamsApi", "kind": "Interface" }, + { "name": "GridPastedValueParser", "kind": "TypeAlias" }, { "name": "GridPinnedColumnFields", "kind": "Interface" }, { "name": "GridPinnedColumnPosition", "kind": "Enum" }, { "name": "GridPinnedColumns", "kind": "Interface" }, @@ -575,10 +577,12 @@ { "name": "GridTypeFilterInputValueProps", "kind": "TypeAlias" }, { "name": "GridUpdateAction", "kind": "TypeAlias" }, { "name": "GridValidRowModel", "kind": "TypeAlias" }, + { "name": "GridValueFormatter", "kind": "TypeAlias" }, { "name": "GridValueFormatterParams", "kind": "Interface" }, - { "name": "GridValueGetterParams", "kind": "Interface" }, + { "name": "GridValueGetter", "kind": "TypeAlias" }, { "name": "GridValueOptionsParams", "kind": "Interface" }, - { "name": "GridValueSetterParams", "kind": "Interface" }, + { "name": "GridValueParser", "kind": "TypeAlias" }, + { "name": "GridValueSetter", "kind": "TypeAlias" }, { "name": "GridViewColumnIcon", "kind": "Variable" }, { "name": "GridViewHeadlineIcon", "kind": "Variable" }, { "name": "GridViewStreamIcon", "kind": "Variable" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index 0540bef175505..6e1bffb88d86e 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -113,6 +113,7 @@ { "name": "GridClearIcon", "kind": "Variable" }, { "name": "GridCloseIcon", "kind": "Variable" }, { "name": "GridColDef", "kind": "TypeAlias" }, + { "name": "GridColSpanFn", "kind": "TypeAlias" }, { "name": "GridColType", "kind": "TypeAlias" }, { "name": "GridColTypeDef", "kind": "TypeAlias" }, { "name": "GridColumnApi", "kind": "Interface" }, @@ -212,8 +213,8 @@ { "name": "GridDataPinnedRowNode", "kind": "Interface" }, { "name": "gridDataRowIdsSelector", "kind": "Variable" }, { "name": "gridDateComparator", "kind": "Variable" }, - { "name": "gridDateFormatter", "kind": "Function" }, - { "name": "gridDateTimeFormatter", "kind": "Function" }, + { "name": "gridDateFormatter", "kind": "Variable" }, + { "name": "gridDateTimeFormatter", "kind": "Variable" }, { "name": "GridDeleteForeverIcon", "kind": "Variable" }, { "name": "GridDeleteIcon", "kind": "Variable" }, { "name": "GridDensity", "kind": "TypeAlias" }, @@ -530,10 +531,12 @@ { "name": "GridTypeFilterInputValueProps", "kind": "TypeAlias" }, { "name": "GridUpdateAction", "kind": "TypeAlias" }, { "name": "GridValidRowModel", "kind": "TypeAlias" }, + { "name": "GridValueFormatter", "kind": "TypeAlias" }, { "name": "GridValueFormatterParams", "kind": "Interface" }, - { "name": "GridValueGetterParams", "kind": "Interface" }, + { "name": "GridValueGetter", "kind": "TypeAlias" }, { "name": "GridValueOptionsParams", "kind": "Interface" }, - { "name": "GridValueSetterParams", "kind": "Interface" }, + { "name": "GridValueParser", "kind": "TypeAlias" }, + { "name": "GridValueSetter", "kind": "TypeAlias" }, { "name": "GridViewColumnIcon", "kind": "Variable" }, { "name": "GridViewHeadlineIcon", "kind": "Variable" }, { "name": "GridViewStreamIcon", "kind": "Variable" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index 0813d4b722ed9..a14da1163acf4 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -103,6 +103,7 @@ { "name": "GridClearIcon", "kind": "Variable" }, { "name": "GridCloseIcon", "kind": "Variable" }, { "name": "GridColDef", "kind": "TypeAlias" }, + { "name": "GridColSpanFn", "kind": "TypeAlias" }, { "name": "GridColType", "kind": "TypeAlias" }, { "name": "GridColTypeDef", "kind": "TypeAlias" }, { "name": "GridColumnApi", "kind": "Interface" }, @@ -193,8 +194,8 @@ { "name": "GridDataPinnedRowNode", "kind": "Interface" }, { "name": "gridDataRowIdsSelector", "kind": "Variable" }, { "name": "gridDateComparator", "kind": "Variable" }, - { "name": "gridDateFormatter", "kind": "Function" }, - { "name": "gridDateTimeFormatter", "kind": "Function" }, + { "name": "gridDateFormatter", "kind": "Variable" }, + { "name": "gridDateTimeFormatter", "kind": "Variable" }, { "name": "GridDeleteForeverIcon", "kind": "Variable" }, { "name": "GridDeleteIcon", "kind": "Variable" }, { "name": "GridDensity", "kind": "TypeAlias" }, @@ -484,10 +485,12 @@ { "name": "GridTypeFilterInputValueProps", "kind": "TypeAlias" }, { "name": "GridUpdateAction", "kind": "TypeAlias" }, { "name": "GridValidRowModel", "kind": "TypeAlias" }, + { "name": "GridValueFormatter", "kind": "TypeAlias" }, { "name": "GridValueFormatterParams", "kind": "Interface" }, - { "name": "GridValueGetterParams", "kind": "Interface" }, + { "name": "GridValueGetter", "kind": "TypeAlias" }, { "name": "GridValueOptionsParams", "kind": "Interface" }, - { "name": "GridValueSetterParams", "kind": "Interface" }, + { "name": "GridValueParser", "kind": "TypeAlias" }, + { "name": "GridValueSetter", "kind": "TypeAlias" }, { "name": "GridViewColumnIcon", "kind": "Variable" }, { "name": "GridViewHeadlineIcon", "kind": "Variable" }, { "name": "GridViewStreamIcon", "kind": "Variable" }, From ff52290c751446cd18caf306fb4c592308681991 Mon Sep 17 00:00:00 2001 From: Lukas Date: Thu, 1 Feb 2024 22:21:26 +0200 Subject: [PATCH 08/35] v7.0.0-beta.1 (#11903) Signed-off-by: Lukas Co-authored-by: Andrew Cherniavskii --- CHANGELOG.md | 247 ++++++++++++++++++ package.json | 2 +- .../grid/x-data-grid-generator/package.json | 4 +- .../grid/x-data-grid-premium/package.json | 6 +- packages/grid/x-data-grid-pro/package.json | 4 +- packages/grid/x-data-grid/package.json | 2 +- packages/x-charts/package.json | 6 +- packages/x-date-pickers-pro/package.json | 4 +- packages/x-date-pickers/package.json | 2 +- 9 files changed, 262 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0886f83e7f00e..9a1706e2d9d50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,169 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## 7.0.0-beta.1 + +_Feb 1, 2024_ + +We'd like to offer a big thanks to the 12 contributors who made this release possible. Here are some highlights ✨: + +- 🏃 Improve the filtering performance of the Data Grid by changing the `GridColDef` methods signatures (#11573) @cherniavskii +- 🎁 The Line Chart component now has animation by default (#11620) @alexfauquette +- 🚀 All charts have click handlers (#11411) @alexfauquette + Test their respective documentation demonstrations to know more about the data format: + + - [Scatter Chart](https://next.mui.com/x/react-charts/scatter/#click-event) + - [Line Chart](https://next.mui.com/x/react-charts/lines/#click-event) + - [Bar Chart](https://next.mui.com/x/react-charts/bars/#click-event) + - [Pie Chart](https://next.mui.com/x/react-charts/pie/#click-event) + + Big thanks to @giladappsforce and @yaredtsy for their contribution on exploring this feature. + +### Data Grid + +### Breaking changes + +- The signature of `GridColDef['valueGetter']` has been changed for performance reasons: + + ```diff + - valueGetter: ({ value, row }) => value, + + valueGetter: (value, row, column, apiRef) => value, + ``` + + The `GridValueGetterParams` interface has been removed: + + ```diff + - const customValueGetter = (params: GridValueGetterParams) => params.row.budget; + + const customValueGetter: GridValueGetterFn = (value, row) => row.budget; + ``` + +- The signature of `GridColDef['valueFormatter']` has been changed for performance reasons: + + ```diff + - valueFormatter: ({ value }) => value, + + valueFormatter: (value, row, column, apiRef) => value, + ``` + + The `GridValueFormatterParams` interface has been removed: + + ```diff + - const gridDateFormatter = ({ value, field, id }: GridValueFormatterParams) => value.toLocaleDateString(); + + const gridDateFormatter: GridValueFormatter = (value: Date) => value.toLocaleDateString(); + ``` + +- The signature of `GridColDef['valueSetter']` has been changed for performance reasons: + + ```diff + - valueSetter: (params) => { + - const [firstName, lastName] = params.value!.toString().split(' '); + - return { ...params.row, firstName, lastName }; + - } + + valueSetter: (value, row) => { + + const [firstName, lastName] = value!.toString().split(' '); + + return { ...row, firstName, lastName }; + +} + ``` + + The `GridValueSetterParams` interface has been removed: + + ```diff + - const setFullName = (params: GridValueSetterParams) => { + - const [firstName, lastName] = params.value!.toString().split(' '); + - return { ...params.row, firstName, lastName }; + - }; + + const setFullName: GridValueSetter = (value, row) => { + + const [firstName, lastName] = value!.toString().split(' '); + + return { ...row, firstName, lastName }; + + } + ``` + +- The signature of `GridColDef['valueParser']` has been changed for performance reasons: + + ```diff + - valueParser: (value, params: GridCellParams) => value.toLowerCase(), + + valueParser: (value, row, column, apiRef) => value.toLowerCase(), + ``` + +- The signature of `GridColDef['colSpan']` has been changed for performance reasons: + + ```diff + - colSpan: ({ row, field, value }: GridCellParams) => (row.id === 'total' ? 2 : 1), + + colSpan: (value, row, column, apiRef) => (row.id === 'total' ? 2 : 1), + ``` + +- The signature of `GridColDef['pastedValueParser']` has been changed for performance reasons: + + ```diff + - pastedValueParser: (value, params) => new Date(value), + + pastedValueParser: (value, row, column, apiRef) => new Date(value), + ``` + +- The signature of `GridColDef['groupingValueGetter']` has been changed for performance reasons: + + ```diff + - groupingValueGetter: (params) => params.value.name, + + groupingValueGetter: (value: { name: string }) => value.name, + ``` + +#### `@mui/x-data-grid@7.0.0-beta.1` + +- [DataGrid] Add `toggleAllMode` prop to the `columnsManagement` slot (#10794) @H999 +- [DataGrid] Change `GridColDef` methods signatures (#11573) @cherniavskii +- [DataGrid] Fix row reorder with cell selection (#11783) @PEsteves8 +- [DataGrid] Make columns management' casing consistent (#11858) @MBilalShafi +- [l10n] Improve Hebrew (he-IL) locale (#11788) @danielmishan85 + +#### `@mui/x-data-grid-pro@7.0.0-beta.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan') + +Same changes as in `@mui/x-data-grid@7.0.0-beta.1`. + +#### `@mui/x-data-grid-premium@7.0.0-beta.1` [![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.0.0-beta.1`. + +### Date Pickers + +#### `@mui/x-date-pickers@7.0.0-beta.1` + +- [TimePicker] Add missing toolbar classes descriptions (#11856) @LukasTy + +#### `@mui/x-date-pickers-pro@7.0.0-beta.1` [![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.0.0-beta.1`. + +### Charts + +#### Breaking changes + +- The line chart now have animation by default. + You can disable it with `skipAnimation` prop. + See [animation documentation](next.mui.com/x/react-charts/lines/#animation) for more information. + +- Pie charts `onClick` get renamed `onItemClick` for consistency with other charts click callback. + +`@mui/x-charts@7.0.0-beta.1` + +- [charts] Add `onClick` support (#11411) @alexfauquette +- [charts] Add line animation (#11620) @alexfauquette +- [charts] Document how to modify color according to values (#11824) @alexfauquette +- [charts] Fix Tooltip crash with out of range lines (#11898) @alexfauquette + +### Docs + +- [docs] Add a general uplift to the changelog page (#11396) @danilo-leal +- [docs] Do not reference the Tree View overview page in the API pages (#11826) @flaviendelangle +- [docs] Fix charts API links (#11832) @alexfauquette +- [docs] Improve Support page (#11556) @oliviertassinari +- [docs] Improve column visibility documentation (#11857) @MBilalShafi +- [docs] Polish header @oliviertassinari +- [docs] Sync support page with core @oliviertassinari +- [docs] Update whats new page with "v7 Beta blogpost" content (#11879) @joserodolfofreitas + +### Core + +- [core] Rely on immutable ref when possible (#11847) @oliviertassinari +- [core] Bump monorepo (#11897) @alexfauquette + ## 7.0.0-beta.0 _Jan 26, 2024_ @@ -1873,6 +2036,90 @@ Here is an example of the renaming for the `` component. - [core] Update release instructions as per v7 configuration (#10962) @MBilalShafi - [license] Correctly throw errors (#10924) @oliviertassinari +## 6.19.3 + +_Feb 1, 2024_ + +We'd like to offer a big thanks to the 6 contributors who made this release possible. Here are some highlights ✨: + +- 🌍 Improve Hebrew (he-IL) locale (#11831) @danielmishan85 +- 🐞 Bugfixes +- 📚 Documentation improvements + +### Data Grid + +#### `@mui/x-data-grid@6.19.3` + +- [l10n] Improve Hebrew (he-IL) locale (@danielmishan85) (#11831) + +#### `@mui/x-data-grid-pro@6.19.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-data-grid@6.19.3`. + +#### `@mui/x-data-grid-premium@6.19.3` [![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@6.19.3`. + +### Date Pickers + +#### `@mui/x-date-pickers@6.19.3` + +- [TimePicker] Add missing toolbar classes descriptions (#11862) @LukasTy + +#### `@mui/x-date-pickers-pro@6.19.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-date-pickers@6.19.3`. + +### Charts / `@mui/x-charts@6.19.3` + +- [charts] Document how to modify color according to values (#11854) @alexfauquette + +### Docs + +- [docs] Add a general uplift to the whats new page (#11883) @danilo-leal +- [docs] Fix 404 (#11852) @alexfauquette +- [docs] Fix generation (#11825) @alexfauquette +- [docs] Fix docs:api when typo in slots typing (#11861) @alexfauquette +- [docs] Improve Support page (#11556) @oliviertassinari +- [docs] Sync support page with core @oliviertassinari +- [docs] These API don't exist in MUI X v6 @oliviertassinari +- [docs] Update whats new page with v7 Beta blogpost content (#11886) @joserodolfofreitas + +## 6.19.2 + +_Jan 25, 2024_ + +We'd like to offer a big thanks to the 2 contributors who made this release possible. Here are some highlights ✨: + +- 🚀 Apply the `layout.tabs` class to `Tabs` slot (@LukasTy) (#11782) +- 🐞 Bugfixes + +### Date Pickers + +#### `@mui/x-date-pickers@6.19.2` + +- [pickers] Apply the `layout.tabs` class to `Tabs` slot (@LukasTy) (#11782) + +#### `@mui/x-date-pickers-pro@6.19.2` [![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@6.19.2`, plus: + +- [DateRangePicker] Remove `calendars` prop on `Mobile` (@LukasTy) (#11771) + +### Data Grid + +#### `@mui/x-data-grid@6.19.2` + +- [DataGrid] Fix support for tree with more than 50,000 children (@zenazn) (#11808) + +#### `@mui/x-data-grid-pro@6.19.2` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan') + +Same changes as in `@mui/x-data-grid@6.19.2`. + +#### `@mui/x-data-grid-premium@6.19.2` [![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@6.19.2`. + ## 6.19.1 _Jan 19, 2024_ diff --git a/package.json b/package.json index 5d46619e78196..b572a46f3217c 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "7.0.0-beta.0", + "version": "7.0.0-beta.1", "private": true, "scripts": { "start": "yarn && yarn docs:dev", diff --git a/packages/grid/x-data-grid-generator/package.json b/packages/grid/x-data-grid-generator/package.json index e263a77b43c9d..a6bec07d2e311 100644 --- a/packages/grid/x-data-grid-generator/package.json +++ b/packages/grid/x-data-grid-generator/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid-generator", - "version": "7.0.0-beta.0", + "version": "7.0.0-beta.1", "description": "Generate fake data for demo purposes only.", "author": "MUI Team", "main": "src/index.ts", @@ -35,7 +35,7 @@ "dependencies": { "@babel/runtime": "^7.23.9", "@mui/base": "^5.0.0-beta.34", - "@mui/x-data-grid-premium": "7.0.0-beta.0", + "@mui/x-data-grid-premium": "7.0.0-beta.1", "chance": "^1.1.11", "clsx": "^2.1.0", "lru-cache": "^7.18.3" diff --git a/packages/grid/x-data-grid-premium/package.json b/packages/grid/x-data-grid-premium/package.json index a7b4750b49135..f73cb63df8184 100644 --- a/packages/grid/x-data-grid-premium/package.json +++ b/packages/grid/x-data-grid-premium/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid-premium", - "version": "7.0.0-beta.0", + "version": "7.0.0-beta.1", "description": "The Premium plan edition of the data grid component (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -46,8 +46,8 @@ "@babel/runtime": "^7.23.9", "@mui/system": "^5.15.7", "@mui/utils": "^5.15.7", - "@mui/x-data-grid": "7.0.0-beta.0", - "@mui/x-data-grid-pro": "7.0.0-beta.0", + "@mui/x-data-grid": "7.0.0-beta.1", + "@mui/x-data-grid-pro": "7.0.0-beta.1", "@mui/x-license-pro": "7.0.0-beta.0", "@types/format-util": "^1.0.4", "clsx": "^2.1.0", diff --git a/packages/grid/x-data-grid-pro/package.json b/packages/grid/x-data-grid-pro/package.json index 7d3adb5cb7af1..acb1211be650e 100644 --- a/packages/grid/x-data-grid-pro/package.json +++ b/packages/grid/x-data-grid-pro/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid-pro", - "version": "7.0.0-beta.0", + "version": "7.0.0-beta.1", "description": "The Pro plan edition of the data grid component (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -46,7 +46,7 @@ "@babel/runtime": "^7.23.9", "@mui/system": "^5.15.7", "@mui/utils": "^5.15.7", - "@mui/x-data-grid": "7.0.0-beta.0", + "@mui/x-data-grid": "7.0.0-beta.1", "@mui/x-license-pro": "7.0.0-beta.0", "@types/format-util": "^1.0.4", "clsx": "^2.1.0", diff --git a/packages/grid/x-data-grid/package.json b/packages/grid/x-data-grid/package.json index ee2ae2b86543c..9e3ea51103bd8 100644 --- a/packages/grid/x-data-grid/package.json +++ b/packages/grid/x-data-grid/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid", - "version": "7.0.0-beta.0", + "version": "7.0.0-beta.1", "description": "The community edition of the data grid component (MUI X).", "author": "MUI Team", "main": "src/index.ts", diff --git a/packages/x-charts/package.json b/packages/x-charts/package.json index 441fb68c82a19..37678d8850cdc 100644 --- a/packages/x-charts/package.json +++ b/packages/x-charts/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-charts", - "version": "7.0.0-beta.0", + "version": "7.0.0-beta.1", "description": "The community edition of the charts components (MUI X).", "author": "MUI Team", "main": "./src/index.js", @@ -48,9 +48,9 @@ "clsx": "^2.1.0", "d3-color": "^3.1.0", "d3-delaunay": "^6.0.4", + "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.2.0", - "d3-interpolate": "^3.0.1", "prop-types": "^15.8.1" }, "peerDependencies": { @@ -71,8 +71,8 @@ "devDependencies": { "@types/d3-color": "^3.1.3", "@types/d3-delaunay": "^6.0.4", - "@types/d3-scale": "^4.0.8", "@types/d3-interpolate": "^3.0.4", + "@types/d3-scale": "^4.0.8", "@types/d3-shape": "^3.1.6" }, "exports": { diff --git a/packages/x-date-pickers-pro/package.json b/packages/x-date-pickers-pro/package.json index 94a902cf856ec..c0bbca565a567 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.0.0-beta.0", + "version": "7.0.0-beta.1", "description": "The commercial edition of the date picker components (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -46,7 +46,7 @@ "@mui/base": "^5.0.0-beta.34", "@mui/system": "^5.15.7", "@mui/utils": "^5.15.7", - "@mui/x-date-pickers": "7.0.0-beta.0", + "@mui/x-date-pickers": "7.0.0-beta.1", "@mui/x-license-pro": "7.0.0-beta.0", "clsx": "^2.1.0", "prop-types": "^15.8.1", diff --git a/packages/x-date-pickers/package.json b/packages/x-date-pickers/package.json index 3130ca36a46a5..3052bea9aaac9 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.0.0-beta.0", + "version": "7.0.0-beta.1", "description": "The community edition of the date picker components (MUI X).", "author": "MUI Team", "main": "src/index.ts", From b18b02fe9b35ac50ac1bba31cd405db87413f883 Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Fri, 2 Feb 2024 10:08:09 +0100 Subject: [PATCH 09/35] [code-infra] Move next config to ESM (#11882) --- .eslintrc.js | 6 +++ docs/constants.js | 6 +++ docs/{next.config.js => next.config.mjs} | 52 +++++++++++++------- docs/package.json | 1 + docs/src/modules/utils/{find.js => find.mjs} | 15 +++--- docs/src/modules/utils/findPages.js | 6 --- docs/tsconfig.json | 3 +- scripts/l10n.ts | 7 ++- yarn.lock | 11 ++++- 9 files changed, 71 insertions(+), 36 deletions(-) create mode 100644 docs/constants.js rename docs/{next.config.js => next.config.mjs} (77%) rename docs/src/modules/utils/{find.js => find.mjs} (86%) delete mode 100644 docs/src/modules/utils/findPages.js diff --git a/.eslintrc.js b/.eslintrc.js index 4eecaad75bf5b..823e51ac43da9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -122,6 +122,12 @@ module.exports = { 'filenames/match-exported': ['error'], }, }, + { + files: ['**/*.mjs'], + rules: { + 'import/extensions': ['error', 'ignorePackages'], + }, + }, { files: ['packages/*/src/**/*{.ts,.tsx,.js}'], excludedFiles: ['*.d.ts', '*.spec.ts', '*.spec.tsx'], diff --git a/docs/constants.js b/docs/constants.js new file mode 100644 index 0000000000000..8b2dbe4c383c9 --- /dev/null +++ b/docs/constants.js @@ -0,0 +1,6 @@ +// These are also loaded by scripts that only undestand CommonJS. (l10n) + +module.exports = { + SOURCE_CODE_REPO: 'https://github.com/mui/mui-x', + SOURCE_GITHUB_BRANCH: 'next', // #default-branch-switch +}; diff --git a/docs/next.config.js b/docs/next.config.mjs similarity index 77% rename from docs/next.config.js rename to docs/next.config.mjs index a8b59b0b4f737..a613274fae7dd 100644 --- a/docs/next.config.js +++ b/docs/next.config.mjs @@ -1,28 +1,44 @@ // @ts-check -const path = require('path'); -// @ts-ignore -const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); -// const withTM = require('next-transpile-modules')(['@mui/monorepo']); +import * as path from 'path'; +import * as url from 'url'; +import * as fs from 'fs'; +import { createRequire } from 'module'; +import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; +// const withTM from 'next-transpile-modules')(['@mui/monorepo']; // @ts-expect-error This expected error should be gone once we update the monorepo -const withDocsInfra = require('@mui/monorepo/docs/nextConfigDocsInfra'); -const pkg = require('../package.json'); -const dataGridPkg = require('../packages/grid/x-data-grid/package.json'); -const datePickersPkg = require('../packages/x-date-pickers/package.json'); -const chartsPkg = require('../packages/x-charts/package.json'); -const treeViewPkg = require('../packages/x-tree-view/package.json'); -const { findPages } = require('./src/modules/utils/find'); -const { LANGUAGES, LANGUAGES_SSR } = require('./config'); +import withDocsInfra from '@mui/monorepo/docs/nextConfigDocsInfra.js'; +import { findPages } from './src/modules/utils/find.mjs'; +import { LANGUAGES, LANGUAGES_SSR } from './config.js'; +import constants from './constants.js'; -const workspaceRoot = path.join(__dirname, '../'); +const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url)); +const require = createRequire(import.meta.url); -module.exports = withDocsInfra({ +const workspaceRoot = path.join(currentDirectory, '../'); + +/** + * @param {string} pkgPath + * @returns {{version: string}} + */ +function loadPkg(pkgPath) { + const pkgContent = fs.readFileSync(path.resolve(workspaceRoot, pkgPath, 'package.json'), 'utf8'); + return JSON.parse(pkgContent); +} + +const pkg = loadPkg('.'); +const dataGridPkg = loadPkg('./packages/grid/x-data-grid'); +const datePickersPkg = loadPkg('./packages/x-date-pickers'); +const chartsPkg = loadPkg('./packages/x-charts'); +const treeViewPkg = loadPkg('./packages/x-tree-view'); + +export default withDocsInfra({ // Avoid conflicts with the other Next.js apps hosted under https://mui.com/ assetPrefix: process.env.DEPLOY_ENV === 'development' ? undefined : '/x', env: { // docs-infra LIB_VERSION: pkg.version, - SOURCE_CODE_REPO: 'https://github.com/mui/mui-x', - SOURCE_GITHUB_BRANCH: 'next', // #default-branch-switch + SOURCE_CODE_REPO: constants.SOURCE_CODE_REPO, + SOURCE_GITHUB_BRANCH: constants.SOURCE_GITHUB_BRANCH, GITHUB_TEMPLATE_DOCS_FEEDBACK: '6.docs-feedback.yml', // MUI X related DATA_GRID_VERSION: dataGridPkg.version, @@ -56,8 +72,8 @@ module.exports = withDocsInfra({ ...config.resolve, alias: { ...config.resolve.alias, - docs: path.resolve(__dirname, '../node_modules/@mui/monorepo/docs'), - docsx: path.resolve(__dirname, '../docs'), + docs: path.resolve(currentDirectory, '../node_modules/@mui/monorepo/docs'), + docsx: path.resolve(currentDirectory, '../docs'), }, }, module: { diff --git a/docs/package.json b/docs/package.json index 602319a2772a5..2d44732f09703 100644 --- a/docs/package.json +++ b/docs/package.json @@ -94,6 +94,7 @@ "@babel/preset-typescript": "^7.23.3", "@types/doctrine": "^0.0.9", "@types/stylis": "^4.2.5", + "@types/webpack-bundle-analyzer": "^4.6.3", "cpy-cli": "^5.0.0", "gm": "^1.25.0", "typescript-to-proptypes": "^2.2.1" diff --git a/docs/src/modules/utils/find.js b/docs/src/modules/utils/find.mjs similarity index 86% rename from docs/src/modules/utils/find.js rename to docs/src/modules/utils/find.mjs index 8f912fa149a2e..bdf5ce2240378 100644 --- a/docs/src/modules/utils/find.js +++ b/docs/src/modules/utils/find.mjs @@ -1,5 +1,8 @@ -const fs = require('fs'); -const path = require('path'); +import * as fs from 'fs'; +import * as path from 'path'; +import * as url from 'url'; + +const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url)); const jsRegex = /\.js$/; const blackList = ['/.eslintrc', '/_document', '/_app']; @@ -7,9 +10,9 @@ const blackList = ['/.eslintrc', '/_document', '/_app']; // Returns the Next.js pages available in a nested format. // The output is in the next.js format. // Each pathname is a route you can navigate to. -function findPages( +export function findPages( options = {}, - directory = path.resolve(__dirname, '../../../pages'), + directory = path.resolve(currentDirectory, '../../../pages'), pages = [], ) { fs.readdirSync(directory).forEach((item) => { @@ -71,7 +74,3 @@ function findPages( return pages; } - -module.exports = { - findPages, -}; diff --git a/docs/src/modules/utils/findPages.js b/docs/src/modules/utils/findPages.js deleted file mode 100644 index 8489b12c389fa..0000000000000 --- a/docs/src/modules/utils/findPages.js +++ /dev/null @@ -1,6 +0,0 @@ -import path from 'path'; -import { findPages } from 'docsx/src/modules/utils/find'; - -const pages = findPages({ front: true }, path.resolve(__dirname, '../pages/api-docs')); - -export default pages; diff --git a/docs/tsconfig.json b/docs/tsconfig.json index d5ad1e0aa5831..71d443e218e69 100644 --- a/docs/tsconfig.json +++ b/docs/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "../tsconfig.json", "compilerOptions": { + "allowJs": true, "isolatedModules": true, /* files are emitted by babel */ "noEmit": true, @@ -14,7 +15,7 @@ "pages/**/*.ts*", "data/**/*", "src/modules/components/**/*", - "next.config.js", + "next.config.mjs", "../node_modules/@mui/material/themeCssVarsAugmentation", "../node_modules/dayjs/plugin/utc.d.ts", "../node_modules/dayjs/plugin/timezone.d.ts", diff --git a/scripts/l10n.ts b/scripts/l10n.ts index 6bb5e90d0bcac..94b2bbb98803c 100644 --- a/scripts/l10n.ts +++ b/scripts/l10n.ts @@ -9,7 +9,10 @@ import * as yargs from 'yargs'; import { Octokit } from '@octokit/rest'; import { retry } from '@octokit/plugin-retry'; import localeNames from './localeNames'; -import nextConfig from '../docs/next.config'; +import { + SOURCE_CODE_REPO as DOCS_SOURCE_CODE_REPO, + SOURCE_GITHUB_BRANCH as DOCS_SOURCE_GITHUB_BRANCH, +} from '../docs/constants'; const MyOctokit = Octokit.plugin(retry); @@ -344,7 +347,7 @@ const generateDocReport = async ( localeName, missingKeysCount: infoPerPackage[packageKey].missingKeys.length, totalKeysCount: baseTranslationsNumber[packageKey], - githubLink: `${nextConfig.env.SOURCE_CODE_REPO}/blob/${nextConfig.env.SOURCE_GITHUB_BRANCH}/${info.path}`, + githubLink: `${DOCS_SOURCE_CODE_REPO}/blob/${DOCS_SOURCE_GITHUB_BRANCH}/${info.path}`, }); }); diff --git a/yarn.lock b/yarn.lock index 1d61768874dcd..e279ef85ddb4d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3373,6 +3373,15 @@ resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.10.tgz#04ffa7f406ab628f7f7e97ca23e290cd8ab15efc" integrity sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA== +"@types/webpack-bundle-analyzer@^4.6.3": + version "4.6.3" + resolved "https://registry.yarnpkg.com/@types/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.6.3.tgz#53c26f21134ca2e5049fd2af4f2ffbf8dfe87b4f" + integrity sha512-XYU3m7oRb1tlE8YhwkKLi1xba2buNB9V4VkQtOVTfJuUm/413pE/UCMVcPDFFBwpzGkr9y1WbSEvdPjKVPt0gw== + dependencies: + "@types/node" "*" + tapable "^2.2.0" + webpack "^5" + "@types/ws@^7.4.7": version "7.4.7" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" @@ -14852,7 +14861,7 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.90.0: +webpack@^5, webpack@^5.90.0: version "5.90.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.90.0.tgz#313bfe16080d8b2fee6e29b6c986c0714ad4290e" integrity sha512-bdmyXRCXeeNIePv6R6tGPyy20aUobw4Zy8r0LUS2EWO+U+Ke/gYDgsCh7bl5rB6jPpr4r0SZa6dPxBxLooDT3w== From 57c6f9dcc43bbb5c284150fe40b6c4c60676f92b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Dudak?= <michal@dudak.me> Date: Fri, 2 Feb 2024 11:45:11 +0100 Subject: [PATCH 10/35] [code-infra] Integrate changes from Core's #40842 (#11801) --- babel.config.js | 2 - docs/babel.config.js | 1 - docs/package.json | 5 +- docs/scripts/createXTypeScriptProjects.ts | 2 +- docs/scripts/generateProptypes.ts | 7 +-- tsconfig.json | 2 - yarn.lock | 70 ++++++++++++----------- 7 files changed, 43 insertions(+), 46 deletions(-) diff --git a/babel.config.js b/babel.config.js index 1019a75c38100..45a9cc8bb34ff 100644 --- a/babel.config.js +++ b/babel.config.js @@ -21,11 +21,9 @@ const defaultAlias = { '@mui-internal/api-docs-builder': resolveAliasPath( './node_modules/@mui/monorepo/packages/api-docs-builder', ), - '@mui-internal/docs-utilities': '@mui/monorepo/packages/docs-utilities', '@mui-internal/test-utils': resolveAliasPath( './node_modules/@mui/monorepo/packages/test-utils/src', ), - 'typescript-to-proptypes': '@mui/monorepo/packages/typescript-to-proptypes/src', docs: resolveAliasPath('./node_modules/@mui/monorepo/docs'), test: resolveAliasPath('./test'), packages: resolveAliasPath('./packages'), diff --git a/docs/babel.config.js b/docs/babel.config.js index a32caeb7801f0..44face6ddf1ae 100644 --- a/docs/babel.config.js +++ b/docs/babel.config.js @@ -16,7 +16,6 @@ const alias = { '@mui/monorepo': '../node_modules/@mui/monorepo', '@mui/material-nextjs': '../node_modules/@mui/monorepo/packages/mui-material-nextjs/src', '@mui-internal/api-docs-builder': '../node_modules/@mui/monorepo/packages/api-docs-builder', - '@mui-internal/docs-utilities': '../node_modules/@mui/monorepo/packages/docs-utilities', docs: '../node_modules/@mui/monorepo/docs', docsx: './', }; diff --git a/docs/package.json b/docs/package.json index 2d44732f09703..baa9269d03f51 100644 --- a/docs/package.json +++ b/docs/package.json @@ -92,11 +92,12 @@ "devDependencies": { "@babel/plugin-transform-react-constant-elements": "^7.23.3", "@babel/preset-typescript": "^7.23.3", + "@mui-internal/docs-utils": "^1.0.0", + "@mui-internal/typescript-to-proptypes": "^1.0.2", "@types/doctrine": "^0.0.9", "@types/stylis": "^4.2.5", "@types/webpack-bundle-analyzer": "^4.6.3", "cpy-cli": "^5.0.0", - "gm": "^1.25.0", - "typescript-to-proptypes": "^2.2.1" + "gm": "^1.25.0" } } diff --git a/docs/scripts/createXTypeScriptProjects.ts b/docs/scripts/createXTypeScriptProjects.ts index 88de3ba970729..94239b95fe9a1 100644 --- a/docs/scripts/createXTypeScriptProjects.ts +++ b/docs/scripts/createXTypeScriptProjects.ts @@ -3,7 +3,7 @@ import { createTypeScriptProject, CreateTypeScriptProjectOptions, TypeScriptProject, -} from '@mui/monorepo/packages/api-docs-builder/utils/createTypeScriptProject'; +} from '@mui-internal/docs-utils'; import { getComponentFilesInFolder } from './utils'; const workspaceRoot = path.resolve(__dirname, '../../'); diff --git a/docs/scripts/generateProptypes.ts b/docs/scripts/generateProptypes.ts index 91a1704529075..63620878303cb 100644 --- a/docs/scripts/generateProptypes.ts +++ b/docs/scripts/generateProptypes.ts @@ -2,11 +2,8 @@ import * as yargs from 'yargs'; import * as path from 'path'; import * as fse from 'fs-extra'; import * as prettier from 'prettier'; -import { - getPropTypesFromFile, - injectPropTypesInFile, -} from '@mui/monorepo/packages/typescript-to-proptypes'; -import { fixBabelGeneratorIssues, fixLineEndings } from '@mui-internal/docs-utilities'; +import { getPropTypesFromFile, injectPropTypesInFile } from '@mui-internal/typescript-to-proptypes'; +import { fixBabelGeneratorIssues, fixLineEndings } from '@mui-internal/docs-utils'; import { createXTypeScriptProjects, XTypeScriptProject } from './createXTypeScriptProjects'; async function generateProptypes(project: XTypeScriptProject, sourceFile: string) { diff --git a/tsconfig.json b/tsconfig.json index 89e19bc68a580..b429ed81bc638 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,8 +32,6 @@ "@mui-internal/api-docs-builder/*": [ "./node_modules/@mui/monorepo/packages/api-docs-builder/*" ], - "@mui-internal/docs-utilities": ["./node_modules/@mui/monorepo/packages/docs-utilities"], - "@mui-internal/docs-utilities/*": ["./node_modules/@mui/monorepo/packages/docs-utilities/*"], "test/*": ["./test/*"], "docs/*": ["./node_modules/@mui/monorepo/docs"], "docsx/*": ["./docs/*"] diff --git a/yarn.lock b/yarn.lock index e279ef85ddb4d..e9095f8e43de4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -193,7 +193,7 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== -"@babel/core@^7.11.1", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.23.9", "@babel/core@^7.7.5": +"@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.23.7", "@babel/core@^7.23.9", "@babel/core@^7.7.5": version "7.23.9" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.9.tgz#b028820718000f267870822fec434820e9b1e4d1" integrity sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw== @@ -529,7 +529,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.10.4", "@babel/plugin-syntax-class-properties@^7.12.13": +"@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== @@ -592,7 +592,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.10.4", "@babel/plugin-syntax-jsx@^7.23.3": +"@babel/plugin-syntax-jsx@^7.23.3": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473" integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg== @@ -1318,7 +1318,7 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.11.0", "@babel/types@^7.2.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.4", "@babel/types@^7.23.6", "@babel/types@^7.23.9", "@babel/types@^7.4.4", "@babel/types@^7.6.1": +"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.4", "@babel/types@^7.23.6", "@babel/types@^7.23.9", "@babel/types@^7.4.4", "@babel/types@^7.6.1": version "7.23.9" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.9.tgz#1dd7b59a9a2b5c87f8b41e52770b5ecbf492e002" integrity sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q== @@ -1796,6 +1796,30 @@ react-test-renderer "^18.0.0" semver "^5.7.0" +"@mui-internal/docs-utils@1.0.0", "@mui-internal/docs-utils@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@mui-internal/docs-utils/-/docs-utils-1.0.0.tgz#b1cd8fafe00dca045896daa2977e26eb551b891a" + integrity sha512-TqbdoXrXAk9JhcsGjekriQVU6A0w7oo01CfTfm4mefcKT2Z+RhHeFzG4fJrugN718qLdolJKGMoD7f+u/yBSBw== + dependencies: + rimraf "^5.0.5" + typescript "^5.1.6" + +"@mui-internal/typescript-to-proptypes@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@mui-internal/typescript-to-proptypes/-/typescript-to-proptypes-1.0.2.tgz#93ccfe6f611ffc700e99570a34737842c6cc0c70" + integrity sha512-KpnPqY8MCQBHwmFMCZZxXwG3uREgMAbXKLBzcxlBhYxssZcYdsE/aImWE0B50QfVHBPjkNmt4dcI2UO2VEzS9w== + dependencies: + "@babel/core" "^7.23.7" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-jsx" "^7.23.3" + "@babel/plugin-syntax-typescript" "^7.23.3" + "@babel/types" "^7.23.6" + "@mui-internal/docs-utils" "1.0.0" + doctrine "^3.0.0" + lodash "^4.17.21" + typescript "^5.3.3" + uuid "^9.0.1" + "@mui/base@5.0.0-beta.34", "@mui/base@^5.0.0-beta.34": version "5.0.0-beta.34" resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.34.tgz#44b0f203250a6e3b2d810f37c9720d114182abd0" @@ -1868,7 +1892,7 @@ "@mui/monorepo@https://github.com/mui/material-ui.git#master": version "5.15.7" - resolved "https://github.com/mui/material-ui.git#19ff6ada02dafa827531653801a3b657d58047ba" + resolved "https://github.com/mui/material-ui.git#475e186f1e31d194e1d80621effa8a866411ec30" dependencies: "@googleapis/sheets" "^5.0.5" "@slack/bolt" "^3.17.1" @@ -7961,9 +7985,9 @@ gm@^1.25.0: debug "^3.1.0" google-auth-library@^9.0.0, google-auth-library@^9.5.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-9.6.0.tgz#47a20aad0a358e9798c2adc489a89f1938e9c3ff" - integrity sha512-bM/buCwCeYZjmnzGstwREu3BsnbmnuI064ZGur0NmHyXUxubWMJTCO9kxsyy4T6jdzacHJY3XQWHxX4D4Mc+EA== + version "9.5.0" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-9.5.0.tgz#fd97b78bc1512025b9c9ad3998c60e2d75b6137e" + integrity sha512-OUbP509lWVlZxuMY+Cgomw49VzZFP9myIcVeYEpeBlbXJbPC4R+K4BmO9hd3ciYM5QIwm5W1PODcKjqxtkye9Q== dependencies: base64-js "^1.3.0" ecdsa-sig-formatter "^1.0.11" @@ -10044,7 +10068,7 @@ lodash.upperfirst@4.3.1: resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" integrity sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg== -lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21: +lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -14255,7 +14279,7 @@ tslib@2.5.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== -tslib@^1.13.0, tslib@^1.8.1: +tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -14415,27 +14439,7 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -typescript-to-proptypes@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/typescript-to-proptypes/-/typescript-to-proptypes-2.2.1.tgz#45fd201f6526bc45da3c5c0faa3b00cc23707613" - integrity sha512-FxVo0Rcf/c6dmHxA1DlAmpxct+1SuuDyX3Rl8MkfQt//yvZCMhWOuWZvJ3aP0/5eZTYIb+DpPt7htTL6A1xK9A== - dependencies: - "@babel/core" "^7.11.1" - "@babel/plugin-syntax-class-properties" "^7.10.4" - "@babel/plugin-syntax-jsx" "^7.10.4" - "@babel/types" "^7.11.0" - doctrine "^3.0.0" - lodash "^4.17.14" - tslib "^1.13.0" - typescript "3.8.3" - uuid "^8.1.0" - -typescript@3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" - integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== - -"typescript@>=3 < 6", typescript@^5.3.3: +"typescript@>=3 < 6", typescript@^5.1.6, typescript@^5.3.3: version "5.3.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== @@ -14694,12 +14698,12 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@^8.1.0, uuid@^8.3.0, uuid@^8.3.2: +uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^9.0.0: +uuid@^9.0.0, uuid@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== From e50aae8ae87e63cf67a67b2da5ffad16d8cf9651 Mon Sep 17 00:00:00 2001 From: Olivier Tassinari <olivier.tassinari@gmail.com> Date: Sat, 3 Feb 2024 18:56:16 +0100 Subject: [PATCH 11/35] =?UTF-8?q?[docs]=20Avoid=20the=20use=20of=20MUI?= =?UTF-8?q?=C2=A0Core?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are moving with clear isolation between the product names. MUI Core is effectively Material UI and MUI System, so we might as well mention both. --- .../migration-data-grid-v4.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/data/migration/migration-data-grid-v4/migration-data-grid-v4.md b/docs/data/migration/migration-data-grid-v4/migration-data-grid-v4.md index 7ed8c4c3c7111..3f171622cafb2 100644 --- a/docs/data/migration/migration-data-grid-v4/migration-data-grid-v4.md +++ b/docs/data/migration/migration-data-grid-v4/migration-data-grid-v4.md @@ -9,22 +9,22 @@ productId: x-data-grid ## Introduction This is a reference guide for upgrading your site from MUI X v4 to v5. -MUI X v5 is fully compatible with MUI Core (includes Material UI) v5 and can be used with MUI Core v4 with some additional steps. +MUI X v5 is fully compatible with Material UI v5 and MUI System v5 and can be used with Material UI v4 and MUI System v4 with some additional steps. Most breaking changes are renaming of CSS classes or variables to improve the consistency of the data grid. ## Migrating MUI Core from v4 :::warning -We strongly recommend you [migrate MUI Core to v5](/material-ui/migration/migration-v4/) when using MUI X v5. +We strongly recommend you [migrate Material UI to v5](/material-ui/migration/migration-v4/) when using MUI X v5. However, this might not be possible, depending on the complexity of the application. -The alternative is to install MUI Core v5 and configure it to keep MUI Core v4 running alongside. +The alternative is to install Material UI v5 and configure it to keep Material UI v4 running alongside. ::: ### Using MUI Core v4 with v5 -Using MUI Core v4 with v5 can be achieved with the following steps: +Using Material UI v4 with v5 can be achieved with the following steps: -1. First, make sure you have MUI Core v5 installed. If not, install it with these [instructions](/material-ui/getting-started/installation/). +1. First, make sure you have Material UI v5 installed. If not, install it with these [instructions](/material-ui/getting-started/installation/). 1. Add a custom [`createGenerateClassName`](/system/styles/api/#creategenerateclassname-options-class-name-generator) to disable the generation of global class names in JSS. ```jsx @@ -40,7 +40,7 @@ const generateClassName = createGenerateClassName({ }); ``` -3. Create a v5 theme with the same customizations as the v4 theme. This has to be done as the theme is not shared between different MUI Core versions. +3. Create a v5 theme with the same customizations as the v4 theme. This has to be done as the theme is not shared between different Material UI versions. ```jsx import { createMuiTheme as createThemeV4 } from '@material-ui/core/styles'; @@ -87,7 +87,7 @@ export default function DataGridDemo() { } ``` -**Done!** Now, you can render any dependencies that rely on MUI Core v5 without upgrading from v4, and they will both run seamlessly alongside. +**Done!** Now, you can render any dependencies that rely on Material UI v5 without upgrading from v4, and they will both run seamlessly alongside. For example, the following interactive demo shows how these steps tie together with the data grid: {{"demo": "CoreV5WithCoreV4.js", "hideToolbar": true, "bg": true}} From 819539f3b89dc0a77900399b12ce3d5afbcd0588 Mon Sep 17 00:00:00 2001 From: Olivier Tassinari <olivier.tassinari@gmail.com> Date: Sun, 4 Feb 2024 22:21:18 +0100 Subject: [PATCH 12/35] [code-infra] Simplify bug reproduction (#11849) Signed-off-by: Olivier Tassinari <olivier.tassinari@gmail.com> Co-authored-by: Michel Engelen <32863416+michelengelen@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/1.bug.yml | 4 +--- .github/ISSUE_TEMPLATE/3.pro-support.yml | 5 +---- .github/ISSUE_TEMPLATE/4.premium-support.yml | 5 +---- .github/ISSUE_TEMPLATE/5.priority-support.yml | 5 +---- .../x-data-grid/package.json | 5 ++++- .../x-data-grid/public/index.html | 2 +- .../x-data-grid/src/demo.tsx | 6 +++--- .../x-data-grid/src/index.tsx | 2 +- .../x-data-grid/template.json | 0 .../x-data-grid/tsconfig.json | 0 docs/data/introduction/support/support.md | 19 +++++++++++++++++++ 11 files changed, 32 insertions(+), 21 deletions(-) rename {templates => bug-reproductions}/x-data-grid/package.json (80%) rename {templates => bug-reproductions}/x-data-grid/public/index.html (80%) rename {templates => bug-reproductions}/x-data-grid/src/demo.tsx (80%) rename {templates => bug-reproductions}/x-data-grid/src/index.tsx (82%) rename {templates => bug-reproductions}/x-data-grid/template.json (100%) rename {templates => bug-reproductions}/x-data-grid/tsconfig.json (100%) diff --git a/.github/ISSUE_TEMPLATE/1.bug.yml b/.github/ISSUE_TEMPLATE/1.bug.yml index 61517d69ed6e6..24e3b54a8b5a3 100644 --- a/.github/ISSUE_TEMPLATE/1.bug.yml +++ b/.github/ISSUE_TEMPLATE/1.bug.yml @@ -26,9 +26,7 @@ body: description: | **⚠️ Issues that we can't reproduce can't be fixed.** - If you don't have one, you can use one of these options: - - [DataGrid codesandbox template](https://codesandbox.io/s/github/mui/mui-x/tree/master/templates/x-data-grid?file=/src/demo.tsx) - - Fork any of the examples in our [documentation](https://mui.com/x/introduction/) by [clicking on the codesandbox or stackblitz icon](https://mui.com/static/docs/forking-an-example.png) + Please provide a link to a live example and an unambiguous set of steps to reproduce this bug. See our [documentation](https://mui.com/x/introduction/support/#bug-reproductions) on how to build a reproduction case. value: | Link to live example: (required) diff --git a/.github/ISSUE_TEMPLATE/3.pro-support.yml b/.github/ISSUE_TEMPLATE/3.pro-support.yml index 3e20ea94fc921..c3ef5d1a3e07c 100644 --- a/.github/ISSUE_TEMPLATE/3.pro-support.yml +++ b/.github/ISSUE_TEMPLATE/3.pro-support.yml @@ -36,10 +36,7 @@ body: attributes: label: The problem in depth description: | - **If applicable, please provide a live example to explain your problem.** - If you don't have one, you can use one of these options: - - [DataGrid codesandbox template](https://codesandbox.io/s/github/mui/mui-x/tree/master/templates/x-data-grid?file=/src/demo.tsx) - - Fork any of the examples in our [documentation](https://mui.com/x/introduction/) by [clicking on the codesandbox or stackblitz icon](https://mui.com/static/docs/forking-an-example.png) + Please provide a link to a live example and an unambiguous set of steps to reproduce this bug. See our [documentation](https://mui.com/x/introduction/support/#bug-reproductions) on how to build a reproduction case. - type: textarea attributes: label: Your environment diff --git a/.github/ISSUE_TEMPLATE/4.premium-support.yml b/.github/ISSUE_TEMPLATE/4.premium-support.yml index 106fabecf04d0..fb927c7619ebc 100644 --- a/.github/ISSUE_TEMPLATE/4.premium-support.yml +++ b/.github/ISSUE_TEMPLATE/4.premium-support.yml @@ -36,10 +36,7 @@ body: attributes: label: The problem in depth description: | - **If applicable, please provide a live example to explain your problem.** - If you don't have one, you can use one of these options: - - [DataGrid codesandbox template](https://codesandbox.io/s/github/mui/mui-x/tree/master/templates/x-data-grid?file=/src/demo.tsx) - - Fork any of the examples in our [documentation](https://mui.com/x/introduction/) by [clicking on the codesandbox or stackblitz icon](https://mui.com/static/docs/forking-an-example.png) + Please provide a link to a live example and an unambiguous set of steps to reproduce this bug. See our [documentation](https://mui.com/x/introduction/support/#bug-reproductions) on how to build a reproduction case. - type: textarea attributes: label: Your environment diff --git a/.github/ISSUE_TEMPLATE/5.priority-support.yml b/.github/ISSUE_TEMPLATE/5.priority-support.yml index d7f67770bd6c5..f902b8ed2f407 100644 --- a/.github/ISSUE_TEMPLATE/5.priority-support.yml +++ b/.github/ISSUE_TEMPLATE/5.priority-support.yml @@ -26,10 +26,7 @@ body: attributes: label: The problem in depth description: | - **If you're reporting a bug, please provide a live example for your report.** - If you don't have one, you can use one of these options: - - [DataGrid codesandbox template](https://codesandbox.io/s/github/mui/mui-x/tree/master/templates/x-data-grid?file=/src/demo.tsx) - - Fork any of the examples in our [documentation](https://mui.com/x/introduction/) by [clicking on the codesandbox or stackblitz icon](https://mui.com/static/docs/forking-an-example.png) + Please provide a link to a live example and an unambiguous set of steps to reproduce this bug. See our [documentation](https://mui.com/x/introduction/support/#bug-reproductions) on how to build a reproduction case. - type: textarea attributes: label: Your environment diff --git a/templates/x-data-grid/package.json b/bug-reproductions/x-data-grid/package.json similarity index 80% rename from templates/x-data-grid/package.json rename to bug-reproductions/x-data-grid/package.json index 569a43b6fb606..8178d76e1228b 100644 --- a/templates/x-data-grid/package.json +++ b/bug-reproductions/x-data-grid/package.json @@ -19,6 +19,9 @@ }, "main": "src/index.tsx", "scripts": { - "start": "react-scripts start" + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" } } diff --git a/templates/x-data-grid/public/index.html b/bug-reproductions/x-data-grid/public/index.html similarity index 80% rename from templates/x-data-grid/public/index.html rename to bug-reproductions/x-data-grid/public/index.html index 0a7ab2d3bbbca..80363f8fecc8e 100644 --- a/templates/x-data-grid/public/index.html +++ b/bug-reproductions/x-data-grid/public/index.html @@ -5,7 +5,7 @@ <!-- Fonts to support Material Design --> <link rel="stylesheet" - href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" + href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" /> <!-- Icons to support Material Design --> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> diff --git a/templates/x-data-grid/src/demo.tsx b/bug-reproductions/x-data-grid/src/demo.tsx similarity index 80% rename from templates/x-data-grid/src/demo.tsx rename to bug-reproductions/x-data-grid/src/demo.tsx index 10cc6a348fe17..5417a65f93e8b 100644 --- a/templates/x-data-grid/src/demo.tsx +++ b/bug-reproductions/x-data-grid/src/demo.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import { DataGridPro } from '@mui/x-data-grid-pro'; import { useDemoData } from '@mui/x-data-grid-generator'; +import { DataGrid } from '@mui/x-data-grid'; -export default function DataGridProDemo() { +export default function Demo() { const { data } = useDemoData({ dataSet: 'Commodity', rowLength: 100000, @@ -12,7 +12,7 @@ export default function DataGridProDemo() { return ( <Box sx={{ height: 520, width: '100%' }}> - <DataGridPro + <DataGrid {...data} loading={data.rows.length === 0} rowHeight={38} diff --git a/templates/x-data-grid/src/index.tsx b/bug-reproductions/x-data-grid/src/index.tsx similarity index 82% rename from templates/x-data-grid/src/index.tsx rename to bug-reproductions/x-data-grid/src/index.tsx index 2aaeca271daa3..863f9ac4a3c38 100644 --- a/templates/x-data-grid/src/index.tsx +++ b/bug-reproductions/x-data-grid/src/index.tsx @@ -3,7 +3,7 @@ import * as ReactDOM from 'react-dom/client'; import { StyledEngineProvider } from '@mui/material/styles'; import Demo from './demo'; -ReactDOM.createRoot(document.querySelector('#root')).render( +ReactDOM.createRoot(document.querySelector('#root')!).render( <React.StrictMode> <StyledEngineProvider injectFirst> <Demo /> diff --git a/templates/x-data-grid/template.json b/bug-reproductions/x-data-grid/template.json similarity index 100% rename from templates/x-data-grid/template.json rename to bug-reproductions/x-data-grid/template.json diff --git a/templates/x-data-grid/tsconfig.json b/bug-reproductions/x-data-grid/tsconfig.json similarity index 100% rename from templates/x-data-grid/tsconfig.json rename to bug-reproductions/x-data-grid/tsconfig.json diff --git a/docs/data/introduction/support/support.md b/docs/data/introduction/support/support.md index 5c1d49e2875b5..4884e04a003b2 100644 --- a/docs/data/introduction/support/support.md +++ b/docs/data/introduction/support/support.md @@ -21,6 +21,25 @@ If you think you've found a bug, or you have a new feature idea: - Please don't group multiple topics in one issue. - Please don't comment "+1" on an issue. It spams the maintainers and doesn't help move the issue forward. Use GitHub reactions instead (👍). +### Bug reproductions + +We require bug reports to be accompanied by a **minimal reproduction**. +It significantly increases the odds of fixing the problem. +You have a few possible options to provide it: + +- You can browse the documentation, find an example close to your use case, and then open it in a live editor: + [![Forking an example](https://mui.com/static/docs-infra/forking-an-example.png)](/x/react-date-pickers/getting-started/#render-your-first-component) + + - [Data Grid](/x/react-data-grid/#mit-version-free-forever) + - [Date Pickers](/x/react-date-pickers/getting-started/#render-your-first-component) + - [Charts](/x/react-charts/getting-started/#single-charts) + - [Tree View](/x/react-tree-view/#simpletreeview) + +- You can use a starter template to build a reproduction case with: + <!-- #default-branch-switch --> + - A minimal Data Grid [TypeScript template](https://stackblitz.com/github/mui/mui-x/tree/next/bug-reproductions/x-data-grid?file=src/index.tsx) + - A plain React [JavaScript](https://stackblitz.com/fork/github/stackblitz/starters/tree/main/react) or [TypeScript](https://stackblitz.com/fork/github/stackblitz/starters/tree/main/react-ts) template + ## Stack Overflow We use Stack Overflow for how-to questions. Answers are crowdsourced from expert developers in the MUI X community as well as MUI X maintainers. From 2faec7d336e46145dbce911bf93d4ab8be63aea1 Mon Sep 17 00:00:00 2001 From: Olivier Tassinari <olivier.tassinari@gmail.com> Date: Mon, 5 Feb 2024 01:15:53 +0100 Subject: [PATCH 13/35] [docs] Stable layout between light and dark mode --- docs/data/introduction/licensing/licensing.md | 4 ++-- docs/public/static/x/watermark-dark.png | Bin 37505 -> 37435 bytes docs/public/static/x/watermark-light.png | Bin 36119 -> 36017 bytes 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data/introduction/licensing/licensing.md b/docs/data/introduction/licensing/licensing.md index 2176ffb9e7b2a..538813258a901 100644 --- a/docs/data/introduction/licensing/licensing.md +++ b/docs/data/introduction/licensing/licensing.md @@ -256,10 +256,10 @@ This error indicates that your license key is missing. You might not be allowed The component will look something like this: <div class="only-light-mode"> - <img src="/static/x/watermark-light.png" width="1306" height="536" style="width: 653px; margin-bottom: 2rem;" alt="" loading="lazy"> + <img src="/static/x/watermark-light.png" width="1290" height="536" style="width: 645px; margin-bottom: 2rem;" alt="" loading="lazy"> </div> <div class="only-dark-mode"> - <img src="/static/x/watermark-dark.png" width="1290" height="548" style="width: 645px; margin-bottom: 2rem;" alt="" loading="lazy"> + <img src="/static/x/watermark-dark.png" width="1290" height="536" style="width: 645px; margin-bottom: 2rem;" alt="" loading="lazy"> </div> To solve the issue, you can check the [free trial conditions](#evaluation-trial-licenses), if you are eligible no actions are required. diff --git a/docs/public/static/x/watermark-dark.png b/docs/public/static/x/watermark-dark.png index 09c5dd851364c783dc8483df46b1b94f2407dc77..2275f8c25aa68954dc830125ae17f82bc76e7ef7 100644 GIT binary patch delta 112 zcmZo%%Cvh4(*$uo2@WO(28LB_Zh{O9lbANDPM*kT1QcLs{<C&{LBlo`rpXG1s*@cI dS&77)q8x?1yn^rMDBb`W<LT<>vd$@?2>|8n9{T_Q delta 230 zcmdnJgsE{U(*$uo6%Hl_28Nq<jmH@nCV6aBojkE#1t`FA_|5!V5=w8@9AVr5lwnBd zXJlYFAjizW&|u33<X7_miEk1>;*BAYxRDGbsHD(~ppkokPHwQ>=Q~NobJCI<$(|sZ Zi%(LjAoy*_9H2uOJYD@<);T3K0RT<@Id1>} diff --git a/docs/public/static/x/watermark-light.png b/docs/public/static/x/watermark-light.png index 49cc374b73390d5487eb0eb37b4378edbcdf21e9..53e19304d1e1f667a279fd9e54c8c8c8eebea1a8 100644 GIT binary patch literal 36017 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 literal 36119 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Μk&TTjy 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 OmwCGSxvX<aXaWG%Z{>IZ From bd4b7245537d364337b95e06fc21288db9f9fc74 Mon Sep 17 00:00:00 2001 From: Olivier Tassinari <olivier.tassinari@gmail.com> Date: Mon, 5 Feb 2024 01:20:37 +0100 Subject: [PATCH 14/35] [docs] Follow blank line convention with use client --- docs/data/introduction/licensing/licensing.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/data/introduction/licensing/licensing.md b/docs/data/introduction/licensing/licensing.md index 538813258a901..bb0d60c079c89 100644 --- a/docs/data/introduction/licensing/licensing.md +++ b/docs/data/introduction/licensing/licensing.md @@ -164,7 +164,6 @@ When using Next.js App Router, you have multiple options to install the license ```tsx 'use client'; - import { LicenseInfo } from '@mui/x-license-pro'; LicenseInfo.setLicenseKey('YOUR_LICENSE_KEY'); @@ -174,7 +173,6 @@ LicenseInfo.setLicenseKey('YOUR_LICENSE_KEY'); ```tsx 'use client'; - import { LicenseInfo } from '@mui/x-license-pro'; LicenseInfo.setLicenseKey('YOUR_LICENSE_KEY'); From 3c0590056d641db1d715f472ceb52ca851d14f05 Mon Sep 17 00:00:00 2001 From: Olivier Tassinari <olivier.tassinari@gmail.com> Date: Mon, 5 Feb 2024 03:00:35 +0100 Subject: [PATCH 15/35] [docs] Fix image size and dark mode --- docs/data/introduction/support/support.md | 9 ++++++++- .../docs-infra/forking-an-example-dark.png | Bin 0 -> 47567 bytes .../static/docs-infra/forking-an-example.png | Bin 0 -> 48222 bytes 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 docs/public/static/docs-infra/forking-an-example-dark.png create mode 100644 docs/public/static/docs-infra/forking-an-example.png diff --git a/docs/data/introduction/support/support.md b/docs/data/introduction/support/support.md index 4884e04a003b2..2763c082e4d7d 100644 --- a/docs/data/introduction/support/support.md +++ b/docs/data/introduction/support/support.md @@ -28,7 +28,14 @@ It significantly increases the odds of fixing the problem. You have a few possible options to provide it: - You can browse the documentation, find an example close to your use case, and then open it in a live editor: - [![Forking an example](https://mui.com/static/docs-infra/forking-an-example.png)](/x/react-date-pickers/getting-started/#render-your-first-component) + <a href="/x/react-date-pickers/getting-started/#render-your-first-component"> + <span class="only-light-mode"> + <img src="/static/docs-infra/forking-an-example.png" alt="Forking an example" loading="lazy" width="1548" height="606" style="display: block; max-width: 774px;"> + </span> + <span class="only-dark-mode"> + <img src="/static/docs-infra/forking-an-example-dark.png" alt="Forking an example" loading="lazy" width="1548" height="606" style="display: block; max-width: 774px;"> + </span> + </a> - [Data Grid](/x/react-data-grid/#mit-version-free-forever) - [Date Pickers](/x/react-date-pickers/getting-started/#render-your-first-component) diff --git a/docs/public/static/docs-infra/forking-an-example-dark.png b/docs/public/static/docs-infra/forking-an-example-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..1e388c6ec760324a6dd948603ed9b27ed6c0f339 GIT binary patch literal 47567 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 literal 0 HcmV?d00001 diff --git a/docs/public/static/docs-infra/forking-an-example.png b/docs/public/static/docs-infra/forking-an-example.png new file mode 100644 index 0000000000000000000000000000000000000000..d1a46bb379590bac20c7ae9a7f80a82571a01aa7 GIT binary patch literal 48222 zcmce-1zTG|*EWhvDUu+iXb8dGN|B-gQlL1cSc|)RafcKO?%v|=PLURhJ4K4SOL05t z^Stl(o$LI7lPlSKuGzC^X3d(l);%+K;3`UT_|GVwp`f7PzlA~7P*AX*qoAOD#6d&m zY<o2`qM)=fyoE|?c%U9E{)nPiAqwpp{v?vp?;smwW_HUk`RBRjp7WK6U#Q<?DK_#Q ze;5Yx>hJ*!K;BUP|GdWk`Z`HHMUg4>?Lpnjmy|+RDak~W%*-|^0{X8jOt!D7m^LB% z2d+-wFen(A<FBq^?K->sz~cUB_0ajVXe^CnVUmMMp@tQ&*3A{X{og{9w`i)l6IqSv z%T|qJRD}lzmNlYGTa8Zqg)y}7e--Z#%ASkU+;Y}GQRKU1peqt=F5Vx1IYWuXK|WmR zU#3fYk(Vvcbh!0BKL1=P!JLW%h>CooQdHN-1zm8@6E$9dVT>KREiZ}N9n;v`(Pn*G zN-LisL3Z$^*Y*ngFM^O$@r`oZg@*t09kymWF5N59RnJr`z<yKfeswqfd2z)>`0eZs zqtCok!5&v9m~IARY{lRFb6NQpC=LlgP^T`xPifKb<iuSC0n%9`1}31BlaeyvoKj0l zc2T~vqY*T8TDZ)VPcB8X9xIyr-qk}uD`b{tqgC;dO{Ye$#6>%<Tp|`&sFV!|CX< zLtgaSEwC)Hwi-pDY4^}jCWl{Su{#&(jW{p<)RzgJy)RKK_35h!SNhcE!4m$~6OT|U zdZBPM8<VaB#KK~UY^(YFg<AuRkXkHG@A^EMOX!?c-fSdmdvj2$Tj+n=km}Bhv`>{R zz-@ZDEE1#;@B*HY#3((J<#XHV`5;U51={=R86cXVcq>H*lJ?3tsn)1RHj<1bZ0#G{ z*TIxOCgvkqFM^5Ecf~D=+HMOJ(^(!-|Mk858ZYm;;%WVz1o<NOeSmQQ3H)!;E91+K z2W-FV6V-q9nl&8%4%s!)hfFZbyY2}9S;D|S2K$p8Zij><ajIX6u5C^Wejad<{8!ys zBQYs8w#?SPy-dfR#LJ8T1qb#MaO~0<Df2+%C^HbCi%UT8E55Tx7p&Te8k9+DJ(<fV z1AY^XZ0Mh)tF30s(ne2Iu{a|i{MOkKU;w+{DlkC``R3j47TYi<H%n;V12%yWTZ8AY z@E52j4jl>nKXPy_m#V+V=JyexQa}X*$`l&2x@nMa1r{j^wYIn&`>bsgdtK2=&~&>W zozh9Iq5#8wX{I&Wq^G37V#A4~{{3+1dS8C>3z3e!0mPcfbTr>=tPgFriq>YzRce#K zSDxzy8b1=lOJ>TvwvXP#>vwp&&K|W#ka6wL<P-9~w{poVovpy5%z;5+eItJ~pQ&;s zH_x~oEb5oPf8#yQuHLYySu(9tYbWh373e@91D3-1_d^a^KM!}rGu2VRc^f~!(KoIh zwkJ3=D!qY3N6hCo*go?$F&qp3C8v!)7(lnlrj=YsHl@3tdgJ5k8IH{PulUFTT4hFD zfdSDZ-*94K)V2-BQ|~gnT2yc`@@9xnJG^h6g~iw{wq0EQX$|j(8KNWSdQ7&c441g? zJ<&&EAn@$|29K(|Tj9-e=hJtUYduIeO7}FAa<+bp%jQx0T@fWEC7TT+C#TYVF;q@& z{rq#|@#2pvaj(bw+2iG(RoDqAk#5y$n;XThXH&c4Pf`xpvA-YB5=%d9ot~bu$UwUJ z?{3ZutARWZOYL5?#KiR8&<`Jem(JQ(-E^IBT`L=+zvji#rlmY6UvTg6en|5tHkqlQ zxLX)bZ<Lmn4ynAMCi%NFZd|rmIGVM-?BiPK`*0hAHO_uS(txKZl+Gwh(MOCoN^-by z<=aSj?~DM)y8atlsaTxbkxoV+3pm3i)rnd6`ua3}%xQD4p2wIefmvO$Lbt`{+uQg; zx-0-0`70xrcG-8-!#pe#jrPmiTzYyfdZc}qr;bGh!@BFPl<qMaAh8S~YrAIoX+;8h zw@hAFtj8&@Se&kNq`7!qP$Sqr(Wzfd?bc3}FMIr|A>HYh7a@NZ&+(zDSK~R)^p`|y zL^_sq0*^K4eX9dzg@#?TWWE{ET`(p>Sgs;^492&G_kyE*Hs@{HbM1HNag7G2zUX08 zLY|BAV-YzDM=vh74t2{L+c#Ko>K|Usd&mt<*@Ut;Zxn|Jv4~VTP9|-*y|P_meIem* z?kf4#X>`d4TiE?jwb^R;pcxNo#G3h-is?Lfjf5<R)YMApJYJ_0q}(J;&8q-_)Q^Tk zk>S}ap+fJ&*E-+YYGY``PkHUceb*o(3TydM1vIO&@n+>@T-u=sT@Q?e<kR?q1ddPI zj%;iiU9>Nqhwe<H^<7q047Hs%To2IHi<CP9P9%#wu206p$Jd><IBe$E<{OTK>$kp% zd#ov@zN%HJo+v2g)NTO3BC`n3dTS6CL)G&hw9H~d;Y#`H2UTs2IT{Xs%~Le%#_ptf zb&ybnWZUPcm%kgAK^IC!Pj>c`&P2ehV#&`QhE0hB(~UlToOJ*3KvJ>&%$I@@&>X9a z`2jLS59~E+vn#+z`&Yo9JWY}N7S1}*BmXq(`@D=(IS*_m-HQ9POG*LD)5izwh%gX{ zkf9GtUb-aNl<mD_)rlgcdvpbxfJU}z!|4N&K@0_-($l$^?{X5`n)=Q!Ob1Uq>@LOT zZ)N>t;Z_MBZGSguH=#-9=mDJIXDFBiyw7O`W=>S>k#)(49-k4g?t{sIBP=><jyBs< zyL`Tshs}6oxnIp+x!#s-xaCasW6rzotjz?XrMRYe5rtCWG0T8)n0KZSOn;L^{0uRA zR8_Y|1xHdFznki(^X9KI%hyx5>bb=-$kD(k<F<tzqVrAnFW=wWPZyv+!&@2W?F$Z@ z$v;NpZO{Ks@$#jB#}1AUX%SrtI?Z)ZG-#&CPs4#o4}@rTP5Jx#H2%Y*tgFu;Iet-{ z)Zh)?i_MnMr2yjm@&(r^mjIhjM0zBBl!wcQhaLn*Hy*XORUVlC%nRwl>TmPeFU7sg zS2teAd9OZgq@=z~N=;4u9D}^R#CA{loRoT#68hQ9aHr`g!XY@n=Ymx~N$34SI@cby zyZZaVz?w7lt-&QE6v5QTn2>T`awR;5r6PnpER~aw&<OiZLNX4Cw_<-zG&I>H|G6Ak zG}LQPwU-9NxnVknN{=h;6#y*Caf(yiFcN-ZWfa|wuNy?uec7As?p296cc1xa!EeqF zoIl;py9*10m@=J&T_rB0!RHoN{E)S;-dqEyv50UZ#q+<r6q;wRt-_!gTyx?h<hr(v z#6;XCI~86>5yWeeT^n9UJ~=3mz!v#_(+^oexKOir3O#hiBMZL|{QVSz;#p%ER1Tv? z3*)KaH_z_1P=Jna;@#uVnNZ$hF|jt!YdwnWAd1@bIFkoAorEAxFerZDB3crW<4x#8 z+B|uk#{SOgbtt9%ujSX%w!Pe;rg6_3BPFx^<PbPsnfmU_3%_$tk92^X^g8tZr~~2U zrp9=^3%)m}4VW*2{Z0$}F)dPGc@8yYV1RK;aJcqEp|=)S!Vs{6)QUbPoS7#-q3k<> zdR&9cTnz;sU{gHjCz@Zx6l)V)A9#_TSGufio-IeA^l0mQR&0LYK9+m4Q0RoH<4Px* zGhbYyjf=5KqaS2?3wdtonEpbS@2#n)$xu@?X#8E{B3Z4fG5G>l=e*X#KMBkJuY`Zg zj~`%mbV@PFhE|Ut*<tV3j~?6J0m3*vi3Q)6wxq#%ay1Wl_VFa7XIy7=u>g;4>AcSS z&C0X&*<}ak!g{k5$GX>@YhHPV(52tDF+Mo1dx8JN5`%z+HyZ{du^f_kXZbcuH7KVs z;hb&PHQj!8efn1$yhTQXkr7<&-Tu4`FC?6r*5a4kL~o`hQ}3jy?E)$lRcRsx5{E1b z-R6TfF}ZD}^LYE>%V<@p-*;Jk+C9#Z2LDr0vtAGq9N!DpiCRaR*?T=cZS4rc{$3L+ zf6I$bO0C@<ijNh)c?ur*P!v}sO*1g0U3*F=FZ9UW<@uVE2iB0xRl)QwYoPP}GdRwZ z+VKRFQd;B<XCl4-b471;EVADPK!HuD^@h6x*?=^-Zngt^;Bc^MB>ZMnc>6wymto-t zqdB7LJsxC2uJwuzV98tZT}2w4mi$Yo>0Bz!q8t+)?L}OB&9GZ*f9i*m88mpoXo~h( zcMt|9gQDR;B@Ho?GEa`;6}FOu=JBX>k1Pg5S(Ad@O~j{1tQWcX@PWv|iYC^az4v!} ze%RE&=Ktu7f<y>{hCW9dKy^U~L7QV<0Ic##dn?hw{|-h{o=UwuYJHMy*8Yz1G(X;R zYA8o7;@b@oE;#Rx5Kvsy><hpDyl*{JSV{a~<dGRojl0Sq#)wj>L<cza&-mOGlH41M zGA<C?kP%bt2Dd23fq+dCb#plC^sUWCmn~=CsNXgGA!yZe{)7J&Wvps<)sX(zB#)wl zB}@YyQnF$(8I-{#;(+jC=#n4g$70Af1*ulA(X&dg<K}SAi9Lrh1Dw}i^{sYnQvT9? zK1=$@LgV7{Y_8i|=as$HU$h<}@{fx<%YIMjguk*Pqfqf<9%flcco&PSEzz@iERtn! zBLUyljTtya`A&m%L%jl~#BcpfXIdT2t8=Q$-kffzv$NYk1mfv!j$;-X2pA=T1yU=A zrfYgQy~t&}tKkCf*@gyvBZQP<aSVYWfyX1PnQ4l{T7`)4!59HrbIuA3o5Is|zKH>} z5~upgTX#hKf|K+wR-v+jjX!<EgR=iMnP!AEm|Mk}ze~lLJC_y&pz9Ob)=yytg9h6- z88{3zMWcM#zLL7^g*~h(aG8ryt>4I3R(mty^=k}n6i=G<r$*f;|E7P51>IjpTIP6P z7P&Hd!dG@!ID>^Tm0$1yr7*GU7Y={+5Apyfq8o$ayA|mk7eNMwj*iIRxX^R!VF_;Z zVp>Q2n#HXewqoNicbZQtOuGFy&@7u~Uzo<F1>Ubp(Wmjg!1oMDe@RP`dj1ZDYVi+x zEY-WkwHudE`Ohe}o##iV_ZnB86xG(C4>~N|_<y1grpq`D_^a$wy~i1n3v&ox%F<0V zof507z*|92-Rr_|LV8?1SyG^a@BzJ@Y-+dpXy-{@vv~IfW5-rA)@x|0=Fi0`max~r ztKZWeevwh5=}#77kUS#ZhRp6s9i^>VjvQ94yNU;bdGUcZYTO6r|5`8S6$GfngHgwU z?$oQ^VInPCO&D`=*8c5Jec0?VhU#gd??t*ZFKzVb^`?Cw&_r?s+pB&^@nX00{!6K} zl<3j<NhUfxGU#bU<T$jB#_It0hUMdkJ4rbpV%|0p|K&Ir*VC$8YP}gEf?EPX&8I@L z#`g6!0K0?}mf%<Cg$G3C+R^N^7+*sq{S{{n>9V*c9o?>Uc?n!qWam>SWB)*okPn*o zv40o*g6kvi*tZlYWG?nk)5((W9koidVow*zV#kTiD9Gi^()`O!QejHLeWYqk<Zvgz zp)x;-6@uZQsHqi#x+a`F*?-9UO6lmiGbHC%Ff^kwfz7XkOHABwy7F@Ri9i^F^kn~u zIWP?;B8|o=(EZVs-&n87uecl&K8iMo$NA#rYRb;Y?~cf$OY!Tfq{b%RmY$3s;j&|; zl^sdA@P3Ba<EJ2&ZtjlEB3+^Togs_E{pH8pKX4ZHYwTZ#>ZNho)<4OxwhVuj$G(=3 zpqc3I`(i0vSo{k1HO5U@8mtEFZ)2W0Lf97Q+{Ky%qbm%8WWJ>%cCP%c^ADpT7s;KE z?>v?8X?aS7!VEsPzR-8E<d%7tbPv+B7kaVuh)qKQ1h+GrHY&o^OUPmdj3|@$AI70? z%^97X7AD9(0{exU{$MAVU6GUy5XKFc(8V?=5qsXIns3T|^xd2u(E5M7IAq{u6>wPA z>+qHt%mx|5w%!N3<u!C4)!K<t9oLVd(s77_zHYuF2hp73-StyBFT#Zo;Y5EVC__y` zMjAVx)-x=kOoC^ZJ@^vhsm)gWV%4p&9&pk5t^SfX_l&-|lCoe@a=({!l18EkWT0Y% zfCuoU&Ios{S___(6oezo_vm6r66li64U|+mhRHD9-R23tV`e`Ze98I?+5F{pCiH^l zqc|O%nh1k?4ms;r8M^Y!Z$`(2H>RqpiAA;X*+1SD3x#Pac`k&wb;J7Yw2&x>Q)gXq z?nncvZqmp9tL_ps;4bb1Hr(RP$huQFRD(WK4CmWH>>1S$rTW7jp384^9N_5&!ajQ0 z=#feSZZ-=H2rsLi#m&@Zze*F`o$z^gr{Wh$RKrkK1-_Fu3tj6Ohk+_*j3V2}vVoAD zMfOhi{+f^fG)yQ3u97;yWe6eueDC;jGtRm9<2YR`dz=nkY_xB&!LviCZFF6v<z=@y z{Y06tNw`>y?WwR||HxK+TxKn2^Zh{1H_K#v_yL6pOPr@mc3HZet>T9ko74>dRd)-f z8o;mT^*m9i@B^Si5(_@O<kMm4Bee@`<G-_7lME;$HZ!#A2kSLva4RfM1A)O?&(~0v zi^7blwSH3<M}@8H+PA7dy6Rh#UEGZZK*1I)g4`tbl;wsH5-erJ3+=E#-0(~X$wM`T ziI+EWyy4GYrtvr@N&dA8hEg3q`a_#8Lv6<G6lw5#_QD@6P~>J1Iv~IgkyEoPk)5%O zEDP&|v`@j6jIG)s&ojNce$*_z+V1YLSx~~O;rnsWHsTF4F?$6kVd6cGoDda$m@AfT zs1oF*IDd%<WBw^Z>kvxaFrSbe(qzrdry2?2}o4TT2Z_HKh`dmQLF-&C>3687Cx z{J!?A^Lf41-og(VXnb8wH-3vx*_+{neoP4{*Osena~Vcs(w|C81-!<uU9;??@l)eA zT_{7iyyt?fSzKX5z+%tm@-E`WJr~JSIwl`V?hrWW#)q+=l&HdtLcALE`L&!D@Cf&< zTSX`9)POAqUrGlgz`W_toT-Gn&XvQ7IRv8*^|?*?U(lmAa6rHU>?z=O1?fDbkv;SM zKRCiE(H~k@cdQHRy|W6u+`7J*Ss1i@uH*TlN`slt!+tR&Y#ooQW5_L#`)`=InMB^j zKK2`%oW)Apy3k5D=5i`yC&l6@9X=hoMjPx1FufSGA%r`gLAdw@(6R0g9jH3?LKr}5 zVt@&%@%b^JBa^q!DGfgRx;7j~NIC#7lV0eao9S1L>5q}7@+1Ime#pwFCM_2^-I%;# z;&)&2UidaL^Q$l`*U{|)QM5O`L>K!Xu*W$|6aanxY~Yp{IDXi%IiBs_R-7}^uq$-3 z(!&r8USfO2{igVF^+P^>2FL(EH*;$!Gh5v*G|^sk+j{xlca=WKS}|a!y3K=<_9>UG zvV&98T2>WTRXrLV&!5)>$BMp_y<q%83LNcrEDgR3t$~gc-@IPFj^@_n`Ki@$N-Ym) zMY>w+2*C(bHD->sjAwn*af1%W7*p1WosK)&=P%>xOUcFOqUf7Zo)I&%;+KX&6DuwW z;Qs?1_QIf>*cQcoAix@`{-u|hijI`c*!bPTy0R!kg6aifA0a-aAyYs3TIIF`c(HX| z=>Ct2RJ{S-ml6|ao(yf1@;O|lOfqn$+fT0b)K8DM?t>&-27(J@z;;s_B8uM&h<-ZN zXmjqma6QP#opR%EB`$h5EbSkNaJ@v2+V8_-N*@kUaCERfC%;R$r#9761emU#717>X zM0^Z}y8I<Pg!T#E%vo2o=JKo_<B=t>Ea&THG`LmJ05#j^MgBKL?P<dxuT@7Sz`a2o z8ADB%x0KRSf{Pvz5FF|IRdNx^n|C~S&kv#88R+nx#WG#JD+)-r*CyVl8?*aH3lR?D z8fK&!xE*z99i0SX;z^5ik(lH=9+)jifhRhoq-ecQB>9)=RJD<dbimpW7NOYRevLO2 z%j5n~Fa;M=5|?G+a0s>HVaImIDYlURFm4!)W8J-*?Om7iZg<dMmVHTB-QCh%m|Nbk zC|}fsMl|leVzoeg9KYEfUaKd}r1J6&KD=m<;6K5(S&smYl}LO6gmmMfH^s9GD}*p` zwOz-JXDv1e(AmMUV|8E9L>Gs}0oYId|KMeuF*q?efdD8!EF5id1}Cno6tj5C$!rYy z>%c`IYI;saqh&>Vdip~cPO0%o!oYixdQ--(tnqM;nZe4oc>r=b*~@RR{N2#}^H}cg zwyqr;A$2e(F)&t+Y+$!}`y)3_U>A}0)ta)tU(fKckhf3sreTj<XkDb@&#<tl0~uJa ze<w!5g7Z6Fg4ke&)|hcNPzu<6dgOUI1yHkgewGm4?~eEX5lrejX5c2uZj<+VyEDNj z2d;y6-EfAp5E5p*;It6!btQhyz4aT>Z$RY6Z>n)}D%&UvgWN^Dl}@T1Z3jUTq!3g^ zO8BPa>pzu;PJc4;4_8k*!8CqnT5S$!(s8I=MsB@ZdoFLh?i46DxV4{vbE-_2TRS4A zeDt}8f4BnC9Vx5E9lYfC<U_$CuguTN>_q~s{;uXh4n!;NS2naD#j^OD;^;)tXa(E< zk^C_!yW5dHXOB*Gy41%VG>*)niw_jq&8_^m&_fDV?>+44FjRv7v`@g4C!@0<bnv{j zH+q^79;w5czw>-sRgy^Tij)-|$-OHlzQFo86&{=4dhTFjf?Bl=LF-p!TVLr#?D#$1 zW!IrE8>Lf6nlRXOi&vbzc)Z{4oWg;d(4H#63E#dER=J<K%J$x~{QO;6>`;-he{3`R z>E3+nn~3%0A`v_RUucdlmM+c$L&L|zBjCM%`YX6vWxSG*ejc%CjFiyBR+;mr-Adtz z4hi^Ox|sS1Hgnx#TOXBsUdG!`97J*KkrN&|41E_w5F;wLsp`KQ&tlC+(m0+6C2Zo$ z<S*YY#i)tB*Wi_Zh8tHqSyK`Qovyh269B!x9_WE}8|+yB4^%AIX#{|4&w8FD%tQMP z%zrbu*}x?7G)v#FUdFKs$G`fnki@>4ZE_aNP7FfilqVj*Wy#0t!;HzHlW5YO_VHRW zNf?!V#o8cyO!Xy?G*mc|Cc4v>BU46XRB4%MJPXzxwF4~bHyRy<S0e)yg&^=7g6IQN zq9O*)%9~gI#i};2v|m$}e39s4NMMDY(7VZc^3I9>x8RV`ce3scq$>)2Ey<f(7OO|^ zI$7R0xZlhFnt1WDW#9fE?rSD?>~29CYSag<X9gVkj#$Zak*T#!pDBgp7K0{C+Icve zPU4a{YJ0!!DQka3$)8eKYv@^d%5{m><aA98#PXy7@-UM_D8uK~I*#XE_x(G8qXM10 zVQ;dR)LQy$#$XLbxhqy}J8^^R*xA;R?d3=();aHv2YhqYRxx1WAh*KbH}ES{i57jr z^3&(d`Z2EmLExTGJ@1H86OW&qcO<}Wq54LBNU!ZS(y8j=c513skk_if+39o}nOfHc z{_b^9&18Tonm~#AL6A1uzWI=#naNF6Qw)Ok_AAiA!%*oMLV&Z%Mn}uF(51$bznogT zHAMhlao_8O%gThV*tuP?t^Jgp2;jM#zmkwrNv$&QL$ts`-}KSN+BQaRYur2D`l)C9 zu;L>EoY6L4Z91aAHCbx@=?Xmi7Ih<2+5R3ua`8D~(=w{kGIG>=we-2yh~}&wt;(om z9&nIxRxup9^sa|%k(?cHnQBDma}O^>D?yG!_53Uvyb2Jxt@|?n;eWPKD&D0(Va95A zxJ`})K>uS__@prC*FFq%jD9As8<KSKljvNuZ-az=Ph>F{Kd=$70_|V3KW@-bwB+3R zkTx&0yrijOz-?+0VM3rrI#Z?{-(qJPs#Dm5v=pOb4Tr(+x8@P$4f#i*)=Ltu5ihuK z<u|fWa#;hRkQ!CA_tzx`jq8fpjMQTz+H>oOo)|{s>THmz(hOa5hNR_>FNrnz-jDwM z7#ci~y?LuoZy>y$br<6Q8<W6@;C}A+<xj^dAn1XtvET1%0uTTo^BHF1hwvC>7LHfG zJTnwFKiT*)YRy5|=XbNeeA2sXVc+?9NDCCxMlf4dKzlBY<U+-J6M3K@0HvTCX<_1! z$VqaiSnKcc?^|Sehlm+U`wmib)|d2qBU^}~_7pwF=LKkkO2%b4Kswe$moDR<IRlJe zWpEFpWgPk7e4ZEk)Ue=lrNZ9BX{~b4Z-UF7x+3_d&qdGvqlCKoSseKH91~1mlm7)b zm9KSAm$q_I;J@)(XUgUk!P1R?e3Jn>=Q<x{<%KbSQF#O!1e2(|BkY^%lBDImBFhG} zLG0QOk?=KGf)X=NUDQ!VU-KOTRu{~MO3~D!n3k_V{aN)B_|MxqMc}(+Dxhf*_g3p} z(!xA1H0~K&AQUHw!>ee{Z$Db(nBWi!{`#u=6}H`eO>lW52tXik)2t!!@-}w!Z|D;e z9rn>SmJXeiJ}VM~Y53Mx0)TY9A>y8h{{Q;sh>0TEv*@bIiXSy;U7VQe;CLL(XYe9W zPmr|l;*P^;A?#vyX0`-VK&ir|4!39~%oq)bkQ@>5BVakVg+b~)FRVmg2lq5m^j14> zjR@8ZS_MF5v8lTGx{t@;Sw5FHLk^i=8`vsa-jf#MIDT?at-qkj(-dE7{Qe>giU|UE z9-K0XupWtAkI^S~))Q?8zmCwtfD^p{%DhSaXsj{%qt#Z=t13ltEm9f(asQU)SOC`h z=pcw2vuEKjykjEqjZpj^LEZD4bK65r;rbqr3rj-~!io&41n_IjKAS9tt9-2gg>g&E zRWJE#ZH9k((g8%i+g0&(B@IDJP=N3?>cA%rgshANEPM}_`x#8eHzU~XBfwfzW4VVX z?-$^>=f;W`jc%aZ8<OJ<`$}Q($>Y?tZZ}pgQ8?t!)zUH!IdVn1KU<l+o!~3@<BPZ@ zuFDQUuFweB&8HWT%&ALe!?NezZz%Tz<X?sFA{EBI1qy?vBKjp{K)6cTt8<E9g4tE- ze+bEw@~HlHU49@8b;|quoNfOf#7j8leOK^-=z|&Fhqg%p@7X_Bj9N--Q-3ahZzK24 zgGw;Uvx1>fxGp(C4Sfn2VS#utI^Ae}@%NHBOEG>Ou3td3z8gF)Z-}kUd=N#wR-c}Z zLAQ5-m@4|sQ_h2WpD$cZ@WaFs|BKR(Lpr_nZ3$-XEnCmqG2tF%P{aO+nNI$hZ>@94 zZO%xl3!DJjYHjrT=h~}Tc#JCy;#?Z1%DJ=8J7f&2Lfp9kgT24h{Y{A(l?pye&o1Kg zs4{`kvmDo%LV<Z2*j$9sScZgQncfUW+(hQgOap=^6O2>Xd-%wWy~zQ}$CZ-ryHTZA z^|Q+<yspBD+C&-JwcBU}GiCae18}`K<i3FOeehd;unFqw^9fqk=Osn2Hfgrca!8_$ z7%EISe^B{m#sg)f*@hxv6(%Q7C$u+Q()O&hI^}xJU+%8D!or+k&B?o2O50^BI%PdJ zN%%F;DwQfdhk_5nQUYhwSyKJWPpdIy*&5j5*JIpv@$O5XubvM6ghW}(kzlQ`Fb^qW zV(8-Je=sy8pNHXh3DfYM>+*Uz%@A|&>9M(YD90Gu{JK95IQyAjj)L;eJlTFIDZ@es zS5+@y!lFT!#VKiPxm1$mh0O;JAgOHgwEq?!IVwud+xACpqqGV4ncv=dO*u_XaYR2z z`@P}@w2ozD_*p`mZJL_4+X=;fJ^A?~kVKCQ=(ppt0}+v__G?FvIn(zoLrGTQm%r`E zdZ-~#{@uoRGx1NS+n-(%A-NwC5nCUU?UU^}_1Y&RJhQEx*B`K@9br_Y*gvZ`@1vMB zkDLFLRo{r63{X-YFm_&b$zcacVg(~vEMs|bc_MraeL}tVjsPz<(7cC(>l_I>et2;; zrLWliK}01V2!e*<|H^Jxd*?6x0NkyLx56TOc@6QJl_1iXuuRB?1)?T9Mc(mn)Q2xl z`?DZRl;J=9hcVDtnK1%-9}aW-vUHwSPkxzyN;}IW`qy87L{YUH-}U~n->Z9v>-Evj ztzFcAy^$Co&WC&VuavtlEuZwPo~|>Uxu8lRnKdeJNu20&77pEJ;Nn99sKS(~zN0KC zC`Ay8a>PIC3wKkC6!M1hRqYLl`1>~<6v(s$gKBO{ksC7QFP|4jR17J3flPxSI(q`8 z&ciQ}X_VsSV=b}Pe}(-uYI0Yh6=eUCh$3cH)e6FY1uVH$oh$!aRI!|MZ_y45nJK}l zZ#EclvXA~R{Ux}lE<ME4{67qwA_#BOf14inLpq#)Ndt!qHRQqAKju!3QZWe;X5xRi zL(}pKQD*CKBr^&{!Y3|v8hJ<gx(a;>`x^J3qD%5%x_^8p|3kBgH7&FM)ULsXj}`O- z(f{c6uQc1qU^L%)DRN@5{&`%PKfH0)I?8Hu*xzYR@2KC>UCeQ;{TW3m=!o?@wJw2( zg%PR5lC@mCS+igk0q+P(9gRAXoIi>$k&S4qZT%Th3v_s#AG#31bKeqn#(T4@bIxHm z)}%dJ*^jy|JNjLTT#thZS%o|lZ$eEJLRmt`q4VX-S^@G&%G<AhkaFx5)3rEREBUL9 zHa0a+6QeH3BM%o;-cEU<prlAc=;DY|l`(8cfgJVeiA5ID_k$xs+;1tQRb3wY<{Q3P z|1TA3xY~AMPB-1PmF>`LZ@RAalg#plMjT!;XAHRjS#0vv6GHyOipg}^MG^ZwX~D|j zdac1~Tu@ldGZAzaI-ajg2~s$63cPOj5RDmld|`;D$H~bl^3483>opELkvpOCT)v~+ z2dvL(0<UPtQ<}{BeatPe0*R#RRvG^w{zB8(;6_G9mHM5AYTggG!`j>5WfYR+Ha0fG z{pi>oCW;jZHOL;Hsqcteq?B#OWQ*aoqW<bHLu7%1^BGj-ch59cwVk&(NRqIZs*I*} zu7&PhNy7TkKHqN?AB;B{kDEd(ya@oKOuSVo;Y8huP*2WyLK@L-&4I5e0_I{*c!F4Q zNm(?swApECR_AD8bWu-|Sx3~#5FQ>}nS|8TVih3%%UAL<XN~qp-F6bZylh{$pFc!2 z9a#K&CHpoZ`%}G{{yo*>8Csz>sDcH)@p)QLw)Y2Av}^v`ib+^XTO91@b^M2SKvf{1 z>`L}C0R`{k7A6gnj^ej}o?Iz~{S`@kV9wL`x@1X!c6HJ1&)9dHy%bsO4C+N>@%`mm zE6HbAAZGx0oL~MKnBG6pB8ozDeD{`wA`?x7C^^FtlejBfSrHzkEDx&@VF<(WH}n4q z3g^r9t&#R{s3+J>DepRNCr^QzS{npseT9G%pb5}mVh^de(6`X=dInVqkG#irv#cfG z(T{Dhr)$G^D<{ly^RUFUfV!uM(W8&>UzR_;z3)caYfc`}r4u&PYu(Vjb<;2P51jj6 zQUs0ps{jFOj9P@Nm7=LI@_^RXFdLKf2AlO<!r-`mx*SN0*YRT&z}WNeUYNm?8eZ<d z9?Z?nA?Xsw)ApdBzmclO^9qTB(a7e@(MD#AK6L7%k(Nvy{I1_FC>O~!Ao2X-{Gx*W zQ?uKj0^4VulY>kWvme7`hjp@BT?9Djbw~RI?Uy;057uAoEXLu`=>~$3^6d!6!z!47 zKPBHnG$d~SQkpPLX1O1W?a&IowX^$2f1%a_%0Oko?aN({GOu+?hQFu)^_x6)ugLdJ zIJ4q*-1)7ikN$*>mOy^=kFS3VsELNe1<)c%Dab*4Jx8}y2Du$s5_;`bA?<koK=*&l z=pV1|qp^_hF`x66sqbXn+~SaD<7D%B>$@~YIiYQ@30b1N%8odk6U)13{T{ifE`4Uz z0x2X3>jjtg<=T%y4A)a+fNz`q$>Nc;QT&CB>raRAtY+yflKvz=eSd#*-i8@L!Eg1x z=|d_-{eErGMNe4FbB^V9cfT=&;S~FaI+H}JdSTbYYL^@NO_K$$RTcZyJcfz4Myk|J z`qfUZ#~tVcnnhAL?<$cz8~JXI+_EoUqO(LzJ>$vBBa%6l?JcpxA`iF!rs*~w<}l%r zah}?4kNokPm~OQ1k*XB;xm2t;m&S6v{i|K{#`3JLs>(r`zE3&htJ%64hqnGifqown zQOwy-4Rq8lE;RUTn-ud(jCRW?oK|KaE$%PF>#{Hld`iKv<7ulYIv=0i3DX{WFg-m$ z2@-IW$f5=JF?orZZKY0{@cl$(gE%18{9<qNlV>1=eBRyQv@a(6>!$NI7e+lXC1v4G z&fs3gXFSA>(YFDf3P)l_Y9!655n#a(mGk<`y7jDW3a>2|)a&W7Js}PEwec3!-pN~D zUwU*=0s#Op*XPS8qOli{HR*;)^N}sG6a{i2tG`XiiR7!=8dS01{E0f5^V3USmtgW| z?+JORnlgB-?K~L@ODrX&<=*kr!Y&3ht&wyfjS97THB(mC{W)ymf4novp~b(0L$~dB z1lLJN;tq(3Vm`Ca6}72?v!)8igtX#EOSOcPU-sxq_4>FR)3Z50HOu=|ai3JHB~tW@ zQ}Yd}7mj9-&g5K|&)0>G*X79L`)qw5u$^o1*(z(kuUBQj#-C;)2o1{37qgN2bo-au zLEn~e&x&L7OHhHc_dCi8OTpzf^S1LB>|~g2KHC)u6fR-l;(U#sfOI?0uY%U5GyFbX zXBy?&jZV{P-WXy2w1xf8fw*Ah#;_>z;ad6R@^D83u?aInJg{~C^_P5U&(k9i{i~P9 z71oU(6_Pmn7{2Ggqkgc?_XFc`gny8srr=Fw;4|?2VNMHbmRR4xnkt}<{COaB&W+<K zpb%K4+LKaEY=JK_TKH<NMNmvEYhV6*XcU!t{`)umKZ=?a5?khEu@U`UTd)103vLI^ z9v4`C$Pq{vu{R8<74`W0cN-gSHD&2=_eig_B(Tu_gb-C2Ni3bk{`0sor|?;NxYlfs z3kJOoO*4+IQt0QlQcw(YrqswLip(i9-nI*8ek6ZZZ~r8z*ykR8@%Pm!l~SfKpWy^a z0>!9pe^qR&+i@=6Cx*~zV`e>{0vMe}vfZ1D)c(1H1+RXBu94gxxxFcC4D-s5t&d!N z%j;aQuS){bQypN~-@Oa#4b8BVN%Nrw+dHK&22q=@ffOD(J#%q0W2i<P$}HBjDm2Sx zr+Gy=**AE}ubnUT0wwZLgTjhq_;=GX1k8OOSegozv&8C|(DDt~Jw=d=46K1u4Mx_a zfSp5}V8~U81=L;sd(2L*=K#J{s6X|!p{H`(H$`#tBk%MJiza``-OM*$S9d_F*4^S% zepAmp$>mEfy*5bQ1g5gKH0A)t1qP)pO$d5KDr?inLdo@<0tx&giA7RsV&c6B`cl0q z+ODYxwVj=y1Stvr7U{x@60t*-fVs5g>-tZNC|Osv*DusCRB_SvKmc`WKx`o+3jS$a zyN-}^HhHo6u`fLS?l0LZOv&$96fKr{Hz3iGMCCTy<0k*~KfOaAJBQ?u+}dJXd>@6o zOG=m}k_{L*6Kg0OUMxC_+@mIIapV>;f1S|b-P<#H6aIj0IL<bS)+JP)I@^&;!7^zU zr<+!9VVo~NLcxkHtR#9c$S5jgZe7g0p0i69=2dwzQoG3tdMX%3Xm%e!SSHT60_?_u zQq+4Pz-sG|hDDbNdiUA_jJUe^N6>G{SX7AT<Gswy!1M)Wt;wj@-xLDWl<=~cHS4Ho zu3N2A&1B)*xi(Fa_71vCddY}wD7Sz1fw%)a3Eo(o?I6j(cYrI^z@_{M&MG+DV0-S# zkjwRIOg*j9fM=7Xc|n#BwqfVID491VBW>T4FXDE@Ioo=5^fVa+E%Fml9zQ`wk0Qm8 z5?rfu<V-CJd2zU}y{qdD^HqJGX@~x+&L`}{=p-W|s<J(=pCeRYhy6o}FMaOIUzAoY zsXo|*b9BGyoHT51@nY}aJa!2Y+3f6h*vV3hK2JqceXdsdeH0}_=$vdSk4qO}F);Pg z!xuyX3BShwS+)Z2Q_c#UGJrDwDF3RFnnF^{x7Wm#%En@f4`>H()?1va@s2tHf|P2; zdDAe-<M#dMvUHOwKQJh9=hKKgo*ljMLbVt(m!%8+>9k-Uw;CyRfa%X)K=kCl^ep71 z*s!k*BD{?EhR1gY1Zb|wV;CHeN!n)DZU`J;*X~ADBS`(sE=9(Rl9A&2lB9DJV|g5x zplRgfEhFM@k|`#u3 AQ#g>Vos(mY&kX%iR_BTGANa^gsJzm2b@U>q&y`nQUrIM zjjJ(4rwHW<R^0ZF?N-j;F0*P>jC?5%3M1fS4rP3y%_Hf=i?ad}-3nu>VQA$v>JhaK zM_I-DMfDg$LiF{0Ce{RwSo_)wj46FXl7R9MRW`LZ8?SJ8HOGu9-`g!}g>yg|DSOf# zO*F^_v_Xc%aVsdmX3IRo_75FWKZ>%E3yuQA1dHJoe3Phfo~9z<U3N3GhuawtfJexU zTr}hx2K#HP+1!Zksqotacgqk{rx!46xO)L%3#317>5T?TrD`$v4)BOYB|@qNfc0iY z!-w&KQ|g-mrh=x^q{^w-v<7S@`X?%O^};T%X>vq(QhL3H=SI%%t1#Wl{xY>NTAKU7 z+k4#x@68-+!&LmHAOXQY<|cx*p~~O5U#O(pz41g3US&nWn-EN@XGOrm4xv~@{?xy# z9QnGiqRCEzhdx=IMv%tVt9mDnukwE}>+&gEZn>cRmFk=<CGo+<m|n)w(GjB53k2gL zEY=G+R9L)@&^%{`y+L$Fm#Thk?|u*P2Go$2vi^X4Mt~4Ss_|sO9SF>;P#H}ti!w^7 z%$L3vENUf@q-E|6QJ0|Dpy3-<5WxHcv@WhXz417VtlDd~tEVqCiX5FE9Yej^>X60< z3kg#c{VezY&fyUk3?XXAo|to6z)XXmy&G|L8?5w~1Eg<+frsbDJq5Pj2K_XUXEBkg z4>5jE+WIk((dlpes<%xPc=@`!_5Yf$jK$XPzgpuEMgHeug8!#AF7R;CSpuuoazRNM z5H#Ol&4qa1E<0?|?0mI!{(@8B@3#2mNVj&h?(W)+yO^1o+14?S^EFQhlJ5EMGj0=R z>=D^nLYys_x->p*J6P*g`u>}Ig}J%8KwQhTPntvInh=cmJ}Q2e)9WDU1u1UI(s@A4 z3AoJ_2zi!9AmSI6+1Wp`9eh!Zhx_*)-qh#juH>*mb)9txb};x`18{jGPQ0rced6E? z>8W_#rMvPrZN`v(*lFzkp6iK`NhBUiE~Ev&0(pqHw3upsr;XdJHW%R2b?%CO?@SOo zwD77sbfbEP2%_fjOt)?O5-akH)3^1uiTvNa{<YZ;*&G;mHnPW3XGgxz-tMcDRApf? zuai!!szBegs6@SrFsY32pu1Fg6_^gSsge=VD?;*0YmN8~cm(+TbwPqX<M&j$t3&{V z7STFIAXF4lEbC~RaSxsdT^AYa=<T=Rd}Y4+eQcJ;?7bc2eJ<l5)>$g`JL&^0wGlbc z`*wS}=)u_>CX$Ym?g(K2^>}xNM)2-dvd46ZrqQxZI^4I7BFG=>Zgd|E_K1->)d>q{ ze=FyYJ{_@61;$)A4y%e*!%S7gN0;%;!wzFV%-HW>uI;4J9eLY3u2dDn^l69h6~0e0 zeM4Z`St(&S-&cK5!an@~&9+1y1_RlITNOrcuWMzkFb-#tm7cPFt>>*30nqZII`o2D zg^E91Vw_Fu%-cm~Sp0cm*eB5HE<HHZ^NbC+(Y&ochMqo@w<$y37uor}^6B!Jp6QRz zXuArtNnqQDxAH>I>QV6Jx)a+Qv4f*|;!((O?JR}m)mwCQX$UN<yc`t_`G{srT+!GS z1)0;>WhZyk$1<)hAFQ@^nFnXsVg9*)y>r3`AO9>rsh2AtcU~8pAMgC`x1Se>vFAIT z09vpK%d$6k8RNV}Txu;G#~Z`di5CkB6Dg-yGl_pxhTTXx)`ZbdO>d_g8??u819ByE zYmwkS7zA~_kbPu)?3M#kE-k&48a^-!4@};QN(8A!Z`Yy0cMQO{J16uphacU!b%s3f zDJI(Ext!V;;g@?4ob-Uasr}=-vA*|}KJ`EduZgtZ>1JXFP8Bd)Z{)4ZAhrA8A=pi7 zfeZtV;^M-0emUfPd`oBb>s0Nuy6sUqMwG{qTU5`o`LjD?+m+1s0)E(63D#(>EOfAO ze2`#C(@V%ogaxYJ_^Oe7^?fL2a!h#rvS-UjZ^rFF1~%(_w@Zv3`TeR`v(<?<Gv&6h zL%d&W1_RX(!ND0SZYrA|0(GMB59hD2;Zqo-^|*rckdJ}}%O^j=$3e>M&mdqzDH3N} z-))yjnr0`jfWlryY?L12%))+e!v!<#XL1xo&d{uIGpiGWo7(V({ADvAl<+anK$bN* zoWPT^hE=oIACwYKRt9UDcwLD#37QfM2>z7i1_EX?u~-Y0wFk12Wcp8g4^X_0>MJ|e zlxsn%zVJ;pj2xolz82<-h3+?#Mc=kF!mkGV<jg)0OyM|ib4OpIh2kZUiFem)e(GzA zMS&wAYoR9guq3ca%QMJ8h1e@iee*h=7CBm;Q6WT87H|;%u9kg58Xh*WVABFp?NT7n zvZ^MyZ?{(a+B0purn^4=bnbVIj@RHPB1x6Q5j{aM&+%G2N2rfyvU)y*OEXq2S_-Zi z`}~D8qm0FMqY=ooP6)v)xvNVF`4UoLvotjy@bE*~u`146FB-^EX_ggTV-uy{Mf!tQ zTk?y%F9zJ<`}hU<38#ScqujOMw6fDn;$J+rBtPh!@f@<Sf~2*-Da`lUgjPMASzRIk zf6DkHRDWCZ(t)(&uCBQX-(r+}l?i&<`fU6XGH{;p6Eyx!i+6SYdn=SV*fwZk5H*ZS zk|1B%zBS+ROKC;xxcd@vN`c<(g(i8+v?rg3x50c#>_qNpJ$AD0Xu>0+D(<hIIy;eM zgFnAU={!efXUn{7TQfU~D*BQn^C<0Frbkh8Zf+~QXuNk~71J04(5y@mIE|onv7aRe znY|g;>fV7VLsxCbJ+h1Bdql9_7pJQewoM?Pv)YAoPF(_^kJ$n>iJz56yLofh<f2{# z2l8Z9(mjvU|JZN^80Ff2t$4tLS&unLTd1fM7R4V?q3U5hlE%NF4C}`=#b(i1>uVcc zc*Q);-^1`u0$fvZ!V=vZB*Zu>rll;QSAh*5JH+cHQik?rfnsN|8}l)7k3w2WzdD$_ zz`bo_*UHPHhofQ-=F$ePvif^>(ecEaK9q34_!I1biL$$Np-$d$<L{I`R(~WrJ(GQC zSvS_+B?o@W(1^wDm@|RL!Y`z2GJm3-Q~mtI-qter%g)G(@{fNzzg0t1J4syI9!)xE z(P6FL2!R3*1<RqlhrVaN(FCblU2NKqrV2Yg|J_K+n2H4lGcZy(5`D1@*>Ct`rj89K zS^RhnzSTs@!M^CpwHZij+@Y8K`=tVU$SF+wc_`($ThI!|qMR#Ls!9<68{kSohXWHj z>LtM%J2kgmmeXF=k8oX;zk5;TZE2r{2WkWkrU`_}=e2MM0T4A9SJToM4k<vH|NR3b znJ1QNG6|gmRr{X0r(J;D<_>;H5<`i`Jm4;$&vu<JkU?Y%<6eYk%P*J!(ocTk05?A? zStG&?czmGD>Q}c~9o3X$xQ=S4W~;AvGoYgJD=crqPB=gLSwAp35HbC(K(gz4gD2m$ zw7kSEKb-7E7qq!m60{|jbXc*#MBrQxxvnKu>P>pRMzy|8Fn9yv_{8L(Je#^rhp=$& zz2&Uzys72-=yz@#T>DKDEP96#1Ju@bHlRziBq!P$dw6ysWw0>cl9i3yra6OGmG;&3 z!=w%BJXZHiA&mWVLv}Kvc3`A!m{@BewMf&I&#g9-FiZ_ku2jF`vMrx5@3Tr4rs)mK zD;bUPu948tu4~i#E(Hgp1Hs7r`#>NyYmb<!YVRZB`lk63q^d7~PwuHbvl?+>sS<Cc z{98&u+raZu*D0Ct+AN;or}_(h22bN^GM+EwnGN1;h6OXL?@|+azXReWnHvd|+S<!T zcb<fQI)P$;9PKcf(q^x*Zfh-jawVXh$`X=%r)RmhL@=uvwaC|rR;NaVF4&kLihM6D zp<bG-P6oq(S!Vt^Pg7r(sS@MHK{Bm3Tf8irEK|I+ZsQJK(srqZe*v-r0OEts7x7y^ zjqE-ij!vp(mFs()GK^EGs-w}K{AjHc%})8e&(wTECRFeaCv*%U<zt$fHi6$g?o4#D z*E3A6hGStXMCY-=5(KY=VzU_xFt+gw7=O;1q=0ztrEVW?=do?tagl#dpn^gFCS{>K zPTV1V#Vt->Dh?1(hnXYY_hx%lF8g}x$jf=01u+2v;QG6u6HOZtYaO>fbzO=(C1l(o z_edjYQ3G7XbvjQMF1go^aez083yc+5ZjreOAy~r2cW=+QT?m^4%HGw@UX)}Pe=ru) zRB`(lRz8+HR+(r?L&rLLc@8|If}}N)z#uQ@Lr$DQs$52V&t{|%tihSc)6OnI-e`HB zpcmU3SiB%UG<fNB0AdgXXy8qyBGnYpxPC84M25P@UrlTeb}bb>e5RMY#mHsE8-F^} zn+e{D!3C~LvhvN3Q3|P3zhquuBR3>Y3Q=w2f2$A>!NT~ioZap>GDsW(<4a#toWMy` zn4#{o#b&76Uuel&6Y#UNE9Xj9Rq}rylRF25|2nA0gv0RFeS){OvZJ;&_IWztG65K{ zg#6y$2}|9k><&zl)pQcTWMiiS{zbD|EZ}N`EqPsy(|glvJ{_N%Ld!I8U6UI~HA^Zs zGV#$2<29q?E`1P`+;=?3$O`hi{!QeWm0wo$nGOEpFxjyu0tZuK8Jy;15lp6}m+_hq zXu3QiM?N=sGP>szGDQ>Nx)*yG?BZ0Ud;M{@Dl~r9A6ngA#_K4N0?`cCZ_FghQvky> zu>2<fkK(&;LiT(536}UP#c!|G8yDTShZ~pPx_eSjFd?~qfrAGP(iPx~g`=jhqh1M7 zx<F_(We%#4d=S(?vt_j_jP?@=40@2#0b8@hY`qYktZ(KWGWW8Vf4VMgoGy$Jz1$#z zxy<?yHekX*Lo%C`n3?R(5HA)Z>*S-kkF%v-1yWg=YQmL0GrKA#g-Myb|1Z^lO_)A| zSjENnKmLR=k@7x<f(7!Cqzod-XR49b2c`%ZgBgI?*xRzK^3$Yspg7MM%hV73K(uEl z#eqLj;RzSD1@wK20Em%H0ygI*KWxeY{?dW4-~Z^h#(0$?Pr|@<(6Xjg!|6(&;zmSS z$n@+t9AMXn?{-Z}mbn#_+@~?*0hm32ubC)tr-Tm(ZstB>YdYed(erehT5WW=19>sV zZrdT-IBFhF*gb{kj}=4sp+uf&$d_2&6~Iag#<v*05*)ldIaG2X;pYmG=f_);d7{*t za}@P92mb1WKu4;n7@{HTFCf5&(0wmN?XsJbcZWgMyw-hfjT2kaE6n8|9|?hU<+*7; zJr^*-W1nFt@#-U(yD0NTleUG*CG+~SJQ&}{YVGn!<sBRXMSi&;9nbzzvWVSl<j{z_ z^s4spXxJ$PL4!wju@D8G2w3|;pv&H_`D`0Y$Y`hp_&#Pn5NehcEIdP$uihr@z8Re5 z^0i<$5c=WzTEi0KOxT71B471zDw+2=-3vHQ!C3K=S6kTt$%YAnhI37wt>h`WFehby zr~H&THpUD4>Ph=uv52as@P}S)KLh7x|MF(Egq}88T8?%o>c#;@bqPf3s0Sbc-r#sk zgVzB_RVl;-&Y{68B5Ii_pJ#tAXMeSUGy`8aj~<Fi5kI^FQ8^Mo%7c}j{=&OMI%i)J zY)4OD_6&9*wHp3SCl3^RZ$tMsnXO<xB(DEwLKqTuX93yBSx7&|7M+YZPpdtCFJ<l= zHlu-n$qPkM5($d2;mj0jNYnp5O#m5CXWk{3MS)Kwh>5|112h@|fHF2kt)V|j*zhx# z1Vd|xin2enilBm-Wg?IsTAK!jeZ^sE1O2Gv{-pxxx8nYy^3984JJX16E^5k@UYip9 zjljCQnjWS>>@Les7KGY29zT7`rvn55+N#-OzI|5GMc}-k^J;YgfUPF>TO!;5F|zK} z<)o!En-XApP<XwlLy;UJJcq+-qcol)eIFqG)*srI=3x6c5&->MJJJkVYF_wwcN$Cc z(L=q)zmMe%fz;mXO^#;}sR<+kLWG%PK+qOP_p6XFwCl1D8@^?G^fq{;$4_??vPK8= zUqO>r{!Xf`47!`W2F1o>mwwmwQ3BKV-6oZau8|N4Os7<K*ycA8n#Spw3nKY9Z2u2; zZ`l_|)3gr<hu{kYw`GwaAxO~ROIRd0L4pMj?(V+06M}E>ke~sAy96f?+}#Q8{D<>8 zulv4VJfGm%7qGvbnVz2Ns-voUx{kJy03*Wn99c#IF@?WKsf_NFHSwLzfa0cVO=tG1 z&kveJeeZ9Mcur4{(?s(7iA*le)2VD<Ql5fJ(L^jeK#h38%V-w$Y^2ZSQ$BT|0@2U9 zWB9moKC{ud_TO7RD<lxocK|w%4%wJ39i*bm+$!?!9=ybge$|C|vDkErSj7HgPVJH* zHL<N6M2`anB}%{+E%GxOPZp!|+XT$1L9yaToDupPb$pPZ)3civGsE9#aMU&Oa0g~& z{%7tqa{6o!+NdO*Rg#Jb=XVT_41v!v`w*csmw>YHzwuxncA5!-CLPS|@ieD$(m01B z*o*To{oLlA#EJ`y?cY&Az>CUlq_R!TsP`!V;3+u_yrLt_{~fN((-fy%?6%n!Mx7t~ zqGhN4Gjk8<a!>;7Zgy${=ScaQO(wCpe$?_;*spaF=#o8$Tg+`EUOEuNS^Ig%SuAY8 zzeeN!kkcKc-`VkBM@51ZQqe-%+n{ECTRib~6w3@kDTxyn;DM;dDc?~^Q9Sh=%(ae< zxDH@iz+U0*&p;rwFx%msiQk|E;uaKkR~E-YPciQGr?7&TX-U&5u2-66ukEz#;eJuE z>W8xgn4PDnGw&VaDE=mYmZ_$$2MG~o#pcG#w{ZA|p)WM9ZV<rBCv3^h%t#>Fubfh1 z)_K1=7tEB`(IuH(`JH`{_^w(lF+l6j)whSSgeU{vGqLzot8{@}2C#bAp40bg5MFrG z4EFt23H_#$Y}a<Y&w`E&N3>Axa^C<e*0AJpP~LPRJH0-*OmyG<rEn5@yc#eD%%Pw# zJ3;_u{69k>K(PH~RZ)mzg=tsche7i7$GBdX-%%wB)R5y(+a_6no{QTDXJ$J8B9EC= zyW@7Vto|838|4pG#PJ(&U>>*Txc$+OPH!&IMe4;HhZ&p8jT-taZt?>Wol4+-EIw#( zmI~si$8$ehg4&$t%0Bj~2m1xiWh+B7a4h~(Dwl=GZ)iFd4U`-f!1#<^_fRq`{@~6; ziGA`FROcIxqC^X|TmYO$T|F*CzzH$Q|1|{#4nx-a-t=quuc~$4#{j7M)_B)~PEn>` zn>3)jw;;Avbjmk1*psg!O||V`NT;$S*_fHRBb(MZKEYtiuht!)Y%w(+9YcfX5EJlo zqmrnmFo`3m7@y6=Rb;B~O4R?dtD=JCvBRyS;K5Pqnor=$$IO8a18{NPcZEz!V)5)~ z=5{P-PW2~~T9Br@7~%d<&w^TNSW@9gRpi1=i9x@7{!i1-V*nZ;CPlP@lqHMEu5t-K zCl-D|eIKO3eHkcB^L*@*HxL?J;S_J8@VARPwUa4Z2-bP|ckshD(GWYKoN=wvTHG03 zJc|R^I6&TlgRTQ`2(Rs;j<vEjdC}onUdyJ;7u%AMTeYiCQlMS_U(06qxo4CuJiMQP z;sK3|xJvV9;)teV<#W6(?+v4`>BR^!l;1?n*Msv7ZZpH-yb3(Xpb8EyYLa$LOmc?q zKf2g|-)9Ms?JzCG3U%YE(#xO#u3V5$@VH|H(`M-Z;v0=^_X7ZeYuuemJ(8*l8Z6ZQ z&KC9D+%V`!z^x1Y;g$y`e;E=Sj8Nc!yZf*lqL8i+uI+V&Sgs%XJcP+sAq>;B?gcky zT3sZ?a0_?mW4FZ9(y3sbcvrK2x0)LGaJ3#1`W1!4YH{#u8E3-p6d_%JMP2Zr!H?yw zX?dT;3_#I-CK4|N(tv~4G8OXB`#(Q{>uMx%1U%RB$V4hnc>&8Kq1VMO`S@r%4hT8_ zeloZY)(grK>d3}G9%<k7d~t*pGs_AwQ2O=y=gX&bgqattrJ}jbXR^4LB=(zIAaLVq zV)nuxZ+I!oioEMdlz=FffeRxp=m$bs@mZzv$6EJRE){I2<kggqay_!kJhKN+-nC1; z0YYSh3<~pKUcdZif8MTbv-JE?Z@`euvQVZs5($K^R6G@6+{1fAm_|d~#<L6p5Nhhg zl}~}c+)%`OxamAPJE6Rh1|qri!K`N1*W7M9yeHn;%R7!`_&>o1hXk0_Jf1*i5?^2~ z{NS#YsQ&)=SYv+IYyZogASP)4$D+jbX|7Bb8O1;(XPI*WO)@Mpc{SV5VcLR@aN<-X zOT$Wk+vobWpY75J2{PvY%?enich-!j8tSEz;o<f=_VSEN0z3oE4Cc^FSk;4^8Y@p+ zG6d;@I3hX>8x8s<`!;)@QR70|HGs-^%v*~<5Hk?1JbjE-9K^xLu0iiVC?)inENo;! zxlCPXAQ39XkSOt;m7`~^-s7V^a)aV>8!JV0DzJ{wq@c2#R=N!&deAGB{dqHe(9202 zslQgv3Z3)2c}x>7%I3<JTeL;UxJ2H1QCRVMN^Fy_h|B|)5!q^e>6<JMF-=KVUp9-{ zPvu~Y-zb{#SsQUT+c(KWSTR7O1Ri?4s0N-A(nkV_eRpe9BOU&zdQk63<ak;(FHsVP z@J?+drM}Ogi^WVc`J#I;ER9n+@seYx>QcW|fkKwrZ-BGHPi0y)Clx;IxBIPj-3fI< zne0<>%6ur|XOYuTZ7N=}<o-oqH)?iMpnn7s{f@F)r#810UAz@m)q~(!%g<e!-rvsc zb%w-s32l)eU}6#!_T*IT=4;DI)(46!j=yg}M3sLkC)aDWU-^)<i=Qe4L&zwEm6fsm zs$}gu*!`j6=q57=Es}b2^QWcB+Ldw&?Hh8ZNUj_?s3#P+!O;GCOpld<7eutHdoQBZ zlE2_e(oyh$I0C}Bv0moAd(3HqoQSZ)8iYH$kUGCJ38~^B3D8_zUQa-ET#}7M12;8Q zJxc{Xyv-58=j2nx!(I+)ULiXMt^?AY=)Q3j2V)5ZPmgJC-$-WTK_)AFEtE+H7_>tq zc$bwR^fI@Nz&irMP?~6i-Ux)oy=gxm{$@W=zt()65>qZA{*<QYm4mrLcn!FJaIE9W zH}1bIs3auuYvX2WADY-+W4s&AT*-(NvuL&;fGh4H!-%i!p^qwVJk0=0CpW~0xGNIH zSq%H&zdpZAY`LA#(;brszr!!Rq9Xqx{9_hLSlrb<aaoQWBJ|KMpJ{Sk$ySDj<Z-;c zxn<Yf#D&a%{ZW~Oky)q4=q#Fl@q4!D@f6W-I>PTFoE-1Bn|HHrc6J-XId@3s?<@^P zDDcZ}*Qz*sx8c=qP2<9SJKomLFh_3QTxYs1Zj!HlRAA`npx<4%p+$FCHPg2=i3_J@ zqkM_XN7GCofblHYbzMWVYTr25TpfklBwPXN2|kBmcq|2AknAbQEG@49X7|op2!Y&T zcvNnYC(u{TB1d4X8a5aN1!hn%;H*j1num;TJHn|OHd%E#<~CAsnA6zo(~MpOpP)25 zb(5YwfQM|OOA=Dg3~+Fd)P8BUfix+n*-%D~-ffddAX37nsB)%ILAhh`?mL*Xfxpst z5T~^zZ>Q*s0NkO-*gv|Sb|r8L<l=AnM^cr##E}Am$aK3832d5(-)?x-2zUOv=&g9P zJye`%92h?<C%$QzC~#Kxa3vOQ%9=r36(Nb{N$BRS%(g(+(rH~~@UXvl(MXbKc^a{J z*CBSsGyPFjY+P0~CKQ-vvpB|61H3^Uk(z>Agn+ymE(G~9k;-6eM6}Qj8S+cT$l9ND zLu@P_b=%V?4ROo&wV+J0qo(ZU&gmLu-KMQ`qDWjhqbT+u?4_NNKyvi8Ljt#6>4;y) zG_aig+=4c7dsu$8#UtjI*(<;e5SQ>^YX7cnL#hu7<DrZCQ&teD+_^k~l+OBG<lV1} zo0`q#u5PRY+zv;EU;HSKnZ@u-(6vc>E`wq3CC-~DbP{0RsuiVrQ07?%L`UmgeBvGu ztp)SjT~58Sj<D~8saZVvyigseV*g_4DQdrO4OgsUO&j;Znzb#0sdeRr1K|u`(~g<P zLXlG&t8L&WFB04c<7LFb>*3cIW6FIVBl*a%YTwn`{g6Cc{{k<{Pw`IlUCkkMqu87r zn;VV~7Z3LjZegQM-!CGXKoG=XWshijSHeXgmo(Jch?W+DXrm+{Eymj<mQs^Bijkx+ znG$L95%Wr3jg_)jh{LoXnbhM#&3*l>bp#FoFb(8a74Ql{w|Gw=z9yz5d*m?%87F{5 z1d84$l(vPDcP`n8h{8-VD8Hr-eGH=B5<4yeQ^7w-6(!RV;yTr;Y-U}yvy<Z;L0Wy* zLe-|rag1Linrz4Dw{?VNM6~VsJ;XlD@qc|vsZs{-oET-nU7G)DE%`E)xAr=epzkt1 z7>JG)1d#J5<dICESba00XZ{Y3j44@d4mgyYoEj*gSK3DEwn5m~?N2Y`++ta-5?6EZ z?lyR5i?HavaFWsaQxg7t$Ab+TE$^_WMxsbAo7JZ4D6keh*MC%;mCihM_Y*lh`!J=I zSq1KxPCoe&&7aHsCU@F_#Jz;ZMa8!0&zCV<cP|?(1S%O{lt@%v=11zxO9+X#hMhA% zPi*8x_+-(|*gXaVyp<OEJu{i-PoC1ynHjy}T06eR{6PpQ$#s50%&TRtOA`>*(~XsX z(?W1d_b(m}_Ejm%YpJb5b8tY?K>ALK*I_?_rY!KO+}@vi0JdW3{5o`UwZhunY^=i- zRfe1y*=c*Fr5ukeoWSogHzu7MW`gg4CRWdeMxx$b_#4p1#=ij=wCy~wryRBU?us;! z8Q&hx%L+-_-aiU2XpH$Q7CjD8<P7$Q#IV2&Ii(pJS3md{MAxgUsLb*e;nnWUOOd~Z z-GnupYx-#fXuCRPY40x!t^7e$9=|Z-?K2i?`K+(;o)=|0^kss~auh2}?!|8V{jMV7 zIa|(vTCTCXa4jDD?C?4t&sl1RtcWskK9;xcQgJLa;h5bi-}h0&9t`Ikk8L|Nznd>D z_Zl0==InNvgRuxy4dKX&XPSFTE7Jc}x};#;uX|Hudr7K~FRh>pOvf9z^H`~T?S6R= z1By~Cope%QbSl)D7T;diU<O`Yf4WRh%8vs|!FI1v3d}GfpabTF`xEY<<1bocpL<e$ zA8r;m^^Q2gR$<{8ncX-<sGTXst6fFi+WITUmLPCI07Wh4FT{_Tii~0*5UlAok#XUu zVl$j^gH17JD^qKijJ#gsd4+;Ra7fh$cf4>8$p?089{$&dBaY;h_kI5Tks6~O)FV_k ziiMOqB1OC%PlC|VOUU^^sxGn(+iEP4y<DgajORZI-ti#k8&k(qan_mKhNhROMRDr6 zQomwk2_N_pc}Ma@U}L$mzYJOkI_1O0eMz{6){4D)KEme&?W;8Hx5CVrRqob`;aGIH zH!i}LCzELzSuU>Sw#z^s#-dZ{h!Msy988{Eu>Z~BMnK<{{B0Dz4`zy#G^BgCB*99~ z*VSx2G4tN8WjBHCd-GvHn8w^U4Zpj=vkS4?sr*y}w3krR+S)&MmZF!)F!dt0H|)&q z!-+~F-@K{UIU-0w&+(Rx6Oy{E2^Ay`z@6zGc(y!2LVM%WqPrpX{lD&$ns`RaStHu* z%SZzC8TypLbVgtTtO#*gu2<@aQ$XL411X~3^Sm_{Qq}Tdw{gh$(l#)Eb8uKSh&?dV zFY=(j`yd6G94vx!%Z`(PRjr5K*A}nJ3tvQSedMXP7u{IGC3MW7l^mOUtJGk+pkpk% zl*B9d=PULH7)N1(F~vf3<=E7RDAo#o-?;@TiYc)H5@w~sFytH@mQXE~Zg70~tyrO| z0K2M+W;o_9hw1vakG=4Ijml4q)IGh*_$rX&f`>$uE+g!Mmx6=N$4f|UU@5HX5~9B6 zxgG{<MuAxpaU@1|x78=qE=&FQIm%-vxldS7A|&E1K!hT2A@y)*u*07@g(2_3f@$~4 zv=;O!-Eb^SXBK*8`UvR4X$!-F`>&;#&R_4@v0M={@yHYOz;Z}gW4y+R!oWEDZ;D<U zbLC$NyjE9c@y7#(BT+&UvhdNw$(3;;pgiGqwtoo0ff&r$A%gFM1T8{yd2!`=wICZk zSdlzi5|^S!>+lJ*1D^}p*CwH0zZZrxnnu0Q_}=swFKjl+!v()^qOi97YLOu>gwy6E z!U)xl(0fsp*=Qs3k6cjxppmj<!K>8_#<8u@)#xG;uhn6L78Q&+0jJ3*DJ~Y!TQI`G zMKcr%cDx>#2Ictgn^q4Ckhy!q_P{DE-=0awTWq`k#uDb7Of==!b^l_EdMC1eSuC|Q z`g_n^h5x*Jzbl{v8bhdp&J_fVLKaZx4wn23!f%19d(Y2DlLXq<{5VTtwsm~tpvf4% z**??tb@C6qj)}pWEK~qJSkm);h0#x{aa#sQEZ<ST$ydr#kF8}j<bk+goZoKVtSZXc zb%s4gb9d5i?x$Dm+XW^X>iuZbPZs8f%3XQ29b!J~J>kd8akD*F9ShWJb#KuP$qu>* zgl*fNzJrM%lNRwtW_@_pL~Q-!4YlOcG=-HZxN-APEMmIVxm(dlDNAM%*@ci*+A&%4 z{E)P9huD2J`=lQz)HspOC(?7I|IAr}Ck~XAJi%kuO5GgFP;$oFBuFkC$a-ByvGf)o zebwE$gEEq=|Jbq|-L;as(vhce#3!VCtb%xO6IBuHxt<t4mKJlsBm9RPR#k;Y;(C2` zWph!qses++O7i5#Mt^eHfA~`W|MA!G6pAQWc#$&UtulCD-;%kwIFQov;BXPb^Y5o> zEeV>OmyDWXlG2&d2SvEH7-$T7SJbCnfd>cv^Fh~7kZ+eimIn{GGmJX^@bGR>X4Skm zY5KTh)-eC$X7hI9v6Kd;D61~3BWoyYCTs2Cov3ne;vB!_tLJxnve>d-*fROmrO9d* z4>-|Zg7If*iO^NP^C#3alQb15V*a}bwDh)T<1)7Uv86c7le#|0Xa)~xVz6dTJc%Lc zPkMncJ#gd+$Rxq^7l$;~t4%ocYl-M<gFixc|B%~KC79wVWiw7@2!W`djv8sZJf5AQ z0UD&s+!}Ps=4N}CbbJYV{LwsBSuNu2*x+;UsO{tiJ^uy4<2|EJd=Yu+s2N{m5LBsp zL-ae3r;?>PimD(FIWVaFw0Rz87JHIs`S|mu7V~_PabOG?{8y0Kg6m_!&r2Oy{`K4{ zV`;>?rBmH|EZ`^qQPxc~#tj@=_{`nCS<OJ9-Hy#8Epcl&;}T>QvH{t~p@P5DSZ#c4 z)Bj_pVP+nWJ>)azJN)eTZop4Zq84_R?~G-IP-GD4(|V$AlQq=9)mM8;csc0>CK+MO zLkFQzP>rU$1O}j*=LwY7zk=Ezvz$i@qQm~RBVY<>!jqsCh`c;BeA<T$<1Lymso;Pl zf$}5ekS9!IQ6MLp7)FX0pk%Ma9kW@W2~4RcL|AWJoCG8+a$wHF4^;4)h8p1Xk<ceh zs*xb41ZUgL4r!n_+}ZAd?{k40*kJl2m5t$Z3cSaA20wPt1|E<OA4!3gB)Np)(dvE= zNpZBY>?^?@jrNTU7P5e*7zp4h_E#a3B0(OBdL%Yp%IGEveS*sH$Wkm2`?ofCKIcid zLFD5hLv9b)HPVYV536{X^HZSYY4~;Z-S*_hUD$rD7~kUUi1*q22Q#x2Y~vTPKVciH z(>x?_Xb;+xC#QW<4JEeUzo(bATnLX0?7`PnJzO&T&9c>b5s$RcEKnP&r=zoO!<PXj zW@dJa$%>~d>JShvFqT^$=gLklcY6jhW@fG~^CzVULTR8Y;`G0kDYCeEs!|7?%zp-- z??J(%FM$WS=j80CFXg;-0opkfJN3IugYg1_$uXyoXe`|{6^kAiU{4)67gKotD37Nq zryjFSX=xWLwWAG0a40j<5q^WKf7{C^s4A!T=0nwTh@5tA`J{_m`8};Cb>{SPW4ba4 zd5|07_;?Gzcvwggx>3-C@#L~eTn3;7>j(o|MGz#Lkg#_M6oUW)v#_FPl>y7DCipUQ zKi*L31@sOEk(H}#AtHa2JKUFkh5`<emE8bZ1O%S78O<UVlZc{}@HytUJ+mi1+2dL9 z^C4Rl@H~8gQ*!=IW#j(Co*6(T*-;G?nVRA8@R+wPcRGwn^cb{KZtQtBami5>H@krw z^jiMZxp9waC7g&B4vEC@GMqUNZ_WAE)C-AhC7v!R5iSswrIQlzpC|ssUhBmwE;`nC zuT7^oX<2w@+-?wPJ@p(T_SbL~sL7L5=Gkj*@T?<rCA8T+gzyGaXWrLmaRr9h$_h^? zy8M^)S&CQ>l%M6za5kPk4O<X862tR#ci(KgXw(f<QwyCul;WZiGSg4BD}*oi!fm<H zO1O^D=!fM_cNkK4@`Fx=#Ypm*P5WuK=}!K{x`&M7GO)bAaCN=eT_lwTbuGhL{-HGn z_<_+<pte%P5+I3Flg4T?zCGuA();+a6oQVK{S2JcM955y67iAGJUtxUJCBm+yflC| za-;SwBP*PYD=No&zfpz9?p~Q#cI_M}TnY*MPv=#Sc)<jwOpVr=EMsNf)9dlOHS!qB z@(YoN4&1tm37A%cIOd#2^je$mBPV<NoTkg|p19QwN3+5~{1>U+OkCbv@PwkMc9Fp1 z!bM(woKolEIB1SFgb<(vb-X%WudlD)+1VLP=hp;DV*ZpnT7_pT-^Q(MR*(M<7Y~*l z&6LW|Rl#v#justRZo2(xky5&$Q1==VPqQV)XI%Q%$g{Kdnt0knT&UNZoA1``=WsMT zoFEPVP5)n>V@(tYQ^|7`P_jy$3_)^e9*R2xlmxw`j%G*;PXI`qVY2?(Z%qT}f(Zg? zHJ%eVkbwytgf7mAN4<qPYH!O8j;53!?2d=pGSE}gAeCS87~`qeIpJic5IDjMEcZyr zoUicq?b~&d7;51^Q&U^a4Uf;@nI81`2=DZf#J)+VK=Gtd!NXw{Sn<o*{e8md!tAOW zU;8q4Re>TkF3)m^<G(Gff0n9t+Eg5{f!G0L#7mpRVkJV^MbNSEgb44aIIEFe<vECx z`B`*&7Z?u4PN~y}q_x5{)gQCNeD&&wWn9x024>%mXuLR<BK7Z7Q@;0w@~>63Ce&{D zpN89gUtv9<0DswpP0*BnI!RYi+f41hGD1w?u$3Ps3~0SbZg^?X)!5$>@lpQw;eA3w zXP?)(&F}I7uP-y{LLYMXisB>B%B{5qlCMm3^GN)HO!r><sTCR*-lforzDS-(<7B?F zvA5%DcKos@0x^F98zj{JNfX&im4GQcl74PJ3y(gUHTXFP3H{74P0AG*V~6iy`yC?5 zZ|0k}?{*o|;=tK=D>im`m(XbHe|A;(rII#8qEk|^0jU;uz*|Uv<L*U+<zK;RpF7im zITn{nTk5SvzI3<#Q8mYv(uba;E;7O}NCclfx0(J82}fz`S;2u9<H?zccEj5ty>{xz z^TIHnZ*0H%2T0swZrw)9*LNM5cLy=Phy=y-dh;#J(U9rx>glR)HZ(1|WkmYmH&95B z^DjPZp5Gb4Jgz6{ltGNPH2z`4EwDP?@v($6Vf%-oXWax5$V^0;%}1P!fGWos{h=>u zl>C4Td><jw0EWJbG2u;8b+54{YJU#1U9tIsrJv7%-53%D21f4iFK=NDI}bBGCZ<|A z<@L_$U2)lmF~rhOXN>YEA1EJA*kvJ%aV8+5y`{mK600uBD?F=MzborNvUfJ|hlTP4 zpHSX2*E5_9jw@KDqayK>YQ3SrLniTK#KgqTKr}^-eGrTMaAMmS81-^eZ^z@iS(xx- z0<_%MUEXopjVwRrZ1ZLz4@C=WRw+}6Ga&Evr|_f9*z=<6UlF0*12<o&5?I<>ubx(- z7#w9juw8icEgW6$w7!$TZ2$BLKk5iaNb-+0QHRM*+v$GPhoQ1R4W1m98$S*Ku^DU% zwx({tzz+rAL<yXO^8dcOP3S#`u5&yB)XQkhNQS%|09D$QtnT}u4(z-ra45K}cvM8n z<sGK0!o}NPiFPn<#?bZMv*+Ai`2sI_W_NG8S>d<rDExn9Ov}Fhl%C7@8RuyNEr$d` zkH*GGS~Npl-m9gArze^3!XM5;XB~%W<kdkECcG}wo60C~eV=<Zkg5K|!UGjQi3UAx zd~>Z0NH%ZHLN;l$b=$#VJK=dGH7TZXU~I%Kju0|fBU14}Iy0!iA5>XY-&jpp8RvtR z1U+^Oa+c;Ub}D;Hc8~u&ym>3?AN1G`h<5+<hL|>(fQe|?yhbab_d~dNv$R%oI@42y z-U?6obVBy+oeX3AhwksLVW$}CMQzCBk>vfWiBMk#j-2{(3(T)Ns`{D@Hyy5U^pDh( zu962^QCR*HCT$5YB_p?q6?QA{j#97VQ16Jp&v2hT`?iQAXqunj3Xr%czkAL96}dmM zS{w5@T$vi3bp$^%*yY;$Ceo@_n1c2|mjg~5Jy>~@(*nh28DnU1k_Q{aZGR74X%kop zz51q#jp+>ASzbOElHp6aVws<C4UA2Jj$$avgVB<--)1hnR}MnzYWNuqMb}+3A0aHp z2;D}K)O2&{U#7g<9s540thY-h;ipZ0fP0#ZTxNnIQpy;A7G3u~r+(z+C{<CUEGQrk zvG-^i1PSx|qA_w4!2SV3f2Mu@8tYg+<A`QKI!=O`fnw@eh0-JgG&rse!?BuhI8K&7 zLCenJj2pq9=yw}I>V|Mx(AAG%XC6_CNHgaGY`xM+t4@XI<loeRtXmYfkDY}hkBFaL zHcwc_4stkIpps+#%db|~&BZBlvXI9B-PE%>RJ<mfoKCpbXkgA7iQ2^8Fb$+bq6%{H zTegftGEi#Ma6U-LI<8ItB;+SfLZDG!9j70}q?THj&apU5Fqq9eC?uyoA<+i`FoxUy zXM%-<G@sMcTDAj)3ay60QbMWN?FX4K#r{ol=U}S+an~8gjqf&{q%O_EHpOJ!Lr$@V zm+ccm4t>>Bj!$Fr&MoQ|K0ye>Qxw+Xpy4a9M<<eZ{1n6nh-YzXrI1iM6&mB%Yawf| z_;lmE{za78%-GzI*Pb;|tThfW@WAl=U~8V9(sSVT|5qLEFJ`Ne1kF|Dsq;;xN^J_F z%AmI1DGr%}pbvePZv7v?&Kua?iC<`6(vK5a_tfUJ+CP^A%T%P3P<ECV&wL|m%r$^v z6k(Y75SLgi^Yx?Kt{x4(@qPMEecMe%OXrG|5stvi;DEdC)vmG6<U}XydxVX2WvMW* zX9FtXKG%74=lr|IUl&+GFFaiGeZsQ1HDOD&X}u;6mQRX>AX-U<jwS-Z2|^06{zr=e zzEUFEWx=S=4%cePt9*QLexd9lvo(u3rnb-5aN@}Z&k;45u-B27qpPLR*_Vs964qP4 z<a5K0gARVXWYO&Z>e|qPOfG()!J~zr-%n#&TYQZDhwR1O7wkccT;<9H7B>>Iwa9Nc zR1rw`idDWCYl@vwf_l+gJ>+c-d(#Ol*R9$Km^Yub%_S&*vP$h1nq6IcXGzG2yTd=6 zy=yeGOEG8l$ZiO(o%x-kqcb=r->7ORdpcV%hhncOkI_pN^%f+30qsitXZwjq-Bt$u z_^~|~u@zr`VcKxsQ+BS7E6DCC!*Tbn946$+`b@Uk`7MldbxMHt9KvH6(_(4%0qxIc zZTaXpZ(=(5In}@&OKF?K1srb=+jgQJ4-;)?X-ie^yKQ!T9)vMI0h2Y(3&92~a1PSf zD@tYPYoFNi)??|RhA9$C>)1@0BO~L1`x2n>7()rrUO$H^sy&wMDgoPi4md(AXh`U- z4c51SQ|25Y)$1RJc_{36RV1p?8q18MZoiT7ib`EiHSPmwRpk(ufRO?<>X`Jm(b3I+ z*pujyLq0P}eBLT0_fm4xDCku5R*v^L!O-jE2Og+c2dC;?9X_7LLN;^e+0C8;_-kW4 z!}D%>xHCp5#_q=6ZYK5IzCa}}W4vwDg4sa{B%XhbXD&|fz|Y_Z^T`5>ThO-<9rvTt zgBu}34R%>#k0oo_U{sbc$hAqvd(iq7;9gwEon1GjI!-OQy*Y*CK(gQL);6_gCW&=H zxpznyr3;{1NWG3y(oim&Y_Qlr!7or4FWIXhCA$`|A`9O83<*`+bi!|KPh67ZVQowm zo1_%%qKDI=QDtvn61%EY{Q$$j69Kv61yMr%E=@(y-#m=*tmz?xqq-fn&e31mT<_(% zr`Pi*s74c5j$69`I}i<ui5qot?vH<OQmTACZ*XcarE>M4TRVSSNiVkhIT`AoP=pD% zHlXG{m_QC3M!)k;_Vm5!5jPPDOQX^71BWcHsl$P`J?%0hp<K$;N;h@=eZ_(mm5X<I zl*KO)@ykG*9X#1QQbxT}8T~inQJG;1(R+*2<aN^?gQNR(!8B}eb@$j9X#8`W3~h>H z3Dyjs2$vV-{pi!V*nGzJ4EVab2`oE2TbPGeZk^@s(O1;H?pY6X7Lm?Bu{7e8wPx6_ zI~qh}K|e(Z{{iKHqF3oe=yPSG1kCR}B3ClKw_=^;58*<i$$ya!SL2}H&9*+4@R+0s zeLYw5;-cnLQ}U>1QejVk)#f^CUZS#GobBATd)7e40uYi@D*CAel3%HMZu$#|w`={L zT1?%Q>4bd!pKjr;`jr0`OX1boYzJ@S-k*BbTD=7!$sx3W*!v&VOM)(Ag9LF@tgNh} z5_(lGnbzCTrh4WC$!4SBA3jKnXZ0Th{hSEoy29ds(~0_y-Nb(}d@BxLX`vixkJ|iz z!D4N5P@8*RBt>AT{g&SZ1dz0C8F9Jc;2ja;<AzB|e6l9iBJ*k5{$PNy*2~Mg!2pj# zBhm&f&uKBL0I6GDS!H}fReCn2S>4>4WsSy@hWcl+Trqb`$&iSb_71X$-eJRDD*o5p z1*y(s+1X;r>r)@MpVS%=%Z`r+4&KYZ1uch-FT=s9jEF}C_~(&q0k|uB#a0hFj!fRV zZkxj19?HFbviFMV=>U!}Ha=Tv+P9W2GE6qOA?`@jv!>e~Iqb3b$shjA+^;N18Ikd5 z(q?;_1XGDI&=n|vGY7^HLiQIAK}e$*IXw!NI5ALPHP@Ng;)WDrpt6a7{9s9w0baBJ zyBpF;y&}N>Le_*?R)e<ne)qxc;{<UNqxWS7yMHOw-S=PdDuAZ6c0u4^v7mzyu&P+0 z>-TK%@0kMOHV*hH2U7JEhmY)<KCtNQ5fcE6Bb3BsRH0-EgsA?ub|HJWVmP#+nYG}i z#rs3%%;<&4+je$}WK(VfMaj!EQ(i!ck#}`Ve-i!ar4z$E#~6|%PO~d8Q<6wF(5oe5 zO9o;QDZ#Y?&Z_k>u?o`fH7Ur&6XF))o=ZL3nk~@9oi4R4a<5S9%T4Z`(aYHdPHo(` zbaa6bof^f%b4KCwFQ4$PJLi2bexjv9&l&wE-p98hTcPlTw@K^BU4|F}adt{lA+17j zaUyv?VIAtkl^jT#y6zK1<<xwHdP^bdOF^!RxlV4*4=wB2ut_O7#CQ{DB(f3d9bCTq zx*5n0{U03_=07q0iaY|yZtJx{^zm(_Zye%b1z8^Q+2L#04y!<{^x2_8)ZygGtZp4# z8`Nf-W7maiVf*)#>L%cWyEGLv4!WqANX4DCY1?u$CjcQ-4I8+Aj&bR#{`{%I(sLZL zxh)jZR7k`<PJPFa%==osmPl_#b{AqaDs6Y!;J6kF2u9KDSUhx8GXo$q`46tdz0QTm z1#u@q!^b;1_OJ4!?^>pUXN9m66`Jz;KMx`xa$2%^a;@PF<QO}Z9#5Ho@F3k8i&9~d zl44cQwm`F%T96*^vyP+i2<34xFP|)3AF<h9E`WS!E~o0evTH*8q3siw?^E0R(4Jx4 z5tXbrUDJ`uvX5h0z7J@N7PYUCMQjZlZh0QjolKbA_|J$*2UM3HCBQbpXV$W)|AWJr ze#Vi?aYZD=??AZMoj)Q|l6!f~Y{i98UiaUM<=E9%%O_8KYK|})mN*P?tI(3g`JJM} zTwm$fJrHC{0Hgq7O5hJrQiahUwOkF|T%JPF^)ux(nY%R!vTL;3Xy4ADdNS9^oG6K$ za{<Gt4ktcAhDf-)Uisg-jT@39SiRcDYkXj2ZBg?IP!*r&%C{0RYtIC`f7I?~)j;1( zg?wze(LL0j_%x4!f|e~S-)5LLSrOW=tGQFm|4mX|%NWxQPIM;6-w0;oM{sGne7)Hn zSIn-}JX+@Sm(*#{6KYkhe2sypY0er`NJC-P6qzC%QEVlF<@EW1XA94VIcQF)HE8?A z!y1hQ>N5!V3xSX60Xe&{jhI8`&bj8Et<2JPBHodDHv}$zS_xHr6x&l&!2dqtaW141 zH=Y9?LDKt8932DM)F|iW_=ei|)_4L{0XC1}k@i=sJl=HAsM?r<wZCng-HhyBNbJPN zUz!u5;P%!~J$!ZTa_r_nX(U}dxo(U-r%X#W&yfO{c^X1n6FPlt@83#CJl)~?LZh6O zif;wa>M2~lhx;u>Jm91#8ZIdp4y^4aOI9PhasRJ}c>XjA`kX)y#6^aK&hX~3vvPng z(gUn70K|=tjkROZ1hpBi5na;fLs&ol4_L%E&=E4Kd;kt9gMRiuvhn<@z$;R+dAPu# zxi-U>EbwY(1Y}3_f3Lz|f&Y35+=-De2g3U382(YI1Qt&TV6p{0DBe#QB+V%g(8By1 zPDTK*#Fhhzp#S%p{{k-%YyQ*z|7axaRvEPZ^TCHQ2V(S+Y#y+308x<td5V9|X{q?T z?`PmG+iCcc3^-Q#e~v*6Sb&9oU!TM8Cx!oaZqRKwwSa~^psfGR%60RGOEr{lFDXc7 zeN!8*-?VD=gyGtKene0o=Wb6RtJq2gBxtFr2GZmC7gq@65W?u@qSTyDeu*0I^DJZ4 z)t3(k!i*DY@z~F_ZCmiW?2jyZtAOb<C6O~Gv-Y%FUj_V2Ous_sxr>M!=jr-dr*MOZ z<~ts*vv~QlF^TKU?C+*GOJ}|Yz8TAlD!VoP1(w?NZ<yFmuYHu0x_eVZ#*p6VHo5GJ z3ScUU35Uf9W&vq{9Ktr_-ws77J8%9>g7#9xk@qvM%hJJ3%*HcRvt}gzqAEJi)31_- zr?*g=-1w&b1bb{Q(aBbqIfXCY<~A{+h&>y$OaJ~>1QnaX3tv_<<Mk%)Rp}n1%9WVF z3)wZ_0y(~a<ol0yGXmr8<m4pkLBRC9yKBY<o{pil`D^9Xrz3NQyI-lMOmHTS1pB3( zxc6%*P$pqniuBH-E{K!&&NlyBgAXD)_*ozO_mWr8A!>j>NvQ>(b4eMLY_SxUlu&g0 zZy1paK|n0g(Bh%Bc&C{mL?W8i5qrHuD4D5OeN$Pi@F(N37kjg|vPsbc7+=;e$*;aj zq<oW~n;LG6nRziIbfzVB>XjdC-e<`^!X__EeAku>VWoW3`tS7rsvHZD&X~-3kLq4y z^l_Hc_xc>^d*h>-I_u+zpUVs<0cpy%n;#eb;#(=COki%t;(lr`1sYTL2BLD^WYCG& zfNeCX6f-Zj?k8P2CK!y(8qM7vCqPGOsel3b&y3=uR<7iH|86@#@}^TtS~{dI7b4^+ z8Qs&jCL;9>MHL@6m4~#m{7Zq195{(;NQCaJ_2ti_TCySiJcwhL4T_H@f}Dr*qI_U7 zkue@v&4YbV&;9>#2SaG>6B3Q<gkBWsc%autmmdp!<%f4%x>5E2>bsM|`FwS4#{?Pn zIfr!Ot8Ok~dl;N-e3w1CrKvMt?iUx8F0%Z3CK?+;d$$CqUOY{-_v<hJEYyNJMoQGw zqmRuDAKzpz74N7-N?T8X3UOygPntTn!@$nQ=aC~bYnf8BRf<PS<E?youYc1d+1uK! z8Qt<gy}7n`b~bWEG#Y%014KK8>ZotH#Ov{0#CJ_v&_q&z$-#>)m{{@CZLuS286_`H zzk|ycVk)o?^XNjiO|8TNTvNpy2Ap1aMsj;!>rq@-4iY{5)ByuM&@j9gsq(0$5@BQ> zy7p7hj;de%03pOntT?&lmg-Tw@o~AVQ-AlxMvF(Q2&3nzweRL+)Au>FkKz5NVIOBy zA(iXC430?yxc&pB=b&w(XYC?a_~UI~U{3ws+(S*nO{H_;mMdg(4_vxGMMYL-za~Io z3GMp<=}31$lvvau%$OH8r?X0BBfPa2w_=WAWM@M{_@8blcS2GN9--!OlH{L=5q3g8 z%0Z`A+z3&5>YNUdD-fE!npkT!2JxSEti7hxe(TSmH@WL^?R@3>IZb6Yukm{lMqWZ6 ze}yblZp2&ytgv>8<SzPCT39NyPM=G+6rT~EQ!Ug=b9B#UPld<CS-H7m>q>*!&^1-7 zmd`OdA%caLSl5;neN%!60;Y-cDzu45hz``L=QU$22U$iK3Wp<e5ppf*^$!};Zd&zE zGO_%K_atu7`DI_=M%TH_Ct&us4eUs!U;EKNKlZb?w$agJd-kiA>Ci))mNWb9$OS9v zS5zdzkD1~Aj$>bMc?m@7s$V9si0oM{9<Pm!MGW4bG~Vs?lee_)yzzN2Nt%-MC=NY| ze~oSBEdyZAC?UyE*f1BBNT#R7)PwmUd&ZhTv-MqVQ|-V2@sTmWEMbPuRaITtJErsa z5?IHI?&8GkvNJQ|v+%Z@O;50olDYt|Nb<Zk@$ajvIVY<(6H?&z^xr1Pf0C*`YpO5{ zm?vYvt6wj8jVnftWL!J)@C{JZyq!o2gzj^6A0?AbzQKY+!!79uVZD+fx59}Rz04~@ zc1$Ulv2e>j8ABEfv^TaG^xR7Y1Wr6rUxK0Anvn@?Q(!3yS}Gd|Z@x@yBHOK~l;6WW z2n6@Qjm^XAykh@+D)q&CWl0?DV<fRy`X-k?`_5r?Kh@PL0ZYd`c3z*lh)53^!@xFF zpD~Vw_-TkF5?nG@nFXMj{UM3yDZ&M*G^nf{RvKw?g_D+5*@(@Oz3}IUwA9&pE!b=w zF7)gO$?gq|d9E|vV!I~ye;z?ZjN<#Sksykq>*;^}7-*nZAi#qlY@X4YU=fDKTq}U* zUW|X<CNikkp}jOyf<dEk3PX@t81(xnPw6*l|Au;w+Vb6_t0ePz+>hQg>wlNlUL&G& zS%1UIYqJfF>s5UsK$?mr+!wsGx+s<s^=9ER&6gjtl;iFy;H}>&`tDOu=>7403VH(B zs|BQ_?+XfVGUF^R_YIbwB$8-acHq5y`_~o~|CNXUg*<sCVPfYt%G`52B=Konc;0)r z4{Q|qJZ~Ip&i+Ol*D)mdBm?w;Ao8}Ea(MKGrHb~n<Bh}4OU7+eMVN19U=Nqt-RNE$ zkpKBZ0f7-eg`Iv@d;CWn7oKnErZJfo3Hd}&f_TU;`zBf^G^qPwH@0-v=<+PPazccC z{EW@zS*k3OJ_9!Tp>f|(FtF)GSG|qv2L+X=Mda+4NsSeu%$R*Me$_^YNN|dvuM&DS z=TD6gtrX@#$Wu<e6}wd2jP7Bk=Aku7ap4*w7EuXJeRg>l-uXCoC5zU4(Gv?_lCstf z2;(~QW#8oR<0>qEPAOH)r1ecx#l72=!Mt;zBb=7<qz=M&E3o-vc13vb=^P_$jX_?d zyl=|tZMAZOEA?kg(BDx(6&5?_bH*>Dhr>zHm~lx_{_F}%ewhY#foaF0XTWY!xddGI zZLxhjwel2pEr>04+MFg=^<}{jGbA|rw@1OCLF&D)j{TZTo4hUxENvE>^-%2Q>f)m= zcfT6gOqDN_xIo8RS9@X$pW4h+!!z-zg~mOgWA!e(z>d1EM@wzOZn_N(X^j(~Us>_l zEi~FKHnVAd&(p6wdF^>>;rm`+ArT&#;I{C?id2j{`j(-Gd;2&!G22blX#;05Aj|9E z=k02~d}_kin~THUsl$b)S#CbucfhD2!K<UakJ3v?GW)71Oh#``@fUUQ;YrEzV>S!j z=IT|wwU}>?Sjgj7cX_qVD{x!3f}yC!?<MmT3@|`~6HdqqL16$(S?QOO?yr)ib$)oo z1E3q_gUS$SiF-*IB5+-helYp{Om+W^2_4iF*k$3%pBV-d!$YZ(HGpAS%9YMvc1ki1 zhS|5koYKhBH~V5}mX>Pc^>t9%RW8}xOj$%MgG%qhg5eiM80z9*Dy_&rQ}2hG56q*5 z<1o#HPDu|djjsqb<I$Yn)@DZx<zZ{W@vF>(BG(ti{$s+#6f6)SpX*aQ{XbFUJeMeG ztfxoI9gFwpwG>+ZDEDL!-I$h%JJt5flF`2uIw!xquN{#2#NhbDa-zhjeSJ-jOO{3H zczq}__LHcOr|<gQPp6?)uZx52*9Hx)(V9b9BI$l>)b6zAdvGG=<E$$4;h|I#g%ktr zdgtxDi}wped`Ze3Q*CU-aV&K4e1E!sf;xW>Hat76u5Il(jLY-*YJ(p4%U&oNrIhur zL3ss_a8wwyhB&-RVdB$o<i%8XRK92L_E18h+wx*n7|6**<kItrdb4iX9Y1ERm(xR_ zXFnySkE-+*E`p)mMjezh2HFJ-4)Z*&<cV)iGe53kjA54&ftE`v;JvQlPp7RvLgK#P zwf*H!zh`JQp(o@zqN>EG;ydi)bVTF$xoeFhLt>5#QJrg;H`M40cWmsQja}h>?`-z! zI!L=K9TfrqW3IBrQ-CP}E>>PUr6LN@k6mr5g}mIhfH6X5>Rs5phO)&L?`{4N4rU6w z4fg9)7=_d+JPTWrLVWyP@KK<EOgWM|=9R4Yx1QI6^|zwHZUqj_TGn%QT!%Hjcb-jk zj_bc}!FK6P1O`Tzb&a#j9bu*kp9P)Fd<mzLm<Y_+;-4SAyZNs?Ib7N}6aQGNaKX$| zSxVeJ#lg=aw1V|lFkj|qvlVTsa(t3&DsAfh?qU_W!IZEcv>}C{#`uBcDdeg5ZCVHh z<Gt-xLV4>+M~TBw<CBb%K-^|bAO8($PxE;<$M`B<UYh6IlK2oz!O#rPd|8Zk8Po(+ zc&Unf@i29Ip3~Uv(pH>|=)K4hhHE;n->V;H(xy~z1hL`j=MxV1X+cd}e7C(VM7~W$ z=pcuL{t7|ofpGS`?%6VSp+r1^M_hRHFvOoJ;$WhLetM{W#bMBqXZJLPeW>!D00UXe zbd}j4t3#|Hn8fMh3>{9%+9~1fYyk9RW03MN8yT@&`%9SpeT{V<W>;wzvjG&E`N@7~ zY=5@)1kaF^UE1^R`fOLI0-&aZ=^15tWTRm}o06pwu%~NjcK^EqZyr(3OSu^3n0)Cv z0zlJK*qWOGLX_>>R4`UMyyjZ~REr)~;;O@-&8(tr&ugqL3}I#SWDWXC5>UMf<8CkG zB7+4#@6b`VSkwpJleRd;>28WDOmSx_!txN`KHFSU8`QYG=l(WsH)XTOz@viUbI=O$ zvHHA|zE%siDRiQH*)9q8`o4pfV(D$~d|y0#>>;rYaXi$B=|!Z)6n-?j$ZRFNit8=( ztwE#ln24^;<`AkP)XbPVz(R$5e)^9dii5)eh8H|CN9X%n4~^GXaj-)ygHOD`o>6C6 zui{`lVe{kSU}3+aXfu5*IK<Jl{9#J=Jbg2sK}Nmh&(%C~Re}qSOXVk0eRuk3qD5=y z-?eMPij}(KGJr{OUA^0Z{*(Rcl(IOY`1BqL{wspnn}9DTEI3sT7F;FHfv}_>-Ds+L z<tq&AwS-Qjh7W__C%tlOjY59{$6TbZo-#ubxm&HBFyIbP*e_drYqD^b4-xU6!-HGX zf3kV4*|Pkjf@70;CR*N5KJHh*YgQuM*Y5w3NyvvnAQ7S(qemMCfo%R}F)^Zg#KGK_ zP{U*;(tMuk*oxUyzn1S!nVeXB_%Fu2h8+J4nwa@vb&^Fabrpv>fOOsGo3a)`X4YiR z=%?M}`6JK{*x(FQIW56xcoqkn9;owL`@7Ar)NIZY1i#JUeU~GICfygNAqb>V5qlZN zwM-0N4leiU-HJ9L$RIR`k#Spgl$M52T(1Kv0nNbmGe3eZrlhQ5;e-(ARLq`H9U<uB z+b(bwEyQTG&f4<@P1=JMEcl__7a{an)AnQjPialNgSjwq)5s??^rMjv54hFnzqJH< zA<El}qTJUZ*&7^cuV(@nWw*sdlj&?&F{a0Hh$}1Ndfz3E3LK`lY)@@bpEr?TEvoCi z5*4V_-M&tE3Z0-Ne;;h4O$O|*G0ryllju?z0|d8kx_l7!+zDvf(_{$D2ApvvX>+xs znmEEAs;2p9adF|ujOF391~$OjI0EOJV|v0)3{^EE1KbyVc*N65-Xr2^8Vk|QdUz1W z6xVTuk4AvJW-3kP7i@;JMD8{|sug|EKyyN3T{qZYY!P#TLq2A%L5kzvYESC*D5`u| zSe~jdmQ|%sulzpS6N+B?kB1G{YZA0$pM8CB1naNqECDvu)e%=^M)3Gov|GiMDIm7{ zts5?U<1nqT=sEi=PqI8=Yn*3c_t#CsR3Jf{rHRyUzEzteFK+g`v1$W2_v69`HxyJt zpj{cYCvAx{smS?Ml$}0Cf{JcuMk&R1h-T}7NZQ?StpXJtH~Uw;s@G-nDDL*%-Yd&$ z)jX6uYxoO+k-yA9Kg7YxnGd|vqW->2gmlBPD5P0db$4=wpC)=Sn#lo=HA<}UPvnBQ zmL2JVmxaRDd|oE+0kK0Ev@UUp__~%zn}dkRZe0qTp7C~q%<rccutU`CS*{2jA+Sx- zXWtXv=i}>wEuLp3m9<x&xm5zP#^T2(4YG?$cNHBHT%uf!)|^PSC-;q|f;1loXgjRR z+RG&!S?ygkxeDtT7W}2|l*$*{+mse@#zfP`#Be4#z8NzhkY#`KVLeAs2>at4?k72M zm9D@PQm3>}nUw9#>R529jdp;i<_{j6rGoybPB^t^hGnB{+d<pr7Y=hoqT0a;v)vb` zjH{%H{WzF=zf-)$F#h&}GLdr^x<_yKLWM52153_(An-e|xPN7?!3?3eTf?^&P%K=v z-m+ViVZx)l(7y>v#LISd|I^Fd{4kIK<!&o(d+=&`7u6oj7?g|;hi#l!&>ePs8TGuG z9=D`98T8tB;xH-Tpc_qk3<Uv;Qu)$JJGuvI=U9Qhi}c)^s^|!Vj??~S$f6c&)`_2} zQ+c6V2c#=+8Pc=te?!KxLC?j*w$J>bu=!?z?=&Y#NHVX()hv5e+{ksz6RO<_4BY5s zUb)yivck8QiYoI>z8Op5J_g~Kz!-nP<`C`SOyC;I^Xb`B{rzrkq}g*|Wv=<ktJ$c* z-~96zT*UbFd{oJ^k`!w+<qto~u_Ts0IZ9YPtH&|<@X`ExPKF!|)vEPLS1Tm*=M-lm zEHSD3gj3PC-hD!d9W{ZK-^HdD{TXt3_I)3j8h&$$NvF-oQ@Far8|hra7bN=Z4&9o* zNSIa4?>?JsM+oQ*%Pd@b>{cQnA0vJY!0bf|)fz&eb#Z$p<rNm~o^MRTjg>M)qw!;W z;?ZwiG11(F0-_bc%Vf%*^9`SHIyEg65!>T~WEa!^=oJ=d|Csk><xTt>!Go^&c5Dn6 zB?zhnK=z}MHCX8g`M~MnIF0t;uWeF0dk5m+6?bb%9_0>rX{bUmvV2@Gf7KIDPbqLS z5zA>IfL!gL-^6;z32lbqQLpp>yVYFJ{}oQm1A^`1q3d7u=j7VxfleC(eP;RV{i(C1 zyXO_To{z3Gc!oYcgbqw`-EvW_(}V55{X`8#`n_=!x<v=x4c^B-&si<jeF1S>>=1f# z@~G`4-&0;bq?!7YjXF?$&{rF9tTv&_r_jwnl2=r$<b>91z=)xFIVVwT!_>8+tC7CJ zzRHpYTSsl?b3!PtBi$GoE=jW`U!@hO2eZWbo}~)dcH6PuI@BP4wx?4Uj9-#+tEql) z=Wd@us6@wwN8|mSLtp=JZ!NkR#@359Ns<J6&X<*Wp~KSp;|s{<l(Hq1tt~y`eY{$3 zfYif1murm@)w*>f59LK3OKb>KdOOk7>C0laEImn5;%|!{5Y71gQrx;V61kh`Fg8Cc z?PuFLkD9g#>-8$vO;J3~nT6j)`uiuW^n@8~`+}c`S$U&r<+r9?Z>BMML}4ty^xr8S zF44zhs{Ch=T-fLce;7}LRysAyw5ymNQt%9J>pV`(XhF;2eFEqNJSwKo)_Tq6M)>*z zppG<HtY@K6n8?tj&Ik$!>tM-uhf4{oAAdmlqp0(rVLNONxn_k?s?<<Bv0$O+yY(9d zphlDjLG8(CV<{v!GDsH1AF4AkYx<K@Xd3_SMrQx$G<p%jFoC3<t>WXxBS@$&vW9sr zo)(J_pVIPTX7HveAti#8OzaHCl`R06>-r`&2Yu&at-n6)_S-pC^QAgzH8to=;A@6z zfsol{s$V=S6jIgE<&6dEQ-DxxVFpoZR^7FYHVOG3m`#sBtg<+1L03j{9JL187U(Wl zv9ZO!X}e1Pqy{rP$VnhR07=5*+(Vfu4B|w9ygqelnckM6jlRuuMZyw=4_~6bB8gMe zlymOsp%(L<1Gd0c86IN5kpo6K_Fa<}J}fT?oK)|d<@@xkMB}STdx`EBBLPstN!52o z>W`svt=yIe)_+`X9%CAR=$Jo!JfD`h&_UYGnndgW>+U_HqG+0c(Zz&-f-cEGTowru zlqg727FaTi1OWk+Bw2D;k|<%xEVxLPCFh)zpyZr0h~%7ey0iGa@B93_f9^f!J6|8p z08`U7)m7Ei-8Eg+8%hC;X2bK%H^D6J4d;U<yDjcxl7_7OePZPGwkzGz_dmM8e|bM- zyg#jy(QtoId`tYR$es_3M=Aa$_+97+;IOPj?>12%GFld$3~KP#@A$gGxv7fu0i=6l ze<-#IdJYY>!snBDllcd&Ns-mpP$~<I;2svokWST;&)mRTZ(HlDW~Dqu(!MqK78~=x zHT8El{g%Zb)fUc}ul1SNbIi-nd?l3=BIA@+@QdDFC+QFOf-x}DA#nWC`5XejE@SdN zhuJ_v%^%e)Gb0Y!{Pdv0p;5i93|5$TN=OT!BG0YUJzSZ*iAuw?BDc@J<3p9hd&_MW zmKOw!35#DP%u^O0X$-|GJ4Hp?O+4Wv1M-K3XL`WS_-=7II)y_aEKv~@6B2p8fe8kx z@$c^J8H~`q9Yf@&B;QM2<n?|93h&mifx6>2uoN{ZNPfrvld}~-R`;~(;X)rp#&F=* zl48G)lj*1EmgancyjCxLE8F+N_OdIbrn=GguxfP9Nq4PV(me_DyUBuVqjnW(jTyWa zX^d)i&+hU%5B4Plyi22kc1n}__#;jS;)T#Zs$KL%#25xVV}CoI+1q`ATt)N9NIv<K zANxs#j&(>n!29vdmoh8ud(K_zexKeFx87=K&LUv$c#{)ddsc@id*%=!VJt>EPhh7? ze$S^Xi|oUi)Xp%C%XnmirSwE&k*dn<yWOA7;>k1@gG+XC>AQ3BdQ*?bU4FcpA9p+% zk@S&CEY;G?Z}H5Ixkdh0YZKD1pj32ILg?67XBdF*H_BXFfb#-4WOb#@nw)&2op!0< zecO|})=og$4JaK*{^jiuUrW$xSZY5oqP!4lwcK7<B03>CIpIDCOEMp{OYY~?)fkf3 z6Hj2d0rXwt2LE`k3KEFyO-$qTOR8HJz;ZuW2D*jbnpT{$_=CyTn7R68sXL~|?GsZ3 zz7<m$J>V4sj*Zp1{&2-zK?3<RW!dKNI$sWF6<zK!eqNoF<mAO(Pwtst70sPnV()ef zMN>c-*3a@l!@r)-X6D}9c|b`nE{3E!d@QO?+kEiwg7H~7uyUroA9vHU;;<X<4RI&a z?IFioN52B%oz32e%m-BBpL88^Sif4?CxYX;aYA>YCu|RHFw+=#{rm?TgZ(Q>G6HaU zjD(%OUoJ(UXUPYCw@eaiP4p5eQXD&0YIy-{s{cMMN#-?OI+nUfy2`!ldgI!cn{xFa zG+p<d8#iwd+<##gZs8tu&XZ_`1oLzp9FaR1+A9(k9*rY|<kb|w<;kIq(@e`$4hj2) zSnKIOp+`9*?kQwg@3}3rJ|5af7i?lWV0x7272GF1C=06QIvj`$V8)l$U;4c!vHv2X zjgbkp+h})Uazbb6#u5sPOEn}%V_-Ci^8#mc=w^1GKP4F%DstG)r<31iNKL$Ax{OF* zCz<%JHC;BxJ6%_VG;!#WH4lIfkVmW`z_~Ob!0~n1hxt*YBtO4n2CRaEc$btFz=2Zp zZ4_SmJwOKqF9}meJCux>{~^^**dMcso=<0lhMMF_$@Zh5&cq<;FSrdJ(7U)pY(ij_ z6AJ!MV`TfbCK3dgP%iatYnc-T&c&Kb%AcUt>60Dd5wN&X4x)K_3r2MF!QqG3Lv|>^ zP*@ip9V!I)(Blbxi3@!|f4FypApDyW1$*XRuFfX`X??>&ja`9#Ng9Hnm(oe;n{l_@ zgQ3eOlRq~m=+cuMFS`2eT<uiY5lrZtAuu@hEgQ=7<Z{b`)zI<}@0-%LL_in__&#+~ zZ$-~d7hM@yY>9cX#r#e=g)B5QsOre}^*ZT@>6cS5Sk*0^QU;r|QbfbwyyU2?g;jv| z>|B9E!a`v4Q=yk69&;3+7k|<L(H6f&F|ei?#7dmi`hA@PIOJf3V0R3_hy<ysCdVrs zqIhgC+Bo%}CVeq`_dYdPyS?o2P}}WIL%*GHq+HQ@<OiBDT@`?49S}5B8V=d|h?9Gg z?YZkG=<z$8bT*aI&2p)IWfia4s=kH646AjJOhNLk=F&-}mNy?1*Kl0G^vv9otj~8P z9k%pV+oDqLd)Eb%0g`D2XomKTJ)hbFG%2#w0owBuh;4!PxYY({`uv<mpwl)^$|^?8 zsvNbzOAAeZmTX(4A?CX1O-+sn^D*adn&nXCXp=p|-UU^sis|K0SS%bO24-}^lZLv5 z!Qw@BcsH1k4havX?XSN*EU*6?Zbp^QRsUP|OZuZ{ZB;9`x$PZzOSu({gJaAM)<&Zk zBHD(|Tm?x!N(?RQrsl|71U&5^AKf-7hF|l5t0WoPFcJFNV2DEDP{IiYge|s#vUb`i z?rGy}O8LvgJ9Fp7Ba!|v5FI#sXvMH0Wn`{=4x`m7$m9!yAeyDHjqJ6WqKk9tr+v-$ z^x8k`Ouk82f|Gf{p@QrnUzi6R3bu2^eApVvJ<K->c&aYgF*maH0s_R*gx>s4Ny+iX zQR<>K5QZ{B878)D+r{rAyYA^#DB76wMHu}7o=Xz~L4e4^-E2$Om2oNTnnKaxs=AAV zVZahs4VNiL``Sw=7!Qb6yrpMpnH$23#e*Q=Fl=L%)lO^&LssTOwdJ1g&>?l1aO1tc zHvt`c!*9?Xsw3kOJ0Goc)qrOC!a&j;QC-iEt)@BT{aAUxjB$*Fh2nkUdkHO=EliK_ z>B+qdK|9ceNaG?+qt+v>WdK$vz7v8B0Rpsuz{-zJkBVT}T}q>?w%8Y+@6z4c)Aik+ ziYk`Eex`ujy(GT>Sus3(5f<nk{}hziU419k0$M=@#A*RQ4y);|RwcKXMo|#*bP2J$ z=F9;<Tgb5?7lU$_*capB;ku8OCsFmxx3v91l1&eNEWDWWC4smr0)T^J&{lUV%myq{ z<yv>GK20k*_O#US@~vW?@Nh>AbG2Of2F&EH68xbICHB_?1dgT5B$qX1+^q)Bdo&Id zk|^-JN)kA{n2X5%SKS?k{l$gAk}@jyD1k<IlydGQ5Bb8dLO7yBnJ?H7_K|6NOoU<I zfyzY*N<Qme%*B#qnuMV^rMmVzh}tBQc?tzi|M0``TH4EUp>R&v2rqU9((_{RIT#Ok zgbrNnZaX-Mdg&V85_wID*5H9A5#q$h5YiKQ^%Be&ffBUE!dMBzUf}g7*wC1;z+AKL zqF_!qnL!X1k<4aN*!9>nSyn<jd{U3eerh@KCZYa>J6>xq!(TH1A#-<7pz-{xY@~am zz*`zYa^jXa*7eh%u*<su3=rNOlyYpEFu9j;cYw#s45e>ggF@k~uuBGl#9`P~E<_Ef z*9aoTh~~#C^G*mS?1=Xt)zyU{DoE#Eg&JNXQ}Wt&V%7z^1CBRf2eXSd*pUL+yi}we zpYT|k)C>!m>EMV^(QJYlJ>k+zve66$k$*VAD2QMs_ZsPp4q__A28f;}_gvKxteEnb zI&ejB&y>2pyRpy%c(9Z*?w~F;b(a=(yaCfzMtpPNe*V)Ivt=rBw<+j;?c!B#=JBd% ziNz2fXXd};dps{GHNe(9N4%!8toivU_vqJQ4d?lkoX+VdYZ6hnb>#d<H};^?TW4h0 z^-yMn-CycMnQP_xdjYYf<ryXw7SWzZZp7G3roTi9_3QX<oBl;D2IvNiNhS%q_7-+F zs;IDj@~3hka)a$~Q_*SViv16+q-~{we<-e_)>2|3%uHm{V)y%wLr7rx=7&JBS+QWN zV9a}ZFlrkoB^cI)NhTSaw`vxeT6oLqP^#7fZ%)g;gb>i1|F*~ehXHmGw)7PXmtZgU zT{0Ebm^x^1=t|TDwnWkHXE3gM3~UY37mJa3F;@fqBN?z*c)l=UTWp@lBx`tYfGy_N zH0@yl<8w)J!j&2GmzIEy`rCntaf-^ErHm2p(-<Y8E&RfjtvpB{amh;r&EGDp%S5<> zEF5(z9C9;pu8lBL?D5f6FnauKXz;+0R3Y=9=B^J<KSv0XlfMeWz3oC+C!c%wy9>>7 zDh_^Y^-qJps%pa&6G)+CUPX1_P2p!4u1PBW!uOuKPox?iAY1mcB*Q#OE)LwY-$j^> zCT}Z|0Sf1_{l;!URaJGs&K2|nm9bKhkue`7eA5eP+me|!Rc!Lvru*?&6m=pY<F=9_ zu3c~6B9TZ{)wAQFS`pB17_Yjis%i%>^3IJl7)phVk7Z?giEZTP#lE8HGfqC16Z)?{ z+qi1K*}lm=QvJz=AOV@e0$cQZ-Jz`x*gRV0V&8@p5#ib?*%G6(N>NIi!y)(i3ljH* z4gS2aeQ`b#ueKLZR%#CetZW3w5{&7(l5dnOZ>=O?e5zBic`RO?=x3+qwUZuC!n?$e za3=es+PLFP;DEN<*^2Iv-5Ry2$D88x6+ytJ^Qf=9U``_SI?Ix0vBm8FoGL1P=d<(z zB^3S`7;*4GtE6}zA=}S^J{B$~fzniwf%j^FeRQ>LR=i{BL33kDd?XTpVu6@vT(Q;F z)tNaJtmm8}AoZkjq3Fj&<?s_nALbsM!0!gUu9@ccKdH7w4h~IfZccMfl#x^}i>m*z zZhZl0CCFo15CI|oN_(j~?#^c-H^s9#jHs{Sf<SL11EvviGzT}5raG5WU;9k+pO%4s zyiLNw*jd?_me^1~-47^FR_`q_O?fLj0SpFtTv>#nG=DAMzA$KtE3lKsG6(Qwnf>QT zKHw}dE{jHvs_=cp^!bc_yMWr&!5xRq;KH1<rmthPag7U>6}k9suP%t5ir}b_RAd4J z)a{-YI~>s6I+KDh;bw8%>Kz{>1=|i6Dj!>HydZz@g607N7fhT4IfEOubm_XtlE`$| z-XXwY_&`VAWA3)8SeUcZ^wr-ovT>oSGT};Mvp8S`K~Hv6Y%v5~@lNv8cp*NLcLAP& zSOwc&FDO=H6^H=@A07Z``ysK60`8}bc5lR>Fzga=KH(jJCJX=CSkYt8V}7w&z_x(I zxF1}@J+>%d=klEp=nWu{osunP*2UrXee&J!F}MihTj6O*h0uiqkz@sOUlAMuAOnB# z3XP$onO2chg_#{>%sqKL9MvEIRqc*d4;fBOpl%KH&KUK5u~+{E&Ar3pA^#63n(E%a zK<93FMP&a0O=u!-bgSTaBW5JsnOmU+lE(!ug8;%#37=p8ABeMB`(L0xTK@(WY5W&d zFqhyiEV?22ueaM|QU34kqAP;MgP_sN<}b1x9nn_)>mSQnlJBuNK6rGZ<1hZK{0kH; z`Y(|C#>~G!{8Rr1&8__xv~+ZSG<5ZnK_5~J!`X?YJ4LsYL05xtykBJF4ywsBbI>1I z`%<uBJokgU(uwc*<j5j9whiO+)oy=XZ8%*^-~aqm>eYM7e;LGrj7L{d8`)&3i=MK1 z(Er1z<KxO#g1Y-c0v^-<+$rdL8YZf%>%#EgI{+a}(WQI>PdpNE5!V2F3+CR12~17x zz(C@Gf9W}!;goZ6Ylt<O!hiDnFBg>ghAmHbxH)QtJ>E(Et#@9N+W5S-dw$P{_G%P= z2wY#Z(1B7UNJ|UklYBrajEIC8SV$NEXT12e0yASaW^TXMaf5qthVLzV!<+}BRZ}K= zd4^h;Tnz*}t(H<vf!O=EI_${vSijER;p4^YqMV9O=S$U{=ZVu&Iga0hKjY!F@Q1sU zk;eI<sf~h2VFSH?&7srB!E2D73{`fZE%U1Ttw<XwEIV;aM2?)xp-|gQwsiGRBg)Cq z+)!Ym1;n+J*kV?fhLAp8wZ|=nFL2C!>nkWL(r31A-K+VN7MULFiEHo^Tj05A^}$vx zOIO3x%M2X1sAC!9EqF>rE$k14yIOZtDF`nKdeW;=P#MSW-4*BD!FP%Ao-%+@WMF(b zZSl>~Zh-1vj8y=}l2okC2m>%@!bu&NSpmQQ|GDz`0&R^fZhV+M_bOXrCR<lhOEjRU zHkahRZhrBww%L>Y;dbSUN?^3#1&-0hluD**5jAOErI7cHZ8R(t`ZRV+3@QU00LxPd zBxPGqWcFtg)Ocr|A{<t{t=Vw>e@I;Km>q?GmLLES@!)}eH19?Uk;%Wq_R!=J>0|Fk zYZuOiE?r9j=61b+EexEG@@c~;{Nf}&+|zV0D|Z2PRFDEQNCJQhTa9L%ub&J$@fgE% zqK5Z82Mj(|_4wccc)tKbUtE@I$H)`U%#k8FEj$pxad;45atrc!8LmS2!yGre0EyAY zaXmb-8x|$}Ljyl8FI)k#@Nv-2pU}Fv{GM(izj_sdSO$2~6LYe8vy+rJiiHAO!4vUq z=VHYYf%XGh3uLGG<)GPdL<6acXI>BNC!U9yqiBa7lMHZ>H!xKx2y1~t)8+wvnLXfU zAad3Okxe=9amA_u6G>5BwMPkpDOkUw#~jySSm&!C4@15a6~spAg!njl!&*-}`Ww?0 z>s_a`L8s*7TPj{<oBf74%qT%hoCdX<AE_{b*<)WHY_w4Nk8Ze6^}rvc1uAw0?N0O_ zJuqH^Ef8yneC^)C?8b9uDo8YJgqS7xI<@W=D$LD6pKMMA!x|`h+k>9IPEYANAP@70 zr2_=8T|{#-={)K6V?|7-l3#V?Fpfu#UOX?IiTIlSW}->7Bgl3+Z0*P`-3h~l@cm<? zEFwlGN?QB+v~|)EaZWt2QIvxSkbTE85pQ1VN3^PTK5d**;ir{GQNcusLIdXkH}Jn^ zKVNC`wXbEbhkXsq1@;I)!CqzJ$0r>QEpe4BJ4ymtdt2DUv&U{eheveay>C<ZTUX>o zN%qtl4y{@{m~X5^YCvVkK_D_+6TY4gK*kINP~9(AKz8~fGR(Ekrr{!ua*t`mM)|4M z(^`1ACOzv$%&-D8TFJp)E-yyyjl!GDo+VvdaO@Kb;W+Jp+iv-<X-&oa6sPrreI`ZK zlbkua?g@#8ef@DaHLei8wc{Gh20;)mShS9%A6xp(#?|eX0a~td7+78Cftc0!^KrJk z@;{}mymIVfd;%!iLkAdMVv3iw%h57;*PHe_Xu7LT(VUbYOuT6<_*z_8wjwd#`lGxe zV5ympb#A->m#fDV|7v~fdl~^F&PWSTJPCotc+b>At!w@DyUt}HOI==#10q0b5?txx z^@sU0qtGq=i`j-h1l!VCsRfXt?zYLFL?0B?)x_rgtP$2VS{%+*<P(iFkTl~{l|OoD z8OE4!7~jbkPi^TY+!Zik5|w!DpEEVfscBR1X8YT3skYN)3-4j=;vM|Qi%`;%F%M38 zp3i*W5{EjfWw2US+{pN&A?2NN0$cL^hOLK39Q2`@F2lAO7K==0=eJI@Pjbh%W-B?q z(PXwqFhxzZ^AizAV$xXXfTQHokMKL(E#i-)xI4N7`N~MwGG(66w7aI2<D-2`meE@( zW$Jgc#lRB|(lGzyiw1S+B-19pB?>%fD4;b!@mQuf8J?oxZ$QJ$JfCedB;GbA(wMS} z8>)TY(fo(BBK5-@wRp#z^N#1_e(`41`KVP0{c#`U7{23I<E<|<X&YV3{^)VijC-w^ zZhf-zPR(77r@`w{qsWmmS!^Niym%tBGPkSZ;HRMnEvif3@ExT0v>9quqwYqpNkxWE zMJq_M)IuQ}`;k`1?ZJyLA8^cua8)QSTBKXBB+|c+v}S63j3Oj!64<ZshO)-lZ;hv> zO?aR5{RV-g$#4mPfRZDX1@&X{)3Mn9d7nz?JvV;oB$p+%nYzyCP`{+I43GlE<7n~2 z&ag##uHqvSNQtk`@c4a#^Cqwed+hRtzqxhC4$^9N<;J&Y^Kx|agGi%2xlrMw5h~}p zx?l5!kGM~yZ}q%F4ht)Jc5x$<7Gq}1-#`&b!h2{Ds-u>CKA*)l(riO)sp2vQJU|{8 z$$wkM$4>j*d6n;*d%35`$lIhC>JAgabAN&P>YpQ|#?t!kI>)!2&ZM}_Q^?B`N^ehp z{j~D)L*3yTvDy&B+!GkFBR%S#a9(@<*&Qgtk;=NbUyFpOVE6W`k$Kq*-R|p`4oRTh zzq!Z#o<*(#pBk>dyaI`MEhSi%Be1va#`le?yIfQJvA&q+Pj#xqQcdvPYIT2-0v~sK zp{C$5Owg3WNL5;JU^w}4Z*br=yns~(d_73gMaicB^c{Wfg^RtQV+Vl_G}F2!Xh_eB z+li80P#WuIDv-4?YCGH@IH>&IM$&Bl3F}kYM-orA8bq>8m*wP-KW@E>Ocx8c+zUlG zL3_FbtKi5^CG~mX!N(fYsx})ot!U|ic`9$XG~}#3S0(f(n+qI^-92cjTuhL(s*Kd& zHT<JhNz0S-S1-Rq5{%p+?fJwEn-W{TPN8q&s29r3WR|PKq0S1N%l%=+ZYka*7e9Qn z#H}Ba%MXV}b26Zt2mK9hY?S|62`_{Ci^jG1uP7|7SzXt7Aq{)ZL`13*cwJh#-n(!9 zS74D1!FJrF(Cgq^3`dL&R&|8D+~_Y1jC*Ra-DqDjbTMMTw6|`D_~T|X`y+t!Q7(i= zue%-TP*h(cdc{LvjEe1{vWcJzM#Nm=1$K#x9yf0WiU+hniT!K;$DUdhV{+q&dlO-B zwJ+*>3wk!9%9B#cG244kv_z*6mh^^sKoLQ2#BafgRhg?zF7{P^i0UGNfEX2pCR5A@ z>l;sB2&*ss9&a2_f9T}p_L1CWSI~Xe#|sEey%kyr?d`e%t8qzRlMdJF!<SaUte`VL zLyz76;oP{{kc4=#Z24?liGWF=VG=+00mdE!Q&u17hWM9ccU4_2aqS8=LIj~>8TLPg z2BCckoDY;nqOz2Tp!o=TXwRSx)sDk?&YgEL`q0X#varuhW{=rWv+ZxxB&mbA=qVpv zY5Qqi=*JEF67a*}E=AQ9X)>Dd=p&NWj=x+Gn=#?9;r$wnb!OgXn}+s$y}=+YK2EDi zssj!sbg~^%kjBn6#Xx)f^c*5!MPc7pEe;<UN&hmM&yiGIilb%C-N~}z<=<-Ye?~;I zqShZ%@DUBaLWlA@&`q3lW=7Sob-1TP-6uZ0x&4>vP2ncjYM$8S22$1tc!hnVV(dYB z+Yl<R?t4GfdZlmgnZHh25`9(OY)f;6y>QOVh#TdJ(&N!$552{JN=jN8+SzV`M<-nQ zsyl17nCL*loe^<o1Y0SC)#F!o7SUWlFl@^D=X%4VZ;nJ)LeWk}Zqkr|9|v@ME!ylY z?D%x3`oCj`n0Vz^Sm*~9E)>VWjv42J8y8JpF00`aM@VpJ3Swm|s6VWtN2<h7CQ1yS z>8KAf;4fGN?TxT6*THwU+n!)VB*p5bmB<!PJ@S!gUZD%9QHV|8tH&&ya33a8F9^IY zJuVr_WJJh@tJjDexyfMR{gdps*XGuY>nR#-ZogP=k^r{|LVM08+&`U2H7%~}J&kM@ zrV#^s;WC8*x{3Mbx|(auUICSXI%b`4BVTLT76vl?=^NXzJCgbx-y*VhxaO>O7EoQ) z>#nUf>nR@l73MnhaZ~i@mYge5>Em8B{3oSsNL|Ytrsw;uZid?&3JJ%fP}2VJbpNkC zhkXZ|&U%mehf~}?n><gL(hP--+6ZI)<xN{DUb8HZ7tNX7b5iLu*}!04A3+h)2G^i> zbH~ZI$lPQgN9hE`i_uWXF8l1h1LE#l=8_-oV+O8lMg@H-f)I0}+@3a_>Pd5OeG<t` z?)(*7RW=K+_-qYHV7yDNRc-ZsseE*`>g~RE3gw`~wXGziXR|it(XH8N1=W#;l#>3| znR!<RGtRiTqi3UGNqXxVU{$FP50!}w5ArVj?ibWi)Cs2o*_Y7O)#kn<j-w&kqjsO% zNX>Jbe+!inDc0%QdDdsWNStDAj&$DG%<4JR27GHp)8+W9%x4Wg<`P=n)qq_qpN!Zq zu2X-&w);m<&++AWU`mL2r;{vW((aY(XgJ?Iut}s4`u-FHlR4`)jd)T!OY}fp9hcw> zC@Q>Kiv16`6QBtCNdcbhm!4|f;XlzMa|@My&(L5aYb5ykP8C@=Dl9T~H{Gg;neUe$ z)SBa=f|eyCpjk)^?0xYy<E@$AFt`A91LdP{-zLD^W~4|+!{cMk=a@Zs->(idm(vT& zOuuj_A)R!D!`0w5NuQ5N&$FMJ`esD69ksvVLIPj;(iFO`e}7V=1II$fcXr2az)y^{ zotIqOOp4#ZA@0Ds0Vs6fIln@PH1<RLwcDxjz1r#+ZS$fz!%rp8tQZt$me(H}INsmm zhFB#&)DBBOnzSXRgC7J;nvhhzHhN{Y_)uIH@_w=|%krYb<*~yX#=F4+Gocq;rmIFa za`Hh&BleSzZlhSSy1#w6<;-DTR@D#fPB2Ls2Z4FUGUb7pUh+n1dv+-ZF6ewo9FeXm z1q!qCX=F_B0i+7LEnaq*I8BG@H_x@A<j~O}nwSiMode5Cpol??0Vk`1B@4H6g$Cr^ zS!d(}g%_=|cE2zVv6;LL!(DUEg$HO<!_WAt{DHx!9#tMP9;;CMu^)^2yjtvD%Wl;N z1@sLmgGBL1X15=g-1#MV_(&Qm{GsO$WBCy^2imuOJ)XuB`bYK-;hP}B9YxsoaHZd% zI5YoW<M7?nC}yD8nF%F?*I$fr%89HL-pWV_Fw>HTAVB9rJ4Sx2lvNm8VwrlI9jqBb z=~(KbqSSqVhqb%x!6p43e#W};MGd#1ca^%et<vS#GqWWT-f34<LoqNHZ5rO)Y4)SB zbipd7idT8~-Z#a-M?j7{T#-ktpe%S8!ft-B7`HH=Bx4s}e$gOOv69oZJsN+^CE;sj zI9+oS1f&G|D_xJKn6u#O%0@pr-})yN*WO$2*WTy(Inm@gAE@RnZpV8N<L`Z@xLZ6? z3WJ~zg=QVoHJs^ej};@+(?Z%lDzhG!VN)-CQIqb^teiiqK0-$9sL#`C`@@c^ZLLN6 zg~aJwH|0#lpczoW%eJeA_+5N5MRGlNV!$V%$A-sk^#%{+Z{YhI;4X7q(l3j<NqZGo z>s0{GvzrB?@xE;D9lX+7FZ~Bx;|}&mg3=oesq61oUXN=V63~Hh9;EJvS(6SF>rq>& zdcdSwZ*FcpAL(6=2g9-gOR<H$Y@_KE0ptB;d)2!gI&9HuZXDAT+<y_?yTwGZMs`<$ zqIfZxyOuXyG$ufj7$N;W_ceQo|8>2luwh$vwV-Tj>@9#KI>0kQC2>!N|NFp=d}Frf zWG7s}3b`H+^t&D_Y3XL(W2a}mh31f8xstD*MKRXk8K^Ta>x26i0+jzFuGnLoa^6At zT?2mo=(=<z0ZqtWi}l3Oc<E{Rzwp{VTuC(lEQsB2Mwh;wE3vt~-7Hjti#x3T=@^gz zvP8lV4IF=5-~RekK~>!%+bDd?kzsiDEYl6o;UK_JJw@2=#6D8iWLPlZ!tBy(1dOfu zVV1QU(@f&aalmJD95;cHOE<BbNnc1mE6F$HW`2&#-WQoI6h9DcQciOTe~EoE)-f)l zN^=+3{uHDg9Y8fvcb}_ByZVuxIqN<ne^z2sO>-Kt`E%YH!5qzRZBuT-D?5E7y;$>~ z@15cl6%~diI%(oe7%uF||E$P=vyU!XiqQlgTn_emLu~EuUt)XnOlMwGhJWi)Fo+j< zHut#{Ut2fd`KepN$wu323_sgKHGP9)R};;WdGMN**+x=Uo%v@@_l=HE7FN+gfdnYO zaCN24g?Q06Zq6G0&zDr6>VAQJfz6-xq@Qv7n-@;iWY1_{Q6;1gbvima{{ll)CYxkW zxnCd%dU9*eK8h#99$peew|r(W`kZ2g{w{q_%m|C?jiSL?QAg8mCZ-hAU&aG9h*ck0 z+m27^M(^ug@Va)0+xn&o@|?z)-K<(_2D3Nus2F0JaucQFyk^G;+djui)IGkmRyS#P ze>uZpa54=Z6?OsRu6Zj97p>`U!z3sjcL8qe(^2bzV!clJZ037+8)6AiIjGF7HqNQX z^v5&7@vMzQLpYZ?kk2<g#5W{OVTO-r$67r{hx`s$dSDiMTW~@-N<x9LKQsG=c=S+^ zK!s7Sm)<MI)#xhwqqJ1ojaLbVp4nF3K_B8z&hIQF>h+CJnEf*DE${_l4Jy4YYtY56 zKc5X;ORwzqJDpB!vb{wMmbSO&=eN@zN@}(ePFi10U})hX7n@T#25S*E#R%}I-VXuu znCrg^r{IECoaDr<H+05F%tuyi&u4HOB`scGHZXCI*V#7ZG&rBwd81xa5hb`J(wAaq zXSuO&r?&@pjvzLReqw2n(VPG0B>5x_4AD?6<Fh_(P}kLZRaRn7iKM?^y=?MJ$V+VI zpA3U3ft~&(()F;55u4P{;t<5{Ov<E_aNCXI<hI+#EKjz7NmnS%)Y;NRW;@W7af)A; zI{zwb?aj(aa35^9-qSDd>f#c`wBGZbU{PA1zLQ&VZzqf2?!iE{K3qS-lr&yJ$3Lc5 z!`jC|esfCglcsaLT1h*zkTub6cBJs*2KVW;Qiq{}_giNNx|Q*)GUN<RL_@hYGx2Ww zp`J<Z^0}9$5(Fp>;xmSt2*Z9hH$=NzH%TSnyojdn3AoQ<VRF`r;2SPB;^t4gf(gu& zdVHhx?5(dKYWzEl1}kdy-l*Yz(4IiS-KM^s#pH$Kk!+Q`MDf9*Mla5S&51gCafqui zzuo$u=0^z@?5b1GGRDjG;o%q4ci8i=NuFNfyw)F^VEkCFwBI3cgBO?+9`lJGuln>i zP=>|q7Cp$%sxbye?MsLY4ya&_1Dc}j_tKAj0%w{t#i!n|R?>;CFzreQ=c$lnSssi2 z5$Botz}QzOCVvO!m)O_0Q2npwb2MzaVnxm47qs0Y#eGPEqS3B%9RnQq!MAC9CTsOF z-|aYiwMp&E9oT<%I|%%QnSo7&F_*iUvwv*6L2OK^VWn3&pjl*o?-8_@TkDa*XPUay zXpNC@WZcq-HbbhQooPmrBnibGaQgMKSW=_M@{_t-VfOhGZx|;VbzQAI9uA$n0fZIj zT3|V=!1I-DZ(U0$wa4|mfoYvdF1j=Qd_+X!XQ{>1GO-A^uG`U4B9K=8YERLn5`kV~ zzuiP>+ODQ!#05))wz*F!bzP48cQ_rN-@*5WQCITi3sUlf#U?(oA^ZfP%BD09Vb^!6 z*)98bn&nxXwtQfgwQ<R$t*`<9))L6UNBM8V0?Q%IlQ9eN>qua(mwioIRE3hsl4>w7 zXikb>Eo0q@DZ3ut(>3J<v#gFv4n;q4oOL{~nIA?a;<e>uhCD&mot=|ej|G{hyRIQs zC@!hQ8LS~p@Wo-+PAKhYahu#Hgjn>nM+m%uQ%&lXejyEex2nuLDt|bZ7^SctpT&#q zcrO?^iD)w^Un{Y&kU7};0>c|*qfR$K_`qbE#<{hENV%ZBlTRIts0-#dEZLna$FK0l z>{ls|R2o!8%dZXe(t^vSSapS8FfdNHkGxuEQp{~npw~*ME&Vu6BI=ST+s;4bmhKu9 z#r}742y{k>`F_6QlIX?hMAGVWGc64=dc;BhyhO<!f`NwU#c3yPpa|4&Rh_z<=D8d^ z$;GI1m5fmXpeIAtx^THn|MR<-kfu>q@^a<p4QBEnY8N$qcoI*?4gZJ=qVjlAnTMPQ zqj=&{nbF0S<6J3RmwcgvLZB7t)&;IG2LXhFj?Ro)Y$6e=F>phFfFm?8lf5<nS!4bk zrizd>nfKU>I5(5ERUpi>LCDd)VllwUoc~pT!In}#eW(J&rf_U9I8YD@7EW@X+pgss zTta(LW*)P+!}Wtz!27i03vSzKR;q`YCjG|ytq(0ToZ*yFMQ)#YRY(6Tp}~+315pEm zA<Y>tX<SxOWhTX(kD(O~FDjxni}k<U&d@4+I9_ER@SbdAK5J1NvSOlN46pNis2&ac zW7lI}C@8XOEe@fMO`++<kg{m(Wc8<;TP&|vI(xhSZf4jt&%4K>Sk&>JK00ygsZD2k zAJeHhs`VND<>KHD_%3)P^#D2FUi)!6YoYIC@(d{z5Dn&nD&vJlI|CzIoP8VXLcTJ! z;xAG=IJ9DreCXFpIMi8_D7)SV=1jic;WQoTR-)S#t7}+9-YGA<1DhHqK=GN6%(`W? zYkt(-lqpUbY&oF%c<G~|gZj;dG;2Ln&NE9NRoCtBIF8tecUeFB9g?PcB00z~LcAce z(bo#Z7u{c;h~~?A^%1VGySQ9t6361smTV8t2YT~bk=9$Ob04!e=GE0CYca3&vl0av z#+WG?=tD~aSR`#L$*yW@;LLmFMr|)wVj6r29d+OMvPXDq(uW3KEBrda%|(DZPX~s9 z3Fo1#J|l%u{FA~31^h3tt3E}AG~)h~56x!mCnFhOs7cx`{|E<cU^!ards52{VZ(NK zKDCYnANew-SMG&$x))6FXp+4<^4R`Cb<2Zsz8p;#G5D-W?)dj{J9UzW>dGnGkc;P* zDo){pl?KM%up`-sviOIJwVUsM6x8pn6g48EmrrQicD-fxsV@h1Ix~29e_ruJ0>y|s zVDe}|`7!qPHdV$@QK%-Gd$l-%Ybck>K-*__W~Q%SaWwujyskdMq&P88T$NAoLYAS9 zzUS<~;B{NV{exYlE4}4Xugc41I+_heo98i0Ps8gMzdJB0nYi%)LnSh={gXM+^~r>I zEi|UG4l|Lv%?N6<CkYnW&6{mls^qt=o#BKmHHgmSZ<3#vL#V01E#WNM*^eGuS3fW_ z?RJ{;!jsqH@19wzIt4IA%oF#$SEc`|2~ToUwb=Mpp>f?ugb-C^y;f0QqTOqD2dD8K z%q0QoT+JC@JdHK19s%}AG8z?5;q($BdR-E8C$hZo)!AchE-Z|N4yye7k0$Ybq7RS= z77}GY{X(4!HmFHYNdg6aVc(p&?l+{i8!(D#AfD7K^r>gfvm3B#rhCJ3YmP8rh?C`X z{g1DN&RW`9B9q*ga~(0W19AwI@P$vh7V9*G#_pTi*AN4Kw_u_EHXFk8Q0*|2K?ODZ z_}_e8<R*`Vc2q>wqxHORnQmy<>m@Hc(Gur#zO$Y7*|?>a9hmKMST||0JV1#*{1#*& zs7WO!5Ok4G6cN13);F`Hy<L=eKKsj7K2~7X6<>wjAosY~pH>ywLB@JyS%d5=lMbtJ zTz{1>S*4X{xYYc|+$JYSHK*9A!O_3^AM@n*DTKMvct|zgE!(gY-ZRNO#;I0SbRhFQ zuSi`s(64AiZY`v>;xr>elhVM*p>k$_ee_)_H1nQij<y{z!;BMtEKwK2w>8os+aw+= zn*If@mZPorcN$BU+Z?F(?hg1X-)|q<8Y_B)bt3wh{E|Z+e-eh*ROI2;-l)@0&+$(> z&IR&soYEp40svcqr?fkNgUR7K3sLT*#RaOlngyWsiKCHW*diP7ml*3Z>80c9W7s9G z%Y7G@OH0uIch^M%9DhR7hAXcU^KU;1nmG{}#2dU4bzKGT$_G3HqGcH?2i5iO$;@Iu zsKs=}NXWuX5}4JW{iyaa*M{j!p%n^&bw{u$72TntL;b=Q-lm)oUJYMiyir@$bD@gq zf)kug{Jr@hJSi;i6+2jdA=8X%f@-7f^0n}G>0asKbPANAzbaqQM$G#EZbz~&OJJS) z3}>qGgZJky7eTm_381Sg{;-aMj>gn3rW5N+dyC8dA7xMt@3-J6+*&&c{?~1=eTD?K zJ=HiYxrwQC+~E+{RJ0YYLWNudoX2u-<YaS;l!-<JxbLAK^D71#+Zy^|LPvk2P2Doa z@n6rgN?|kC_>eRE6DK)B`ZzoU&yr`MODaLI$hl)vwOY4>x&$A<%K)OoW4h1uG__47 z7#3N$<V5rFc!twLSPoZ3nxEiV%QNkiRCv*GK@0c!@ku;wkm4Jc4>%y$9Bl#qh_-SL zfJKhH|JrmaP{scmH=>7p2(u0I=reE*gaKI_V$YCqKJw>|)9XKRrtQhmnFLn8SN@8^ zMksS(d0G3;pVX<i^7Bi>aC*8@sBDI|sF0fqO>3{12v2>abbI=8!g%h@3^vCxp$N&; zsyLA|Cp?HF0@?=cT-EVimcnjV7H+#?t9VYHU+B8vK$izxAbneN+jE$}Uk_eKTsTnV zPPvx39@ONfTH>BSJ&}Hz+yd<k=U3G=g0dDK7YIbhMFj6{4@CO}$5X|RZ<`MQCm?`A zX3?AIQ)NLpPq_j)bxYz5GmV^DOqY6<>&4d6P75ILMh68c{w5zO2Hn|p9A@HR3&6pX z4b6iVLQ76-tDz0H#S7mD0g>2G=(I=g0TS-gB*i`1_h_2&i1BX9$~)rY*P|93(FV^g zM@QcC#^#E2VQQKua6E&i{tub0aMz0i-RJgn!2KUjnx~FIQm@~I<Hl7F+zt|8S3R!A zU;i;~$2tgbZQ-s^+_otYE+_yHD^5HAUmowlN%AcTTFsDAV5{)5mV^Q<=jB_^{|AP% B9g+Y5 literal 0 HcmV?d00001 From 00b6b27380611d81e4c0ae16fc117047e2b70594 Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE <flaviendelangle@gmail.com> Date: Mon, 5 Feb 2024 09:06:15 +0100 Subject: [PATCH 16/35] [pickers] Limit the valid values of `TDate` (#11791) Co-authored-by: alexandre <alex.fauquette@gmail.com> --- .../custom-columns/EditingWithDatePickers.tsx | 2 +- .../WrappedSingleInputDateRangePicker.tsx | 3 +- .../lifecycle/LifeCycleDateFieldEmpty.js | 2 +- .../lifecycle/LifeCycleDateFieldEmpty.tsx | 2 +- .../LifeCycleDateFieldEmpty.tsx.preview | 2 +- .../lifecycle/LifeCycleDateRangeField.js | 5 +- .../lifecycle/LifeCycleDateRangeField.tsx | 7 +-- .../LifeCycleDateRangeField.tsx.preview | 5 +- .../x/api/date-pickers/date-calendar.json | 10 +-- docs/pages/x/api/date-pickers/date-field.json | 10 +-- .../pages/x/api/date-pickers/date-picker.json | 10 +-- .../api/date-pickers/date-range-calendar.json | 10 +-- .../date-pickers/date-range-picker-day.json | 2 +- .../x/api/date-pickers/date-range-picker.json | 10 +-- .../x/api/date-pickers/date-time-field.json | 18 +++--- .../x/api/date-pickers/date-time-picker.json | 18 +++--- .../date-pickers/date-time-range-picker.json | 18 +++--- .../api/date-pickers/desktop-date-picker.json | 10 +-- .../desktop-date-range-picker.json | 10 +-- .../desktop-date-time-picker.json | 18 +++--- .../desktop-date-time-range-picker.json | 18 +++--- .../api/date-pickers/desktop-time-picker.json | 10 +-- .../x/api/date-pickers/digital-clock.json | 10 +-- .../api/date-pickers/mobile-date-picker.json | 10 +-- .../mobile-date-range-picker.json | 10 +-- .../date-pickers/mobile-date-time-picker.json | 18 +++--- .../mobile-date-time-range-picker.json | 18 +++--- .../api/date-pickers/mobile-time-picker.json | 10 +-- .../x/api/date-pickers/month-calendar.json | 10 +-- .../multi-input-date-range-field.json | 10 +-- .../multi-input-date-time-range-field.json | 18 +++--- .../multi-input-time-range-field.json | 10 +-- .../multi-section-digital-clock.json | 10 +-- .../pages/x/api/date-pickers/pickers-day.json | 2 +- .../single-input-date-range-field.json | 10 +-- .../single-input-date-time-range-field.json | 18 +++--- .../single-input-time-range-field.json | 10 +-- .../api/date-pickers/static-date-picker.json | 10 +-- .../static-date-range-picker.json | 10 +-- .../date-pickers/static-date-time-picker.json | 18 +++--- .../api/date-pickers/static-time-picker.json | 10 +-- docs/pages/x/api/date-pickers/time-clock.json | 10 +-- docs/pages/x/api/date-pickers/time-field.json | 10 +-- .../pages/x/api/date-pickers/time-picker.json | 10 +-- .../x/api/date-pickers/year-calendar.json | 10 +-- docs/scripts/generateProptypes.ts | 29 +++++++++ .../DateRangeCalendar/DateRangeCalendar.tsx | 22 +++---- .../DateRangeCalendar.types.ts | 15 ++--- .../src/DateRangeCalendar/useDragRange.ts | 12 ++-- .../src/DateRangePicker/DateRangePicker.tsx | 15 ++--- .../DateRangePicker/DateRangePicker.types.ts | 7 ++- .../DateRangePickerToolbar.tsx | 7 ++- .../src/DateRangePicker/shared.tsx | 13 ++-- .../DateRangePickerDay/DateRangePickerDay.tsx | 16 ++--- .../DateTimeRangePicker.tsx | 28 ++++----- .../DateTimeRangePicker.types.ts | 7 ++- .../DateTimeRangePickerTimeWrapper.tsx | 5 +- .../DateTimeRangePickerToolbar.tsx | 16 ++--- .../src/DateTimeRangePicker/shared.tsx | 11 ++-- .../DesktopDateRangePicker.tsx | 20 +++--- .../DesktopDateRangePicker.types.ts | 7 ++- .../DesktopDateTimeRangePicker.tsx | 30 ++++----- .../DesktopDateTimeRangePicker.types.ts | 7 ++- .../DesktopDateTimeRangePickerLayout.tsx | 3 +- .../MobileDateRangePicker.tsx | 20 +++--- .../MobileDateRangePicker.types.ts | 7 ++- .../MobileDateTimeRangePicker.tsx | 30 ++++----- .../MobileDateTimeRangePicker.types.ts | 7 ++- .../MultiInputDateRangeField.tsx | 20 +++--- .../MultiInputDateRangeField.types.ts | 20 +++--- .../MultiInputDateTimeRangeField.tsx | 28 ++++----- .../MultiInputDateTimeRangeField.types.ts | 21 ++++--- .../MultiInputTimeRangeField.tsx | 20 +++--- .../MultiInputTimeRangeField.types.ts | 22 ++++--- .../SingleInputDateRangeField.tsx | 20 +++--- .../SingleInputDateRangeField.types.ts | 22 ++++--- .../useSingleInputDateRangeField.ts | 8 ++- .../SingleInputDateTimeRangeField.tsx | 23 +++---- .../SingleInputDateTimeRangeField.types.ts | 20 +++--- .../useSingleInputDateTimeRangeField.ts | 11 +++- .../SingleInputTimeRangeField.tsx | 20 +++--- .../SingleInputTimeRangeField.types.ts | 22 ++++--- .../useSingleInputTimeRangeField.ts | 8 ++- .../StaticDateRangePicker.tsx | 20 +++--- .../StaticDateRangePicker.types.ts | 7 ++- .../dateRangeViewRenderers.tsx | 9 ++- .../internals/hooks/models/useRangePicker.ts | 21 ++++--- .../useDesktopRangePicker.tsx | 3 +- .../useDesktopRangePicker.types.ts | 20 +++--- .../hooks/useEnrichedRangePickerFieldProps.ts | 20 ++++-- .../useMobileRangePicker.tsx | 3 +- .../useMobileRangePicker.types.ts | 20 +++--- .../useMultiInputDateRangeField.ts | 17 +++-- .../useMultiInputDateTimeRangeField.ts | 16 +++-- .../useMultiInputTimeRangeField.ts | 22 +++---- .../useStaticRangePicker.tsx | 3 +- .../useStaticRangePicker.types.ts | 17 +++-- .../src/internals/models/dateRange.ts | 7 ++- .../src/internals/models/dateTimeRange.ts | 5 +- .../src/internals/models/fields.ts | 10 ++- .../src/internals/models/timeRange.ts | 5 +- .../src/internals/utils/date-range-manager.ts | 10 +-- .../src/internals/utils/date-utils.ts | 10 +-- .../utils/validation/validateDateRange.ts | 4 +- .../utils/validation/validateDateTimeRange.ts | 4 +- .../src/internals/utils/valueManagers.ts | 3 +- .../x-date-pickers-pro/src/models/range.ts | 6 +- .../src/themeAugmentation/props.d.ts | 34 +++++----- .../AdapterDateFnsBase/AdapterDateFnsBase.ts | 6 ++ .../AdapterDateFnsJalali.ts | 6 ++ .../src/AdapterDayjs/AdapterDayjs.ts | 6 ++ .../src/AdapterLuxon/AdapterLuxon.ts | 6 ++ .../src/AdapterMoment/AdapterMoment.ts | 6 ++ .../AdapterMomentHijri/AdapterMomentHijri.ts | 6 ++ .../AdapterMomentJalaali.ts | 6 ++ .../src/DateCalendar/DateCalendar.tsx | 17 ++--- .../src/DateCalendar/DateCalendar.types.ts | 12 ++-- .../src/DateCalendar/DayCalendar.tsx | 15 ++--- .../tests/validation.DateCalendar.test.tsx | 3 +- .../src/DateCalendar/useCalendarState.tsx | 16 ++--- .../src/DateCalendar/useIsDateDisabled.ts | 3 +- .../src/DateField/DateField.tsx | 15 ++--- .../src/DateField/DateField.types.ts | 22 +++---- .../src/DateField/useDateField.ts | 5 +- .../src/DatePicker/DatePicker.tsx | 15 ++--- .../src/DatePicker/DatePicker.types.ts | 7 ++- .../src/DatePicker/DatePickerToolbar.tsx | 16 ++--- .../x-date-pickers/src/DatePicker/shared.tsx | 20 +++--- .../src/DateTimeField/DateTimeField.tsx | 23 +++---- .../src/DateTimeField/DateTimeField.types.ts | 22 +++---- .../src/DateTimeField/useDateTimeField.ts | 5 +- .../src/DateTimePicker/DateTimePicker.tsx | 23 +++---- .../DateTimePicker/DateTimePicker.types.ts | 7 ++- .../DateTimePicker/DateTimePickerToolbar.tsx | 9 ++- .../src/DateTimePicker/shared.tsx | 18 +++--- .../DesktopDatePicker/DesktopDatePicker.tsx | 21 +++---- .../DesktopDatePicker.types.ts | 8 +-- .../tests/DesktopDatePicker.test.tsx | 9 --- .../DesktopDateTimePicker.tsx | 28 ++++----- .../DesktopDateTimePicker.types.ts | 8 +-- .../DesktopTimePicker/DesktopTimePicker.tsx | 21 +++---- .../DesktopTimePicker.types.ts | 8 +-- .../src/DigitalClock/DigitalClock.tsx | 16 ++--- .../src/DigitalClock/DigitalClock.types.ts | 7 ++- .../LocalizationProvider.tsx | 17 ++--- .../src/MobileDatePicker/MobileDatePicker.tsx | 16 ++--- .../MobileDatePicker.types.ts | 8 +-- .../MobileDateTimePicker.tsx | 29 +++++---- .../MobileDateTimePicker.types.ts | 8 +-- .../tests/MobileDateTimePicker.test.tsx | 9 +-- .../src/MobileTimePicker/MobileTimePicker.tsx | 16 ++--- .../MobileTimePicker.types.ts | 20 +++--- .../src/MonthCalendar/MonthCalendar.tsx | 17 ++--- .../src/MonthCalendar/MonthCalendar.types.ts | 4 +- .../MultiSectionDigitalClock.tsx | 16 ++--- .../MultiSectionDigitalClock.types.ts | 6 +- .../MultiSectionDigitalClock.utils.ts | 10 +-- .../PickersCalendarHeader.tsx | 16 ++--- .../PickersCalendarHeader.types.ts | 13 ++-- .../src/PickersDay/PickersDay.tsx | 9 +-- .../src/PickersLayout/PickersLayout.tsx | 3 +- .../src/PickersLayout/PickersLayout.types.ts | 33 +++++++--- .../src/PickersLayout/usePickerLayout.tsx | 9 ++- .../src/StaticDatePicker/StaticDatePicker.tsx | 16 ++--- .../StaticDatePicker.types.ts | 8 +-- .../StaticDateTimePicker.tsx | 29 +++++---- .../StaticDateTimePicker.types.ts | 8 +-- .../src/StaticTimePicker/StaticTimePicker.tsx | 16 ++--- .../StaticTimePicker.types.ts | 8 +-- .../x-date-pickers/src/TimeClock/Clock.tsx | 7 ++- .../src/TimeClock/ClockNumbers.tsx | 8 +-- .../src/TimeClock/TimeClock.tsx | 16 ++--- .../src/TimeClock/TimeClock.types.ts | 11 ++-- .../src/TimeField/TimeField.tsx | 15 ++--- .../src/TimeField/TimeField.types.ts | 22 +++---- .../src/TimeField/useTimeField.ts | 5 +- .../src/TimePicker/TimePicker.tsx | 15 ++--- .../src/TimePicker/TimePicker.types.ts | 7 ++- .../src/TimePicker/TimePickerToolbar.tsx | 7 ++- .../x-date-pickers/src/TimePicker/shared.tsx | 14 +++-- .../src/YearCalendar/YearCalendar.tsx | 19 +++--- .../src/YearCalendar/YearCalendar.types.ts | 4 +- .../dateTimeViewRenderers.tsx | 5 +- .../dateViewRenderers/dateViewRenderers.tsx | 10 +-- .../internals/hooks/date-helpers-hooks.tsx | 10 +-- .../internals/hooks/useClockReferenceDate.ts | 4 +- .../useDesktopPicker/useDesktopPicker.tsx | 4 +- .../useDesktopPicker.types.ts | 31 +++++++--- .../src/internals/hooks/useField/useField.ts | 4 +- .../hooks/useField/useField.types.ts | 30 ++++++--- .../hooks/useField/useField.utils.ts | 38 +++++++----- .../useField/useFieldCharacterEditing.ts | 9 ++- .../internals/hooks/useField/useFieldState.ts | 4 +- .../hooks/useMobilePicker/useMobilePicker.tsx | 4 +- .../useMobilePicker/useMobilePicker.types.ts | 31 +++++++--- .../internals/hooks/usePicker/usePicker.ts | 4 +- .../hooks/usePicker/usePicker.types.ts | 8 +-- .../hooks/usePicker/usePickerValue.ts | 9 ++- .../hooks/usePicker/usePickerValue.types.ts | 9 +-- .../hooks/usePicker/usePickerViews.ts | 10 +-- .../hooks/useStaticPicker/useStaticPicker.tsx | 4 +- .../useStaticPicker/useStaticPicker.types.ts | 20 +++--- .../src/internals/hooks/useUtils.ts | 14 +++-- .../src/internals/hooks/useValidation.ts | 10 ++- .../internals/hooks/useValueWithTimezone.ts | 10 ++- .../src/internals/hooks/useViews.tsx | 3 +- .../src/internals/models/fields.ts | 10 ++- .../models/props/basePickerProps.tsx | 5 +- .../src/internals/models/props/clock.ts | 8 +-- .../src/internals/models/validation.ts | 15 ++--- .../src/internals/utils/date-time-utils.ts | 15 +++-- .../src/internals/utils/date-utils.ts | 45 ++++++++++---- .../utils/getDefaultReferenceDate.ts | 12 ++-- .../src/internals/utils/time-utils.ts | 20 +++--- .../utils/validation/validateDate.ts | 4 +- .../utils/validation/validateDateTime.ts | 4 +- .../utils/validation/validateTime.ts | 4 +- .../src/internals/utils/valueManagers.ts | 3 +- .../src/locales/utils/pickersLocaleTextApi.ts | 20 ++++-- .../x-date-pickers/src/models/adapters.ts | 3 +- packages/x-date-pickers/src/models/fields.ts | 11 +++- packages/x-date-pickers/src/models/pickers.ts | 4 ++ .../tests/fieldKeyboardInteraction.test.tsx | 6 +- .../src/themeAugmentation/props.d.ts | 62 +++++++++---------- .../timeViewRenderers/timeViewRenderers.tsx | 8 +-- scripts/x-date-pickers-pro.exports.json | 2 + scripts/x-date-pickers.exports.json | 2 + .../describeGregorianAdapter.ts | 12 ++-- .../describeGregorianAdapter.types.ts | 8 +-- .../testCalculations.ts | 9 ++- .../describeHijriAdapter.ts | 4 +- .../describeHijriAdapter.types.ts | 4 +- .../describeJalaliAdapter.ts | 4 +- .../describeJalaliAdapter.types.ts | 4 +- test/utils/pickers/misc.ts | 6 +- 235 files changed, 1631 insertions(+), 1280 deletions(-) diff --git a/docs/data/data-grid/custom-columns/EditingWithDatePickers.tsx b/docs/data/data-grid/custom-columns/EditingWithDatePickers.tsx index 4f8f4803dd6c5..5942bbb3c31c6 100644 --- a/docs/data/data-grid/custom-columns/EditingWithDatePickers.tsx +++ b/docs/data/data-grid/custom-columns/EditingWithDatePickers.tsx @@ -70,7 +70,7 @@ function GridEditDateCell({ field, value, colDef, -}: GridRenderEditCellParams<any, Date | string | null>) { +}: GridRenderEditCellParams<any, Date | null, string>) { const apiRef = useGridApiContext(); const Component = colDef.type === 'dateTime' ? DateTimePicker : DatePicker; diff --git a/docs/data/date-pickers/custom-field/WrappedSingleInputDateRangePicker.tsx b/docs/data/date-pickers/custom-field/WrappedSingleInputDateRangePicker.tsx index 6e104e4b67779..a7f000683fc7c 100644 --- a/docs/data/date-pickers/custom-field/WrappedSingleInputDateRangePicker.tsx +++ b/docs/data/date-pickers/custom-field/WrappedSingleInputDateRangePicker.tsx @@ -8,8 +8,9 @@ import { SingleInputDateRangeFieldProps, } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; -type FieldComponent = (<TDate>( +type FieldComponent = (<TDate extends PickerValidDate>( props: SingleInputDateRangeFieldProps<TDate> & React.RefAttributes<HTMLInputElement>, ) => React.JSX.Element) & { fieldType?: string }; diff --git a/docs/data/date-pickers/lifecycle/LifeCycleDateFieldEmpty.js b/docs/data/date-pickers/lifecycle/LifeCycleDateFieldEmpty.js index ff6c9544090e2..3ed120732789b 100644 --- a/docs/data/date-pickers/lifecycle/LifeCycleDateFieldEmpty.js +++ b/docs/data/date-pickers/lifecycle/LifeCycleDateFieldEmpty.js @@ -12,7 +12,7 @@ export default function LifeCycleDateFieldEmpty() { return ( <Stack spacing={2}> <LocalizationProvider dateAdapter={AdapterDayjs}> - <DateField value={value} onChange={(newValue) => setValue(newValue)} /> + <DateField value={value} onChange={setValue} /> </LocalizationProvider> <Typography>Value: {value == null ? 'null' : value.format('L')}</Typography> </Stack> diff --git a/docs/data/date-pickers/lifecycle/LifeCycleDateFieldEmpty.tsx b/docs/data/date-pickers/lifecycle/LifeCycleDateFieldEmpty.tsx index 22fafe61283b9..6444023122b6b 100644 --- a/docs/data/date-pickers/lifecycle/LifeCycleDateFieldEmpty.tsx +++ b/docs/data/date-pickers/lifecycle/LifeCycleDateFieldEmpty.tsx @@ -12,7 +12,7 @@ export default function LifeCycleDateFieldEmpty() { return ( <Stack spacing={2}> <LocalizationProvider dateAdapter={AdapterDayjs}> - <DateField value={value} onChange={(newValue) => setValue(newValue)} /> + <DateField value={value} onChange={setValue} /> </LocalizationProvider> <Typography>Value: {value == null ? 'null' : value.format('L')}</Typography> </Stack> diff --git a/docs/data/date-pickers/lifecycle/LifeCycleDateFieldEmpty.tsx.preview b/docs/data/date-pickers/lifecycle/LifeCycleDateFieldEmpty.tsx.preview index 7f22674742a9f..1746e78fd888d 100644 --- a/docs/data/date-pickers/lifecycle/LifeCycleDateFieldEmpty.tsx.preview +++ b/docs/data/date-pickers/lifecycle/LifeCycleDateFieldEmpty.tsx.preview @@ -1,4 +1,4 @@ <LocalizationProvider dateAdapter={AdapterDayjs}> - <DateField value={value} onChange={(newValue) => setValue(newValue)} /> + <DateField value={value} onChange={setValue} /> </LocalizationProvider> <Typography>Value: {value == null ? 'null' : value.format('L')}</Typography> \ No newline at end of file diff --git a/docs/data/date-pickers/lifecycle/LifeCycleDateRangeField.js b/docs/data/date-pickers/lifecycle/LifeCycleDateRangeField.js index a77c9d6d5abf8..ff34833efbb6a 100644 --- a/docs/data/date-pickers/lifecycle/LifeCycleDateRangeField.js +++ b/docs/data/date-pickers/lifecycle/LifeCycleDateRangeField.js @@ -14,10 +14,7 @@ export default function LifeCycleDateRangeField() { <Stack spacing={2}> <LocalizationProvider dateAdapter={AdapterDayjs}> <DemoContainer components={['SingleInputDateRangeField']}> - <SingleInputDateRangeField - value={value} - onChange={(newValue) => setValue(newValue)} - /> + <SingleInputDateRangeField value={value} onChange={setValue} /> </DemoContainer> </LocalizationProvider> <Typography> diff --git a/docs/data/date-pickers/lifecycle/LifeCycleDateRangeField.tsx b/docs/data/date-pickers/lifecycle/LifeCycleDateRangeField.tsx index f6cae364e97b8..8bab9a5ad4607 100644 --- a/docs/data/date-pickers/lifecycle/LifeCycleDateRangeField.tsx +++ b/docs/data/date-pickers/lifecycle/LifeCycleDateRangeField.tsx @@ -9,7 +9,7 @@ import { SingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDa import { DateRange } from '@mui/x-date-pickers-pro/models'; export default function LifeCycleDateRangeField() { - const [value, setValue] = React.useState<DateRange<Dayjs | null>>([ + const [value, setValue] = React.useState<DateRange<Dayjs>>([ dayjs('2022-04-17'), null, ]); @@ -18,10 +18,7 @@ export default function LifeCycleDateRangeField() { <Stack spacing={2}> <LocalizationProvider dateAdapter={AdapterDayjs}> <DemoContainer components={['SingleInputDateRangeField']}> - <SingleInputDateRangeField - value={value} - onChange={(newValue) => setValue(newValue)} - /> + <SingleInputDateRangeField value={value} onChange={setValue} /> </DemoContainer> </LocalizationProvider> <Typography> diff --git a/docs/data/date-pickers/lifecycle/LifeCycleDateRangeField.tsx.preview b/docs/data/date-pickers/lifecycle/LifeCycleDateRangeField.tsx.preview index 90f4a115ac5da..4cce05110e86b 100644 --- a/docs/data/date-pickers/lifecycle/LifeCycleDateRangeField.tsx.preview +++ b/docs/data/date-pickers/lifecycle/LifeCycleDateRangeField.tsx.preview @@ -1,9 +1,6 @@ <LocalizationProvider dateAdapter={AdapterDayjs}> <DemoContainer components={['SingleInputDateRangeField']}> - <SingleInputDateRangeField - value={value} - onChange={(newValue) => setValue(newValue)} - /> + <SingleInputDateRangeField value={value} onChange={setValue} /> </DemoContainer> </LocalizationProvider> <Typography> diff --git a/docs/pages/x/api/date-pickers/date-calendar.json b/docs/pages/x/api/date-pickers/date-calendar.json index f0031bb5be3de..e7b9b342558f2 100644 --- a/docs/pages/x/api/date-pickers/date-calendar.json +++ b/docs/pages/x/api/date-pickers/date-calendar.json @@ -10,7 +10,7 @@ "returned": "string" } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableHighlightToday": { "type": { "name": "bool" }, "default": "false" }, @@ -24,8 +24,8 @@ } }, "loading": { "type": { "name": "bool" }, "default": "false" }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "monthsPerRow": { "type": { "name": "enum", "description": "3<br>| 4" }, "default": "3" @@ -68,7 +68,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date using the validation props, except callbacks such as `shouldDisableDate`." }, "renderLoading": { @@ -126,7 +126,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/date-field.json b/docs/pages/x/api/date-pickers/date-field.json index 46e896fb433f9..ac12fc860e072 100644 --- a/docs/pages/x/api/date-pickers/date-field.json +++ b/docs/pages/x/api/date-pickers/date-field.json @@ -9,7 +9,7 @@ }, "default": "'primary'" }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disablePast": { "type": { "name": "bool" }, "default": "false" }, @@ -36,8 +36,8 @@ }, "default": "'none'" }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "name": { "type": { "name": "string" } }, "onChange": { "type": { "name": "func" }, @@ -63,7 +63,7 @@ }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used." }, "required": { "type": { "name": "bool" }, "default": "false" }, @@ -123,7 +123,7 @@ "unstableFieldRef": { "type": { "name": "union", "description": "func<br>| object" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "variant": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/date-picker.json b/docs/pages/x/api/date-pickers/date-picker.json index 76b6407274a7d..b4a4bd93ed6e2 100644 --- a/docs/pages/x/api/date-pickers/date-picker.json +++ b/docs/pages/x/api/date-pickers/date-picker.json @@ -14,7 +14,7 @@ "returned": "string" } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "desktopModeMediaQuery": { "type": { "name": "string" }, "default": "'@media (pointer: fine)'" @@ -35,8 +35,8 @@ "label": { "type": { "name": "node" } }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "monthsPerRow": { "type": { "name": "enum", "description": "3<br>| 4" }, "default": "3" @@ -96,7 +96,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -160,7 +160,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/date-range-calendar.json b/docs/pages/x/api/date-pickers/date-range-calendar.json index afa6e86ecdf77..bc7330a92d879 100644 --- a/docs/pages/x/api/date-pickers/date-range-calendar.json +++ b/docs/pages/x/api/date-pickers/date-range-calendar.json @@ -26,7 +26,7 @@ "type": { "name": "enum", "description": "'end'<br>| 'start'" }, "default": "'start'" }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "disableAutoMonthSwitching": { "type": { "name": "bool" }, "default": "false" }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableDragEditing": { "type": { "name": "bool" }, "default": "false" }, @@ -37,8 +37,8 @@ "fixedWeekNumber": { "type": { "name": "number" }, "default": "undefined" }, "focusedView": { "type": { "name": "enum", "description": "'day'" } }, "loading": { "type": { "name": "bool" }, "default": "false" }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "onChange": { "type": { "name": "func" }, "signature": { @@ -76,7 +76,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date using the validation props, except callbacks such as `shouldDisableDate`." }, "renderLoading": { @@ -118,7 +118,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "view": { "type": { "name": "enum", "description": "'day'" } }, "views": { "type": { "name": "arrayOf", "description": "Array<'day'>" } } }, diff --git a/docs/pages/x/api/date-pickers/date-range-picker-day.json b/docs/pages/x/api/date-pickers/date-range-picker-day.json index 03725816fc5ab..fc19b9e50ec6d 100644 --- a/docs/pages/x/api/date-pickers/date-range-picker-day.json +++ b/docs/pages/x/api/date-pickers/date-range-picker-day.json @@ -1,6 +1,6 @@ { "props": { - "day": { "type": { "name": "any" }, "required": true }, + "day": { "type": { "name": "object" }, "required": true }, "isEndOfHighlighting": { "type": { "name": "bool" }, "required": true }, "isEndOfPreviewing": { "type": { "name": "bool" }, "required": true }, "isFirstVisibleCell": { "type": { "name": "bool" }, "required": true }, diff --git a/docs/pages/x/api/date-pickers/date-range-picker.json b/docs/pages/x/api/date-pickers/date-range-picker.json index 09c5a61c90075..e880dfb8e391d 100644 --- a/docs/pages/x/api/date-pickers/date-range-picker.json +++ b/docs/pages/x/api/date-pickers/date-range-picker.json @@ -26,7 +26,7 @@ "type": { "name": "enum", "description": "'end'<br>| 'start'" }, "default": "'start'" }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "desktopModeMediaQuery": { "type": { "name": "string" }, "default": "'@media (pointer: fine)'" @@ -49,8 +49,8 @@ "label": { "type": { "name": "node" } }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, @@ -97,7 +97,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -145,7 +145,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "viewRenderers": { "type": { "name": "shape", "description": "{ day?: func }" } } }, "name": "DateRangePicker", diff --git a/docs/pages/x/api/date-pickers/date-time-field.json b/docs/pages/x/api/date-pickers/date-time-field.json index 2ccfcbcc7dd5e..6c12c32f7960c 100644 --- a/docs/pages/x/api/date-pickers/date-time-field.json +++ b/docs/pages/x/api/date-pickers/date-time-field.json @@ -10,7 +10,7 @@ }, "default": "'primary'" }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" }, "default": "false" }, @@ -38,12 +38,12 @@ }, "default": "'none'" }, - "maxDate": { "type": { "name": "any" } }, - "maxDateTime": { "type": { "name": "any" } }, - "maxTime": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, - "minDateTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "maxDateTime": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, + "minDateTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "name": { "type": { "name": "string" } }, "onChange": { @@ -70,7 +70,7 @@ }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used." }, "required": { "type": { "name": "bool" }, "default": "false" }, @@ -138,7 +138,7 @@ "unstableFieldRef": { "type": { "name": "union", "description": "func<br>| object" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "variant": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/date-time-picker.json b/docs/pages/x/api/date-pickers/date-time-picker.json index 5416d121b8774..1c10d4ccfcdee 100644 --- a/docs/pages/x/api/date-pickers/date-time-picker.json +++ b/docs/pages/x/api/date-pickers/date-time-picker.json @@ -16,7 +16,7 @@ "returned": "string" } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "desktopModeMediaQuery": { "type": { "name": "string" }, "default": "'@media (pointer: fine)'" @@ -38,12 +38,12 @@ "label": { "type": { "name": "node" } }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "maxDateTime": { "type": { "name": "any" } }, - "maxTime": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, - "minDateTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "maxDateTime": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, + "minDateTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "monthsPerRow": { "type": { "name": "enum", "description": "3<br>| 4" }, @@ -104,7 +104,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -185,7 +185,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/date-time-range-picker.json b/docs/pages/x/api/date-pickers/date-time-range-picker.json index 55d6d1ee2f796..ce588b76b7efb 100644 --- a/docs/pages/x/api/date-pickers/date-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/date-time-range-picker.json @@ -27,7 +27,7 @@ "type": { "name": "enum", "description": "'end'<br>| 'start'" }, "default": "'start'" }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "desktopModeMediaQuery": { "type": { "name": "string" }, "default": "'@media (pointer: fine)'" @@ -53,12 +53,12 @@ "label": { "type": { "name": "node" } }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "maxDateTime": { "type": { "name": "any" } }, - "maxTime": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, - "minDateTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "maxDateTime": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, + "minDateTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "name": { "type": { "name": "string" } }, "onAccept": { @@ -116,7 +116,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -181,7 +181,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/desktop-date-picker.json b/docs/pages/x/api/date-pickers/desktop-date-picker.json index 69ab72f56f8b9..af6728769c595 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-picker.json @@ -14,7 +14,7 @@ "returned": "string" } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableHighlightToday": { "type": { "name": "bool" }, "default": "false" }, @@ -31,8 +31,8 @@ "label": { "type": { "name": "node" } }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "monthsPerRow": { "type": { "name": "enum", "description": "3<br>| 4" }, "default": "3" @@ -92,7 +92,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -156,7 +156,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/desktop-date-range-picker.json b/docs/pages/x/api/date-pickers/desktop-date-range-picker.json index f846abac5f697..6803cc3627dbf 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-range-picker.json @@ -26,7 +26,7 @@ "type": { "name": "enum", "description": "'end'<br>| 'start'" }, "default": "'start'" }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "disableAutoMonthSwitching": { "type": { "name": "bool" }, "default": "false" }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableDragEditing": { "type": { "name": "bool" }, "default": "false" }, @@ -45,8 +45,8 @@ "label": { "type": { "name": "node" } }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, @@ -93,7 +93,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -141,7 +141,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "viewRenderers": { "type": { "name": "shape", "description": "{ day?: func }" } } }, "name": "DesktopDateRangePicker", diff --git a/docs/pages/x/api/date-pickers/desktop-date-time-picker.json b/docs/pages/x/api/date-pickers/desktop-date-time-picker.json index 854019a2a091b..737c15cbb3e37 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-time-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-time-picker.json @@ -16,7 +16,7 @@ "returned": "string" } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableHighlightToday": { "type": { "name": "bool" }, "default": "false" }, @@ -34,12 +34,12 @@ "label": { "type": { "name": "node" } }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "maxDateTime": { "type": { "name": "any" } }, - "maxTime": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, - "minDateTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "maxDateTime": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, + "minDateTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "monthsPerRow": { "type": { "name": "enum", "description": "3<br>| 4" }, @@ -100,7 +100,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -181,7 +181,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/desktop-date-time-range-picker.json b/docs/pages/x/api/date-pickers/desktop-date-time-range-picker.json index 90357b9228f5f..b083f9ceeb1e0 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-time-range-picker.json @@ -27,7 +27,7 @@ "type": { "name": "enum", "description": "'end'<br>| 'start'" }, "default": "'start'" }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "disableAutoMonthSwitching": { "type": { "name": "bool" }, "default": "false" }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableDragEditing": { "type": { "name": "bool" }, "default": "false" }, @@ -49,12 +49,12 @@ "label": { "type": { "name": "node" } }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "maxDateTime": { "type": { "name": "any" } }, - "maxTime": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, - "minDateTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "maxDateTime": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, + "minDateTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "name": { "type": { "name": "string" } }, "onAccept": { @@ -112,7 +112,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -177,7 +177,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/desktop-time-picker.json b/docs/pages/x/api/date-pickers/desktop-time-picker.json index 1b91794a34ccb..8273e26e92d90 100644 --- a/docs/pages/x/api/date-pickers/desktop-time-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-time-picker.json @@ -7,7 +7,7 @@ "type": { "name": "bool" }, "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" }, "default": "false" }, @@ -21,8 +21,8 @@ "inputRef": { "type": { "name": "custom", "description": "ref" } }, "label": { "type": { "name": "node" } }, "localeText": { "type": { "name": "object" } }, - "maxTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "name": { "type": { "name": "string" } }, "onAccept": { @@ -71,7 +71,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "selectedSections": { @@ -118,7 +118,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/digital-clock.json b/docs/pages/x/api/date-pickers/digital-clock.json index 8f3d3af0be1c9..ab41bb11244ee 100644 --- a/docs/pages/x/api/date-pickers/digital-clock.json +++ b/docs/pages/x/api/date-pickers/digital-clock.json @@ -3,14 +3,14 @@ "ampm": { "type": { "name": "bool" }, "default": "`utils.is12HourCycleInCurrentLocale()`" }, "autoFocus": { "type": { "name": "bool" } }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" }, "default": "false" }, "disablePast": { "type": { "name": "bool" }, "default": "false" }, "focusedView": { "type": { "name": "enum", "description": "'hours'" } }, - "maxTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "onChange": { "type": { "name": "func" }, @@ -33,7 +33,7 @@ "openTo": { "type": { "name": "enum", "description": "'hours'" } }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid time using the validation props, except callbacks such as `shouldDisableTime`." }, "shouldDisableTime": { @@ -67,7 +67,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", "description": "'hours'" } }, "views": { "type": { "name": "arrayOf", "description": "Array<'hours'>" }, diff --git a/docs/pages/x/api/date-pickers/mobile-date-picker.json b/docs/pages/x/api/date-pickers/mobile-date-picker.json index d519138df7f8d..54682e73a7af4 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-picker.json @@ -14,7 +14,7 @@ "returned": "string" } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableHighlightToday": { "type": { "name": "bool" }, "default": "false" }, @@ -31,8 +31,8 @@ "label": { "type": { "name": "node" } }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "monthsPerRow": { "type": { "name": "enum", "description": "3<br>| 4" }, "default": "3" @@ -92,7 +92,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -156,7 +156,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/mobile-date-range-picker.json b/docs/pages/x/api/date-pickers/mobile-date-range-picker.json index 88e6f7786dc1b..a4e7fd4f0ee02 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-range-picker.json @@ -22,7 +22,7 @@ "type": { "name": "enum", "description": "'end'<br>| 'start'" }, "default": "'start'" }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "disableAutoMonthSwitching": { "type": { "name": "bool" }, "default": "false" }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableDragEditing": { "type": { "name": "bool" }, "default": "false" }, @@ -41,8 +41,8 @@ "label": { "type": { "name": "node" } }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "name": { "type": { "name": "string" } }, "onAccept": { "type": { "name": "func" }, @@ -89,7 +89,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -137,7 +137,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "viewRenderers": { "type": { "name": "shape", "description": "{ day?: func }" } } }, "name": "MobileDateRangePicker", diff --git a/docs/pages/x/api/date-pickers/mobile-date-time-picker.json b/docs/pages/x/api/date-pickers/mobile-date-time-picker.json index df40abdc0f886..dfc374df13ffd 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-time-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-time-picker.json @@ -16,7 +16,7 @@ "returned": "string" } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableHighlightToday": { "type": { "name": "bool" }, "default": "false" }, @@ -34,12 +34,12 @@ "label": { "type": { "name": "node" } }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "maxDateTime": { "type": { "name": "any" } }, - "maxTime": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, - "minDateTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "maxDateTime": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, + "minDateTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "monthsPerRow": { "type": { "name": "enum", "description": "3<br>| 4" }, @@ -100,7 +100,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -172,7 +172,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/mobile-date-time-range-picker.json b/docs/pages/x/api/date-pickers/mobile-date-time-range-picker.json index 688f24d49b0d3..fdbfb01fa0753 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-time-range-picker.json @@ -23,7 +23,7 @@ "type": { "name": "enum", "description": "'end'<br>| 'start'" }, "default": "'start'" }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "disableAutoMonthSwitching": { "type": { "name": "bool" }, "default": "false" }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableDragEditing": { "type": { "name": "bool" }, "default": "false" }, @@ -45,12 +45,12 @@ "label": { "type": { "name": "node" } }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "maxDateTime": { "type": { "name": "any" } }, - "maxTime": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, - "minDateTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "maxDateTime": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, + "minDateTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "name": { "type": { "name": "string" } }, "onAccept": { @@ -108,7 +108,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -173,7 +173,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/mobile-time-picker.json b/docs/pages/x/api/date-pickers/mobile-time-picker.json index 59748eba26059..ff478590ca5df 100644 --- a/docs/pages/x/api/date-pickers/mobile-time-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-time-picker.json @@ -7,7 +7,7 @@ "type": { "name": "bool" }, "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" }, "default": "false" }, @@ -21,8 +21,8 @@ "inputRef": { "type": { "name": "custom", "description": "ref" } }, "label": { "type": { "name": "node" } }, "localeText": { "type": { "name": "object" } }, - "maxTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "name": { "type": { "name": "string" } }, "onAccept": { @@ -71,7 +71,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "selectedSections": { @@ -109,7 +109,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/month-calendar.json b/docs/pages/x/api/date-pickers/month-calendar.json index 55c00405e6710..2fe02db3fe453 100644 --- a/docs/pages/x/api/date-pickers/month-calendar.json +++ b/docs/pages/x/api/date-pickers/month-calendar.json @@ -1,13 +1,13 @@ { "props": { "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" } }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableHighlightToday": { "type": { "name": "bool" }, "default": "false" }, "disablePast": { "type": { "name": "bool" }, "default": "false" }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "monthsPerRow": { "type": { "name": "enum", "description": "3<br>| 4" }, "default": "3" @@ -18,7 +18,7 @@ }, "readOnly": { "type": { "name": "bool" } }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid month using the validation props, except callbacks such as `shouldDisableMonth`." }, "shouldDisableMonth": { @@ -44,7 +44,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } } + "value": { "type": { "name": "object" } } }, "name": "MonthCalendar", "imports": [ diff --git a/docs/pages/x/api/date-pickers/multi-input-date-range-field.json b/docs/pages/x/api/date-pickers/multi-input-date-range-field.json index 43fa71b3f73fd..ab581f1f6f69f 100644 --- a/docs/pages/x/api/date-pickers/multi-input-date-range-field.json +++ b/docs/pages/x/api/date-pickers/multi-input-date-range-field.json @@ -1,7 +1,7 @@ { "props": { "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "direction": { "type": { "name": "union", @@ -18,8 +18,8 @@ "type": { "name": "enum", "description": "'dense'<br>| 'spacious'" }, "default": "\"dense\"" }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "onChange": { "type": { "name": "func" }, "signature": { @@ -43,7 +43,7 @@ }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used." }, "selectedSections": { @@ -90,7 +90,7 @@ } }, "useFlexGap": { "type": { "name": "bool" }, "default": "false" }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } } + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } } }, "name": "MultiInputDateRangeField", "imports": [ diff --git a/docs/pages/x/api/date-pickers/multi-input-date-time-range-field.json b/docs/pages/x/api/date-pickers/multi-input-date-time-range-field.json index 481f133235df6..3ad6a4c4bc6bc 100644 --- a/docs/pages/x/api/date-pickers/multi-input-date-time-range-field.json +++ b/docs/pages/x/api/date-pickers/multi-input-date-time-range-field.json @@ -2,7 +2,7 @@ "props": { "ampm": { "type": { "name": "bool" }, "default": "`utils.is12HourCycleInCurrentLocale()`" }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "direction": { "type": { "name": "union", @@ -20,12 +20,12 @@ "type": { "name": "enum", "description": "'dense'<br>| 'spacious'" }, "default": "\"dense\"" }, - "maxDate": { "type": { "name": "any" } }, - "maxDateTime": { "type": { "name": "any" } }, - "maxTime": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, - "minDateTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "maxDateTime": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, + "minDateTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "onChange": { "type": { "name": "func" }, @@ -50,7 +50,7 @@ }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used." }, "selectedSections": { @@ -105,7 +105,7 @@ } }, "useFlexGap": { "type": { "name": "bool" }, "default": "false" }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } } + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } } }, "name": "MultiInputDateTimeRangeField", "imports": [ diff --git a/docs/pages/x/api/date-pickers/multi-input-time-range-field.json b/docs/pages/x/api/date-pickers/multi-input-time-range-field.json index 9ea14b1bd7785..230921861f532 100644 --- a/docs/pages/x/api/date-pickers/multi-input-time-range-field.json +++ b/docs/pages/x/api/date-pickers/multi-input-time-range-field.json @@ -2,7 +2,7 @@ "props": { "ampm": { "type": { "name": "bool" }, "default": "`utils.is12HourCycleInCurrentLocale()`" }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "direction": { "type": { "name": "union", @@ -20,8 +20,8 @@ "type": { "name": "enum", "description": "'dense'<br>| 'spacious'" }, "default": "\"dense\"" }, - "maxTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "onChange": { "type": { "name": "func" }, @@ -46,7 +46,7 @@ }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used." }, "selectedSections": { @@ -93,7 +93,7 @@ } }, "useFlexGap": { "type": { "name": "bool" }, "default": "false" }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } } + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } } }, "name": "MultiInputTimeRangeField", "imports": [ diff --git a/docs/pages/x/api/date-pickers/multi-section-digital-clock.json b/docs/pages/x/api/date-pickers/multi-section-digital-clock.json index f87b4cc0e5445..792a65ce1208b 100644 --- a/docs/pages/x/api/date-pickers/multi-section-digital-clock.json +++ b/docs/pages/x/api/date-pickers/multi-section-digital-clock.json @@ -3,7 +3,7 @@ "ampm": { "type": { "name": "bool" }, "default": "`utils.is12HourCycleInCurrentLocale()`" }, "autoFocus": { "type": { "name": "bool" } }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" }, "default": "false" }, @@ -14,8 +14,8 @@ "description": "'hours'<br>| 'meridiem'<br>| 'minutes'<br>| 'seconds'" } }, - "maxTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "onChange": { "type": { "name": "func" }, @@ -43,7 +43,7 @@ }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid time using the validation props, except callbacks such as `shouldDisableTime`." }, "shouldDisableTime": { @@ -83,7 +83,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/pickers-day.json b/docs/pages/x/api/date-pickers/pickers-day.json index 42e74730e2908..1380c63391db3 100644 --- a/docs/pages/x/api/date-pickers/pickers-day.json +++ b/docs/pages/x/api/date-pickers/pickers-day.json @@ -1,6 +1,6 @@ { "props": { - "day": { "type": { "name": "any" }, "required": true }, + "day": { "type": { "name": "object" }, "required": true }, "isFirstVisibleCell": { "type": { "name": "bool" }, "required": true }, "isLastVisibleCell": { "type": { "name": "bool" }, "required": true }, "outsideCurrentMonth": { "type": { "name": "bool" }, "required": true }, diff --git a/docs/pages/x/api/date-pickers/single-input-date-range-field.json b/docs/pages/x/api/date-pickers/single-input-date-range-field.json index bf3556552fea7..0b8a151594e24 100644 --- a/docs/pages/x/api/date-pickers/single-input-date-range-field.json +++ b/docs/pages/x/api/date-pickers/single-input-date-range-field.json @@ -9,7 +9,7 @@ }, "default": "'primary'" }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disablePast": { "type": { "name": "bool" }, "default": "false" }, @@ -36,8 +36,8 @@ }, "default": "'none'" }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "name": { "type": { "name": "string" } }, "onChange": { "type": { "name": "func" }, @@ -63,7 +63,7 @@ }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used." }, "required": { "type": { "name": "bool" }, "default": "false" }, @@ -107,7 +107,7 @@ "unstableFieldRef": { "type": { "name": "union", "description": "func<br>| object" } }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "variant": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/single-input-date-time-range-field.json b/docs/pages/x/api/date-pickers/single-input-date-time-range-field.json index 2e611014ece1d..5ea7d709048a7 100644 --- a/docs/pages/x/api/date-pickers/single-input-date-time-range-field.json +++ b/docs/pages/x/api/date-pickers/single-input-date-time-range-field.json @@ -10,7 +10,7 @@ }, "default": "'primary'" }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" }, "default": "false" }, @@ -38,12 +38,12 @@ }, "default": "'none'" }, - "maxDate": { "type": { "name": "any" } }, - "maxDateTime": { "type": { "name": "any" } }, - "maxTime": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, - "minDateTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "maxDateTime": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, + "minDateTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "name": { "type": { "name": "string" } }, "onChange": { @@ -70,7 +70,7 @@ }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used." }, "required": { "type": { "name": "bool" }, "default": "false" }, @@ -122,7 +122,7 @@ "unstableFieldRef": { "type": { "name": "union", "description": "func<br>| object" } }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "variant": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/single-input-time-range-field.json b/docs/pages/x/api/date-pickers/single-input-time-range-field.json index 4e6f7c5e11346..3c00fc18fb75d 100644 --- a/docs/pages/x/api/date-pickers/single-input-time-range-field.json +++ b/docs/pages/x/api/date-pickers/single-input-time-range-field.json @@ -10,7 +10,7 @@ }, "default": "'primary'" }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" }, "default": "false" }, @@ -38,8 +38,8 @@ }, "default": "'none'" }, - "maxTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "name": { "type": { "name": "string" } }, "onChange": { @@ -66,7 +66,7 @@ }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used." }, "required": { "type": { "name": "bool" }, "default": "false" }, @@ -110,7 +110,7 @@ "unstableFieldRef": { "type": { "name": "union", "description": "func<br>| object" } }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "variant": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/static-date-picker.json b/docs/pages/x/api/date-pickers/static-date-picker.json index 32cf7df69729f..169d9df97f5b2 100644 --- a/docs/pages/x/api/date-pickers/static-date-picker.json +++ b/docs/pages/x/api/date-pickers/static-date-picker.json @@ -10,7 +10,7 @@ "returned": "string" } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableHighlightToday": { "type": { "name": "bool" }, "default": "false" }, @@ -23,8 +23,8 @@ "fixedWeekNumber": { "type": { "name": "number" }, "default": "undefined" }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "monthsPerRow": { "type": { "name": "enum", "description": "3<br>| 4" }, "default": "3" @@ -78,7 +78,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -136,7 +136,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/static-date-range-picker.json b/docs/pages/x/api/date-pickers/static-date-range-picker.json index 13df18576c7c3..7147a6a57dd4b 100644 --- a/docs/pages/x/api/date-pickers/static-date-range-picker.json +++ b/docs/pages/x/api/date-pickers/static-date-range-picker.json @@ -22,7 +22,7 @@ "type": { "name": "enum", "description": "'end'<br>| 'start'" }, "default": "'start'" }, - "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "disableAutoMonthSwitching": { "type": { "name": "bool" }, "default": "false" }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableDragEditing": { "type": { "name": "bool" }, "default": "false" }, @@ -37,8 +37,8 @@ "fixedWeekNumber": { "type": { "name": "number" }, "default": "undefined" }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "onAccept": { "type": { "name": "func" }, "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } @@ -79,7 +79,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -121,7 +121,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, "viewRenderers": { "type": { "name": "shape", "description": "{ day?: func }" } } }, "name": "StaticDateRangePicker", diff --git a/docs/pages/x/api/date-pickers/static-date-time-picker.json b/docs/pages/x/api/date-pickers/static-date-time-picker.json index de69515b02677..49608fc99029e 100644 --- a/docs/pages/x/api/date-pickers/static-date-time-picker.json +++ b/docs/pages/x/api/date-pickers/static-date-time-picker.json @@ -12,7 +12,7 @@ "returned": "string" } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableHighlightToday": { "type": { "name": "bool" }, "default": "false" }, @@ -26,12 +26,12 @@ "fixedWeekNumber": { "type": { "name": "number" }, "default": "undefined" }, "loading": { "type": { "name": "bool" }, "default": "false" }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "maxDateTime": { "type": { "name": "any" } }, - "maxTime": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, - "minDateTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "maxDateTime": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, + "minDateTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "monthsPerRow": { "type": { "name": "enum", "description": "3<br>| 4" }, @@ -86,7 +86,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "renderLoading": { @@ -152,7 +152,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/static-time-picker.json b/docs/pages/x/api/date-pickers/static-time-picker.json index d0995c15ec712..5cf72df9cbf49 100644 --- a/docs/pages/x/api/date-pickers/static-time-picker.json +++ b/docs/pages/x/api/date-pickers/static-time-picker.json @@ -3,7 +3,7 @@ "ampm": { "type": { "name": "bool" }, "default": "`utils.is12HourCycleInCurrentLocale()`" }, "ampmInClock": { "type": { "name": "bool" }, "default": "true on desktop, false on mobile" }, "autoFocus": { "type": { "name": "bool" } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" }, "default": "false" }, @@ -13,8 +13,8 @@ "default": "\"mobile\"" }, "localeText": { "type": { "name": "object" } }, - "maxTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "onAccept": { "type": { "name": "func" }, @@ -57,7 +57,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "shouldDisableTime": { @@ -89,7 +89,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/time-clock.json b/docs/pages/x/api/date-pickers/time-clock.json index 86d8ec9214f7c..f569a5c964f98 100644 --- a/docs/pages/x/api/date-pickers/time-clock.json +++ b/docs/pages/x/api/date-pickers/time-clock.json @@ -4,7 +4,7 @@ "ampmInClock": { "type": { "name": "bool" }, "default": "false" }, "autoFocus": { "type": { "name": "bool" } }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" }, "default": "false" }, @@ -15,8 +15,8 @@ "description": "'hours'<br>| 'minutes'<br>| 'seconds'" } }, - "maxTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "onChange": { "type": { "name": "func" }, @@ -44,7 +44,7 @@ }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid time using the validation props, except callbacks such as `shouldDisableTime`." }, "shouldDisableTime": { @@ -76,7 +76,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/time-field.json b/docs/pages/x/api/date-pickers/time-field.json index ad24b2bd2a52c..8f87d61b8c3ad 100644 --- a/docs/pages/x/api/date-pickers/time-field.json +++ b/docs/pages/x/api/date-pickers/time-field.json @@ -10,7 +10,7 @@ }, "default": "'primary'" }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" }, "default": "false" }, @@ -38,8 +38,8 @@ }, "default": "'none'" }, - "maxTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "name": { "type": { "name": "string" } }, "onChange": { @@ -66,7 +66,7 @@ }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used." }, "required": { "type": { "name": "bool" }, "default": "false" }, @@ -110,7 +110,7 @@ "unstableFieldRef": { "type": { "name": "union", "description": "func<br>| object" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "variant": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/time-picker.json b/docs/pages/x/api/date-pickers/time-picker.json index 071c5ad8f4c25..d3386734875f2 100644 --- a/docs/pages/x/api/date-pickers/time-picker.json +++ b/docs/pages/x/api/date-pickers/time-picker.json @@ -7,7 +7,7 @@ "type": { "name": "bool" }, "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "desktopModeMediaQuery": { "type": { "name": "string" }, "default": "'@media (pointer: fine)'" @@ -25,8 +25,8 @@ "inputRef": { "type": { "name": "custom", "description": "ref" } }, "label": { "type": { "name": "node" } }, "localeText": { "type": { "name": "object" } }, - "maxTime": { "type": { "name": "any" } }, - "minTime": { "type": { "name": "any" } }, + "maxTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, "minutesStep": { "type": { "name": "number" }, "default": "1" }, "name": { "type": { "name": "string" } }, "onAccept": { @@ -75,7 +75,7 @@ "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, "selectedSections": { @@ -122,7 +122,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "view": { "type": { "name": "enum", diff --git a/docs/pages/x/api/date-pickers/year-calendar.json b/docs/pages/x/api/date-pickers/year-calendar.json index 2d97dfcb66042..cd8b9dc24feb7 100644 --- a/docs/pages/x/api/date-pickers/year-calendar.json +++ b/docs/pages/x/api/date-pickers/year-calendar.json @@ -1,20 +1,20 @@ { "props": { "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "defaultValue": { "type": { "name": "any" } }, + "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" } }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, "disableHighlightToday": { "type": { "name": "bool" }, "default": "false" }, "disablePast": { "type": { "name": "bool" }, "default": "false" }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxDate": { "type": { "name": "object" } }, + "minDate": { "type": { "name": "object" } }, "onChange": { "type": { "name": "func" }, "signature": { "type": "function(value: TDate) => void", "describedArgs": ["value"] } }, "readOnly": { "type": { "name": "bool" } }, "referenceDate": { - "type": { "name": "any" }, + "type": { "name": "object" }, "default": "The closest valid year using the validation props, except callbacks such as `shouldDisableYear`." }, "shouldDisableYear": { @@ -40,7 +40,7 @@ "text": "timezones documentation" } }, - "value": { "type": { "name": "any" } }, + "value": { "type": { "name": "object" } }, "yearsPerRow": { "type": { "name": "enum", "description": "3<br>| 4" }, "default": "3" diff --git a/docs/scripts/generateProptypes.ts b/docs/scripts/generateProptypes.ts index 63620878303cb..4a4473dad12b6 100644 --- a/docs/scripts/generateProptypes.ts +++ b/docs/scripts/generateProptypes.ts @@ -7,6 +7,30 @@ import { fixBabelGeneratorIssues, fixLineEndings } from '@mui-internal/docs-util import { createXTypeScriptProjects, XTypeScriptProject } from './createXTypeScriptProjects'; async function generateProptypes(project: XTypeScriptProject, sourceFile: string) { + const isTDate = (name: string) => { + if (['x-date-pickers', 'x-date-pickers-pro'].includes(project.name)) { + const T_DATE_PROPS = [ + 'value', + 'defaultValue', + 'minDate', + 'maxDate', + 'minDateTime', + 'maxDateTime', + 'minTime', + 'maxTime', + 'referenceDate', + 'day', + 'currentMonth', + ]; + + if (T_DATE_PROPS.includes(name)) { + return true; + } + } + + return false; + }; + const components = getPropTypesFromFile({ filePath: sourceFile, project, @@ -44,8 +68,13 @@ async function generateProptypes(project: XTypeScriptProject, sourceFile: string return false; } + if (isTDate(name)) { + return false; + } + return undefined; }, + shouldUseObjectForDate: ({ name }) => isTDate(name), }); if (components.length === 0) { diff --git a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx index f0a2b77125434..bd573303ca85b 100644 --- a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx +++ b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx @@ -32,6 +32,7 @@ import { useControlledValueWithTimezone, useViews, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { getReleaseInfo } from '../internals/utils/releaseInfo'; import { dateRangeCalendarClasses, @@ -114,7 +115,7 @@ const DayCalendarForRange = styled(DayCalendar)(({ theme }) => ({ }, })) as typeof DayCalendar; -function useDateRangeCalendarDefaultizedProps<TDate>( +function useDateRangeCalendarDefaultizedProps<TDate extends PickerValidDate>( props: DateRangeCalendarProps<TDate>, name: string, ): DateRangeCalendarDefaultizedProps<TDate> { @@ -155,7 +156,7 @@ const useUtilityClasses = (ownerState: DateRangeCalendarOwnerState<any>) => { return composeClasses(slots, getDateRangeCalendarUtilityClass, classes); }; -type DateRangeCalendarComponent = (<TDate>( +type DateRangeCalendarComponent = (<TDate extends PickerValidDate>( props: DateRangeCalendarProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -169,10 +170,9 @@ type DateRangeCalendarComponent = (<TDate>( * * - [DateRangeCalendar API](https://mui.com/x/api/date-pickers/date-range-calendar/) */ -const DateRangeCalendar = React.forwardRef(function DateRangeCalendar<TDate>( - inProps: DateRangeCalendarProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const DateRangeCalendar = React.forwardRef(function DateRangeCalendar< + TDate extends PickerValidDate, +>(inProps: DateRangeCalendarProps<TDate>, ref: React.Ref<HTMLDivElement>) { const props = useDateRangeCalendarDefaultizedProps(inProps, 'MuiDateRangeCalendar'); const shouldHavePreview = useMediaQuery(DEFAULT_DESKTOP_MODE_MEDIA_QUERY, { defaultMatches: false, @@ -683,7 +683,7 @@ DateRangeCalendar.propTypes = { * The default selected value. * Used when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * If `true`, after selecting `start` date calendar will not automatically switch to the month of `end` date. * @default false @@ -737,11 +737,11 @@ DateRangeCalendar.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Callback fired when the value changes. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. @@ -800,7 +800,7 @@ DateRangeCalendar.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component rendered on the "day" view when `props.loading` is true. * @returns {React.ReactNode} The node to render when loading. @@ -859,7 +859,7 @@ DateRangeCalendar.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.types.ts b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.types.ts index 3752678575acb..b79cbe3a8a570 100644 --- a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.types.ts +++ b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.types.ts @@ -2,7 +2,7 @@ import * as React from 'react'; import { SxProps } from '@mui/system'; import { SlotComponentProps } from '@mui/base/utils'; import { Theme } from '@mui/material/styles'; -import { TimezoneProps } from '@mui/x-date-pickers/models'; +import { PickerValidDate, TimezoneProps } from '@mui/x-date-pickers/models'; import { PickersCalendarHeader, PickersCalendarHeaderProps, @@ -28,7 +28,7 @@ import { UseRangePositionProps } from '../internals/hooks/useRangePosition'; export type DateRangePosition = 'start' | 'end'; -export interface DateRangeCalendarSlots<TDate> +export interface DateRangeCalendarSlots<TDate extends PickerValidDate> extends PickersArrowSwitcherSlots, Omit<DayCalendarSlots<TDate>, 'day'>, PickersCalendarHeaderSlots { @@ -46,7 +46,7 @@ export interface DateRangeCalendarSlots<TDate> day?: React.ElementType<DateRangePickerDayProps<TDate>>; } -export interface DateRangeCalendarSlotProps<TDate> +export interface DateRangeCalendarSlotProps<TDate extends PickerValidDate> extends PickersArrowSwitcherSlotProps, Omit<DayCalendarSlotProps<TDate>, 'day'>, PickersCalendarHeaderSlotProps<TDate> { @@ -62,7 +62,7 @@ export interface DateRangeCalendarSlotProps<TDate> >; } -export interface ExportedDateRangeCalendarProps<TDate> +export interface ExportedDateRangeCalendarProps<TDate extends PickerValidDate> extends ExportedDayCalendarProps<TDate>, BaseDateValidationProps<TDate>, DayRangeValidationProps<TDate>, @@ -105,7 +105,7 @@ export interface ExportedDateRangeCalendarProps<TDate> disableDragEditing?: boolean; } -export interface DateRangeCalendarProps<TDate> +export interface DateRangeCalendarProps<TDate extends PickerValidDate> extends ExportedDateRangeCalendarProps<TDate>, UseRangePositionProps, ExportedUseViewsOptions<'day'> { @@ -155,11 +155,12 @@ export interface DateRangeCalendarProps<TDate> availableRangePositions?: DateRangePosition[]; } -export interface DateRangeCalendarOwnerState<TDate> extends DateRangeCalendarProps<TDate> { +export interface DateRangeCalendarOwnerState<TDate extends PickerValidDate> + extends DateRangeCalendarProps<TDate> { isDragging: boolean; } -export type DateRangeCalendarDefaultizedProps<TDate> = DefaultizedProps< +export type DateRangeCalendarDefaultizedProps<TDate extends PickerValidDate> = DefaultizedProps< DateRangeCalendarProps<TDate>, | 'views' | 'openTo' diff --git a/packages/x-date-pickers-pro/src/DateRangeCalendar/useDragRange.ts b/packages/x-date-pickers-pro/src/DateRangeCalendar/useDragRange.ts index 32a85ed3aeef8..5ac9cdc668000 100644 --- a/packages/x-date-pickers-pro/src/DateRangeCalendar/useDragRange.ts +++ b/packages/x-date-pickers-pro/src/DateRangeCalendar/useDragRange.ts @@ -1,11 +1,11 @@ import * as React from 'react'; import useEventCallback from '@mui/utils/useEventCallback'; -import { MuiPickersAdapter, PickersTimezone } from '@mui/x-date-pickers/models'; +import { MuiPickersAdapter, PickersTimezone, PickerValidDate } from '@mui/x-date-pickers/models'; import { DateRangePosition } from './DateRangeCalendar.types'; import { DateRange } from '../models'; import { isEndOfRange, isStartOfRange } from '../internals/utils/date-utils'; -interface UseDragRangeParams<TDate> { +interface UseDragRangeParams<TDate extends PickerValidDate> { disableDragEditing?: boolean; utils: MuiPickersAdapter<TDate>; setRangeDragDay: (value: TDate | null) => void; @@ -29,13 +29,13 @@ interface UseDragRangeEvents { onTouchEnd?: React.TouchEventHandler<HTMLButtonElement>; } -interface UseDragRangeResponse<TDate> extends UseDragRangeEvents { +interface UseDragRangeResponse<TDate extends PickerValidDate> extends UseDragRangeEvents { isDragging: boolean; rangeDragDay: TDate | null; draggingDatePosition: DateRangePosition | null; } -const resolveDateFromTarget = <TDate>( +const resolveDateFromTarget = <TDate extends PickerValidDate>( target: EventTarget, utils: MuiPickersAdapter<TDate>, timezone: PickersTimezone, @@ -87,7 +87,7 @@ const resolveElementFromTouch = ( return null; }; -const useDragRangeEvents = <TDate>({ +const useDragRangeEvents = <TDate extends PickerValidDate>({ utils, setRangeDragDay, setIsDragging, @@ -276,7 +276,7 @@ const useDragRangeEvents = <TDate>({ }; }; -export const useDragRange = <TDate>({ +export const useDragRange = <TDate extends PickerValidDate>({ disableDragEditing, utils, onDatePositionChange, diff --git a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.tsx b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.tsx index d05c30cdbde64..221f24079569b 100644 --- a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.tsx @@ -3,11 +3,12 @@ import PropTypes from 'prop-types'; import useMediaQuery from '@mui/material/useMediaQuery'; import { useThemeProps } from '@mui/material/styles'; import { refType } from '@mui/utils'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DesktopDateRangePicker } from '../DesktopDateRangePicker'; import { MobileDateRangePicker } from '../MobileDateRangePicker'; import { DateRangePickerProps } from './DateRangePicker.types'; -type DatePickerComponent = (<TDate>( +type DatePickerComponent = (<TDate extends PickerValidDate>( props: DateRangePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -21,7 +22,7 @@ type DatePickerComponent = (<TDate>( * * - [DateRangePicker API](https://mui.com/x/api/date-pickers/date-range-picker/) */ -const DateRangePicker = React.forwardRef(function DateRangePicker<TDate>( +const DateRangePicker = React.forwardRef(function DateRangePicker<TDate extends PickerValidDate>( inProps: DateRangePickerProps<TDate>, ref: React.Ref<HTMLDivElement>, ) { @@ -84,7 +85,7 @@ DateRangePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * CSS media query when `Mobile` mode will be changed to `Desktop`. * @default '@media (pointer: fine)' @@ -171,11 +172,11 @@ DateRangePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Name attribute used by the `input` element in the Field. * Ignored if the field has several inputs. @@ -251,7 +252,7 @@ DateRangePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component rendered on the "day" view when `props.loading` is true. * @returns {React.ReactNode} The node to render when loading. @@ -338,7 +339,7 @@ DateRangePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), /** * Define custom view renderers for each section. * If `null`, the section will only have field editing. diff --git a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.types.ts b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.types.ts index 7b1bfae34e522..619d929549386 100644 --- a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.types.ts @@ -1,3 +1,4 @@ +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DesktopDateRangePickerProps, DesktopDateRangePickerSlots, @@ -9,15 +10,15 @@ import { MobileDateRangePickerSlotProps, } from '../MobileDateRangePicker'; -export interface DateRangePickerSlots<TDate> +export interface DateRangePickerSlots<TDate extends PickerValidDate> extends DesktopDateRangePickerSlots<TDate>, MobileDateRangePickerSlots<TDate> {} -export interface DateRangePickerSlotProps<TDate> +export interface DateRangePickerSlotProps<TDate extends PickerValidDate> extends DesktopDateRangePickerSlotProps<TDate>, MobileDateRangePickerSlotProps<TDate> {} -export interface DateRangePickerProps<TDate> +export interface DateRangePickerProps<TDate extends PickerValidDate> extends DesktopDateRangePickerProps<TDate>, MobileDateRangePickerProps<TDate> { /** diff --git a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePickerToolbar.tsx index 7e83059f084b1..149bc4c9bf069 100644 --- a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePickerToolbar.tsx @@ -12,6 +12,7 @@ import { useLocaleText, ExportedBaseToolbarProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DateRange } from '../models'; import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; import { @@ -29,7 +30,7 @@ const useUtilityClasses = (ownerState: DateRangePickerToolbarProps<any>) => { return composeClasses(slots, getDateRangePickerToolbarUtilityClass, classes); }; -export interface DateRangePickerToolbarProps<TDate> +export interface DateRangePickerToolbarProps<TDate extends PickerValidDate> extends Omit< BaseToolbarProps<DateRange<TDate>, 'day'>, 'views' | 'view' | 'onViewChange' | 'onChange' | 'isLandscape' @@ -67,7 +68,7 @@ const DateRangePickerToolbarContainer = styled('div', { * - [DateRangePickerToolbar API](https://mui.com/x/api/date-pickers/date-range-picker-toolbar/) */ const DateRangePickerToolbar = React.forwardRef(function DateRangePickerToolbar< - TDate extends unknown, + TDate extends PickerValidDate, >(inProps: DateRangePickerToolbarProps<TDate>, ref: React.Ref<HTMLDivElement>) { const utils = useUtils<TDate>(); const props = useThemeProps({ props: inProps, name: 'MuiDateRangePickerToolbar' }); @@ -153,7 +154,7 @@ DateRangePickerToolbar.propTypes = { * @default "––" */ toolbarPlaceholder: PropTypes.node, - value: PropTypes.arrayOf(PropTypes.any).isRequired, + value: PropTypes.arrayOf(PropTypes.object).isRequired, } as any; export { DateRangePickerToolbar }; diff --git a/packages/x-date-pickers-pro/src/DateRangePicker/shared.tsx b/packages/x-date-pickers-pro/src/DateRangePicker/shared.tsx index 652ad32094229..5a0b72b9bdd09 100644 --- a/packages/x-date-pickers-pro/src/DateRangePicker/shared.tsx +++ b/packages/x-date-pickers-pro/src/DateRangePicker/shared.tsx @@ -10,6 +10,7 @@ import { BasePickerInputProps, PickerViewRendererLookup, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DateRangeValidationError, DateRange } from '../models'; import { DateRangeCalendarSlots, @@ -23,7 +24,8 @@ import { } from './DateRangePickerToolbar'; import { DateRangeViewRendererProps } from '../dateRangeViewRenderers'; -export interface BaseDateRangePickerSlots<TDate> extends DateRangeCalendarSlots<TDate> { +export interface BaseDateRangePickerSlots<TDate extends PickerValidDate> + extends DateRangeCalendarSlots<TDate> { /** * Custom component for the toolbar rendered above the views. * @default DateTimePickerToolbar @@ -31,11 +33,12 @@ export interface BaseDateRangePickerSlots<TDate> extends DateRangeCalendarSlots< toolbar?: React.JSXElementConstructor<DateRangePickerToolbarProps<TDate>>; } -export interface BaseDateRangePickerSlotProps<TDate> extends DateRangeCalendarSlotProps<TDate> { +export interface BaseDateRangePickerSlotProps<TDate extends PickerValidDate> + extends DateRangeCalendarSlotProps<TDate> { toolbar?: ExportedDateRangePickerToolbarProps; } -export interface BaseDateRangePickerProps<TDate> +export interface BaseDateRangePickerProps<TDate extends PickerValidDate> extends Omit< BasePickerInputProps<DateRange<TDate>, TDate, 'day', DateRangeValidationError>, 'view' | 'views' | 'openTo' | 'onViewChange' | 'orientation' @@ -63,12 +66,12 @@ export interface BaseDateRangePickerProps<TDate> } type UseDateRangePickerDefaultizedProps< - TDate, + TDate extends PickerValidDate, Props extends BaseDateRangePickerProps<TDate>, > = LocalizedComponent<TDate, DefaultizedProps<Props, keyof BaseDateValidationProps<TDate>>>; export function useDateRangePickerDefaultizedProps< - TDate, + TDate extends PickerValidDate, Props extends BaseDateRangePickerProps<TDate>, >(props: Props, name: string): UseDateRangePickerDefaultizedProps<TDate, Props> { const utils = useUtils<TDate>(); diff --git a/packages/x-date-pickers-pro/src/DateRangePickerDay/DateRangePickerDay.tsx b/packages/x-date-pickers-pro/src/DateRangePickerDay/DateRangePickerDay.tsx index 9647c304b1628..a7609833e7466 100644 --- a/packages/x-date-pickers-pro/src/DateRangePickerDay/DateRangePickerDay.tsx +++ b/packages/x-date-pickers-pro/src/DateRangePickerDay/DateRangePickerDay.tsx @@ -5,6 +5,7 @@ import { useLicenseVerifier } from '@mui/x-license-pro'; import { alpha, styled, useThemeProps } from '@mui/material/styles'; import { unstable_composeClasses as composeClasses } from '@mui/utils'; import { useUtils } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { PickersDay, PickersDayProps } from '@mui/x-date-pickers/PickersDay'; import { DateRangePickerDayClasses, @@ -15,7 +16,7 @@ import { getReleaseInfo } from '../internals/utils/releaseInfo'; const releaseInfo = getReleaseInfo(); -export interface DateRangePickerDayProps<TDate> +export interface DateRangePickerDayProps<TDate extends PickerValidDate> extends Omit<PickersDayProps<TDate>, 'classes' | 'onBlur' | 'onFocus' | 'onKeyDown'> { /** * Set to `true` if the `day` is in a highlighted date range. @@ -259,18 +260,17 @@ const DateRangePickerDayDay = styled(PickersDay, { ...(ownerState.draggable && { touchAction: 'none', }), -})) as unknown as <TDate>( +})) as unknown as <TDate extends PickerValidDate>( props: PickersDayProps<TDate> & { ownerState: OwnerState }, ) => React.JSX.Element; -type DateRangePickerDayComponent = <TDate>( +type DateRangePickerDayComponent = <TDate extends PickerValidDate>( props: DateRangePickerDayProps<TDate> & React.RefAttributes<HTMLButtonElement>, ) => React.JSX.Element; -const DateRangePickerDayRaw = React.forwardRef(function DateRangePickerDay<TDate>( - inProps: DateRangePickerDayProps<TDate>, - ref: React.Ref<HTMLButtonElement>, -) { +const DateRangePickerDayRaw = React.forwardRef(function DateRangePickerDay< + TDate extends PickerValidDate, +>(inProps: DateRangePickerDayProps<TDate>, ref: React.Ref<HTMLButtonElement>) { const props = useThemeProps({ props: inProps, name: 'MuiDateRangePickerDay' }); const { className, @@ -376,7 +376,7 @@ DateRangePickerDayRaw.propTypes = { /** * The date to show. */ - day: PropTypes.any.isRequired, + day: PropTypes.object.isRequired, /** * If `true`, renders as disabled. * @default false diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.tsx index 63d70c656b7c9..7b55b94cca536 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.tsx @@ -2,18 +2,18 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import useMediaQuery from '@mui/material/useMediaQuery'; import { useThemeProps } from '@mui/material/styles'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DateTimeRangePickerProps } from './DateTimeRangePicker.types'; import { DesktopDateTimeRangePicker } from '../DesktopDateTimeRangePicker'; import { MobileDateTimeRangePicker } from '../MobileDateTimeRangePicker'; -type DateTimeRangePickerComponent = (<TDate>( +type DateTimeRangePickerComponent = (<TDate extends PickerValidDate>( props: DateTimeRangePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; -const DateTimeRangePicker = React.forwardRef(function DateTimeRangePicker<TDate>( - inProps: DateTimeRangePickerProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const DateTimeRangePicker = React.forwardRef(function DateTimeRangePicker< + TDate extends PickerValidDate, +>(inProps: DateTimeRangePickerProps<TDate>, ref: React.Ref<HTMLDivElement>) { const props = useThemeProps({ props: inProps, name: 'MuiDateTimeRangePicker' }); const { desktopModeMediaQuery = '@media (pointer: fine)', ...other } = props; @@ -78,7 +78,7 @@ DateTimeRangePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * CSS media query when `Mobile` mode will be changed to `Desktop`. * @default '@media (pointer: fine)' @@ -175,29 +175,29 @@ DateTimeRangePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Maximal selectable moment of time with binding to date, to set max time in each day use `maxTime`. */ - maxDateTime: PropTypes.any, + maxDateTime: PropTypes.object, /** * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Minimal selectable moment of time with binding to date, to set min time in each day use `minTime`. */ - minDateTime: PropTypes.any, + minDateTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -290,7 +290,7 @@ DateTimeRangePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component rendered on the "day" view when `props.loading` is true. * @returns {React.ReactNode} The node to render when loading. @@ -406,7 +406,7 @@ DateTimeRangePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.types.ts index 1e755b824bda2..ef4308ee99016 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.types.ts @@ -1,3 +1,4 @@ +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DesktopDateTimeRangePickerProps, DesktopDateTimeRangePickerSlots, @@ -9,15 +10,15 @@ import { MobileDateTimeRangePickerSlotProps, } from '../MobileDateTimeRangePicker'; -export interface DateTimeRangePickerSlots<TDate> +export interface DateTimeRangePickerSlots<TDate extends PickerValidDate> extends DesktopDateTimeRangePickerSlots<TDate>, MobileDateTimeRangePickerSlots<TDate> {} -export interface DateTimeRangePickerSlotProps<TDate> +export interface DateTimeRangePickerSlotProps<TDate extends PickerValidDate> extends DesktopDateTimeRangePickerSlotProps<TDate>, MobileDateTimeRangePickerSlotProps<TDate> {} -export interface DateTimeRangePickerProps<TDate> +export interface DateTimeRangePickerProps<TDate extends PickerValidDate> extends DesktopDateTimeRangePickerProps<TDate>, MobileDateTimeRangePickerProps<TDate> { /** diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerTimeWrapper.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerTimeWrapper.tsx index 465bcc3f6e1de..9bc3597b7927e 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerTimeWrapper.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerTimeWrapper.tsx @@ -7,6 +7,7 @@ import { TimeViewWithMeridiem, BaseClockProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DateTimeRangePickerView } from '../internals/models'; import { DateRange } from '../models'; import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; @@ -14,7 +15,7 @@ import { isRangeValid } from '../internals/utils/date-utils'; import { calculateRangeChange } from '../internals/utils/date-range-manager'; export type DateTimeRangePickerTimeWrapperProps< - TDate, + TDate extends PickerValidDate, TView extends DateTimeRangePickerView, TComponentProps extends Omit< BaseClockProps<TDate, TimeViewWithMeridiem>, @@ -43,7 +44,7 @@ export type DateTimeRangePickerTimeWrapperProps< * @ignore - internal component. */ function DateTimeRangePickerTimeWrapper< - TDate, + TDate extends PickerValidDate, TView extends DateTimeRangePickerView, TComponentProps extends Omit< BaseClockProps<TDate, TimeViewWithMeridiem>, diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx index 5b384ac900ab6..1af69fa551241 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx @@ -11,6 +11,7 @@ import { DateOrTimeViewWithMeridiem, WrapperVariant, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DateTimePickerToolbarProps, DateTimePickerToolbar, @@ -36,7 +37,7 @@ const useUtilityClasses = (ownerState: DateTimeRangePickerToolbarProps<any>) => type DateTimeRangeViews = Exclude<DateOrTimeViewWithMeridiem, 'year' | 'month'>; -export interface DateTimeRangePickerToolbarProps<TDate> +export interface DateTimeRangePickerToolbarProps<TDate extends PickerValidDate> extends BaseToolbarProps<DateRange<TDate>, DateTimeRangeViews>, Pick<UseRangePositionResponse, 'rangePosition' | 'onRangePositionChange'>, ExportedDateTimeRangePickerToolbarProps { @@ -59,11 +60,12 @@ const DateTimeRangePickerToolbarRoot = styled('div', { flexDirection: 'column', }); -type DateTimeRangePickerStartOrEndToolbarProps<TDate> = DateTimePickerToolbarProps<TDate> & { - ownerState?: DateTimeRangePickerToolbarProps<TDate>; -}; +type DateTimeRangePickerStartOrEndToolbarProps<TDate extends PickerValidDate> = + DateTimePickerToolbarProps<TDate> & { + ownerState?: DateTimeRangePickerToolbarProps<TDate>; + }; -type DateTimeRangePickerStartOrEndToolbarComponent = <TDate>( +type DateTimeRangePickerStartOrEndToolbarComponent = <TDate extends PickerValidDate>( props: DateTimeRangePickerStartOrEndToolbarProps<TDate>, ) => React.JSX.Element; @@ -91,7 +93,7 @@ const DateTimeRangePickerToolbarEnd = styled(DateTimePickerToolbar, { })) as DateTimeRangePickerStartOrEndToolbarComponent; const DateTimeRangePickerToolbar = React.forwardRef(function DateTimeRangePickerToolbar< - TDate extends unknown, + TDate extends PickerValidDate, >(inProps: DateTimeRangePickerToolbarProps<TDate>, ref: React.Ref<HTMLDivElement>) { const props = useThemeProps({ props: inProps, name: 'MuiDateTimeRangePickerToolbar' }); const utils = useUtils<TDate>(); @@ -228,7 +230,7 @@ DateTimeRangePickerToolbar.propTypes = { */ toolbarPlaceholder: PropTypes.node, toolbarVariant: PropTypes.oneOf(['desktop', 'mobile']), - value: PropTypes.arrayOf(PropTypes.any).isRequired, + value: PropTypes.arrayOf(PropTypes.object).isRequired, /** * Currently visible picker view. */ diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx index d893dbe01b40d..cba6a59a1aa25 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx @@ -17,6 +17,7 @@ import { UseViewsOptions, DateTimeValidationProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { TimeViewRendererProps } from '@mui/x-date-pickers/timeViewRenderers'; import { DigitalClockSlots, DigitalClockSlotProps } from '@mui/x-date-pickers/DigitalClock'; import { @@ -42,7 +43,7 @@ import { ExportedDateTimeRangePickerTabsProps, } from './DateTimeRangePickerTabs'; -export interface BaseDateTimeRangePickerSlots<TDate> +export interface BaseDateTimeRangePickerSlots<TDate extends PickerValidDate> extends DateRangeCalendarSlots<TDate>, DigitalClockSlots, MultiSectionDigitalClockSlots { @@ -58,7 +59,7 @@ export interface BaseDateTimeRangePickerSlots<TDate> toolbar?: React.JSXElementConstructor<DateTimeRangePickerToolbarProps<TDate>>; } -export interface BaseDateTimeRangePickerSlotProps<TDate> +export interface BaseDateTimeRangePickerSlotProps<TDate extends PickerValidDate> extends DateRangeCalendarSlotProps<TDate>, DigitalClockSlotProps, MultiSectionDigitalClockSlotProps { @@ -72,7 +73,7 @@ export interface BaseDateTimeRangePickerSlotProps<TDate> toolbar?: ExportedDateTimeRangePickerToolbarProps; } -export interface BaseDateTimeRangePickerProps<TDate> +export interface BaseDateTimeRangePickerProps<TDate extends PickerValidDate> extends Omit< BasePickerInputProps< DateRange<TDate>, @@ -119,7 +120,7 @@ export interface BaseDateTimeRangePickerProps<TDate> } type UseDateTimeRangePickerDefaultizedProps< - TDate, + TDate extends PickerValidDate, Props extends BaseDateTimeRangePickerProps<TDate>, > = LocalizedComponent< TDate, @@ -130,7 +131,7 @@ type UseDateTimeRangePickerDefaultizedProps< }; export function useDateTimeRangePickerDefaultizedProps< - TDate, + TDate extends PickerValidDate, Props extends BaseDateTimeRangePickerProps<TDate>, >(props: Props, name: string): UseDateTimeRangePickerDefaultizedProps<TDate, Props> { const utils = useUtils<TDate>(); diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx index 09532eee819d3..fd25ff438f808 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { extractValidationProps, PickerViewRendererLookup } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { resolveComponentProps } from '@mui/base/utils'; import { refType } from '@mui/utils'; import { rangeValueManager } from '../internals/utils/valueManagers'; @@ -12,7 +13,7 @@ import { useDesktopRangePicker } from '../internals/hooks/useDesktopRangePicker' import { validateDateRange } from '../internals/utils/validation/validateDateRange'; import { DateRange } from '../models'; -type DesktopDateRangePickerComponent = (<TDate>( +type DesktopDateRangePickerComponent = (<TDate extends PickerValidDate>( props: DesktopDateRangePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -26,10 +27,9 @@ type DesktopDateRangePickerComponent = (<TDate>( * * - [DesktopDateRangePicker API](https://mui.com/x/api/date-pickers/desktop-date-range-picker/) */ -const DesktopDateRangePicker = React.forwardRef(function DesktopDateRangePicker<TDate>( - inProps: DesktopDateRangePickerProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const DesktopDateRangePicker = React.forwardRef(function DesktopDateRangePicker< + TDate extends PickerValidDate, +>(inProps: DesktopDateRangePickerProps<TDate>, ref: React.Ref<HTMLDivElement>) { // Props with the default values common to all date time pickers const defaultizedProps = useDateRangePickerDefaultizedProps< TDate, @@ -120,7 +120,7 @@ DesktopDateRangePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * If `true`, after selecting `start` date calendar will not automatically switch to the month of `end` date. * @default false @@ -201,11 +201,11 @@ DesktopDateRangePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Name attribute used by the `input` element in the Field. * Ignored if the field has several inputs. @@ -281,7 +281,7 @@ DesktopDateRangePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component rendered on the "day" view when `props.loading` is true. * @returns {React.ReactNode} The node to render when loading. @@ -368,7 +368,7 @@ DesktopDateRangePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), /** * Define custom view renderers for each section. * If `null`, the section will only have field editing. diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.types.ts b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.types.ts index 4f83197bad5ca..364776776e06d 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.types.ts @@ -1,4 +1,5 @@ import { MakeOptional } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { UseDesktopRangePickerSlots, UseDesktopRangePickerSlotProps, @@ -10,15 +11,15 @@ import { BaseDateRangePickerSlotProps, } from '../DateRangePicker/shared'; -export interface DesktopDateRangePickerSlots<TDate> +export interface DesktopDateRangePickerSlots<TDate extends PickerValidDate> extends BaseDateRangePickerSlots<TDate>, MakeOptional<UseDesktopRangePickerSlots<TDate, 'day'>, 'field'> {} -export interface DesktopDateRangePickerSlotProps<TDate> +export interface DesktopDateRangePickerSlotProps<TDate extends PickerValidDate> extends BaseDateRangePickerSlotProps<TDate>, Omit<UseDesktopRangePickerSlotProps<TDate, 'day'>, 'tabs'> {} -export interface DesktopDateRangePickerProps<TDate> +export interface DesktopDateRangePickerProps<TDate extends PickerValidDate> extends BaseDateRangePickerProps<TDate>, DesktopRangeOnlyPickerProps<TDate> { /** diff --git a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx index b0c6b36d18cd2..74f358cae9dce 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx @@ -8,6 +8,7 @@ import { PickerViewRenderer, PickerViewRendererLookup, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { resolveComponentProps } from '@mui/base/utils'; import { renderDigitalClockTimeView, @@ -36,7 +37,7 @@ import { DateTimeRangePickerTimeWrapper } from '../DateTimeRangePicker/DateTimeR import { RANGE_VIEW_HEIGHT } from '../internals/constants/dimensions'; import { DesktopDateTimeRangePickerLayout } from './DesktopDateTimeRangePickerLayout'; -const rendererInterceptor = function rendererInterceptor<TDate>( +const rendererInterceptor = function rendererInterceptor<TDate extends PickerValidDate>( inViewRenderers: PickerViewRendererLookup<DateRange<TDate>, DateTimeRangePickerView, any, any>, popperView: DateTimeRangePickerView, rendererProps: DefaultizedProps< @@ -88,14 +89,13 @@ const rendererInterceptor = function rendererInterceptor<TDate>( ); }; -type DesktopDateRangePickerComponent = (<TDate>( +type DesktopDateRangePickerComponent = (<TDate extends PickerValidDate>( props: DesktopDateTimeRangePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; -const DesktopDateTimeRangePicker = React.forwardRef(function DesktopDateTimeRangePicker<TDate>( - inProps: DesktopDateTimeRangePickerProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const DesktopDateTimeRangePicker = React.forwardRef(function DesktopDateTimeRangePicker< + TDate extends PickerValidDate, +>(inProps: DesktopDateTimeRangePickerProps<TDate>, ref: React.Ref<HTMLDivElement>) { // Props with the default values common to all date time range pickers const defaultizedProps = useDateTimeRangePickerDefaultizedProps< TDate, @@ -225,7 +225,7 @@ DesktopDateTimeRangePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * If `true`, after selecting `start` date calendar will not automatically switch to the month of `end` date. * @default false @@ -316,29 +316,29 @@ DesktopDateTimeRangePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Maximal selectable moment of time with binding to date, to set max time in each day use `maxTime`. */ - maxDateTime: PropTypes.any, + maxDateTime: PropTypes.object, /** * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Minimal selectable moment of time with binding to date, to set min time in each day use `minTime`. */ - minDateTime: PropTypes.any, + minDateTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -431,7 +431,7 @@ DesktopDateTimeRangePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component rendered on the "day" view when `props.loading` is true. * @returns {React.ReactNode} The node to render when loading. @@ -547,7 +547,7 @@ DesktopDateTimeRangePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.types.ts index 3f956449fba72..a692b4307fe44 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.types.ts @@ -1,4 +1,5 @@ import { MakeOptional } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { UseDesktopRangePickerSlots, UseDesktopRangePickerSlotProps, @@ -11,15 +12,15 @@ import { } from '../DateTimeRangePicker/shared'; import { DateTimeRangePickerView } from '../internals/models'; -export interface DesktopDateTimeRangePickerSlots<TDate> +export interface DesktopDateTimeRangePickerSlots<TDate extends PickerValidDate> extends BaseDateTimeRangePickerSlots<TDate>, MakeOptional<UseDesktopRangePickerSlots<TDate, DateTimeRangePickerView>, 'field'> {} -export interface DesktopDateTimeRangePickerSlotProps<TDate> +export interface DesktopDateTimeRangePickerSlotProps<TDate extends PickerValidDate> extends BaseDateTimeRangePickerSlotProps<TDate>, Omit<UseDesktopRangePickerSlotProps<TDate, DateTimeRangePickerView>, 'tabs' | 'toolbar'> {} -export interface DesktopDateTimeRangePickerProps<TDate> +export interface DesktopDateTimeRangePickerProps<TDate extends PickerValidDate> extends BaseDateTimeRangePickerProps<TDate>, DesktopRangeOnlyPickerProps<TDate> { /** diff --git a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePickerLayout.tsx b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePickerLayout.tsx index 3bb22d7026339..37d9dc97df208 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePickerLayout.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePickerLayout.tsx @@ -8,13 +8,14 @@ import { pickersLayoutClasses, usePickerLayout, } from '@mui/x-date-pickers/PickersLayout'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DateRange } from '../models'; import { DateTimeRangePickerView } from '../internals/models/dateTimeRange'; /** * @ignore - internal component. */ -export function DesktopDateTimeRangePickerLayout<TDate>( +export function DesktopDateTimeRangePickerLayout<TDate extends PickerValidDate>( props: PickersLayoutProps<DateRange<TDate>, TDate, DateTimeRangePickerView>, ) { const { toolbar, tabs, content, actionBar, shortcuts } = usePickerLayout(props); diff --git a/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx index c4464ff216a80..bd01168d00536 100644 --- a/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { extractValidationProps, PickerViewRendererLookup } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { resolveComponentProps } from '@mui/base/utils'; import { refType } from '@mui/utils'; import { rangeValueManager } from '../internals/utils/valueManagers'; @@ -12,7 +13,7 @@ import { useMobileRangePicker } from '../internals/hooks/useMobileRangePicker'; import { validateDateRange } from '../internals/utils/validation/validateDateRange'; import { DateRange } from '../models'; -type MobileDateRangePickerComponent = (<TDate>( +type MobileDateRangePickerComponent = (<TDate extends PickerValidDate>( props: MobileDateRangePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -26,10 +27,9 @@ type MobileDateRangePickerComponent = (<TDate>( * * - [MobileDateRangePicker API](https://mui.com/x/api/date-pickers/mobile-date-range-picker/) */ -const MobileDateRangePicker = React.forwardRef(function MobileDateRangePicker<TDate>( - inProps: MobileDateRangePickerProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const MobileDateRangePicker = React.forwardRef(function MobileDateRangePicker< + TDate extends PickerValidDate, +>(inProps: MobileDateRangePickerProps<TDate>, ref: React.Ref<HTMLDivElement>) { // Props with the default values common to all date time pickers const defaultizedProps = useDateRangePickerDefaultizedProps< TDate, @@ -116,7 +116,7 @@ MobileDateRangePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * If `true`, after selecting `start` date calendar will not automatically switch to the month of `end` date. * @default false @@ -197,11 +197,11 @@ MobileDateRangePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Name attribute used by the `input` element in the Field. * Ignored if the field has several inputs. @@ -277,7 +277,7 @@ MobileDateRangePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component rendered on the "day" view when `props.loading` is true. * @returns {React.ReactNode} The node to render when loading. @@ -364,7 +364,7 @@ MobileDateRangePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), /** * Define custom view renderers for each section. * If `null`, the section will only have field editing. diff --git a/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.types.ts b/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.types.ts index a5e6cc05419cd..9bb677638253b 100644 --- a/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.types.ts @@ -1,4 +1,5 @@ import { MakeOptional } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { UseMobileRangePickerSlots, UseMobileRangePickerSlotProps, @@ -10,15 +11,15 @@ import { BaseDateRangePickerSlotProps, } from '../DateRangePicker/shared'; -export interface MobileDateRangePickerSlots<TDate> +export interface MobileDateRangePickerSlots<TDate extends PickerValidDate> extends BaseDateRangePickerSlots<TDate>, MakeOptional<UseMobileRangePickerSlots<TDate, 'day'>, 'field'> {} -export interface MobileDateRangePickerSlotProps<TDate> +export interface MobileDateRangePickerSlotProps<TDate extends PickerValidDate> extends BaseDateRangePickerSlotProps<TDate>, Omit<UseMobileRangePickerSlotProps<TDate, 'day'>, 'tabs'> {} -export interface MobileDateRangePickerProps<TDate> +export interface MobileDateRangePickerProps<TDate extends PickerValidDate> extends BaseDateRangePickerProps<TDate>, MobileRangeOnlyPickerProps<TDate> { /** diff --git a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx index 5799916f98367..3a1878ce53655 100644 --- a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx @@ -10,6 +10,7 @@ import { PickerViewRenderer, DefaultizedProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { resolveComponentProps } from '@mui/base/utils'; import { renderDigitalClockTimeView, @@ -35,7 +36,7 @@ import { MultiInputDateTimeRangeField } from '../MultiInputDateTimeRangeField'; import { DateTimeRangePickerTimeWrapper } from '../DateTimeRangePicker/DateTimeRangePickerTimeWrapper'; import { RANGE_VIEW_HEIGHT } from '../internals/constants/dimensions'; -const rendererInterceptor = function rendererInterceptor<TDate>( +const rendererInterceptor = function rendererInterceptor<TDate extends PickerValidDate>( inViewRenderers: PickerViewRendererLookup<DateRange<TDate>, DateTimeRangePickerView, any, any>, popperView: DateTimeRangePickerView, rendererProps: DefaultizedProps< @@ -102,14 +103,13 @@ const rendererInterceptor = function rendererInterceptor<TDate>( }); }; -type MobileDateRangePickerComponent = (<TDate>( +type MobileDateRangePickerComponent = (<TDate extends PickerValidDate>( props: MobileDateTimeRangePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; -const MobileDateTimeRangePicker = React.forwardRef(function MobileDateTimeRangePicker<TDate>( - inProps: MobileDateTimeRangePickerProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const MobileDateTimeRangePicker = React.forwardRef(function MobileDateTimeRangePicker< + TDate extends PickerValidDate, +>(inProps: MobileDateTimeRangePickerProps<TDate>, ref: React.Ref<HTMLDivElement>) { // Props with the default values common to all date time range pickers const defaultizedProps = useDateTimeRangePickerDefaultizedProps< TDate, @@ -220,7 +220,7 @@ MobileDateTimeRangePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * If `true`, after selecting `start` date calendar will not automatically switch to the month of `end` date. * @default false @@ -311,29 +311,29 @@ MobileDateTimeRangePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Maximal selectable moment of time with binding to date, to set max time in each day use `maxTime`. */ - maxDateTime: PropTypes.any, + maxDateTime: PropTypes.object, /** * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Minimal selectable moment of time with binding to date, to set min time in each day use `minTime`. */ - minDateTime: PropTypes.any, + minDateTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -426,7 +426,7 @@ MobileDateTimeRangePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component rendered on the "day" view when `props.loading` is true. * @returns {React.ReactNode} The node to render when loading. @@ -542,7 +542,7 @@ MobileDateTimeRangePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.types.ts index e7d18f3c649b9..de00d8476319d 100644 --- a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.types.ts @@ -1,4 +1,5 @@ import { MakeOptional } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { UseMobileRangePickerSlots, UseMobileRangePickerSlotProps, @@ -11,15 +12,15 @@ import { } from '../DateTimeRangePicker/shared'; import { DateTimeRangePickerView } from '../internals/models'; -export interface MobileDateTimeRangePickerSlots<TDate> +export interface MobileDateTimeRangePickerSlots<TDate extends PickerValidDate> extends BaseDateTimeRangePickerSlots<TDate>, MakeOptional<UseMobileRangePickerSlots<TDate, DateTimeRangePickerView>, 'field'> {} -export interface MobileDateTimeRangePickerSlotProps<TDate> +export interface MobileDateTimeRangePickerSlotProps<TDate extends PickerValidDate> extends BaseDateTimeRangePickerSlotProps<TDate>, Omit<UseMobileRangePickerSlotProps<TDate, DateTimeRangePickerView>, 'tabs' | 'toolbar'> {} -export interface MobileDateTimeRangePickerProps<TDate> +export interface MobileDateTimeRangePickerProps<TDate extends PickerValidDate> extends BaseDateTimeRangePickerProps<TDate>, MobileRangeOnlyPickerProps<TDate> { /** diff --git a/packages/x-date-pickers-pro/src/MultiInputDateRangeField/MultiInputDateRangeField.tsx b/packages/x-date-pickers-pro/src/MultiInputDateRangeField/MultiInputDateRangeField.tsx index 31242ffb5927a..6cc3b8d20e970 100644 --- a/packages/x-date-pickers-pro/src/MultiInputDateRangeField/MultiInputDateRangeField.tsx +++ b/packages/x-date-pickers-pro/src/MultiInputDateRangeField/MultiInputDateRangeField.tsx @@ -16,6 +16,7 @@ import { FieldsTextFieldProps, convertFieldResponseIntoMuiTextFieldProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { MultiInputDateRangeFieldProps } from './MultiInputDateRangeField.types'; import { useMultiInputDateRangeField } from '../internals/hooks/useMultiInputRangeField/useMultiInputDateRangeField'; import { UseDateRangeFieldProps } from '../internals/models/dateRange'; @@ -59,7 +60,7 @@ const MultiInputDateRangeFieldSeparator = styled( }, )({}); -type MultiInputDateRangeFieldComponent = (<TDate>( +type MultiInputDateRangeFieldComponent = (<TDate extends PickerValidDate>( props: MultiInputDateRangeFieldProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -73,10 +74,9 @@ type MultiInputDateRangeFieldComponent = (<TDate>( * * - [MultiInputDateRangeField API](https://mui.com/x/api/multi-input-date-range-field/) */ -const MultiInputDateRangeField = React.forwardRef(function MultiInputDateRangeField<TDate>( - inProps: MultiInputDateRangeFieldProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const MultiInputDateRangeField = React.forwardRef(function MultiInputDateRangeField< + TDate extends PickerValidDate, +>(inProps: MultiInputDateRangeFieldProps<TDate>, ref: React.Ref<HTMLDivElement>) { const themeProps = useThemeProps({ props: inProps, name: 'MuiMultiInputDateRangeField', @@ -173,7 +173,7 @@ MultiInputDateRangeField.propTypes = { /** * The default value. Use when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * Defines the `flex-direction` style property. * It is applied for all screen sizes. @@ -216,11 +216,11 @@ MultiInputDateRangeField.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Callback fired when the value changes. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. @@ -253,7 +253,7 @@ MultiInputDateRangeField.propTypes = { * For example, on time fields it will be used to determine the date to set. * @default The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * The currently selected sections. * This prop accept four formats: @@ -361,7 +361,7 @@ MultiInputDateRangeField.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), } as any; export { MultiInputDateRangeField }; diff --git a/packages/x-date-pickers-pro/src/MultiInputDateRangeField/MultiInputDateRangeField.types.ts b/packages/x-date-pickers-pro/src/MultiInputDateRangeField/MultiInputDateRangeField.types.ts index 9638f73727ac5..8b741a80e9201 100644 --- a/packages/x-date-pickers-pro/src/MultiInputDateRangeField/MultiInputDateRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/MultiInputDateRangeField/MultiInputDateRangeField.types.ts @@ -1,4 +1,5 @@ import * as React from 'react'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { SlotComponentProps } from '@mui/base/utils'; import Typography from '@mui/material/Typography'; import Stack, { StackProps } from '@mui/material/Stack'; @@ -9,21 +10,21 @@ import { MultiInputFieldRefs } from '../internals/models/fields'; import { MultiInputRangeFieldClasses, RangePosition } from '../models'; export type UseMultiInputDateRangeFieldParams< - TDate, + TDate extends PickerValidDate, TTextFieldSlotProps extends {}, > = UseMultiInputRangeFieldParams<UseMultiInputDateRangeFieldProps<TDate>, TTextFieldSlotProps>; -export interface UseMultiInputDateRangeFieldProps<TDate> +export interface UseMultiInputDateRangeFieldProps<TDate extends PickerValidDate> extends Omit<UseDateRangeFieldProps<TDate>, 'unstableFieldRef' | 'clearable' | 'onClear'>, MultiInputFieldRefs {} -export type UseMultiInputDateRangeFieldComponentProps<TDate, TChildProps extends {}> = Omit< - TChildProps, - keyof UseMultiInputDateRangeFieldProps<TDate> -> & +export type UseMultiInputDateRangeFieldComponentProps< + TDate extends PickerValidDate, + TChildProps extends {}, +> = Omit<TChildProps, keyof UseMultiInputDateRangeFieldProps<TDate>> & UseMultiInputDateRangeFieldProps<TDate>; -export interface MultiInputDateRangeFieldProps<TDate> +export interface MultiInputDateRangeFieldProps<TDate extends PickerValidDate> extends UseMultiInputDateRangeFieldComponentProps<TDate, Omit<StackProps, 'position'>> { autoFocus?: boolean; /** @@ -42,7 +43,8 @@ export interface MultiInputDateRangeFieldProps<TDate> slotProps?: MultiInputDateRangeFieldSlotProps<TDate>; } -export type MultiInputDateRangeFieldOwnerState<TDate> = MultiInputDateRangeFieldProps<TDate>; +export type MultiInputDateRangeFieldOwnerState<TDate extends PickerValidDate> = + MultiInputDateRangeFieldProps<TDate>; export interface MultiInputDateRangeFieldSlots { /** @@ -64,7 +66,7 @@ export interface MultiInputDateRangeFieldSlots { separator?: React.ElementType; } -export interface MultiInputDateRangeFieldSlotProps<TDate> { +export interface MultiInputDateRangeFieldSlotProps<TDate extends PickerValidDate> { root?: SlotComponentProps<typeof Stack, {}, MultiInputDateRangeFieldOwnerState<TDate>>; textField?: SlotComponentProps< typeof TextField, diff --git a/packages/x-date-pickers-pro/src/MultiInputDateTimeRangeField/MultiInputDateTimeRangeField.tsx b/packages/x-date-pickers-pro/src/MultiInputDateTimeRangeField/MultiInputDateTimeRangeField.tsx index 3820e3f57814c..64ec39d23c327 100644 --- a/packages/x-date-pickers-pro/src/MultiInputDateTimeRangeField/MultiInputDateTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/MultiInputDateTimeRangeField/MultiInputDateTimeRangeField.tsx @@ -16,6 +16,7 @@ import { FieldsTextFieldProps, convertFieldResponseIntoMuiTextFieldProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { MultiInputDateTimeRangeFieldProps } from './MultiInputDateTimeRangeField.types'; import { useMultiInputDateTimeRangeField } from '../internals/hooks/useMultiInputRangeField/useMultiInputDateTimeRangeField'; import { UseDateTimeRangeFieldProps } from '../internals/models/dateTimeRange'; @@ -57,7 +58,7 @@ const MultiInputDateTimeRangeFieldSeparator = styled( }, )({}); -type MultiInputDateTimeRangeFieldComponent = (<TDate>( +type MultiInputDateTimeRangeFieldComponent = (<TDate extends PickerValidDate>( props: MultiInputDateTimeRangeFieldProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -71,10 +72,9 @@ type MultiInputDateTimeRangeFieldComponent = (<TDate>( * * - [MultiInputDateTimeRangeField API](https://mui.com/x/api/multi-input-date-time-range-field/) */ -const MultiInputDateTimeRangeField = React.forwardRef(function MultiInputDateTimeRangeField<TDate>( - inProps: MultiInputDateTimeRangeFieldProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const MultiInputDateTimeRangeField = React.forwardRef(function MultiInputDateTimeRangeField< + TDate extends PickerValidDate, +>(inProps: MultiInputDateTimeRangeFieldProps<TDate>, ref: React.Ref<HTMLDivElement>) { const themeProps = useThemeProps({ props: inProps, name: 'MuiMultiInputDateTimeRangeField', @@ -176,7 +176,7 @@ MultiInputDateTimeRangeField.propTypes = { /** * The default value. Use when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * Defines the `flex-direction` style property. * It is applied for all screen sizes. @@ -224,29 +224,29 @@ MultiInputDateTimeRangeField.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Maximal selectable moment of time with binding to date, to set max time in each day use `maxTime`. */ - maxDateTime: PropTypes.any, + maxDateTime: PropTypes.object, /** * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Minimal selectable moment of time with binding to date, to set min time in each day use `minTime`. */ - minDateTime: PropTypes.any, + minDateTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -284,7 +284,7 @@ MultiInputDateTimeRangeField.propTypes = { * For example, on time fields it will be used to determine the date to set. * @default The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * The currently selected sections. * This prop accept four formats: @@ -400,7 +400,7 @@ MultiInputDateTimeRangeField.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), } as any; export { MultiInputDateTimeRangeField }; diff --git a/packages/x-date-pickers-pro/src/MultiInputDateTimeRangeField/MultiInputDateTimeRangeField.types.ts b/packages/x-date-pickers-pro/src/MultiInputDateTimeRangeField/MultiInputDateTimeRangeField.types.ts index 3189bf67c2b7c..f83594e58fb1f 100644 --- a/packages/x-date-pickers-pro/src/MultiInputDateTimeRangeField/MultiInputDateTimeRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/MultiInputDateTimeRangeField/MultiInputDateTimeRangeField.types.ts @@ -3,6 +3,7 @@ import { SlotComponentProps } from '@mui/base/utils'; import Typography from '@mui/material/Typography'; import Stack, { StackProps } from '@mui/material/Stack'; import TextField from '@mui/material/TextField'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { UseDateTimeRangeFieldDefaultizedProps, UseDateTimeRangeFieldProps, @@ -12,21 +13,21 @@ import { UseMultiInputRangeFieldParams } from '../internals/hooks/useMultiInputR import { MultiInputRangeFieldClasses, RangePosition } from '../models'; export type UseMultiInputDateTimeRangeFieldParams< - TDate, + TDate extends PickerValidDate, TTextFieldSlotProps extends {}, > = UseMultiInputRangeFieldParams<UseMultiInputDateTimeRangeFieldProps<TDate>, TTextFieldSlotProps>; -export interface UseMultiInputDateTimeRangeFieldProps<TDate> +export interface UseMultiInputDateTimeRangeFieldProps<TDate extends PickerValidDate> extends Omit<UseDateTimeRangeFieldProps<TDate>, 'unstableFieldRef' | 'clearable' | 'onClear'>, MultiInputFieldRefs {} -export type UseMultiInputDateTimeRangeFieldComponentProps<TDate, TChildProps extends {}> = Omit< - TChildProps, - keyof UseMultiInputDateTimeRangeFieldProps<TDate> -> & +export type UseMultiInputDateTimeRangeFieldComponentProps< + TDate extends PickerValidDate, + TChildProps extends {}, +> = Omit<TChildProps, keyof UseMultiInputDateTimeRangeFieldProps<TDate>> & UseMultiInputDateTimeRangeFieldProps<TDate>; -export interface MultiInputDateTimeRangeFieldProps<TDate> +export interface MultiInputDateTimeRangeFieldProps<TDate extends PickerValidDate> extends UseMultiInputDateTimeRangeFieldComponentProps<TDate, Omit<StackProps, 'position'>> { autoFocus?: boolean; /** @@ -45,7 +46,7 @@ export interface MultiInputDateTimeRangeFieldProps<TDate> slotProps?: MultiInputDateTimeRangeFieldSlotProps<TDate>; } -export type MultiInputDateTimeRangeFieldOwnerState<TDate> = +export type MultiInputDateTimeRangeFieldOwnerState<TDate extends PickerValidDate> = MultiInputDateTimeRangeFieldProps<TDate>; export interface MultiInputDateTimeRangeFieldSlots { @@ -68,7 +69,7 @@ export interface MultiInputDateTimeRangeFieldSlots { separator?: React.ElementType; } -export interface MultiInputDateTimeRangeFieldSlotProps<TDate> { +export interface MultiInputDateTimeRangeFieldSlotProps<TDate extends PickerValidDate> { root?: SlotComponentProps<typeof Stack, {}, MultiInputDateTimeRangeFieldOwnerState<TDate>>; textField?: SlotComponentProps< typeof TextField, @@ -83,7 +84,7 @@ export interface MultiInputDateTimeRangeFieldSlotProps<TDate> { } export type UseMultiInputDateTimeRangeFieldDefaultizedProps< - TDate, + TDate extends PickerValidDate, AdditionalProps extends {}, > = UseDateTimeRangeFieldDefaultizedProps<TDate> & Omit<AdditionalProps, 'value' | 'defaultValue' | 'onChange'>; diff --git a/packages/x-date-pickers-pro/src/MultiInputTimeRangeField/MultiInputTimeRangeField.tsx b/packages/x-date-pickers-pro/src/MultiInputTimeRangeField/MultiInputTimeRangeField.tsx index 0cc0564271325..03ad3860bce26 100644 --- a/packages/x-date-pickers-pro/src/MultiInputTimeRangeField/MultiInputTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/MultiInputTimeRangeField/MultiInputTimeRangeField.tsx @@ -16,6 +16,7 @@ import { FieldsTextFieldProps, convertFieldResponseIntoMuiTextFieldProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { MultiInputTimeRangeFieldProps } from './MultiInputTimeRangeField.types'; import { useMultiInputTimeRangeField } from '../internals/hooks/useMultiInputRangeField/useMultiInputTimeRangeField'; import { UseTimeRangeFieldProps } from '../internals/models/timeRange'; @@ -59,7 +60,7 @@ const MultiInputTimeRangeFieldSeparator = styled( }, )({}); -type MultiInputTimeRangeFieldComponent = (<TDate>( +type MultiInputTimeRangeFieldComponent = (<TDate extends PickerValidDate>( props: MultiInputTimeRangeFieldProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -73,10 +74,9 @@ type MultiInputTimeRangeFieldComponent = (<TDate>( * * - [MultiInputTimeRangeField API](https://mui.com/x/api/multi-input-time-range-field/) */ -const MultiInputTimeRangeField = React.forwardRef(function MultiInputTimeRangeField<TDate>( - inProps: MultiInputTimeRangeFieldProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const MultiInputTimeRangeField = React.forwardRef(function MultiInputTimeRangeField< + TDate extends PickerValidDate, +>(inProps: MultiInputTimeRangeFieldProps<TDate>, ref: React.Ref<HTMLDivElement>) { const themeProps = useThemeProps({ props: inProps, name: 'MuiMultiInputTimeRangeField', @@ -179,7 +179,7 @@ MultiInputTimeRangeField.propTypes = { /** * The default value. Use when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * Defines the `flex-direction` style property. * It is applied for all screen sizes. @@ -228,12 +228,12 @@ MultiInputTimeRangeField.propTypes = { * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -271,7 +271,7 @@ MultiInputTimeRangeField.propTypes = { * For example, on time fields it will be used to determine the date to set. * @default The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * The currently selected sections. * This prop accept four formats: @@ -376,7 +376,7 @@ MultiInputTimeRangeField.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), } as any; export { MultiInputTimeRangeField }; diff --git a/packages/x-date-pickers-pro/src/MultiInputTimeRangeField/MultiInputTimeRangeField.types.ts b/packages/x-date-pickers-pro/src/MultiInputTimeRangeField/MultiInputTimeRangeField.types.ts index 8cd1cb9682d5e..3dde1f4009337 100644 --- a/packages/x-date-pickers-pro/src/MultiInputTimeRangeField/MultiInputTimeRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/MultiInputTimeRangeField/MultiInputTimeRangeField.types.ts @@ -3,6 +3,7 @@ import { SlotComponentProps } from '@mui/base/utils'; import Typography from '@mui/material/Typography'; import Stack, { StackProps } from '@mui/material/Stack'; import TextField from '@mui/material/TextField'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { UseTimeRangeFieldDefaultizedProps, UseTimeRangeFieldProps, @@ -12,21 +13,21 @@ import { MultiInputFieldRefs } from '../internals/models/fields'; import { MultiInputRangeFieldClasses, RangePosition } from '../models'; export type UseMultiInputTimeRangeFieldParams< - TDate, + TDate extends PickerValidDate, TTextFieldSlotProps extends {}, > = UseMultiInputRangeFieldParams<UseMultiInputTimeRangeFieldProps<TDate>, TTextFieldSlotProps>; -export interface UseMultiInputTimeRangeFieldProps<TDate> +export interface UseMultiInputTimeRangeFieldProps<TDate extends PickerValidDate> extends Omit<UseTimeRangeFieldProps<TDate>, 'unstableFieldRef' | 'clearable' | 'onClear'>, MultiInputFieldRefs {} -export type UseMultiInputTimeRangeFieldComponentProps<TDate, TChildProps extends {}> = Omit< - TChildProps, - keyof UseMultiInputTimeRangeFieldProps<TDate> -> & +export type UseMultiInputTimeRangeFieldComponentProps< + TDate extends PickerValidDate, + TChildProps extends {}, +> = Omit<TChildProps, keyof UseMultiInputTimeRangeFieldProps<TDate>> & UseMultiInputTimeRangeFieldProps<TDate>; -export interface MultiInputTimeRangeFieldProps<TDate> +export interface MultiInputTimeRangeFieldProps<TDate extends PickerValidDate> extends UseMultiInputTimeRangeFieldComponentProps<TDate, Omit<StackProps, 'position'>> { autoFocus?: boolean; /** @@ -45,7 +46,8 @@ export interface MultiInputTimeRangeFieldProps<TDate> slotProps?: MultiInputTimeRangeFieldSlotProps<TDate>; } -export type MultiInputTimeRangeFieldOwnerState<TDate> = MultiInputTimeRangeFieldProps<TDate>; +export type MultiInputTimeRangeFieldOwnerState<TDate extends PickerValidDate> = + MultiInputTimeRangeFieldProps<TDate>; export interface MultiInputTimeRangeFieldSlots { /** @@ -67,7 +69,7 @@ export interface MultiInputTimeRangeFieldSlots { separator?: React.ElementType; } -export interface MultiInputTimeRangeFieldSlotProps<TDate> { +export interface MultiInputTimeRangeFieldSlotProps<TDate extends PickerValidDate> { root?: SlotComponentProps<typeof Stack, {}, MultiInputTimeRangeFieldOwnerState<TDate>>; textField?: SlotComponentProps< typeof TextField, @@ -78,7 +80,7 @@ export interface MultiInputTimeRangeFieldSlotProps<TDate> { } export type UseMultiInputTimeRangeFieldDefaultizedProps< - TDate, + TDate extends PickerValidDate, AdditionalProps extends {}, > = UseTimeRangeFieldDefaultizedProps<TDate> & Omit<AdditionalProps, 'value' | 'defaultValue' | 'onChange'>; diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx index 79fdcbfcb1ff8..ca3db91f8151f 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx @@ -5,6 +5,7 @@ import { useThemeProps } from '@mui/material/styles'; import { useSlotProps } from '@mui/base/utils'; import { useClearableField } from '@mui/x-date-pickers/hooks'; import { convertFieldResponseIntoMuiTextFieldProps } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { refType } from '@mui/utils'; import { SingleInputDateRangeFieldProps, @@ -13,7 +14,7 @@ import { import { useSingleInputDateRangeField } from './useSingleInputDateRangeField'; import { FieldType } from '../internals/models'; -type DateRangeFieldComponent = (<TDate>( +type DateRangeFieldComponent = (<TDate extends PickerValidDate>( props: SingleInputDateRangeFieldProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any; fieldType?: FieldType }; @@ -27,10 +28,9 @@ type DateRangeFieldComponent = (<TDate>( * * - [SingleInputDateRangeField API](https://mui.com/x/api/single-input-date-range-field/) */ -const SingleInputDateRangeField = React.forwardRef(function SingleInputDateRangeField<TDate>( - inProps: SingleInputDateRangeFieldProps<TDate>, - inRef: React.Ref<HTMLDivElement>, -) { +const SingleInputDateRangeField = React.forwardRef(function SingleInputDateRangeField< + TDate extends PickerValidDate, +>(inProps: SingleInputDateRangeFieldProps<TDate>, inRef: React.Ref<HTMLDivElement>) { const themeProps = useThemeProps({ props: inProps, name: 'MuiSingleInputDateRangeField', @@ -101,7 +101,7 @@ SingleInputDateRangeField.propTypes = { /** * The default value. Use when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * If `true`, the component is disabled. * @default false @@ -188,11 +188,11 @@ SingleInputDateRangeField.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Name attribute of the `input` element. */ @@ -235,7 +235,7 @@ SingleInputDateRangeField.propTypes = { * For example, on time fields it will be used to determine the date to set. * @default The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * If `true`, the label is displayed as required and the `input` element is required. * @default false @@ -334,7 +334,7 @@ SingleInputDateRangeField.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), /** * The variant to use. * @default 'outlined' diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts index 82aab457b364c..8e022305bf596 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts @@ -2,25 +2,27 @@ import * as React from 'react'; import { SlotComponentProps } from '@mui/base/utils'; import TextField from '@mui/material/TextField'; import { FieldsTextFieldProps } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { UseClearableFieldSlots, UseClearableFieldSlotProps } from '@mui/x-date-pickers/hooks'; import { UseDateRangeFieldDefaultizedProps, UseDateRangeFieldProps } from '../internals/models'; -export interface UseSingleInputDateRangeFieldProps<TDate> extends UseDateRangeFieldProps<TDate> {} +export interface UseSingleInputDateRangeFieldProps<TDate extends PickerValidDate> + extends UseDateRangeFieldProps<TDate> {} export type UseSingleInputDateRangeFieldDefaultizedProps< - TDate, + TDate extends PickerValidDate, AdditionalProps extends {}, > = UseDateRangeFieldDefaultizedProps<TDate> & Omit<AdditionalProps, 'value' | 'defaultValue' | 'onChange'>; -export type UseSingleInputDateRangeFieldComponentProps<TDate, TChildProps extends {}> = Omit< - TChildProps, - keyof UseSingleInputDateRangeFieldProps<TDate> -> & +export type UseSingleInputDateRangeFieldComponentProps< + TDate extends PickerValidDate, + TChildProps extends {}, +> = Omit<TChildProps, keyof UseSingleInputDateRangeFieldProps<TDate>> & UseSingleInputDateRangeFieldProps<TDate>; export type SingleInputDateRangeFieldProps< - TDate, + TDate extends PickerValidDate, TChildProps extends {} = FieldsTextFieldProps, > = UseSingleInputDateRangeFieldComponentProps<TDate, TChildProps> & { /** @@ -35,7 +37,8 @@ export type SingleInputDateRangeFieldProps< slotProps?: SingleInputDateRangeFieldSlotProps<TDate>; }; -export type SingleInputDateRangeFieldOwnerState<TDate> = SingleInputDateRangeFieldProps<TDate>; +export type SingleInputDateRangeFieldOwnerState<TDate extends PickerValidDate> = + SingleInputDateRangeFieldProps<TDate>; export interface SingleInputDateRangeFieldSlots extends UseClearableFieldSlots { /** @@ -46,6 +49,7 @@ export interface SingleInputDateRangeFieldSlots extends UseClearableFieldSlots { textField?: React.ElementType; } -export interface SingleInputDateRangeFieldSlotProps<TDate> extends UseClearableFieldSlotProps { +export interface SingleInputDateRangeFieldSlotProps<TDate extends PickerValidDate> + extends UseClearableFieldSlotProps { textField?: SlotComponentProps<typeof TextField, {}, SingleInputDateRangeFieldOwnerState<TDate>>; } diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts index e4fd9f760d11a..267533708dcb5 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts @@ -5,6 +5,7 @@ import { useField, splitFieldInternalAndForwardedProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { UseSingleInputDateRangeFieldComponentProps, UseSingleInputDateRangeFieldDefaultizedProps, @@ -13,7 +14,10 @@ import { import { rangeValueManager, rangeFieldValueManager } from '../internals/utils/valueManagers'; import { validateDateRange } from '../internals/utils/validation/validateDateRange'; -export const useDefaultizedDateRangeFieldProps = <TDate, AdditionalProps extends {}>( +export const useDefaultizedDateRangeFieldProps = < + TDate extends PickerValidDate, + AdditionalProps extends {}, +>( props: UseSingleInputDateRangeFieldProps<TDate>, ): UseSingleInputDateRangeFieldDefaultizedProps<TDate, AdditionalProps> => { const utils = useUtils<TDate>(); @@ -29,7 +33,7 @@ export const useDefaultizedDateRangeFieldProps = <TDate, AdditionalProps extends } as any; }; -export const useSingleInputDateRangeField = <TDate, TChildProps extends {}>( +export const useSingleInputDateRangeField = <TDate extends PickerValidDate, TChildProps extends {}>( inProps: UseSingleInputDateRangeFieldComponentProps<TDate, TChildProps>, ) => { const props = useDefaultizedDateRangeFieldProps<TDate, TChildProps>(inProps); diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx index 1afa9c2ddc87d..f2635d79d128a 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx @@ -5,6 +5,7 @@ import { convertFieldResponseIntoMuiTextFieldProps } from '@mui/x-date-pickers/i import { useThemeProps } from '@mui/material/styles'; import { useSlotProps } from '@mui/base/utils'; import { useClearableField } from '@mui/x-date-pickers/hooks'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { refType } from '@mui/utils'; import { SingleInputDateTimeRangeFieldProps, @@ -13,7 +14,7 @@ import { import { useSingleInputDateTimeRangeField } from './useSingleInputDateTimeRangeField'; import { FieldType } from '../internals/models'; -type DateRangeFieldComponent = (<TDate>( +type DateRangeFieldComponent = (<TDate extends PickerValidDate>( props: SingleInputDateTimeRangeFieldProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any; fieldType?: FieldType }; @@ -28,7 +29,7 @@ type DateRangeFieldComponent = (<TDate>( * - [SingleInputDateTimeRangeField API](https://mui.com/x/api/single-input-date-time-range-field/) */ const SingleInputDateTimeRangeField = React.forwardRef(function SingleInputDateTimeRangeField< - TDate, + TDate extends PickerValidDate, >(inProps: SingleInputDateTimeRangeFieldProps<TDate>, inRef: React.Ref<HTMLDivElement>) { const themeProps = useThemeProps({ props: inProps, @@ -107,7 +108,7 @@ SingleInputDateTimeRangeField.propTypes = { /** * The default value. Use when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * If `true`, the component is disabled. * @default false @@ -199,29 +200,29 @@ SingleInputDateTimeRangeField.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Maximal selectable moment of time with binding to date, to set max time in each day use `maxTime`. */ - maxDateTime: PropTypes.any, + maxDateTime: PropTypes.object, /** * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Minimal selectable moment of time with binding to date, to set min time in each day use `minTime`. */ - minDateTime: PropTypes.any, + minDateTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -269,7 +270,7 @@ SingleInputDateTimeRangeField.propTypes = { * For example, on time fields it will be used to determine the date to set. * @default The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * If `true`, the label is displayed as required and the `input` element is required. * @default false @@ -376,7 +377,7 @@ SingleInputDateTimeRangeField.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), /** * The variant to use. * @default 'outlined' diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts index 1dfb93aeeec09..9a6b6b88d7fc0 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts @@ -3,26 +3,27 @@ import { SlotComponentProps } from '@mui/base/utils'; import TextField from '@mui/material/TextField'; import { FieldsTextFieldProps } from '@mui/x-date-pickers/internals'; import { UseClearableFieldSlots, UseClearableFieldSlotProps } from '@mui/x-date-pickers/hooks'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { UseDateTimeRangeFieldDefaultizedProps, UseDateTimeRangeFieldProps, } from '../internals/models'; -export interface UseSingleInputDateTimeRangeFieldProps<TDate> +export interface UseSingleInputDateTimeRangeFieldProps<TDate extends PickerValidDate> extends UseDateTimeRangeFieldProps<TDate> {} export type UseSingleInputDateTimeRangeFieldDefaultizedProps< - TDate, + TDate extends PickerValidDate, AdditionalProps extends {}, > = UseDateTimeRangeFieldDefaultizedProps<TDate> & AdditionalProps; -export type UseSingleInputDateTimeRangeFieldComponentProps<TDate, TChildProps extends {}> = Omit< - TChildProps, - keyof UseSingleInputDateTimeRangeFieldProps<TDate> -> & +export type UseSingleInputDateTimeRangeFieldComponentProps< + TDate extends PickerValidDate, + TChildProps extends {}, +> = Omit<TChildProps, keyof UseSingleInputDateTimeRangeFieldProps<TDate>> & UseSingleInputDateTimeRangeFieldProps<TDate>; -export interface SingleInputDateTimeRangeFieldProps<TDate> +export interface SingleInputDateTimeRangeFieldProps<TDate extends PickerValidDate> extends UseSingleInputDateTimeRangeFieldComponentProps<TDate, FieldsTextFieldProps> { /** * Overridable component slots. @@ -36,7 +37,7 @@ export interface SingleInputDateTimeRangeFieldProps<TDate> slotProps?: SingleInputDateTimeRangeFieldSlotProps<TDate>; } -export type SingleInputDateTimeRangeFieldOwnerState<TDate> = +export type SingleInputDateTimeRangeFieldOwnerState<TDate extends PickerValidDate> = SingleInputDateTimeRangeFieldProps<TDate>; export interface SingleInputDateTimeRangeFieldSlots extends UseClearableFieldSlots { @@ -48,7 +49,8 @@ export interface SingleInputDateTimeRangeFieldSlots extends UseClearableFieldSlo textField?: React.ElementType; } -export interface SingleInputDateTimeRangeFieldSlotProps<TDate> extends UseClearableFieldSlotProps { +export interface SingleInputDateTimeRangeFieldSlotProps<TDate extends PickerValidDate> + extends UseClearableFieldSlotProps { textField?: SlotComponentProps< typeof TextField, {}, diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts index 815b8f7ae74f0..d6afd05119409 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts @@ -5,6 +5,7 @@ import { useDefaultDates, splitFieldInternalAndForwardedProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { UseSingleInputDateTimeRangeFieldComponentProps, UseSingleInputDateTimeRangeFieldDefaultizedProps, @@ -13,7 +14,10 @@ import { import { rangeValueManager, rangeFieldValueManager } from '../internals/utils/valueManagers'; import { validateDateTimeRange } from '../internals/utils/validation/validateDateTimeRange'; -export const useDefaultizedTimeRangeFieldProps = <TDate, AdditionalProps extends {}>( +export const useDefaultizedTimeRangeFieldProps = < + TDate extends PickerValidDate, + AdditionalProps extends {}, +>( props: UseSingleInputDateTimeRangeFieldProps<TDate>, ): UseSingleInputDateTimeRangeFieldDefaultizedProps<TDate, AdditionalProps> => { const utils = useUtils<TDate>(); @@ -37,7 +41,10 @@ export const useDefaultizedTimeRangeFieldProps = <TDate, AdditionalProps extends } as any; }; -export const useSingleInputDateTimeRangeField = <TDate, TChildProps extends {}>( +export const useSingleInputDateTimeRangeField = < + TDate extends PickerValidDate, + TChildProps extends {}, +>( inProps: UseSingleInputDateTimeRangeFieldComponentProps<TDate, TChildProps>, ) => { const props = useDefaultizedTimeRangeFieldProps<TDate, TChildProps>(inProps); diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx index 64050ad98d9a9..c719820f233f7 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import MuiTextField from '@mui/material/TextField'; import { useClearableField } from '@mui/x-date-pickers/hooks'; import { convertFieldResponseIntoMuiTextFieldProps } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { useThemeProps } from '@mui/material/styles'; import { useSlotProps } from '@mui/base/utils'; import { refType } from '@mui/utils'; @@ -13,7 +14,7 @@ import { import { useSingleInputTimeRangeField } from './useSingleInputTimeRangeField'; import { FieldType } from '../internals/models'; -type DateRangeFieldComponent = (<TDate>( +type DateRangeFieldComponent = (<TDate extends PickerValidDate>( props: SingleInputTimeRangeFieldProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any; fieldType?: FieldType }; @@ -27,10 +28,9 @@ type DateRangeFieldComponent = (<TDate>( * * - [SingleInputTimeRangeField API](https://mui.com/x/api/single-input-time-range-field/) */ -const SingleInputTimeRangeField = React.forwardRef(function SingleInputTimeRangeField<TDate>( - inProps: SingleInputTimeRangeFieldProps<TDate>, - inRef: React.Ref<HTMLDivElement>, -) { +const SingleInputTimeRangeField = React.forwardRef(function SingleInputTimeRangeField< + TDate extends PickerValidDate, +>(inProps: SingleInputTimeRangeFieldProps<TDate>, inRef: React.Ref<HTMLDivElement>) { const themeProps = useThemeProps({ props: inProps, name: 'MuiSingleInputTimeRangeField', @@ -106,7 +106,7 @@ SingleInputTimeRangeField.propTypes = { /** * The default value. Use when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * If `true`, the component is disabled. * @default false @@ -199,12 +199,12 @@ SingleInputTimeRangeField.propTypes = { * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -252,7 +252,7 @@ SingleInputTimeRangeField.propTypes = { * For example, on time fields it will be used to determine the date to set. * @default The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * If `true`, the label is displayed as required and the `input` element is required. * @default false @@ -348,7 +348,7 @@ SingleInputTimeRangeField.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), /** * The variant to use. * @default 'outlined' diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts index aee8a1558ebcc..2145337104a91 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts @@ -2,23 +2,25 @@ import * as React from 'react'; import { SlotComponentProps } from '@mui/base/utils'; import TextField from '@mui/material/TextField'; import { FieldsTextFieldProps } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { UseClearableFieldSlots, UseClearableFieldSlotProps } from '@mui/x-date-pickers/hooks'; import { UseTimeRangeFieldDefaultizedProps, UseTimeRangeFieldProps } from '../internals/models'; -export interface UseSingleInputTimeRangeFieldProps<TDate> extends UseTimeRangeFieldProps<TDate> {} +export interface UseSingleInputTimeRangeFieldProps<TDate extends PickerValidDate> + extends UseTimeRangeFieldProps<TDate> {} export type UseSingleInputTimeRangeFieldDefaultizedProps< - TDate, + TDate extends PickerValidDate, AdditionalProps extends {}, > = UseTimeRangeFieldDefaultizedProps<TDate> & AdditionalProps; -export type UseSingleInputTimeRangeFieldComponentProps<TDate, TChildProps extends {}> = Omit< - TChildProps, - keyof UseSingleInputTimeRangeFieldProps<TDate> -> & +export type UseSingleInputTimeRangeFieldComponentProps< + TDate extends PickerValidDate, + TChildProps extends {}, +> = Omit<TChildProps, keyof UseSingleInputTimeRangeFieldProps<TDate>> & UseSingleInputTimeRangeFieldProps<TDate>; -export interface SingleInputTimeRangeFieldProps<TDate> +export interface SingleInputTimeRangeFieldProps<TDate extends PickerValidDate> extends UseSingleInputTimeRangeFieldComponentProps<TDate, FieldsTextFieldProps> { /** * Overridable component slots. @@ -32,7 +34,8 @@ export interface SingleInputTimeRangeFieldProps<TDate> slotProps?: SingleInputTimeRangeFieldSlotProps<TDate>; } -export type SingleInputTimeRangeFieldOwnerState<TDate> = SingleInputTimeRangeFieldProps<TDate>; +export type SingleInputTimeRangeFieldOwnerState<TDate extends PickerValidDate> = + SingleInputTimeRangeFieldProps<TDate>; export interface SingleInputTimeRangeFieldSlots extends UseClearableFieldSlots { /** @@ -43,6 +46,7 @@ export interface SingleInputTimeRangeFieldSlots extends UseClearableFieldSlots { textField?: React.ElementType; } -export interface SingleInputTimeRangeFieldSlotProps<TDate> extends UseClearableFieldSlotProps { +export interface SingleInputTimeRangeFieldSlotProps<TDate extends PickerValidDate> + extends UseClearableFieldSlotProps { textField?: SlotComponentProps<typeof TextField, {}, SingleInputTimeRangeFieldOwnerState<TDate>>; } diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts index dc016b777afe6..92de900e89e66 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts @@ -3,6 +3,7 @@ import { useField, splitFieldInternalAndForwardedProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { UseSingleInputTimeRangeFieldComponentProps, UseSingleInputTimeRangeFieldDefaultizedProps, @@ -11,7 +12,10 @@ import { import { rangeValueManager, rangeFieldValueManager } from '../internals/utils/valueManagers'; import { validateTimeRange } from '../internals/utils/validation/validateTimeRange'; -export const useDefaultizedTimeRangeFieldProps = <TDate, AdditionalProps extends {}>( +export const useDefaultizedTimeRangeFieldProps = < + TDate extends PickerValidDate, + AdditionalProps extends {}, +>( props: UseSingleInputTimeRangeFieldProps<TDate>, ): UseSingleInputTimeRangeFieldDefaultizedProps<TDate, AdditionalProps> => { const utils = useUtils<TDate>(); @@ -27,7 +31,7 @@ export const useDefaultizedTimeRangeFieldProps = <TDate, AdditionalProps extends } as any; }; -export const useSingleInputTimeRangeField = <TDate, TChildProps extends {}>( +export const useSingleInputTimeRangeField = <TDate extends PickerValidDate, TChildProps extends {}>( inProps: UseSingleInputTimeRangeFieldComponentProps<TDate, TChildProps>, ) => { const props = useDefaultizedTimeRangeFieldProps<TDate, TChildProps>(inProps); diff --git a/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.tsx b/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.tsx index a77cd758fdd81..58ac192fe5c84 100644 --- a/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { PickerViewRendererLookup } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { useStaticRangePicker } from '../internals/hooks/useStaticRangePicker'; import { StaticDateRangePickerProps } from './StaticDateRangePicker.types'; import { useDateRangePickerDefaultizedProps } from '../DateRangePicker/shared'; @@ -9,7 +10,7 @@ import { rangeValueManager } from '../internals/utils/valueManagers'; import { validateDateRange } from '../internals/utils/validation/validateDateRange'; import { DateRange } from '../models'; -type StaticDateRangePickerComponent = (<TDate>( +type StaticDateRangePickerComponent = (<TDate extends PickerValidDate>( props: StaticDateRangePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -23,10 +24,9 @@ type StaticDateRangePickerComponent = (<TDate>( * * - [StaticDateRangePicker API](https://mui.com/x/api/date-pickers/static-date-range-picker/) */ -const StaticDateRangePicker = React.forwardRef(function StaticDateRangePicker<TDate>( - inProps: StaticDateRangePickerProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const StaticDateRangePicker = React.forwardRef(function StaticDateRangePicker< + TDate extends PickerValidDate, +>(inProps: StaticDateRangePickerProps<TDate>, ref: React.Ref<HTMLDivElement>) { const defaultizedProps = useDateRangePickerDefaultizedProps< TDate, StaticDateRangePickerProps<TDate> @@ -107,7 +107,7 @@ StaticDateRangePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.arrayOf(PropTypes.any), + defaultValue: PropTypes.arrayOf(PropTypes.object), /** * If `true`, after selecting `start` date calendar will not automatically switch to the month of `end` date. * @default false @@ -167,11 +167,11 @@ StaticDateRangePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. @@ -228,7 +228,7 @@ StaticDateRangePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component rendered on the "day" view when `props.loading` is true. * @returns {React.ReactNode} The node to render when loading. @@ -287,7 +287,7 @@ StaticDateRangePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.arrayOf(PropTypes.any), + value: PropTypes.arrayOf(PropTypes.object), /** * Define custom view renderers for each section. * If `null`, the section will only have field editing. diff --git a/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.types.ts b/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.types.ts index 1f4c529a9ac1e..78406f30dc31c 100644 --- a/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.types.ts @@ -1,4 +1,5 @@ import { MakeOptional } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { StaticRangeOnlyPickerProps, UseStaticRangePickerSlots, @@ -10,15 +11,15 @@ import { BaseDateRangePickerSlotProps, } from '../DateRangePicker/shared'; -export interface StaticDateRangePickerSlots<TDate> +export interface StaticDateRangePickerSlots<TDate extends PickerValidDate> extends BaseDateRangePickerSlots<TDate>, UseStaticRangePickerSlots<TDate, 'day'> {} -export interface StaticDateRangePickerSlotProps<TDate> +export interface StaticDateRangePickerSlotProps<TDate extends PickerValidDate> extends BaseDateRangePickerSlotProps<TDate>, UseStaticRangePickerSlotProps<TDate, 'day'> {} -export interface StaticDateRangePickerProps<TDate> +export interface StaticDateRangePickerProps<TDate extends PickerValidDate> extends BaseDateRangePickerProps<TDate>, MakeOptional<StaticRangeOnlyPickerProps, 'displayStaticWrapperAs'> { /** diff --git a/packages/x-date-pickers-pro/src/dateRangeViewRenderers/dateRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/dateRangeViewRenderers/dateRangeViewRenderers.tsx index 5f557b87785ee..7253a0cd14c85 100644 --- a/packages/x-date-pickers-pro/src/dateRangeViewRenderers/dateRangeViewRenderers.tsx +++ b/packages/x-date-pickers-pro/src/dateRangeViewRenderers/dateRangeViewRenderers.tsx @@ -1,9 +1,12 @@ import * as React from 'react'; import { DateOrTimeViewWithMeridiem } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DateRangeCalendar, DateRangeCalendarProps } from '../DateRangeCalendar'; -export interface DateRangeViewRendererProps<TDate, TView extends DateOrTimeViewWithMeridiem> - extends Omit<DateRangeCalendarProps<TDate>, 'views'> { +export interface DateRangeViewRendererProps< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends Omit<DateRangeCalendarProps<TDate>, 'views'> { views: readonly TView[]; } @@ -11,7 +14,7 @@ export interface DateRangeViewRendererProps<TDate, TView extends DateOrTimeViewW * We don't pass all the props down to `DateRangeCalendar`, * because otherwise some unwanted props would be passed to the HTML element. */ -export const renderDateRangeViewCalendar = <TDate extends unknown>({ +export const renderDateRangeViewCalendar = <TDate extends PickerValidDate>({ value, defaultValue, referenceDate, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/models/useRangePicker.ts b/packages/x-date-pickers-pro/src/internals/hooks/models/useRangePicker.ts index a4239295a40e2..9c78331a02851 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/models/useRangePicker.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/models/useRangePicker.ts @@ -9,6 +9,7 @@ import { DateOrTimeViewWithMeridiem, ExportedBaseTabsProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { ExportedPickersLayoutSlots, ExportedPickersLayoutSlotProps, @@ -21,26 +22,30 @@ import { } from '../useEnrichedRangePickerFieldProps'; import { DateRange } from '../../../models'; -export interface UseRangePickerSlots<TDate, TView extends DateOrTimeViewWithMeridiem> - extends ExportedPickersLayoutSlots<DateRange<TDate>, TDate, TView>, +export interface UseRangePickerSlots< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends ExportedPickersLayoutSlots<DateRange<TDate>, TDate, TView>, RangePickerFieldSlots {} -export interface UseRangePickerSlotProps<TDate, TView extends DateOrTimeViewWithMeridiem> - extends ExportedPickersLayoutSlotProps<DateRange<TDate>, TDate, TView>, +export interface UseRangePickerSlotProps< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends ExportedPickersLayoutSlotProps<DateRange<TDate>, TDate, TView>, RangePickerFieldSlotProps<TDate> { tabs?: ExportedBaseTabsProps; toolbar?: ExportedBaseToolbarProps; } -export interface RangeOnlyPickerProps<TDate> +export interface RangeOnlyPickerProps<TDate extends PickerValidDate> extends BaseNonStaticPickerProps, - UsePickerValueNonStaticProps<TDate | null, RangeFieldSection>, + UsePickerValueNonStaticProps<DateRange<TDate>, RangeFieldSection>, UsePickerViewsNonStaticProps, BaseRangeNonStaticPickerProps, UseRangePositionProps {} export interface UseRangePickerProps< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TError, TExternalProps extends UsePickerViewsProps<any, any, TView, any, any>, @@ -52,7 +57,7 @@ export interface RangePickerAdditionalViewProps extends Pick<UseRangePositionResponse, 'rangePosition' | 'onRangePositionChange'> {} export interface UseRangePickerParams< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseRangePickerProps< TDate, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx index d52fe387b6e7e..b7f2c73c90729 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx @@ -15,6 +15,7 @@ import { UsePickerValueFieldResponse, ExportedBaseTabsProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DesktopRangePickerAdditionalViewProps, UseDesktopRangePickerParams, @@ -30,7 +31,7 @@ import { useRangePosition } from '../useRangePosition'; const releaseInfo = getReleaseInfo(); export const useDesktopRangePicker = < - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseDesktopRangePickerProps<TDate, TView, any, TExternalProps>, >({ diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts index b2fa4f0681e0c..a98872b25d9eb 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts @@ -4,6 +4,7 @@ import { UsePickerViewsProps, DateOrTimeViewWithMeridiem, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { RangeOnlyPickerProps, RangePickerAdditionalViewProps, @@ -13,15 +14,20 @@ import { UseRangePickerSlots, } from '../models/useRangePicker'; -export interface UseDesktopRangePickerSlots<TDate, TView extends DateOrTimeViewWithMeridiem> - extends UseRangePickerSlots<TDate, TView>, +export interface UseDesktopRangePickerSlots< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends UseRangePickerSlots<TDate, TView>, PickersPopperSlots {} -export interface UseDesktopRangePickerSlotProps<TDate, TView extends DateOrTimeViewWithMeridiem> - extends UseRangePickerSlotProps<TDate, TView>, +export interface UseDesktopRangePickerSlotProps< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends UseRangePickerSlotProps<TDate, TView>, PickersPopperSlotProps {} -export interface DesktopRangeOnlyPickerProps<TDate> extends RangeOnlyPickerProps<TDate> { +export interface DesktopRangeOnlyPickerProps<TDate extends PickerValidDate> + extends RangeOnlyPickerProps<TDate> { /** * If `true`, the start `input` element is focused during the first mount. */ @@ -29,7 +35,7 @@ export interface DesktopRangeOnlyPickerProps<TDate> extends RangeOnlyPickerProps } export interface UseDesktopRangePickerProps< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TError, TExternalProps extends UsePickerViewsProps<any, any, TView, any, any>, @@ -55,7 +61,7 @@ export interface UseDesktopRangePickerProps< export interface DesktopRangePickerAdditionalViewProps extends RangePickerAdditionalViewProps {} export interface UseDesktopRangePickerParams< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseDesktopRangePickerProps<TDate, TView, any, TExternalProps>, > extends UseRangePickerParams< diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts index b0b28d35faf27..9fb579a2e3af9 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts @@ -9,6 +9,7 @@ import { BaseSingleInputFieldProps, FieldSelectedSections, FieldRef, + PickerValidDate, } from '@mui/x-date-pickers/models'; import { UseClearableFieldSlots, UseClearableFieldSlotProps } from '@mui/x-date-pickers/hooks'; import { PickersInputLocaleText } from '@mui/x-date-pickers/locales'; @@ -54,7 +55,8 @@ export interface RangePickerFieldSlots extends UseClearableFieldSlots { textField?: React.ElementType<TextFieldProps>; } -export interface RangePickerFieldSlotProps<TDate> extends UseClearableFieldSlotProps { +export interface RangePickerFieldSlotProps<TDate extends PickerValidDate> + extends UseClearableFieldSlotProps { field?: SlotComponentProps< React.ElementType< BaseMultiInputFieldProps<DateRange<TDate>, TDate, RangeFieldSection, unknown> @@ -73,7 +75,7 @@ export interface RangePickerFieldSlotProps<TDate> extends UseClearableFieldSlotP } export interface UseEnrichedRangePickerFieldPropsParams< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TError, FieldProps extends BaseFieldProps< @@ -105,7 +107,11 @@ export interface UseEnrichedRangePickerFieldPropsParams< onViewChange?: (view: TView) => void; } -const useMultiInputFieldSlotProps = <TDate, TView extends DateOrTimeViewWithMeridiem, TError>({ +const useMultiInputFieldSlotProps = < + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, + TError, +>({ wrapperVariant, open, actions, @@ -281,7 +287,11 @@ const useMultiInputFieldSlotProps = <TDate, TView extends DateOrTimeViewWithMeri return enrichedFieldProps; }; -const useSingleInputFieldSlotProps = <TDate, TView extends DateOrTimeViewWithMeridiem, TError>({ +const useSingleInputFieldSlotProps = < + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, + TError, +>({ wrapperVariant, open, actions, @@ -398,7 +408,7 @@ const useSingleInputFieldSlotProps = <TDate, TView extends DateOrTimeViewWithMer }; export const useEnrichedRangePickerFieldProps = < - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TError, >( diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx index 7bb0d98f26d12..7db23cf2c4a4d 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx @@ -13,6 +13,7 @@ import { UsePickerValueFieldResponse, ExportedBaseTabsProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import useId from '@mui/utils/useId'; import { MobileRangePickerAdditionalViewProps, @@ -29,7 +30,7 @@ import { useRangePosition } from '../useRangePosition'; const releaseInfo = getReleaseInfo(); export const useMobileRangePicker = < - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseMobileRangePickerProps<TDate, TView, any, TExternalProps>, >({ diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.types.ts b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.types.ts index b89b4733e2e26..39235ce0b0d5a 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.types.ts @@ -4,6 +4,7 @@ import { UsePickerViewsProps, DateOrTimeViewWithMeridiem, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { RangeOnlyPickerProps, RangePickerAdditionalViewProps, @@ -13,18 +14,23 @@ import { UseRangePickerSlots, } from '../models/useRangePicker'; -export interface UseMobileRangePickerSlots<TDate, TView extends DateOrTimeViewWithMeridiem> - extends UseRangePickerSlots<TDate, TView>, +export interface UseMobileRangePickerSlots< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends UseRangePickerSlots<TDate, TView>, PickersModalDialogSlots {} -export interface UseMobileRangePickerSlotProps<TDate, TView extends DateOrTimeViewWithMeridiem> - extends UseRangePickerSlotProps<TDate, TView>, +export interface UseMobileRangePickerSlotProps< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends UseRangePickerSlotProps<TDate, TView>, PickersModalDialogSlotProps {} -export interface MobileRangeOnlyPickerProps<TDate> extends RangeOnlyPickerProps<TDate> {} +export interface MobileRangeOnlyPickerProps<TDate extends PickerValidDate> + extends RangeOnlyPickerProps<TDate> {} export interface UseMobileRangePickerProps< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TError, TExternalProps extends UsePickerViewsProps<any, any, TView, any, any>, @@ -50,7 +56,7 @@ export interface UseMobileRangePickerProps< export interface MobileRangePickerAdditionalViewProps extends RangePickerAdditionalViewProps {} export interface UseMobileRangePickerParams< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseMobileRangePickerProps<TDate, TView, any, TExternalProps>, > extends UseRangePickerParams< diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateRangeField.ts b/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateRangeField.ts index 082676318eb8b..47088f346682e 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateRangeField.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateRangeField.ts @@ -13,7 +13,7 @@ import { UseFieldResponse, useControlledValueWithTimezone, } from '@mui/x-date-pickers/internals'; -import { DateValidationError } from '@mui/x-date-pickers/models'; +import { DateValidationError, PickerValidDate } from '@mui/x-date-pickers/models'; import { useDefaultizedDateRangeFieldProps } from '../../../SingleInputDateRangeField/useSingleInputDateRangeField'; import { UseMultiInputDateRangeFieldParams } from '../../../MultiInputDateRangeField/MultiInputDateRangeField.types'; import { @@ -25,7 +25,10 @@ import type { UseMultiInputRangeFieldResponse } from './useMultiInputRangeField. import { DateRangeValidationError, DateRange } from '../../../models'; import { excludeProps } from './shared'; -export const useMultiInputDateRangeField = <TDate, TTextFieldSlotProps extends {}>({ +export const useMultiInputDateRangeField = < + TDate extends PickerValidDate, + TTextFieldSlotProps extends {}, +>({ sharedProps: inSharedProps, startTextFieldProps, unstableStartFieldRef, @@ -99,10 +102,7 @@ export const useMultiInputDateRangeField = <TDate, TTextFieldSlotProps extends { rangeValueManager.defaultErrorState, ); - const startFieldProps: UseDateFieldComponentProps< - TDate, - UseDateFieldDefaultizedProps<TTextFieldSlotProps> - > = { + const startFieldProps: UseDateFieldComponentProps<TDate, UseDateFieldDefaultizedProps<TDate>> = { error: !!validationError[0], ...startTextFieldProps, disabled, @@ -119,10 +119,7 @@ export const useMultiInputDateRangeField = <TDate, TTextFieldSlotProps extends { onSelectedSectionsChange, }; - const endFieldProps: UseDateFieldComponentProps< - TDate, - UseDateFieldDefaultizedProps<TTextFieldSlotProps> - > = { + const endFieldProps: UseDateFieldComponentProps<TDate, UseDateFieldDefaultizedProps<TDate>> = { error: !!validationError[1], ...endTextFieldProps, format, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateTimeRangeField.ts b/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateTimeRangeField.ts index 9c182c1d2523d..d398a8b5e1ab5 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateTimeRangeField.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateTimeRangeField.ts @@ -16,7 +16,7 @@ import { UseFieldResponse, useControlledValueWithTimezone, } from '@mui/x-date-pickers/internals'; -import { DateTimeValidationError } from '@mui/x-date-pickers/models'; +import { DateTimeValidationError, PickerValidDate } from '@mui/x-date-pickers/models'; import type { UseMultiInputDateTimeRangeFieldDefaultizedProps, UseMultiInputDateTimeRangeFieldParams, @@ -31,7 +31,10 @@ import { rangeValueManager } from '../../utils/valueManagers'; import type { UseMultiInputRangeFieldResponse } from './useMultiInputRangeField.types'; import { excludeProps } from './shared'; -export const useDefaultizedDateTimeRangeFieldProps = <TDate, AdditionalProps extends {}>( +export const useDefaultizedDateTimeRangeFieldProps = < + TDate extends PickerValidDate, + AdditionalProps extends {}, +>( props: UseMultiInputDateTimeRangeFieldProps<TDate>, ): UseMultiInputDateTimeRangeFieldDefaultizedProps<TDate, AdditionalProps> => { const utils = useUtils<TDate>(); @@ -55,7 +58,10 @@ export const useDefaultizedDateTimeRangeFieldProps = <TDate, AdditionalProps ext } as any; }; -export const useMultiInputDateTimeRangeField = <TDate, TTextFieldSlotProps extends {}>({ +export const useMultiInputDateTimeRangeField = < + TDate extends PickerValidDate, + TTextFieldSlotProps extends {}, +>({ sharedProps: inSharedProps, startTextFieldProps, unstableStartFieldRef, @@ -130,7 +136,7 @@ export const useMultiInputDateTimeRangeField = <TDate, TTextFieldSlotProps exten const startFieldProps: UseDateTimeFieldComponentProps< TDate, - UseDateTimeFieldDefaultizedProps<TTextFieldSlotProps> + UseDateTimeFieldDefaultizedProps<TDate> > = { error: !!validationError[0], ...startTextFieldProps, @@ -149,7 +155,7 @@ export const useMultiInputDateTimeRangeField = <TDate, TTextFieldSlotProps exten const endFieldProps: UseDateTimeFieldComponentProps< TDate, - UseDateTimeFieldDefaultizedProps<TTextFieldSlotProps> + UseDateTimeFieldDefaultizedProps<TDate> > = { error: !!validationError[1], ...endTextFieldProps, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputTimeRangeField.ts b/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputTimeRangeField.ts index eab2cd035f40a..8656009ce3f2e 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputTimeRangeField.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputTimeRangeField.ts @@ -14,7 +14,7 @@ import { UseFieldResponse, useControlledValueWithTimezone, } from '@mui/x-date-pickers/internals'; -import { TimeValidationError } from '@mui/x-date-pickers/models'; +import { PickerValidDate, TimeValidationError } from '@mui/x-date-pickers/models'; import { validateTimeRange, TimeRangeComponentValidationProps, @@ -29,7 +29,10 @@ import { rangeValueManager } from '../../utils/valueManagers'; import type { UseMultiInputRangeFieldResponse } from './useMultiInputRangeField.types'; import { excludeProps } from './shared'; -export const useDefaultizedTimeRangeFieldProps = <TDate, AdditionalProps extends {}>( +export const useDefaultizedTimeRangeFieldProps = < + TDate extends PickerValidDate, + AdditionalProps extends {}, +>( props: UseMultiInputTimeRangeFieldProps<TDate>, ): UseMultiInputTimeRangeFieldDefaultizedProps<TDate, AdditionalProps> => { const utils = useUtils<TDate>(); @@ -45,7 +48,10 @@ export const useDefaultizedTimeRangeFieldProps = <TDate, AdditionalProps extends } as any; }; -export const useMultiInputTimeRangeField = <TDate, TTextFieldSlotProps extends {}>({ +export const useMultiInputTimeRangeField = < + TDate extends PickerValidDate, + TTextFieldSlotProps extends {}, +>({ sharedProps: inSharedProps, startTextFieldProps, unstableStartFieldRef, @@ -118,10 +124,7 @@ export const useMultiInputTimeRangeField = <TDate, TTextFieldSlotProps extends { rangeValueManager.defaultErrorState, ); - const startFieldProps: UseTimeFieldComponentProps< - TDate, - UseTimeFieldDefaultizedProps<TTextFieldSlotProps> - > = { + const startFieldProps: UseTimeFieldComponentProps<TDate, UseTimeFieldDefaultizedProps<TDate>> = { error: !!validationError[0], ...startTextFieldProps, format, @@ -137,10 +140,7 @@ export const useMultiInputTimeRangeField = <TDate, TTextFieldSlotProps extends { onSelectedSectionsChange, }; - const endFieldProps: UseTimeFieldComponentProps< - TDate, - UseTimeFieldDefaultizedProps<TTextFieldSlotProps> - > = { + const endFieldProps: UseTimeFieldComponentProps<TDate, UseTimeFieldDefaultizedProps<TDate>> = { error: !!validationError[1], ...endTextFieldProps, format, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.tsx index f947943079791..75b4ec220d76b 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.tsx @@ -9,6 +9,7 @@ import { ExportedBaseToolbarProps, DateOrTimeViewWithMeridiem, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { UseStaticRangePickerParams, UseStaticRangePickerProps, @@ -28,7 +29,7 @@ const PickerStaticLayout = styled(PickersLayout)(({ theme }) => ({ * - StaticDateRangePicker */ export const useStaticRangePicker = < - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseStaticRangePickerProps<TDate, TView, any, TExternalProps>, >({ diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.types.ts b/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.types.ts index 51b5459780883..2ff34eabfa9ca 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.types.ts @@ -6,6 +6,7 @@ import { StaticOnlyPickerProps, DateOrTimeViewWithMeridiem, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { ExportedPickersLayoutSlots, ExportedPickersLayoutSlotProps, @@ -14,18 +15,22 @@ import { DateRange } from '../../../models'; import { UseRangePositionProps } from '../useRangePosition'; import { RangeFieldSection } from '../../models/fields'; -export interface UseStaticRangePickerSlots<TDate, TView extends DateOrTimeViewWithMeridiem> - extends ExportedPickersLayoutSlots<DateRange<TDate>, TDate, TView> {} +export interface UseStaticRangePickerSlots< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends ExportedPickersLayoutSlots<DateRange<TDate>, TDate, TView> {} -export interface UseStaticRangePickerSlotProps<TDate, TView extends DateOrTimeViewWithMeridiem> - extends ExportedPickersLayoutSlotProps<DateRange<TDate>, TDate, TView> { +export interface UseStaticRangePickerSlotProps< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends ExportedPickersLayoutSlotProps<DateRange<TDate>, TDate, TView> { toolbar?: ExportedBaseToolbarProps; } export interface StaticRangeOnlyPickerProps extends StaticOnlyPickerProps, UseRangePositionProps {} export interface UseStaticRangePickerProps< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TError, TExternalProps extends UseStaticRangePickerProps<TDate, TView, any, TExternalProps>, @@ -44,7 +49,7 @@ export interface UseStaticRangePickerProps< } export interface UseStaticRangePickerParams< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseStaticRangePickerProps<TDate, TView, any, TExternalProps>, > extends Pick< diff --git a/packages/x-date-pickers-pro/src/internals/models/dateRange.ts b/packages/x-date-pickers-pro/src/internals/models/dateRange.ts index 1a31e90846619..422d777db1251 100644 --- a/packages/x-date-pickers-pro/src/internals/models/dateRange.ts +++ b/packages/x-date-pickers-pro/src/internals/models/dateRange.ts @@ -4,13 +4,14 @@ import { MakeOptional, UseFieldInternalProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import type { DateRangeValidationError, DateRange } from '../../models'; import { RangeFieldSection } from './fields'; /** * Props used to validate a day value in range pickers. */ -export interface DayRangeValidationProps<TDate> { +export interface DayRangeValidationProps<TDate extends PickerValidDate> { /** * Disable specific date. * @@ -35,7 +36,7 @@ export interface BaseRangeProps { disabled?: boolean; } -export interface UseDateRangeFieldProps<TDate> +export interface UseDateRangeFieldProps<TDate extends PickerValidDate> extends MakeOptional< UseFieldInternalProps<DateRange<TDate>, TDate, RangeFieldSection, DateRangeValidationError>, 'format' @@ -44,7 +45,7 @@ export interface UseDateRangeFieldProps<TDate> BaseDateValidationProps<TDate>, BaseRangeProps {} -export type UseDateRangeFieldDefaultizedProps<TDate> = DefaultizedProps< +export type UseDateRangeFieldDefaultizedProps<TDate extends PickerValidDate> = DefaultizedProps< UseDateRangeFieldProps<TDate>, keyof BaseDateValidationProps<TDate> | 'format' >; diff --git a/packages/x-date-pickers-pro/src/internals/models/dateTimeRange.ts b/packages/x-date-pickers-pro/src/internals/models/dateTimeRange.ts index 25903be03bd72..3ed96dab9e6bd 100644 --- a/packages/x-date-pickers-pro/src/internals/models/dateTimeRange.ts +++ b/packages/x-date-pickers-pro/src/internals/models/dateTimeRange.ts @@ -7,11 +7,12 @@ import { DateTimeValidationProps, DateOrTimeViewWithMeridiem, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { BaseRangeProps, DayRangeValidationProps } from './dateRange'; import { DateTimeRangeValidationError, DateRange } from '../../models'; import { RangeFieldSection } from './fields'; -export interface UseDateTimeRangeFieldProps<TDate> +export interface UseDateTimeRangeFieldProps<TDate extends PickerValidDate> extends MakeOptional< UseFieldInternalProps< DateRange<TDate>, @@ -33,7 +34,7 @@ export interface UseDateTimeRangeFieldProps<TDate> ampm?: boolean; } -export type UseDateTimeRangeFieldDefaultizedProps<TDate> = DefaultizedProps< +export type UseDateTimeRangeFieldDefaultizedProps<TDate extends PickerValidDate> = DefaultizedProps< UseDateTimeRangeFieldProps<TDate>, keyof BaseDateValidationProps<TDate> | 'format' | 'disableIgnoringDatePartForTimeValidation' >; diff --git a/packages/x-date-pickers-pro/src/internals/models/fields.ts b/packages/x-date-pickers-pro/src/internals/models/fields.ts index 2810560c95174..893c4484c6da9 100644 --- a/packages/x-date-pickers-pro/src/internals/models/fields.ts +++ b/packages/x-date-pickers-pro/src/internals/models/fields.ts @@ -1,7 +1,7 @@ import * as React from 'react'; import { SlotComponentProps } from '@mui/base/utils'; import { BaseFieldProps, FieldsTextFieldProps } from '@mui/x-date-pickers/internals'; -import { FieldSection, FieldRef } from '@mui/x-date-pickers/models'; +import { FieldSection, FieldRef, PickerValidDate } from '@mui/x-date-pickers/models'; export interface RangeFieldSection extends FieldSection { dateName: 'start' | 'end'; @@ -40,8 +40,12 @@ export interface MultiInputFieldRefs { * Props the multi input field can receive when used inside a picker. * Only contains what the MUI component are passing to the field, not what users can pass using the `props.slotProps.field`. */ -export interface BaseMultiInputFieldProps<TValue, TDate, TSection extends FieldSection, TError> - extends BaseFieldProps<TValue, TDate, TSection, TError>, +export interface BaseMultiInputFieldProps< + TValue, + TDate extends PickerValidDate, + TSection extends FieldSection, + TError, +> extends BaseFieldProps<TValue, TDate, TSection, TError>, MultiInputFieldRefs { slots?: { root?: React.ElementType; diff --git a/packages/x-date-pickers-pro/src/internals/models/timeRange.ts b/packages/x-date-pickers-pro/src/internals/models/timeRange.ts index fa99290d503a3..9ec9db5c39232 100644 --- a/packages/x-date-pickers-pro/src/internals/models/timeRange.ts +++ b/packages/x-date-pickers-pro/src/internals/models/timeRange.ts @@ -5,11 +5,12 @@ import { MakeOptional, UseFieldInternalProps, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { TimeRangeValidationError, DateRange } from '../../models'; import { BaseRangeProps } from './dateRange'; import { RangeFieldSection } from './fields'; -export interface UseTimeRangeFieldProps<TDate> +export interface UseTimeRangeFieldProps<TDate extends PickerValidDate> extends MakeOptional< UseFieldInternalProps<DateRange<TDate>, TDate, RangeFieldSection, TimeRangeValidationError>, 'format' @@ -24,7 +25,7 @@ export interface UseTimeRangeFieldProps<TDate> ampm?: boolean; } -export type UseTimeRangeFieldDefaultizedProps<TDate> = DefaultizedProps< +export type UseTimeRangeFieldDefaultizedProps<TDate extends PickerValidDate> = DefaultizedProps< UseTimeRangeFieldProps<TDate>, keyof BaseTimeValidationProps | 'format' >; diff --git a/packages/x-date-pickers-pro/src/internals/utils/date-range-manager.ts b/packages/x-date-pickers-pro/src/internals/utils/date-range-manager.ts index 8470c59ccb44d..bc3eb99ca75cc 100644 --- a/packages/x-date-pickers-pro/src/internals/utils/date-range-manager.ts +++ b/packages/x-date-pickers-pro/src/internals/utils/date-range-manager.ts @@ -1,8 +1,8 @@ -import { MuiPickersAdapter } from '@mui/x-date-pickers/models'; +import { MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models'; import { mergeDateAndTime } from '@mui/x-date-pickers/internals'; import { DateRange, RangePosition } from '../../models'; -interface CalculateRangeChangeOptions<TDate> { +interface CalculateRangeChangeOptions<TDate extends PickerValidDate> { utils: MuiPickersAdapter<TDate>; range: DateRange<TDate>; newDate: TDate | null; @@ -16,12 +16,12 @@ interface CalculateRangeChangeOptions<TDate> { shouldMergeDateAndTime?: boolean; } -interface CalculateRangeChangeResponse<TDate> { +interface CalculateRangeChangeResponse<TDate extends PickerValidDate> { nextSelection: RangePosition; newRange: DateRange<TDate>; } -export function calculateRangeChange<TDate>({ +export function calculateRangeChange<TDate extends PickerValidDate>({ utils, range, newDate: selectedDate, @@ -58,7 +58,7 @@ export function calculateRangeChange<TDate>({ : { nextSelection: 'start', newRange: [start, selectedDate] }; } -export function calculateRangePreview<TDate>( +export function calculateRangePreview<TDate extends PickerValidDate>( options: CalculateRangeChangeOptions<TDate>, ): DateRange<TDate> { if (options.newDate == null) { diff --git a/packages/x-date-pickers-pro/src/internals/utils/date-utils.ts b/packages/x-date-pickers-pro/src/internals/utils/date-utils.ts index e69cea142837b..1d35d15cf6676 100644 --- a/packages/x-date-pickers-pro/src/internals/utils/date-utils.ts +++ b/packages/x-date-pickers-pro/src/internals/utils/date-utils.ts @@ -1,14 +1,14 @@ -import { MuiPickersAdapter } from '@mui/x-date-pickers/models'; +import { MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models'; import { DateRange, NonEmptyDateRange } from '../../models'; -export const isRangeValid = <TDate>( +export const isRangeValid = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, range: DateRange<TDate> | null, ): range is NonEmptyDateRange<TDate> => { return Boolean(range && range[0] && range[1] && !utils.isBefore(range[1], range[0])); }; -export const isWithinRange = <TDate>( +export const isWithinRange = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, day: TDate, range: DateRange<TDate> | null, @@ -16,7 +16,7 @@ export const isWithinRange = <TDate>( return isRangeValid(utils, range) && utils.isWithinRange(day, range); }; -export const isStartOfRange = <TDate>( +export const isStartOfRange = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, day: TDate, range: DateRange<TDate> | null, @@ -24,7 +24,7 @@ export const isStartOfRange = <TDate>( return isRangeValid(utils, range) && utils.isSameDay(day, range[0]!); }; -export const isEndOfRange = <TDate>( +export const isEndOfRange = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, day: TDate, range: DateRange<TDate> | null, diff --git a/packages/x-date-pickers-pro/src/internals/utils/validation/validateDateRange.ts b/packages/x-date-pickers-pro/src/internals/utils/validation/validateDateRange.ts index 6609ced6e8bfb..c0304ff0b9de8 100644 --- a/packages/x-date-pickers-pro/src/internals/utils/validation/validateDateRange.ts +++ b/packages/x-date-pickers-pro/src/internals/utils/validation/validateDateRange.ts @@ -1,4 +1,4 @@ -import { TimezoneProps } from '@mui/x-date-pickers/models'; +import { PickerValidDate, TimezoneProps } from '@mui/x-date-pickers/models'; import { Validator, validateDate, @@ -9,7 +9,7 @@ import { isRangeValid } from '../date-utils'; import { DayRangeValidationProps } from '../../models'; import { DateRangeValidationError, DateRange } from '../../../models'; -export interface DateRangeComponentValidationProps<TDate> +export interface DateRangeComponentValidationProps<TDate extends PickerValidDate> extends DayRangeValidationProps<TDate>, Required<BaseDateValidationProps<TDate>>, DefaultizedProps<TimezoneProps, 'timezone'> {} diff --git a/packages/x-date-pickers-pro/src/internals/utils/validation/validateDateTimeRange.ts b/packages/x-date-pickers-pro/src/internals/utils/validation/validateDateTimeRange.ts index ec00ad04da6d9..2eae3041a2e4a 100644 --- a/packages/x-date-pickers-pro/src/internals/utils/validation/validateDateTimeRange.ts +++ b/packages/x-date-pickers-pro/src/internals/utils/validation/validateDateTimeRange.ts @@ -1,4 +1,4 @@ -import { TimezoneProps } from '@mui/x-date-pickers/models'; +import { PickerValidDate, TimezoneProps } from '@mui/x-date-pickers/models'; import { Validator, validateDateTime, @@ -10,7 +10,7 @@ import { isRangeValid } from '../date-utils'; import { DayRangeValidationProps } from '../../models/dateRange'; import { DateTimeRangeValidationError, DateRange } from '../../../models'; -export interface DateTimeRangeComponentValidationProps<TDate> +export interface DateTimeRangeComponentValidationProps<TDate extends PickerValidDate> extends DayRangeValidationProps<TDate>, TimeValidationProps<TDate>, Required<BaseDateValidationProps<TDate>>, diff --git a/packages/x-date-pickers-pro/src/internals/utils/valueManagers.ts b/packages/x-date-pickers-pro/src/internals/utils/valueManagers.ts index daddcdee38e91..82649345b5d47 100644 --- a/packages/x-date-pickers-pro/src/internals/utils/valueManagers.ts +++ b/packages/x-date-pickers-pro/src/internals/utils/valueManagers.ts @@ -8,6 +8,7 @@ import { getTodayDate, getDefaultReferenceDate, } from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { splitDateRangeSections, removeLastSeparator } from './date-fields-utils'; import type { DateRangeValidationError, @@ -20,7 +21,7 @@ import { RangeFieldSection } from '../models/fields'; export type RangePickerValueManager< TValue = [any, any], - TDate = any, + TDate extends PickerValidDate = any, TError extends | DateRangeValidationError | TimeRangeValidationError diff --git a/packages/x-date-pickers-pro/src/models/range.ts b/packages/x-date-pickers-pro/src/models/range.ts index 3fefdb333b221..92bbff21e1d17 100644 --- a/packages/x-date-pickers-pro/src/models/range.ts +++ b/packages/x-date-pickers-pro/src/models/range.ts @@ -1,5 +1,7 @@ -export type DateRange<TDate> = [TDate | null, TDate | null]; +import { PickerValidDate } from '@mui/x-date-pickers/models'; -export type NonEmptyDateRange<TDate> = [TDate, TDate]; +export type DateRange<TDate extends PickerValidDate> = [TDate | null, TDate | null]; + +export type NonEmptyDateRange<TDate extends PickerValidDate> = [TDate, TDate]; export type RangePosition = 'start' | 'end'; diff --git a/packages/x-date-pickers-pro/src/themeAugmentation/props.d.ts b/packages/x-date-pickers-pro/src/themeAugmentation/props.d.ts index 00e1c345620b3..c43cf07e5baa0 100644 --- a/packages/x-date-pickers-pro/src/themeAugmentation/props.d.ts +++ b/packages/x-date-pickers-pro/src/themeAugmentation/props.d.ts @@ -1,8 +1,8 @@ +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DateRangePickerDayProps } from '../DateRangePickerDay'; import { MultiInputDateRangeFieldProps } from '../MultiInputDateRangeField/MultiInputDateRangeField.types'; import { SingleInputDateRangeFieldProps } from '../SingleInputDateRangeField/SingleInputDateRangeField.types'; import { DateRangeCalendarProps } from '../DateRangeCalendar'; - import { DateRangePickerProps, DateRangePickerToolbarProps } from '../DateRangePicker'; import { DesktopDateRangePickerProps } from '../DesktopDateRangePicker'; import { MobileDateRangePickerProps } from '../MobileDateRangePicker'; @@ -18,32 +18,32 @@ import { ExportedDateTimeRangePickerTabsProps } from '../DateTimeRangePicker/Dat import { ExportedDateTimeRangePickerToolbarProps } from '../DateTimeRangePicker/DateTimeRangePickerToolbar'; export interface PickersProComponentsPropsList { - MuiDateRangeCalendar: DateRangeCalendarProps<unknown>; - MuiDateRangePickerDay: DateRangePickerDayProps<unknown>; + MuiDateRangeCalendar: DateRangeCalendarProps<PickerValidDate>; + MuiDateRangePickerDay: DateRangePickerDayProps<PickerValidDate>; MuiDateTimeRangePickerTabs: ExportedDateTimeRangePickerTabsProps; - MuiDateRangePickerToolbar: DateRangePickerToolbarProps<unknown>; + MuiDateRangePickerToolbar: DateRangePickerToolbarProps<PickerValidDate>; MuiDateTimeRangePickerToolbar: ExportedDateTimeRangePickerToolbarProps; // Multi input range fields - MuiMultiInputDateRangeField: MultiInputDateRangeFieldProps<unknown>; - MuiMultiInputDateTimeRangeField: MultiInputDateTimeRangeFieldProps<unknown>; - MuiMultiInputTimeRangeField: MultiInputTimeRangeFieldProps<unknown>; + MuiMultiInputDateRangeField: MultiInputDateRangeFieldProps<PickerValidDate>; + MuiMultiInputDateTimeRangeField: MultiInputDateTimeRangeFieldProps<PickerValidDate>; + MuiMultiInputTimeRangeField: MultiInputTimeRangeFieldProps<PickerValidDate>; // Single input range fields - MuiSingleInputDateRangeField: SingleInputDateRangeFieldProps<unknown>; - MuiSingleInputDateTimeRangeField: SingleInputDateTimeRangeFieldProps<unknown>; - MuiSingleInputTimeRangeField: SingleInputTimeRangeFieldProps<unknown>; + MuiSingleInputDateRangeField: SingleInputDateRangeFieldProps<PickerValidDate>; + MuiSingleInputDateTimeRangeField: SingleInputDateTimeRangeFieldProps<PickerValidDate>; + MuiSingleInputTimeRangeField: SingleInputTimeRangeFieldProps<PickerValidDate>; // Date Range Pickers - MuiDateRangePicker: DateRangePickerProps<unknown>; - MuiDesktopDateRangePicker: DesktopDateRangePickerProps<unknown>; - MuiMobileDateRangePicker: MobileDateRangePickerProps<unknown>; - MuiStaticDateRangePicker: StaticDateRangePickerProps<unknown>; + MuiDateRangePicker: DateRangePickerProps<PickerValidDate>; + MuiDesktopDateRangePicker: DesktopDateRangePickerProps<PickerValidDate>; + MuiMobileDateRangePicker: MobileDateRangePickerProps<PickerValidDate>; + MuiStaticDateRangePicker: StaticDateRangePickerProps<PickerValidDate>; // Date Time Range Pickers - MuiDateTimeRangePicker: DateTimeRangePickerProps<unknown>; - MuiDesktopDateTimeRangePicker: DesktopDateTimeRangePickerProps<unknown>; - MuiMobileDateTimeRangePicker: MobileDateTimeRangePickerProps<unknown>; + MuiDateTimeRangePicker: DateTimeRangePickerProps<PickerValidDate>; + MuiDesktopDateTimeRangePicker: DesktopDateTimeRangePickerProps<PickerValidDate>; + MuiMobileDateTimeRangePicker: MobileDateTimeRangePickerProps<PickerValidDate>; } declare module '@mui/material/styles' { diff --git a/packages/x-date-pickers/src/AdapterDateFnsBase/AdapterDateFnsBase.ts b/packages/x-date-pickers/src/AdapterDateFnsBase/AdapterDateFnsBase.ts index 2207845c9cf38..a24b3a69e7d14 100644 --- a/packages/x-date-pickers/src/AdapterDateFnsBase/AdapterDateFnsBase.ts +++ b/packages/x-date-pickers/src/AdapterDateFnsBase/AdapterDateFnsBase.ts @@ -117,6 +117,12 @@ type DateFnsAdapterBaseOptions<DateFnsLocale extends DateFnsLocaleBase> = MakeRe longFormatters: Record<'p' | 'P', (token: string, formatLong: any) => string>; }; +declare module '@mui/x-date-pickers/models' { + interface PickerValidDateLookup { + 'date-fns': Date; + } +} + /** * Based on `@date-io/date-fns` * diff --git a/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.ts b/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.ts index c8526d7bfeaed..7b1e651d6c5d2 100644 --- a/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.ts +++ b/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.ts @@ -159,6 +159,12 @@ const NUMBER_SYMBOL_MAP = { '0': '۰', }; +declare module '@mui/x-date-pickers/models' { + interface PickerValidDateLookup { + 'date-fns-jalali': Date; + } +} + /** * Based on `@date-io/date-fns-jalali` * diff --git a/packages/x-date-pickers/src/AdapterDayjs/AdapterDayjs.ts b/packages/x-date-pickers/src/AdapterDayjs/AdapterDayjs.ts index 853b72d4edf1a..667b7eb3ea642 100644 --- a/packages/x-date-pickers/src/AdapterDayjs/AdapterDayjs.ts +++ b/packages/x-date-pickers/src/AdapterDayjs/AdapterDayjs.ts @@ -111,6 +111,12 @@ const MISSING_TIMEZONE_PLUGIN = [ const withLocale = (dayjs: any, locale?: string): Constructor => !locale ? dayjs : (...args) => dayjs(...args).locale(locale); +declare module '@mui/x-date-pickers/models' { + interface PickerValidDateLookup { + dayjs: Dayjs; + } +} + /** * Based on `@date-io/dayjs` * diff --git a/packages/x-date-pickers/src/AdapterLuxon/AdapterLuxon.ts b/packages/x-date-pickers/src/AdapterLuxon/AdapterLuxon.ts index ee8f9a56ac027..295db06c32f41 100644 --- a/packages/x-date-pickers/src/AdapterLuxon/AdapterLuxon.ts +++ b/packages/x-date-pickers/src/AdapterLuxon/AdapterLuxon.ts @@ -83,6 +83,12 @@ const defaultFormats: AdapterFormats = { keyboardDateTime24h: 'D T', }; +declare module '@mui/x-date-pickers/models' { + interface PickerValidDateLookup { + luxon: DateTime; + } +} + /** * Based on `@date-io/luxon` * diff --git a/packages/x-date-pickers/src/AdapterMoment/AdapterMoment.ts b/packages/x-date-pickers/src/AdapterMoment/AdapterMoment.ts index 0a1cca168e1d1..e7b610d466b65 100644 --- a/packages/x-date-pickers/src/AdapterMoment/AdapterMoment.ts +++ b/packages/x-date-pickers/src/AdapterMoment/AdapterMoment.ts @@ -88,6 +88,12 @@ const MISSING_TIMEZONE_PLUGIN = [ 'Find more information on https://mui.com/x/react-date-pickers/timezone/#moment-and-timezone', ].join('\n'); +declare module '@mui/x-date-pickers/models' { + interface PickerValidDateLookup { + moment: Moment; + } +} + /** * Based on `@date-io/moment` * diff --git a/packages/x-date-pickers/src/AdapterMomentHijri/AdapterMomentHijri.ts b/packages/x-date-pickers/src/AdapterMomentHijri/AdapterMomentHijri.ts index f11f166c6b104..a9f102f755b20 100644 --- a/packages/x-date-pickers/src/AdapterMomentHijri/AdapterMomentHijri.ts +++ b/packages/x-date-pickers/src/AdapterMomentHijri/AdapterMomentHijri.ts @@ -86,6 +86,12 @@ const NUMBER_SYMBOL_MAP = { '0': '٠', }; +declare module '@mui/x-date-pickers/models' { + interface PickerValidDateLookup { + 'moment-hijri': Moment; + } +} + /** * Based on `@date-io/hijri` * diff --git a/packages/x-date-pickers/src/AdapterMomentJalaali/AdapterMomentJalaali.ts b/packages/x-date-pickers/src/AdapterMomentJalaali/AdapterMomentJalaali.ts index ca6cc0ed5301b..3ec4415dcb04f 100644 --- a/packages/x-date-pickers/src/AdapterMomentJalaali/AdapterMomentJalaali.ts +++ b/packages/x-date-pickers/src/AdapterMomentJalaali/AdapterMomentJalaali.ts @@ -85,6 +85,12 @@ const NUMBER_SYMBOL_MAP = { '0': '۰', }; +declare module '@mui/x-date-pickers/models' { + interface PickerValidDateLookup { + 'moment-jalaali': Moment; + } +} + /** * Based on `@date-io/jalaali` * diff --git a/packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx b/packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx index 11d8feecdbccc..65371086ad17a 100644 --- a/packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx +++ b/packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx @@ -29,6 +29,7 @@ import { BaseDateValidationProps } from '../internals/models/validation'; import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone'; import { singleItemValueManager } from '../internals/utils/valueManagers'; import { VIEW_HEIGHT } from '../internals/constants/dimensions'; +import { PickerValidDate } from '../models'; const useUtilityClasses = (ownerState: DateCalendarProps<any>) => { const { classes } = ownerState; @@ -40,7 +41,7 @@ const useUtilityClasses = (ownerState: DateCalendarProps<any>) => { return composeClasses(slots, getDateCalendarUtilityClass, classes); }; -function useDateCalendarDefaultizedProps<TDate>( +function useDateCalendarDefaultizedProps<TDate extends PickerValidDate>( props: DateCalendarProps<TDate>, name: string, ): DateCalendarDefaultizedProps<TDate> { @@ -83,7 +84,7 @@ const DateCalendarViewTransitionContainer = styled(PickersFadeTransitionGroup, { overridesResolver: (props, styles) => styles.viewTransitionContainer, })<{ ownerState: DateCalendarProps<any> }>({}); -type DateCalendarComponent = (<TDate>( +type DateCalendarComponent = (<TDate extends PickerValidDate>( props: DateCalendarProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -98,7 +99,7 @@ type DateCalendarComponent = (<TDate>( * * - [DateCalendar API](https://mui.com/x/api/date-pickers/date-calendar/) */ -export const DateCalendar = React.forwardRef(function DateCalendar<TDate>( +export const DateCalendar = React.forwardRef(function DateCalendar<TDate extends PickerValidDate>( inProps: DateCalendarProps<TDate>, ref: React.Ref<HTMLDivElement>, ) { @@ -428,7 +429,7 @@ DateCalendar.propTypes = { * The default selected value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the picker and text field are disabled. * @default false @@ -472,11 +473,11 @@ DateCalendar.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Months rendered per row. * @default 3 @@ -536,7 +537,7 @@ DateCalendar.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component displaying when passed `loading` true. * @returns {React.ReactNode} The node to render when loading. @@ -608,7 +609,7 @@ DateCalendar.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/DateCalendar/DateCalendar.types.ts b/packages/x-date-pickers/src/DateCalendar/DateCalendar.types.ts index b02d1ffc027b4..fec30c35f9302 100644 --- a/packages/x-date-pickers/src/DateCalendar/DateCalendar.types.ts +++ b/packages/x-date-pickers/src/DateCalendar/DateCalendar.types.ts @@ -17,12 +17,12 @@ import { DayValidationProps, } from '../internals/models/validation'; import { ExportedUseViewsOptions } from '../internals/hooks/useViews'; -import { DateView, TimezoneProps } from '../models'; +import { DateView, PickerValidDate, TimezoneProps } from '../models'; import { DefaultizedProps } from '../internals/models/helpers'; import { ExportedYearCalendarProps } from '../YearCalendar/YearCalendar.types'; import { ExportedMonthCalendarProps } from '../MonthCalendar/MonthCalendar.types'; -export interface DateCalendarSlots<TDate> +export interface DateCalendarSlots<TDate extends PickerValidDate> extends PickersCalendarHeaderSlots, DayCalendarSlots<TDate> { /** @@ -33,13 +33,13 @@ export interface DateCalendarSlots<TDate> calendarHeader?: React.ElementType<PickersCalendarHeaderProps<TDate>>; } -export interface DateCalendarSlotProps<TDate> +export interface DateCalendarSlotProps<TDate extends PickerValidDate> extends PickersCalendarHeaderSlotProps<TDate>, DayCalendarSlotProps<TDate> { calendarHeader?: SlotComponentProps<typeof PickersCalendarHeader, {}, DateCalendarProps<TDate>>; } -export interface ExportedDateCalendarProps<TDate> +export interface ExportedDateCalendarProps<TDate extends PickerValidDate> extends ExportedDayCalendarProps<TDate>, ExportedMonthCalendarProps, ExportedYearCalendarProps, @@ -83,7 +83,7 @@ export interface ExportedDateCalendarProps<TDate> onMonthChange?: (month: TDate) => void; } -export interface DateCalendarProps<TDate> +export interface DateCalendarProps<TDate extends PickerValidDate> extends ExportedDateCalendarProps<TDate>, ExportedUseViewsOptions<DateView> { /** @@ -119,7 +119,7 @@ export interface DateCalendarProps<TDate> slotProps?: DateCalendarSlotProps<TDate>; } -export type DateCalendarDefaultizedProps<TDate> = DefaultizedProps< +export type DateCalendarDefaultizedProps<TDate extends PickerValidDate> = DefaultizedProps< DateCalendarProps<TDate>, | 'views' | 'openTo' diff --git a/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx b/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx index 45b1a8fe727c3..e388c1590632b 100644 --- a/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx +++ b/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx @@ -26,10 +26,10 @@ import { import { useIsDateDisabled } from './useIsDateDisabled'; import { findClosestEnabledDate, getWeekdays } from '../internals/utils/date-utils'; import { DayCalendarClasses, getDayCalendarUtilityClass } from './dayCalendarClasses'; -import { TimezoneProps } from '../models'; +import { PickerValidDate, TimezoneProps } from '../models'; import { DefaultizedProps } from '../internals/models/helpers'; -export interface DayCalendarSlots<TDate> { +export interface DayCalendarSlots<TDate extends PickerValidDate> { /** * Custom component for day. * Check the [PickersDay](https://mui.com/x/api/date-pickers/pickers-day/) component. @@ -38,7 +38,7 @@ export interface DayCalendarSlots<TDate> { day?: React.ElementType<PickersDayProps<TDate>>; } -export interface DayCalendarSlotProps<TDate> { +export interface DayCalendarSlotProps<TDate extends PickerValidDate> { day?: SlotComponentProps< typeof PickersDay, {}, @@ -46,7 +46,8 @@ export interface DayCalendarSlotProps<TDate> { >; } -export interface ExportedDayCalendarProps<TDate> extends ExportedPickersDayProps { +export interface ExportedDayCalendarProps<TDate extends PickerValidDate> + extends ExportedPickersDayProps { /** * If `true`, calls `renderLoading` instead of rendering the day calendar. * Can be used to preload information and show it in calendar. @@ -78,7 +79,7 @@ export interface ExportedDayCalendarProps<TDate> extends ExportedPickersDayProps fixedWeekNumber?: number; } -export interface DayCalendarProps<TDate> +export interface DayCalendarProps<TDate extends PickerValidDate> extends ExportedDayCalendarProps<TDate>, DayValidationProps<TDate>, MonthValidationProps<TDate>, @@ -232,7 +233,7 @@ const PickersCalendarWeek = styled('div', { justifyContent: 'center', }); -function WrappedDay<TDate extends unknown>({ +function WrappedDay<TDate extends PickerValidDate>({ parentProps, day, focusableDay, @@ -331,7 +332,7 @@ function WrappedDay<TDate extends unknown>({ /** * @ignore - do not document. */ -export function DayCalendar<TDate>(inProps: DayCalendarProps<TDate>) { +export function DayCalendar<TDate extends PickerValidDate>(inProps: DayCalendarProps<TDate>) { const props = useThemeProps({ props: inProps, name: 'MuiDayCalendar' }); const utils = useUtils<TDate>(); diff --git a/packages/x-date-pickers/src/DateCalendar/tests/validation.DateCalendar.test.tsx b/packages/x-date-pickers/src/DateCalendar/tests/validation.DateCalendar.test.tsx index 9940b97e3d9d4..74eaafe5cfaa3 100644 --- a/packages/x-date-pickers/src/DateCalendar/tests/validation.DateCalendar.test.tsx +++ b/packages/x-date-pickers/src/DateCalendar/tests/validation.DateCalendar.test.tsx @@ -2,9 +2,10 @@ import * as React from 'react'; import { expect } from 'chai'; import { screen, fireEvent } from '@mui-internal/test-utils'; import { DateCalendar, DateCalendarProps } from '@mui/x-date-pickers/DateCalendar'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; import { createPickerRenderer, adapterToUse } from 'test/utils/pickers'; -function WrappedDateCalendar<TDate extends any>( +function WrappedDateCalendar<TDate extends PickerValidDate>( props: Omit<DateCalendarProps<TDate>, 'value' | 'onChange'> & { initialValue: TDate }, ) { const { initialValue, ...other } = props; diff --git a/packages/x-date-pickers/src/DateCalendar/useCalendarState.tsx b/packages/x-date-pickers/src/DateCalendar/useCalendarState.tsx index eebe2fede5ad9..5da5597f0f0c8 100644 --- a/packages/x-date-pickers/src/DateCalendar/useCalendarState.tsx +++ b/packages/x-date-pickers/src/DateCalendar/useCalendarState.tsx @@ -3,12 +3,12 @@ import useEventCallback from '@mui/utils/useEventCallback'; import { SlideDirection } from './PickersSlideTransition'; import { useIsDateDisabled } from './useIsDateDisabled'; import { useUtils } from '../internals/hooks/useUtils'; -import { MuiPickersAdapter, PickersTimezone } from '../models'; +import { MuiPickersAdapter, PickersTimezone, PickerValidDate } from '../models'; import { DateCalendarDefaultizedProps } from './DateCalendar.types'; import { singleItemValueManager } from '../internals/utils/valueManagers'; import { SECTION_TYPE_GRANULARITY } from '../internals/utils/getDefaultReferenceDate'; -interface CalendarState<TDate> { +interface CalendarState<TDate extends PickerValidDate> { currentMonth: TDate; focusedDay: TDate | null; isMonthSwitchingAnimating: boolean; @@ -17,12 +17,12 @@ interface CalendarState<TDate> { type ReducerAction<TType, TAdditional = {}> = { type: TType } & TAdditional; -interface ChangeMonthPayload<TDate> { +interface ChangeMonthPayload<TDate extends PickerValidDate> { direction: SlideDirection; newMonth: TDate; } -interface ChangeFocusedDayPayload<TDate> { +interface ChangeFocusedDayPayload<TDate extends PickerValidDate> { focusedDay: TDate | null; /** * The update does not trigger month switching animation. @@ -32,7 +32,7 @@ interface ChangeFocusedDayPayload<TDate> { } export const createCalendarStateReducer = - <TDate extends unknown>( + <TDate extends PickerValidDate>( reduceAnimations: boolean, disableSwitchToMonthOnDayFocus: boolean, utils: MuiPickersAdapter<TDate>, @@ -93,7 +93,7 @@ export const createCalendarStateReducer = } }; -interface UseCalendarStateParams<TDate> +interface UseCalendarStateParams<TDate extends PickerValidDate> extends Pick< DateCalendarDefaultizedProps<TDate>, | 'value' @@ -110,7 +110,9 @@ interface UseCalendarStateParams<TDate> timezone: PickersTimezone; } -export const useCalendarState = <TDate extends unknown>(params: UseCalendarStateParams<TDate>) => { +export const useCalendarState = <TDate extends PickerValidDate>( + params: UseCalendarStateParams<TDate>, +) => { const { value, referenceDate: referenceDateProp, diff --git a/packages/x-date-pickers/src/DateCalendar/useIsDateDisabled.ts b/packages/x-date-pickers/src/DateCalendar/useIsDateDisabled.ts index 0375516f4e953..7fbde8e847724 100644 --- a/packages/x-date-pickers/src/DateCalendar/useIsDateDisabled.ts +++ b/packages/x-date-pickers/src/DateCalendar/useIsDateDisabled.ts @@ -4,8 +4,9 @@ import { validateDate, } from '../internals/utils/validation/validateDate'; import { useLocalizationContext } from '../internals/hooks/useUtils'; +import { PickerValidDate } from '../models'; -export const useIsDateDisabled = <TDate>({ +export const useIsDateDisabled = <TDate extends PickerValidDate>({ shouldDisableDate, shouldDisableMonth, shouldDisableYear, diff --git a/packages/x-date-pickers/src/DateField/DateField.tsx b/packages/x-date-pickers/src/DateField/DateField.tsx index f654d9db925b1..cf4218512439d 100644 --- a/packages/x-date-pickers/src/DateField/DateField.tsx +++ b/packages/x-date-pickers/src/DateField/DateField.tsx @@ -8,8 +8,9 @@ import { DateFieldProps, DateFieldSlotProps } from './DateField.types'; import { useDateField } from './useDateField'; import { useClearableField } from '../hooks'; import { convertFieldResponseIntoMuiTextFieldProps } from '../internals/utils/convertFieldResponseIntoMuiTextFieldProps'; +import { PickerValidDate } from '../models'; -type DateFieldComponent = (<TDate>( +type DateFieldComponent = (<TDate extends PickerValidDate>( props: DateFieldProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -23,7 +24,7 @@ type DateFieldComponent = (<TDate>( * * - [DateField API](https://mui.com/x/api/date-pickers/date-field/) */ -const DateField = React.forwardRef(function DateField<TDate>( +const DateField = React.forwardRef(function DateField<TDate extends PickerValidDate>( inProps: DateFieldProps<TDate>, inRef: React.Ref<HTMLDivElement>, ) { @@ -95,7 +96,7 @@ DateField.propTypes = { /** * The default value. Use when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the component is disabled. * @default false @@ -182,11 +183,11 @@ DateField.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Name attribute of the `input` element. */ @@ -229,7 +230,7 @@ DateField.propTypes = { * For example, on time fields it will be used to determine the date to set. * @default The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * If `true`, the label is displayed as required and the `input` element is required. * @default false @@ -341,7 +342,7 @@ DateField.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The variant to use. * @default 'outlined' diff --git a/packages/x-date-pickers/src/DateField/DateField.types.ts b/packages/x-date-pickers/src/DateField/DateField.types.ts index 2b358fd2cb153..51a00deb3a8ab 100644 --- a/packages/x-date-pickers/src/DateField/DateField.types.ts +++ b/packages/x-date-pickers/src/DateField/DateField.types.ts @@ -2,7 +2,7 @@ import * as React from 'react'; import { SlotComponentProps } from '@mui/base/utils'; import TextField from '@mui/material/TextField'; import { UseClearableFieldSlots, UseClearableFieldSlotProps } from '../hooks/useClearableField'; -import { DateValidationError, FieldSection } from '../models'; +import { DateValidationError, FieldSection, PickerValidDate } from '../models'; import { UseFieldInternalProps } from '../internals/hooks/useField'; import { DefaultizedProps, MakeOptional } from '../internals/models/helpers'; import { @@ -13,7 +13,7 @@ import { } from '../internals/models/validation'; import { FieldsTextFieldProps } from '../internals/models/fields'; -export interface UseDateFieldProps<TDate> +export interface UseDateFieldProps<TDate extends PickerValidDate> extends MakeOptional< UseFieldInternalProps<TDate | null, TDate, FieldSection, DateValidationError>, 'format' @@ -23,18 +23,17 @@ export interface UseDateFieldProps<TDate> YearValidationProps<TDate>, BaseDateValidationProps<TDate> {} -export type UseDateFieldDefaultizedProps<TDate> = DefaultizedProps< +export type UseDateFieldDefaultizedProps<TDate extends PickerValidDate> = DefaultizedProps< UseDateFieldProps<TDate>, keyof BaseDateValidationProps<any> | 'format' >; -export type UseDateFieldComponentProps<TDate, TChildProps extends {}> = Omit< - TChildProps, - keyof UseDateFieldProps<TDate> -> & - UseDateFieldProps<TDate>; +export type UseDateFieldComponentProps< + TDate extends PickerValidDate, + TChildProps extends {}, +> = Omit<TChildProps, keyof UseDateFieldProps<TDate>> & UseDateFieldProps<TDate>; -export interface DateFieldProps<TDate> +export interface DateFieldProps<TDate extends PickerValidDate> extends UseDateFieldComponentProps<TDate, FieldsTextFieldProps> { /** * Overridable component slots. @@ -48,7 +47,7 @@ export interface DateFieldProps<TDate> slotProps?: DateFieldSlotProps<TDate>; } -export type DateFieldOwnerState<TDate> = DateFieldProps<TDate>; +export type DateFieldOwnerState<TDate extends PickerValidDate> = DateFieldProps<TDate>; export interface DateFieldSlots extends UseClearableFieldSlots { /** @@ -59,6 +58,7 @@ export interface DateFieldSlots extends UseClearableFieldSlots { textField?: React.ElementType; } -export interface DateFieldSlotProps<TDate> extends UseClearableFieldSlotProps { +export interface DateFieldSlotProps<TDate extends PickerValidDate> + extends UseClearableFieldSlotProps { textField?: SlotComponentProps<typeof TextField, {}, DateFieldOwnerState<TDate>>; } diff --git a/packages/x-date-pickers/src/DateField/useDateField.ts b/packages/x-date-pickers/src/DateField/useDateField.ts index 1a7e9c4795687..2d5b495c652d2 100644 --- a/packages/x-date-pickers/src/DateField/useDateField.ts +++ b/packages/x-date-pickers/src/DateField/useDateField.ts @@ -12,8 +12,9 @@ import { validateDate } from '../internals/utils/validation/validateDate'; import { applyDefaultDate } from '../internals/utils/date-utils'; import { useUtils, useDefaultDates } from '../internals/hooks/useUtils'; import { splitFieldInternalAndForwardedProps } from '../internals/utils/fields'; +import { PickerValidDate } from '../models'; -const useDefaultizedDateField = <TDate, AdditionalProps extends {}>( +const useDefaultizedDateField = <TDate extends PickerValidDate, AdditionalProps extends {}>( props: UseDateFieldProps<TDate>, ): AdditionalProps & UseDateFieldDefaultizedProps<TDate> => { const utils = useUtils<TDate>(); @@ -29,7 +30,7 @@ const useDefaultizedDateField = <TDate, AdditionalProps extends {}>( } as any; }; -export const useDateField = <TDate, TChildProps extends {}>( +export const useDateField = <TDate extends PickerValidDate, TChildProps extends {}>( inProps: UseDateFieldComponentProps<TDate, TChildProps>, ) => { const props = useDefaultizedDateField<TDate, TChildProps>(inProps); diff --git a/packages/x-date-pickers/src/DatePicker/DatePicker.tsx b/packages/x-date-pickers/src/DatePicker/DatePicker.tsx index 31068c055fd4d..0a6ecc56822c7 100644 --- a/packages/x-date-pickers/src/DatePicker/DatePicker.tsx +++ b/packages/x-date-pickers/src/DatePicker/DatePicker.tsx @@ -7,8 +7,9 @@ import { DesktopDatePicker } from '../DesktopDatePicker'; import { MobileDatePicker } from '../MobileDatePicker'; import { DatePickerProps } from './DatePicker.types'; import { DEFAULT_DESKTOP_MODE_MEDIA_QUERY } from '../internals/utils/utils'; +import { PickerValidDate } from '../models'; -type DatePickerComponent = (<TDate>( +type DatePickerComponent = (<TDate extends PickerValidDate>( props: DatePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -22,7 +23,7 @@ type DatePickerComponent = (<TDate>( * * - [DatePicker API](https://mui.com/x/api/date-pickers/date-picker/) */ -const DatePicker = React.forwardRef(function DatePicker<TDate>( +const DatePicker = React.forwardRef(function DatePicker<TDate extends PickerValidDate>( inProps: DatePickerProps<TDate>, ref: React.Ref<HTMLDivElement>, ) { @@ -69,7 +70,7 @@ DatePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * CSS media query when `Mobile` mode will be changed to `Desktop`. * @default '@media (pointer: fine)' @@ -144,11 +145,11 @@ DatePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Months rendered per row. * @default 3 @@ -240,7 +241,7 @@ DatePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component displaying when passed `loading` true. * @returns {React.ReactNode} The node to render when loading. @@ -340,7 +341,7 @@ DatePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/DatePicker/DatePicker.types.ts b/packages/x-date-pickers/src/DatePicker/DatePicker.types.ts index 9c3c09d712cea..a287263829adc 100644 --- a/packages/x-date-pickers/src/DatePicker/DatePicker.types.ts +++ b/packages/x-date-pickers/src/DatePicker/DatePicker.types.ts @@ -8,16 +8,17 @@ import { MobileDatePickerSlots, MobileDatePickerSlotProps, } from '../MobileDatePicker'; +import { PickerValidDate } from '../models'; -export interface DatePickerSlots<TDate> +export interface DatePickerSlots<TDate extends PickerValidDate> extends DesktopDatePickerSlots<TDate>, MobileDatePickerSlots<TDate> {} -export interface DatePickerSlotProps<TDate> +export interface DatePickerSlotProps<TDate extends PickerValidDate> extends DesktopDatePickerSlotProps<TDate>, MobileDatePickerSlotProps<TDate> {} -export interface DatePickerProps<TDate> +export interface DatePickerProps<TDate extends PickerValidDate> extends DesktopDatePickerProps<TDate>, MobileDatePickerProps<TDate> { /** diff --git a/packages/x-date-pickers/src/DatePicker/DatePickerToolbar.tsx b/packages/x-date-pickers/src/DatePicker/DatePickerToolbar.tsx index 6ab7b05fbc5ee..aaaaeb64d01cc 100644 --- a/packages/x-date-pickers/src/DatePicker/DatePickerToolbar.tsx +++ b/packages/x-date-pickers/src/DatePicker/DatePickerToolbar.tsx @@ -6,14 +6,15 @@ import { unstable_composeClasses as composeClasses } from '@mui/utils'; import { PickersToolbar } from '../internals/components/PickersToolbar'; import { useLocaleText, useUtils } from '../internals/hooks/useUtils'; import { BaseToolbarProps, ExportedBaseToolbarProps } from '../internals/models/props/toolbar'; -import { DateView } from '../models'; +import { DateView, PickerValidDate } from '../models'; import { DatePickerToolbarClasses, getDatePickerToolbarUtilityClass, } from './datePickerToolbarClasses'; import { resolveDateFormat } from '../internals/utils/date-utils'; -export interface DatePickerToolbarProps<TDate> extends BaseToolbarProps<TDate | null, DateView> { +export interface DatePickerToolbarProps<TDate extends PickerValidDate> + extends BaseToolbarProps<TDate | null, DateView> { classes?: Partial<DatePickerToolbarClasses>; sx?: SxProps<Theme>; } @@ -46,7 +47,7 @@ const DatePickerToolbarTitle = styled(Typography, { }), })); -type DatePickerToolbarComponent = (<TDate>( +type DatePickerToolbarComponent = (<TDate extends PickerValidDate>( props: DatePickerToolbarProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -60,10 +61,9 @@ type DatePickerToolbarComponent = (<TDate>( * * - [DatePickerToolbar API](https://mui.com/x/api/date-pickers/date-picker-toolbar/) */ -export const DatePickerToolbar = React.forwardRef(function DatePickerToolbar<TDate>( - inProps: DatePickerToolbarProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +export const DatePickerToolbar = React.forwardRef(function DatePickerToolbar< + TDate extends PickerValidDate, +>(inProps: DatePickerToolbarProps<TDate>, ref: React.Ref<HTMLDivElement>) { const props = useThemeProps({ props: inProps, name: 'MuiDatePickerToolbar' }); const { value, @@ -148,7 +148,7 @@ DatePickerToolbar.propTypes = { * @default "––" */ toolbarPlaceholder: PropTypes.node, - value: PropTypes.any, + value: PropTypes.object, /** * Currently visible picker view. */ diff --git a/packages/x-date-pickers/src/DatePicker/shared.tsx b/packages/x-date-pickers/src/DatePicker/shared.tsx index f770435368dc4..6618e5b31c731 100644 --- a/packages/x-date-pickers/src/DatePicker/shared.tsx +++ b/packages/x-date-pickers/src/DatePicker/shared.tsx @@ -8,7 +8,7 @@ import { } from '../DateCalendar/DateCalendar.types'; import { useDefaultDates, useUtils } from '../internals/hooks/useUtils'; import { applyDefaultViewProps } from '../internals/utils/views'; -import { DateValidationError, DateView } from '../models'; +import { DateValidationError, DateView, PickerValidDate } from '../models'; import { BasePickerInputProps } from '../internals/models/props/basePickerProps'; import { applyDefaultDate } from '../internals/utils/date-utils'; import { BaseDateValidationProps } from '../internals/models/validation'; @@ -21,7 +21,8 @@ import { import { PickerViewRendererLookup } from '../internals/hooks/usePicker/usePickerViews'; import { DateViewRendererProps } from '../dateViewRenderers'; -export interface BaseDatePickerSlots<TDate> extends DateCalendarSlots<TDate> { +export interface BaseDatePickerSlots<TDate extends PickerValidDate> + extends DateCalendarSlots<TDate> { /** * Custom component for the toolbar rendered above the views. * @default DatePickerToolbar @@ -29,11 +30,12 @@ export interface BaseDatePickerSlots<TDate> extends DateCalendarSlots<TDate> { toolbar?: React.JSXElementConstructor<DatePickerToolbarProps<TDate>>; } -export interface BaseDatePickerSlotProps<TDate> extends DateCalendarSlotProps<TDate> { +export interface BaseDatePickerSlotProps<TDate extends PickerValidDate> + extends DateCalendarSlotProps<TDate> { toolbar?: ExportedDatePickerToolbarProps; } -export interface BaseDatePickerProps<TDate> +export interface BaseDatePickerProps<TDate extends PickerValidDate> extends BasePickerInputProps<TDate | null, TDate, DateView, DateValidationError>, ExportedDateCalendarProps<TDate> { /** @@ -57,17 +59,17 @@ export interface BaseDatePickerProps<TDate> } type UseDatePickerDefaultizedProps< - TDate, + TDate extends PickerValidDate, Props extends BaseDatePickerProps<TDate>, > = LocalizedComponent< TDate, DefaultizedProps<Props, 'views' | 'openTo' | keyof BaseDateValidationProps<TDate>> >; -export function useDatePickerDefaultizedProps<TDate, Props extends BaseDatePickerProps<TDate>>( - props: Props, - name: string, -): UseDatePickerDefaultizedProps<TDate, Props> { +export function useDatePickerDefaultizedProps< + TDate extends PickerValidDate, + Props extends BaseDatePickerProps<TDate>, +>(props: Props, name: string): UseDatePickerDefaultizedProps<TDate, Props> { const utils = useUtils<TDate>(); const defaultDates = useDefaultDates<TDate>(); const themeProps = useThemeProps({ diff --git a/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx b/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx index 21a90d5d8e238..118da3db5daf4 100644 --- a/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx +++ b/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx @@ -8,8 +8,9 @@ import { DateTimeFieldProps, DateTimeFieldSlotProps } from './DateTimeField.type import { useDateTimeField } from './useDateTimeField'; import { useClearableField } from '../hooks'; import { convertFieldResponseIntoMuiTextFieldProps } from '../internals/utils/convertFieldResponseIntoMuiTextFieldProps'; +import { PickerValidDate } from '../models'; -type DateTimeFieldComponent = (<TDate>( +type DateTimeFieldComponent = (<TDate extends PickerValidDate>( props: DateTimeFieldProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -23,7 +24,7 @@ type DateTimeFieldComponent = (<TDate>( * * - [DateTimeField API](https://mui.com/x/api/date-pickers/date-time-field/) */ -const DateTimeField = React.forwardRef(function DateTimeField<TDate>( +const DateTimeField = React.forwardRef(function DateTimeField<TDate extends PickerValidDate>( inProps: DateTimeFieldProps<TDate>, inRef: React.Ref<HTMLDivElement>, ) { @@ -100,7 +101,7 @@ DateTimeField.propTypes = { /** * The default value. Use when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the component is disabled. * @default false @@ -192,29 +193,29 @@ DateTimeField.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Maximal selectable moment of time with binding to date, to set max time in each day use `maxTime`. */ - maxDateTime: PropTypes.any, + maxDateTime: PropTypes.object, /** * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Minimal selectable moment of time with binding to date, to set min time in each day use `minTime`. */ - minDateTime: PropTypes.any, + minDateTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -262,7 +263,7 @@ DateTimeField.propTypes = { * For example, on time fields it will be used to determine the date to set. * @default The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * If `true`, the label is displayed as required and the `input` element is required. * @default false @@ -382,7 +383,7 @@ DateTimeField.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The variant to use. * @default 'outlined' diff --git a/packages/x-date-pickers/src/DateTimeField/DateTimeField.types.ts b/packages/x-date-pickers/src/DateTimeField/DateTimeField.types.ts index 98e0973d76514..984e6cf62b910 100644 --- a/packages/x-date-pickers/src/DateTimeField/DateTimeField.types.ts +++ b/packages/x-date-pickers/src/DateTimeField/DateTimeField.types.ts @@ -1,7 +1,7 @@ import * as React from 'react'; import { SlotComponentProps } from '@mui/base/utils'; import TextField from '@mui/material/TextField'; -import { DateTimeValidationError, FieldSection } from '../models'; +import { DateTimeValidationError, FieldSection, PickerValidDate } from '../models'; import { UseFieldInternalProps } from '../internals/hooks/useField'; import { DefaultizedProps, MakeOptional } from '../internals/models/helpers'; import { @@ -16,7 +16,7 @@ import { import { FieldsTextFieldProps } from '../internals/models/fields'; import { UseClearableFieldSlots, UseClearableFieldSlotProps } from '../hooks/useClearableField'; -export interface UseDateTimeFieldProps<TDate> +export interface UseDateTimeFieldProps<TDate extends PickerValidDate> extends MakeOptional< UseFieldInternalProps<TDate | null, TDate, FieldSection, DateTimeValidationError>, 'format' @@ -35,18 +35,17 @@ export interface UseDateTimeFieldProps<TDate> ampm?: boolean; } -export type UseDateTimeFieldDefaultizedProps<TDate> = DefaultizedProps< +export type UseDateTimeFieldDefaultizedProps<TDate extends PickerValidDate> = DefaultizedProps< UseDateTimeFieldProps<TDate>, keyof BaseDateValidationProps<any> | keyof BaseTimeValidationProps | 'format' >; -export type UseDateTimeFieldComponentProps<TDate, TChildProps extends {}> = Omit< - TChildProps, - keyof UseDateTimeFieldProps<TDate> -> & - UseDateTimeFieldProps<TDate>; +export type UseDateTimeFieldComponentProps< + TDate extends PickerValidDate, + TChildProps extends {}, +> = Omit<TChildProps, keyof UseDateTimeFieldProps<TDate>> & UseDateTimeFieldProps<TDate>; -export interface DateTimeFieldProps<TDate> +export interface DateTimeFieldProps<TDate extends PickerValidDate> extends UseDateTimeFieldComponentProps<TDate, FieldsTextFieldProps> { /** * Overridable component slots. @@ -60,7 +59,7 @@ export interface DateTimeFieldProps<TDate> slotProps?: DateTimeFieldSlotProps<TDate>; } -export type DateTimeFieldOwnerState<TDate> = DateTimeFieldProps<TDate>; +export type DateTimeFieldOwnerState<TDate extends PickerValidDate> = DateTimeFieldProps<TDate>; export interface DateTimeFieldSlots extends UseClearableFieldSlots { /** @@ -71,6 +70,7 @@ export interface DateTimeFieldSlots extends UseClearableFieldSlots { textField?: React.ElementType; } -export interface DateTimeFieldSlotProps<TDate> extends UseClearableFieldSlotProps { +export interface DateTimeFieldSlotProps<TDate extends PickerValidDate> + extends UseClearableFieldSlotProps { textField?: SlotComponentProps<typeof TextField, {}, DateTimeFieldOwnerState<TDate>>; } diff --git a/packages/x-date-pickers/src/DateTimeField/useDateTimeField.ts b/packages/x-date-pickers/src/DateTimeField/useDateTimeField.ts index 7e8236f12b3ab..021ea1cc3baa8 100644 --- a/packages/x-date-pickers/src/DateTimeField/useDateTimeField.ts +++ b/packages/x-date-pickers/src/DateTimeField/useDateTimeField.ts @@ -12,8 +12,9 @@ import { validateDateTime } from '../internals/utils/validation/validateDateTime import { applyDefaultDate } from '../internals/utils/date-utils'; import { useUtils, useDefaultDates } from '../internals/hooks/useUtils'; import { splitFieldInternalAndForwardedProps } from '../internals/utils/fields'; +import { PickerValidDate } from '../models'; -const useDefaultizedDateTimeField = <TDate, AdditionalProps extends {}>( +const useDefaultizedDateTimeField = <TDate extends PickerValidDate, AdditionalProps extends {}>( props: UseDateTimeFieldProps<TDate>, ): AdditionalProps & UseDateTimeFieldDefaultizedProps<TDate> => { const utils = useUtils<TDate>(); @@ -37,7 +38,7 @@ const useDefaultizedDateTimeField = <TDate, AdditionalProps extends {}>( } as any; }; -export const useDateTimeField = <TDate, TChildProps extends {}>( +export const useDateTimeField = <TDate extends PickerValidDate, TChildProps extends {}>( inProps: UseDateTimeFieldComponentProps<TDate, TChildProps>, ) => { const props = useDefaultizedDateTimeField<TDate, TChildProps>(inProps); diff --git a/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.tsx b/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.tsx index d00a9598a5756..f8a709895ef37 100644 --- a/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.tsx +++ b/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.tsx @@ -7,8 +7,9 @@ import { DesktopDateTimePicker } from '../DesktopDateTimePicker'; import { MobileDateTimePicker, MobileDateTimePickerProps } from '../MobileDateTimePicker'; import { DateTimePickerProps } from './DateTimePicker.types'; import { DEFAULT_DESKTOP_MODE_MEDIA_QUERY } from '../internals/utils/utils'; +import { PickerValidDate } from '../models'; -type DateTimePickerComponent = (<TDate>( +type DateTimePickerComponent = (<TDate extends PickerValidDate>( props: DateTimePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -22,7 +23,7 @@ type DateTimePickerComponent = (<TDate>( * * - [DateTimePicker API](https://mui.com/x/api/date-pickers/date-time-picker/) */ -const DateTimePicker = React.forwardRef(function DateTimePicker<TDate>( +const DateTimePicker = React.forwardRef(function DateTimePicker<TDate extends PickerValidDate>( inProps: DateTimePickerProps<TDate>, ref: React.Ref<HTMLDivElement>, ) { @@ -79,7 +80,7 @@ DateTimePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * CSS media query when `Mobile` mode will be changed to `Desktop`. * @default '@media (pointer: fine)' @@ -159,29 +160,29 @@ DateTimePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Maximal selectable moment of time with binding to date, to set max time in each day use `maxTime`. */ - maxDateTime: PropTypes.any, + maxDateTime: PropTypes.object, /** * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Minimal selectable moment of time with binding to date, to set min time in each day use `minTime`. */ - minDateTime: PropTypes.any, + minDateTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -278,7 +279,7 @@ DateTimePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component displaying when passed `loading` true. * @returns {React.ReactNode} The node to render when loading. @@ -407,7 +408,7 @@ DateTimePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.types.ts b/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.types.ts index 11c592b43e4fe..261c0907f258e 100644 --- a/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.types.ts +++ b/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.types.ts @@ -9,16 +9,17 @@ import { MobileDateTimePickerSlots, MobileDateTimePickerSlotProps, } from '../MobileDateTimePicker'; +import { PickerValidDate } from '../models'; -export interface DateTimePickerSlots<TDate> +export interface DateTimePickerSlots<TDate extends PickerValidDate> extends DesktopDateTimePickerSlots<TDate>, MobileDateTimePickerSlots<TDate, DateOrTimeViewWithMeridiem> {} -export interface DateTimePickerSlotProps<TDate> +export interface DateTimePickerSlotProps<TDate extends PickerValidDate> extends DesktopDateTimePickerSlotProps<TDate>, MobileDateTimePickerSlotProps<TDate, DateOrTimeViewWithMeridiem> {} -export interface DateTimePickerProps<TDate> +export interface DateTimePickerProps<TDate extends PickerValidDate> extends DesktopDateTimePickerProps<TDate>, Omit<MobileDateTimePickerProps<TDate, DateOrTimeViewWithMeridiem>, 'views'> { /** diff --git a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx index d817ba20003a7..b622fa791f990 100644 --- a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx +++ b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx @@ -20,13 +20,14 @@ import { formatMeridiem } from '../internals/utils/date-utils'; import { MakeOptional } from '../internals/models/helpers'; import { pickersToolbarTextClasses } from '../internals/components/pickersToolbarTextClasses'; import { pickersToolbarClasses } from '../internals'; +import { PickerValidDate } from '../models'; export interface ExportedDateTimePickerToolbarProps extends ExportedBaseToolbarProps { ampm?: boolean; ampmInClock?: boolean; } -export interface DateTimePickerToolbarProps<TDate> +export interface DateTimePickerToolbarProps<TDate extends PickerValidDate> extends ExportedDateTimePickerToolbarProps, MakeOptional<BaseToolbarProps<TDate | null, DateOrTimeViewWithMeridiem>, 'view'> { /** @@ -209,7 +210,9 @@ const DateTimePickerToolbarAmPmSelection = styled('div', { * * - [DateTimePickerToolbar API](https://mui.com/x/api/date-pickers/date-time-picker-toolbar/) */ -function DateTimePickerToolbar<TDate extends unknown>(inProps: DateTimePickerToolbarProps<TDate>) { +function DateTimePickerToolbar<TDate extends PickerValidDate>( + inProps: DateTimePickerToolbarProps<TDate>, +) { const props = useThemeProps({ props: inProps, name: 'MuiDateTimePickerToolbar' }); const { ampm, @@ -425,7 +428,7 @@ DateTimePickerToolbar.propTypes = { */ toolbarTitle: PropTypes.node, toolbarVariant: PropTypes.oneOf(['desktop', 'mobile']), - value: PropTypes.any, + value: PropTypes.object, /** * Currently visible picker view. */ diff --git a/packages/x-date-pickers/src/DateTimePicker/shared.tsx b/packages/x-date-pickers/src/DateTimePicker/shared.tsx index ff7ef45d18728..feb1531a67877 100644 --- a/packages/x-date-pickers/src/DateTimePicker/shared.tsx +++ b/packages/x-date-pickers/src/DateTimePicker/shared.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { useThemeProps } from '@mui/material/styles'; import { DefaultizedProps } from '../internals/models/helpers'; -import { DateTimeValidationError } from '../models'; +import { DateTimeValidationError, PickerValidDate } from '../models'; import { useDefaultDates, useUtils } from '../internals/hooks/useUtils'; import { DateCalendarSlots, @@ -34,7 +34,9 @@ import { applyDefaultViewProps } from '../internals/utils/views'; import { BaseClockProps, ExportedBaseClockProps } from '../internals/models/props/clock'; import { DateOrTimeViewWithMeridiem, TimeViewWithMeridiem } from '../internals/models'; -export interface BaseDateTimePickerSlots<TDate> extends DateCalendarSlots<TDate>, TimeClockSlots { +export interface BaseDateTimePickerSlots<TDate extends PickerValidDate> + extends DateCalendarSlots<TDate>, + TimeClockSlots { /** * Tabs enabling toggling between date and time pickers. * @default DateTimePickerTabs @@ -47,7 +49,7 @@ export interface BaseDateTimePickerSlots<TDate> extends DateCalendarSlots<TDate> toolbar?: React.JSXElementConstructor<DateTimePickerToolbarProps<TDate>>; } -export interface BaseDateTimePickerSlotProps<TDate> +export interface BaseDateTimePickerSlotProps<TDate extends PickerValidDate> extends DateCalendarSlotProps<TDate>, TimeClockSlotProps { /** @@ -60,8 +62,10 @@ export interface BaseDateTimePickerSlotProps<TDate> toolbar?: ExportedDateTimePickerToolbarProps; } -export interface BaseDateTimePickerProps<TDate, TView extends DateOrTimeViewWithMeridiem> - extends BasePickerInputProps<TDate | null, TDate, TView, DateTimeValidationError>, +export interface BaseDateTimePickerProps< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends BasePickerInputProps<TDate | null, TDate, TView, DateTimeValidationError>, Omit<ExportedDateCalendarProps<TDate>, 'onViewChange'>, ExportedBaseClockProps<TDate>, DateTimeValidationProps<TDate> { @@ -97,7 +101,7 @@ export interface BaseDateTimePickerProps<TDate, TView extends DateOrTimeViewWith } type UseDateTimePickerDefaultizedProps< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, Props extends BaseDateTimePickerProps<TDate, TView>, > = LocalizedComponent< @@ -114,7 +118,7 @@ type UseDateTimePickerDefaultizedProps< >; export function useDateTimePickerDefaultizedProps< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, Props extends BaseDateTimePickerProps<TDate, TView>, >(props: Props, name: string): UseDateTimePickerDefaultizedProps<TDate, TView, Props> { diff --git a/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.tsx b/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.tsx index c338f20d131bc..dcf4c673fc86e 100644 --- a/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.tsx +++ b/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.tsx @@ -7,7 +7,7 @@ import { DesktopDatePickerProps } from './DesktopDatePicker.types'; import { useDatePickerDefaultizedProps } from '../DatePicker/shared'; import { useLocaleText, useUtils } from '../internals/hooks/useUtils'; import { validateDate } from '../internals/utils/validation/validateDate'; -import { DateView } from '../models'; +import { DateView, PickerValidDate } from '../models'; import { useDesktopPicker } from '../internals/hooks/useDesktopPicker'; import { CalendarIcon } from '../icons'; import { DateField } from '../DateField'; @@ -16,7 +16,7 @@ import { renderDateViewCalendar } from '../dateViewRenderers'; import { PickerViewRendererLookup } from '../internals/hooks/usePicker/usePickerViews'; import { resolveDateFormat } from '../internals/utils/date-utils'; -type DesktopDatePickerComponent = (<TDate>( +type DesktopDatePickerComponent = (<TDate extends PickerValidDate>( props: DesktopDatePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -30,10 +30,9 @@ type DesktopDatePickerComponent = (<TDate>( * * - [DesktopDatePicker API](https://mui.com/x/api/date-pickers/desktop-date-picker/) */ -const DesktopDatePicker = React.forwardRef(function DesktopDatePicker<TDate>( - inProps: DesktopDatePickerProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const DesktopDatePicker = React.forwardRef(function DesktopDatePicker< + TDate extends PickerValidDate, +>(inProps: DesktopDatePickerProps<TDate>, ref: React.Ref<HTMLDivElement>) { const localeText = useLocaleText<TDate>(); const utils = useUtils<TDate>(); @@ -116,7 +115,7 @@ DesktopDatePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the picker and text field are disabled. * @default false @@ -185,11 +184,11 @@ DesktopDatePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Months rendered per row. * @default 3 @@ -281,7 +280,7 @@ DesktopDatePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component displaying when passed `loading` true. * @returns {React.ReactNode} The node to render when loading. @@ -381,7 +380,7 @@ DesktopDatePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.types.ts b/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.types.ts index 8c423832fa0da..ef33cb389df47 100644 --- a/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.types.ts +++ b/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.types.ts @@ -9,17 +9,17 @@ import { BaseDatePickerSlotProps, } from '../DatePicker/shared'; import { MakeOptional } from '../internals/models/helpers'; -import { DateView } from '../models'; +import { DateView, PickerValidDate } from '../models'; -export interface DesktopDatePickerSlots<TDate> +export interface DesktopDatePickerSlots<TDate extends PickerValidDate> extends BaseDatePickerSlots<TDate>, MakeOptional<UseDesktopPickerSlots<TDate, DateView>, 'field' | 'openPickerIcon'> {} -export interface DesktopDatePickerSlotProps<TDate> +export interface DesktopDatePickerSlotProps<TDate extends PickerValidDate> extends BaseDatePickerSlotProps<TDate>, ExportedUseDesktopPickerSlotProps<TDate, DateView> {} -export interface DesktopDatePickerProps<TDate> +export interface DesktopDatePickerProps<TDate extends PickerValidDate> extends BaseDatePickerProps<TDate>, DesktopOnlyPickerProps<TDate> { /** 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 5f89b74ea0290..7c64c8832c42a 100644 --- a/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx @@ -307,15 +307,6 @@ describe('<DesktopDatePicker />', () => { expect(screen.getByLabelText('Next month')).not.to.have.attribute('disabled'); }); - - it('should allow to navigate to previous and next month if props.minDate == null', () => { - render(<DesktopDatePicker minDate={null} />); - - openPicker({ type: 'date', variant: 'desktop' }); - - expect(screen.getByLabelText('Previous month')).not.to.have.attribute('disabled'); - expect(screen.getByLabelText('Next month')).not.to.have.attribute('disabled'); - }); }); describe('Validation', () => { diff --git a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx index 64775b786702f..dd39ba02e7794 100644 --- a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx +++ b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx @@ -20,8 +20,9 @@ import { resolveTimeViewsResponse, } from '../internals/utils/date-time-utils'; import { PickersActionBarAction } from '../PickersActionBar'; +import { PickerValidDate } from '../models'; -type DesktopDateTimePickerComponent = (<TDate>( +type DesktopDateTimePickerComponent = (<TDate extends PickerValidDate>( props: DesktopDateTimePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -35,10 +36,9 @@ type DesktopDateTimePickerComponent = (<TDate>( * * - [DesktopDateTimePicker API](https://mui.com/x/api/date-pickers/desktop-date-time-picker/) */ -const DesktopDateTimePicker = React.forwardRef(function DesktopDateTimePicker<TDate>( - inProps: DesktopDateTimePickerProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const DesktopDateTimePicker = React.forwardRef(function DesktopDateTimePicker< + TDate extends PickerValidDate, +>(inProps: DesktopDateTimePickerProps<TDate>, ref: React.Ref<HTMLDivElement>) { const localeText = useLocaleText<TDate>(); const utils = useUtils<TDate>(); @@ -175,7 +175,7 @@ DesktopDateTimePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the picker and text field are disabled. * @default false @@ -249,29 +249,29 @@ DesktopDateTimePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Maximal selectable moment of time with binding to date, to set max time in each day use `maxTime`. */ - maxDateTime: PropTypes.any, + maxDateTime: PropTypes.object, /** * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Minimal selectable moment of time with binding to date, to set min time in each day use `minTime`. */ - minDateTime: PropTypes.any, + minDateTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -368,7 +368,7 @@ DesktopDateTimePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component displaying when passed `loading` true. * @returns {React.ReactNode} The node to render when loading. @@ -497,7 +497,7 @@ DesktopDateTimePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.types.ts b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.types.ts index d36ce2b031455..4848a1477317f 100644 --- a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.types.ts +++ b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.types.ts @@ -9,7 +9,7 @@ import { BaseDateTimePickerSlotProps, } from '../DateTimePicker/shared'; import { MakeOptional } from '../internals/models/helpers'; -import { DateOrTimeView } from '../models'; +import { DateOrTimeView, PickerValidDate } from '../models'; import { DesktopOnlyTimePickerProps } from '../internals/models/props/clock'; import { DateOrTimeViewWithMeridiem } from '../internals/models'; import { @@ -18,7 +18,7 @@ import { } from '../MultiSectionDigitalClock'; import { DigitalClockSlots, DigitalClockSlotProps } from '../DigitalClock'; -export interface DesktopDateTimePickerSlots<TDate> +export interface DesktopDateTimePickerSlots<TDate extends PickerValidDate> extends BaseDateTimePickerSlots<TDate>, MakeOptional< UseDesktopPickerSlots<TDate, DateOrTimeViewWithMeridiem>, @@ -27,13 +27,13 @@ export interface DesktopDateTimePickerSlots<TDate> DigitalClockSlots, MultiSectionDigitalClockSlots {} -export interface DesktopDateTimePickerSlotProps<TDate> +export interface DesktopDateTimePickerSlotProps<TDate extends PickerValidDate> extends BaseDateTimePickerSlotProps<TDate>, ExportedUseDesktopPickerSlotProps<TDate, DateOrTimeViewWithMeridiem>, DigitalClockSlotProps, MultiSectionDigitalClockSlotProps {} -export interface DesktopDateTimePickerProps<TDate> +export interface DesktopDateTimePickerProps<TDate extends PickerValidDate> extends BaseDateTimePickerProps<TDate, DateOrTimeViewWithMeridiem>, DesktopOnlyPickerProps<TDate>, DesktopOnlyTimePickerProps<TDate> { diff --git a/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx b/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx index de810cb47552b..659c364afb4e9 100644 --- a/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx +++ b/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx @@ -20,9 +20,9 @@ import { PickersActionBarAction } from '../PickersActionBar'; import { TimeViewWithMeridiem } from '../internals/models'; import { resolveTimeFormat } from '../internals/utils/time-utils'; import { resolveTimeViewsResponse } from '../internals/utils/date-time-utils'; -import { TimeView } from '../models/views'; +import { TimeView, PickerValidDate } from '../models'; -type DesktopTimePickerComponent = (<TDate>( +type DesktopTimePickerComponent = (<TDate extends PickerValidDate>( props: DesktopTimePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -36,10 +36,9 @@ type DesktopTimePickerComponent = (<TDate>( * * - [DesktopTimePicker API](https://mui.com/x/api/date-pickers/desktop-time-picker/) */ -const DesktopTimePicker = React.forwardRef(function DesktopTimePicker<TDate>( - inProps: DesktopTimePickerProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const DesktopTimePicker = React.forwardRef(function DesktopTimePicker< + TDate extends PickerValidDate, +>(inProps: DesktopTimePickerProps<TDate>, ref: React.Ref<HTMLDivElement>) { const localeText = useLocaleText<TDate>(); const utils = useUtils<TDate>(); @@ -157,7 +156,7 @@ DesktopTimePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the picker and text field are disabled. * @default false @@ -211,12 +210,12 @@ DesktopTimePicker.propTypes = { * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -296,7 +295,7 @@ DesktopTimePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * The currently selected sections. * This prop accept four formats: @@ -384,7 +383,7 @@ DesktopTimePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.types.ts b/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.types.ts index 6f3735460d58e..ec9a50c0c2c48 100644 --- a/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.types.ts +++ b/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.types.ts @@ -16,21 +16,21 @@ import { MultiSectionDigitalClockSlots, MultiSectionDigitalClockSlotProps, } from '../MultiSectionDigitalClock'; -import { TimeView } from '../models'; +import { PickerValidDate, TimeView } from '../models'; -export interface DesktopTimePickerSlots<TDate> +export interface DesktopTimePickerSlots<TDate extends PickerValidDate> extends BaseTimePickerSlots<TDate>, MakeOptional<UseDesktopPickerSlots<TDate, TimeViewWithMeridiem>, 'field' | 'openPickerIcon'>, DigitalClockSlots, MultiSectionDigitalClockSlots {} -export interface DesktopTimePickerSlotProps<TDate> +export interface DesktopTimePickerSlotProps<TDate extends PickerValidDate> extends BaseTimePickerSlotProps, ExportedUseDesktopPickerSlotProps<TDate, TimeViewWithMeridiem>, DigitalClockSlotProps, MultiSectionDigitalClockSlotProps {} -export interface DesktopTimePickerProps<TDate> +export interface DesktopTimePickerProps<TDate extends PickerValidDate> extends BaseTimePickerProps<TDate, TimeViewWithMeridiem>, DesktopOnlyPickerProps<TDate>, DesktopOnlyTimePickerProps<TDate> { diff --git a/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx b/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx index 94fcdb8d9f895..e3824be369071 100644 --- a/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx +++ b/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx @@ -14,7 +14,7 @@ import { PickerViewRoot } from '../internals/components/PickerViewRoot'; import { getDigitalClockUtilityClass } from './digitalClockClasses'; import { DigitalClockProps } from './DigitalClock.types'; import { useViews } from '../internals/hooks/useViews'; -import { TimeView } from '../models'; +import { PickerValidDate, TimeView } from '../models'; import { DIGITAL_CLOCK_VIEW_HEIGHT } from '../internals/constants/dimensions'; import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone'; import { singleItemValueManager } from '../internals/utils/valueManagers'; @@ -81,7 +81,7 @@ const DigitalClockItem = styled(MenuItem, { }, })); -type DigitalClockComponent = (<TDate>( +type DigitalClockComponent = (<TDate extends PickerValidDate>( props: DigitalClockProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -95,7 +95,7 @@ type DigitalClockComponent = (<TDate>( * * - [DigitalClock API](https://mui.com/x/api/date-pickers/digital-clock/) */ -export const DigitalClock = React.forwardRef(function DigitalClock<TDate extends unknown>( +export const DigitalClock = React.forwardRef(function DigitalClock<TDate extends PickerValidDate>( inProps: DigitalClockProps<TDate>, ref: React.Ref<HTMLDivElement>, ) { @@ -352,7 +352,7 @@ DigitalClock.propTypes = { * The default selected value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the picker views and text field are disabled. * @default false @@ -381,12 +381,12 @@ DigitalClock.propTypes = { * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -429,7 +429,7 @@ DigitalClock.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid time using the validation props, except callbacks such as `shouldDisableTime`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Disable specific time. * @template TDate @@ -479,7 +479,7 @@ DigitalClock.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/DigitalClock/DigitalClock.types.ts b/packages/x-date-pickers/src/DigitalClock/DigitalClock.types.ts index 35b88400f1a92..7b98c84670d60 100644 --- a/packages/x-date-pickers/src/DigitalClock/DigitalClock.types.ts +++ b/packages/x-date-pickers/src/DigitalClock/DigitalClock.types.ts @@ -1,3 +1,4 @@ +import * as React from 'react'; import { SlotComponentProps } from '@mui/base/utils'; import MenuItem from '@mui/material/MenuItem'; import { DigitalClockClasses } from './digitalClockClasses'; @@ -6,9 +7,9 @@ import { DigitalClockOnlyProps, ExportedBaseClockProps, } from '../internals/models/props/clock'; -import { TimeView } from '../models'; +import { PickerValidDate, TimeView } from '../models'; -export interface ExportedDigitalClockProps<TDate> +export interface ExportedDigitalClockProps<TDate extends PickerValidDate> extends ExportedBaseClockProps<TDate>, DigitalClockOnlyProps {} @@ -24,7 +25,7 @@ export interface DigitalClockSlotProps { digitalClockItem?: SlotComponentProps<typeof MenuItem, {}, Record<string, any>>; } -export interface DigitalClockProps<TDate> +export interface DigitalClockProps<TDate extends PickerValidDate> extends ExportedDigitalClockProps<TDate>, BaseClockProps<TDate, Extract<TimeView, 'hours'>> { /** diff --git a/packages/x-date-pickers/src/LocalizationProvider/LocalizationProvider.tsx b/packages/x-date-pickers/src/LocalizationProvider/LocalizationProvider.tsx index 956bf452ccb75..e7f74202614ad 100644 --- a/packages/x-date-pickers/src/LocalizationProvider/LocalizationProvider.tsx +++ b/packages/x-date-pickers/src/LocalizationProvider/LocalizationProvider.tsx @@ -1,10 +1,10 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { useThemeProps } from '@mui/material/styles'; -import { AdapterFormats, MuiPickersAdapter } from '../models'; +import { AdapterFormats, MuiPickersAdapter, PickerValidDate } from '../models'; import { PickersInputLocaleText } from '../locales'; -export interface MuiPickersAdapterContextValue<TDate> { +export interface MuiPickersAdapterContextValue<TDate extends PickerValidDate> { defaultDates: { minDate: TDate; maxDate: TDate; @@ -14,7 +14,7 @@ export interface MuiPickersAdapterContextValue<TDate> { localeText: PickersInputLocaleText<TDate> | undefined; } -export type MuiPickersAdapterContextNullableValue<TDate> = { +export type MuiPickersAdapterContextNullableValue<TDate extends PickerValidDate> = { [K in keyof MuiPickersAdapterContextValue<TDate>]: MuiPickersAdapterContextValue<TDate>[K] | null; }; @@ -25,7 +25,7 @@ if (process.env.NODE_ENV !== 'production') { MuiPickersAdapterContext.displayName = 'MuiPickersAdapterContext'; } -export interface LocalizationProviderProps<TDate, TLocale> { +export interface LocalizationProviderProps<TDate extends PickerValidDate, TLocale> { children?: React.ReactNode; /** * Date library adapter class function. @@ -51,7 +51,7 @@ export interface LocalizationProviderProps<TDate, TLocale> { localeText?: PickersInputLocaleText<TDate>; } -type LocalizationProviderComponent = (<TDate, TLocale>( +type LocalizationProviderComponent = (<TDate extends PickerValidDate, TLocale>( props: LocalizationProviderProps<TDate, TLocale>, ) => React.JSX.Element) & { propTypes?: any }; @@ -67,9 +67,10 @@ type LocalizationProviderComponent = (<TDate, TLocale>( * * - [LocalizationProvider API](https://mui.com/x/api/date-pickers/localization-provider/) */ -export const LocalizationProvider = function LocalizationProvider<TDate, TLocale>( - inProps: LocalizationProviderProps<TDate, TLocale>, -) { +export const LocalizationProvider = function LocalizationProvider< + TDate extends PickerValidDate, + TLocale, +>(inProps: LocalizationProviderProps<TDate, TLocale>) { const { localeText: inLocaleText, ...otherInProps } = inProps; const { utils: parentUtils, localeText: parentLocaleText } = React.useContext( diff --git a/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx b/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx index 33d54782889fa..6453a80e40a31 100644 --- a/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx +++ b/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx @@ -8,14 +8,14 @@ import { useDatePickerDefaultizedProps } from '../DatePicker/shared'; import { useUtils, useLocaleText } from '../internals/hooks/useUtils'; import { validateDate } from '../internals/utils/validation/validateDate'; import { PickerViewRendererLookup } from '../internals/hooks/usePicker/usePickerViews'; -import { DateView } from '../models'; +import { DateView, PickerValidDate } from '../models'; import { DateField } from '../DateField'; import { extractValidationProps } from '../internals/utils/validation/extractValidationProps'; import { singleItemValueManager } from '../internals/utils/valueManagers'; import { renderDateViewCalendar } from '../dateViewRenderers'; import { resolveDateFormat } from '../internals/utils/date-utils'; -type MobileDatePickerComponent = (<TDate>( +type MobileDatePickerComponent = (<TDate extends PickerValidDate>( props: MobileDatePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -29,7 +29,7 @@ type MobileDatePickerComponent = (<TDate>( * * - [MobileDatePicker API](https://mui.com/x/api/date-pickers/mobile-date-picker/) */ -const MobileDatePicker = React.forwardRef(function MobileDatePicker<TDate>( +const MobileDatePicker = React.forwardRef(function MobileDatePicker<TDate extends PickerValidDate>( inProps: MobileDatePickerProps<TDate>, ref: React.Ref<HTMLDivElement>, ) { @@ -113,7 +113,7 @@ MobileDatePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the picker and text field are disabled. * @default false @@ -182,11 +182,11 @@ MobileDatePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Months rendered per row. * @default 3 @@ -278,7 +278,7 @@ MobileDatePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component displaying when passed `loading` true. * @returns {React.ReactNode} The node to render when loading. @@ -378,7 +378,7 @@ MobileDatePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.types.ts b/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.types.ts index 31fb295dbfd76..d6371b06907e5 100644 --- a/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.types.ts +++ b/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.types.ts @@ -9,17 +9,17 @@ import { BaseDatePickerSlotProps, } from '../DatePicker/shared'; import { MakeOptional } from '../internals/models/helpers'; -import { DateView } from '../models'; +import { DateView, PickerValidDate } from '../models'; -export interface MobileDatePickerSlots<TDate> +export interface MobileDatePickerSlots<TDate extends PickerValidDate> extends BaseDatePickerSlots<TDate>, MakeOptional<UseMobilePickerSlots<TDate, DateView>, 'field'> {} -export interface MobileDatePickerSlotProps<TDate> +export interface MobileDatePickerSlotProps<TDate extends PickerValidDate> extends BaseDatePickerSlotProps<TDate>, ExportedUseMobilePickerSlotProps<TDate, DateView> {} -export interface MobileDatePickerProps<TDate> +export interface MobileDatePickerProps<TDate extends PickerValidDate> extends BaseDatePickerProps<TDate>, MobileOnlyPickerProps<TDate> { /** diff --git a/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx b/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx index 4718f0832e3aa..3d4ec9a943da0 100644 --- a/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx +++ b/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx @@ -9,14 +9,14 @@ import { useDateTimePickerDefaultizedProps } from '../DateTimePicker/shared'; import { useLocaleText, useUtils } from '../internals/hooks/useUtils'; import { validateDateTime } from '../internals/utils/validation/validateDateTime'; import { PickerViewRendererLookup } from '../internals/hooks/usePicker/usePickerViews'; -import { DateOrTimeView } from '../models'; +import { DateOrTimeView, PickerValidDate } from '../models'; import { useMobilePicker } from '../internals/hooks/useMobilePicker'; import { extractValidationProps } from '../internals/utils/validation/extractValidationProps'; import { renderDateViewCalendar } from '../dateViewRenderers'; import { renderTimeViewClock } from '../timeViewRenderers'; import { resolveDateTimeFormat } from '../internals/utils/date-time-utils'; -type MobileDateTimePickerComponent = (<TDate>( +type MobileDateTimePickerComponent = (<TDate extends PickerValidDate>( props: MobileDateTimePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -30,10 +30,9 @@ type MobileDateTimePickerComponent = (<TDate>( * * - [MobileDateTimePicker API](https://mui.com/x/api/date-pickers/mobile-date-time-picker/) */ -const MobileDateTimePicker = React.forwardRef(function MobileDateTimePicker<TDate>( - inProps: MobileDateTimePickerProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const MobileDateTimePicker = React.forwardRef(function MobileDateTimePicker< + TDate extends PickerValidDate, +>(inProps: MobileDateTimePickerProps<TDate>, ref: React.Ref<HTMLDivElement>) { const localeText = useLocaleText<TDate>(); const utils = useUtils<TDate>(); @@ -135,7 +134,7 @@ MobileDateTimePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the picker and text field are disabled. * @default false @@ -209,29 +208,29 @@ MobileDateTimePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Maximal selectable moment of time with binding to date, to set max time in each day use `maxTime`. */ - maxDateTime: PropTypes.any, + maxDateTime: PropTypes.object, /** * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Minimal selectable moment of time with binding to date, to set min time in each day use `minTime`. */ - minDateTime: PropTypes.any, + minDateTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -328,7 +327,7 @@ MobileDateTimePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component displaying when passed `loading` true. * @returns {React.ReactNode} The node to render when loading. @@ -436,7 +435,7 @@ MobileDateTimePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.types.ts b/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.types.ts index 29bb903432789..d8b6a4c1d9621 100644 --- a/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.types.ts +++ b/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.types.ts @@ -9,23 +9,23 @@ import { BaseDateTimePickerSlotProps, } from '../DateTimePicker/shared'; import { MakeOptional } from '../internals/models/helpers'; -import { DateOrTimeView } from '../models'; +import { DateOrTimeView, PickerValidDate } from '../models'; import { DateOrTimeViewWithMeridiem } from '../internals/models'; export interface MobileDateTimePickerSlots< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem = DateOrTimeView, > extends BaseDateTimePickerSlots<TDate>, MakeOptional<UseMobilePickerSlots<TDate, TView>, 'field'> {} export interface MobileDateTimePickerSlotProps< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem = DateOrTimeView, > extends BaseDateTimePickerSlotProps<TDate>, ExportedUseMobilePickerSlotProps<TDate, TView> {} export interface MobileDateTimePickerProps< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem = DateOrTimeView, > extends BaseDateTimePickerProps<TDate, TView>, MobileOnlyPickerProps<TDate> { 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 df67f29c014c1..e796cd42c98a5 100644 --- a/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import TextField from '@mui/material/TextField'; import { expect } from 'chai'; import { spy } from 'sinon'; import { fireTouchChangedEvent, screen, userEvent } from '@mui-internal/test-utils'; @@ -31,13 +30,7 @@ describe('<MobileDateTimePicker />', () => { }); it('should render toolbar and tabs by default', () => { - render( - <MobileDateTimePicker - open - value={adapterToUse.date('2021-11-20T10:01:22')} - defaultValue={(params) => <TextField {...params} />} - />, - ); + render(<MobileDateTimePicker open value={adapterToUse.date('2021-11-20T10:01:22')} />); expect(screen.queryByMuiTest('picker-toolbar-title')).not.to.equal(null); expect(screen.getByRole('tab', { name: 'pick date' })).not.to.equal(null); diff --git a/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx b/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx index 242983fde78c7..fc8d5747ef0ea 100644 --- a/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx +++ b/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx @@ -9,13 +9,13 @@ import { useTimePickerDefaultizedProps } from '../TimePicker/shared'; import { useLocaleText, useUtils } from '../internals/hooks/useUtils'; import { PickerViewRendererLookup } from '../internals/hooks/usePicker/usePickerViews'; import { validateTime } from '../internals/utils/validation/validateTime'; -import { TimeView } from '../models'; +import { PickerValidDate, TimeView } from '../models'; import { useMobilePicker } from '../internals/hooks/useMobilePicker'; import { extractValidationProps } from '../internals/utils/validation/extractValidationProps'; import { renderTimeViewClock } from '../timeViewRenderers'; import { resolveTimeFormat } from '../internals/utils/time-utils'; -type MobileTimePickerComponent = (<TDate>( +type MobileTimePickerComponent = (<TDate extends PickerValidDate>( props: MobileTimePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -29,7 +29,7 @@ type MobileTimePickerComponent = (<TDate>( * * - [MobileTimePicker API](https://mui.com/x/api/date-pickers/mobile-time-picker/) */ -const MobileTimePicker = React.forwardRef(function MobileTimePicker<TDate>( +const MobileTimePicker = React.forwardRef(function MobileTimePicker<TDate extends PickerValidDate>( inProps: MobileTimePickerProps<TDate>, ref: React.Ref<HTMLDivElement>, ) { @@ -120,7 +120,7 @@ MobileTimePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the picker and text field are disabled. * @default false @@ -174,12 +174,12 @@ MobileTimePicker.propTypes = { * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -259,7 +259,7 @@ MobileTimePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * The currently selected sections. * This prop accept four formats: @@ -326,7 +326,7 @@ MobileTimePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.types.ts b/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.types.ts index 130e42e7a6b5c..152f1f2402ddf 100644 --- a/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.types.ts +++ b/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.types.ts @@ -9,19 +9,25 @@ import { BaseTimePickerSlotProps, } from '../TimePicker/shared'; import { MakeOptional } from '../internals/models/helpers'; -import { TimeView } from '../models'; +import { PickerValidDate, TimeView } from '../models'; import { TimeViewWithMeridiem } from '../internals/models'; -export interface MobileTimePickerSlots<TDate, TView extends TimeViewWithMeridiem = TimeView> - extends BaseTimePickerSlots<TDate>, +export interface MobileTimePickerSlots< + TDate extends PickerValidDate, + TView extends TimeViewWithMeridiem = TimeView, +> extends BaseTimePickerSlots<TDate>, MakeOptional<UseMobilePickerSlots<TDate, TView>, 'field'> {} -export interface MobileTimePickerSlotProps<TDate, TView extends TimeViewWithMeridiem = TimeView> - extends BaseTimePickerSlotProps, +export interface MobileTimePickerSlotProps< + TDate extends PickerValidDate, + TView extends TimeViewWithMeridiem = TimeView, +> extends BaseTimePickerSlotProps, ExportedUseMobilePickerSlotProps<TDate, TView> {} -export interface MobileTimePickerProps<TDate, TView extends TimeViewWithMeridiem = TimeView> - extends BaseTimePickerProps<TDate, TView>, +export interface MobileTimePickerProps< + TDate extends PickerValidDate, + TView extends TimeViewWithMeridiem = TimeView, +> extends BaseTimePickerProps<TDate, TView>, MobileOnlyPickerProps<TDate> { /** * Overridable component slots. diff --git a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx index d6d5cc1dcb230..a537531d94885 100644 --- a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx +++ b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx @@ -18,6 +18,7 @@ import { singleItemValueManager } from '../internals/utils/valueManagers'; import { SECTION_TYPE_GRANULARITY } from '../internals/utils/getDefaultReferenceDate'; import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone'; import { DIALOG_WIDTH } from '../internals/constants/dimensions'; +import { PickerValidDate } from '../models'; const useUtilityClasses = (ownerState: MonthCalendarProps<any>) => { const { classes } = ownerState; @@ -29,7 +30,7 @@ const useUtilityClasses = (ownerState: MonthCalendarProps<any>) => { return composeClasses(slots, getMonthCalendarUtilityClass, classes); }; -export function useMonthCalendarDefaultizedProps<TDate>( +export function useMonthCalendarDefaultizedProps<TDate extends PickerValidDate>( props: MonthCalendarProps<TDate>, name: string, ): DefaultizedProps< @@ -66,7 +67,7 @@ const MonthCalendarRoot = styled('div', { boxSizing: 'border-box', }); -type MonthCalendarComponent = (<TDate>( +type MonthCalendarComponent = (<TDate extends PickerValidDate>( props: MonthCalendarProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -79,7 +80,7 @@ type MonthCalendarComponent = (<TDate>( * * - [MonthCalendar API](https://mui.com/x/api/date-pickers/month-calendar/) */ -export const MonthCalendar = React.forwardRef(function MonthCalendar<TDate>( +export const MonthCalendar = React.forwardRef(function MonthCalendar<TDate extends PickerValidDate>( inProps: MonthCalendarProps<TDate>, ref: React.Ref<HTMLDivElement>, ) { @@ -314,7 +315,7 @@ MonthCalendar.propTypes = { * The default selected value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true` picker is disabled */ @@ -339,11 +340,11 @@ MonthCalendar.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Months rendered per row. * @default 3 @@ -365,7 +366,7 @@ MonthCalendar.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid month using the validation props, except callbacks such as `shouldDisableMonth`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Disable specific month. * @template TDate @@ -393,5 +394,5 @@ MonthCalendar.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, } as any; diff --git a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.types.ts b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.types.ts index c621ee167c9db..c7a8a148c6f8d 100644 --- a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.types.ts +++ b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.types.ts @@ -2,7 +2,7 @@ import { SxProps } from '@mui/system'; import { Theme } from '@mui/material/styles'; import { MonthCalendarClasses } from './monthCalendarClasses'; import { BaseDateValidationProps, MonthValidationProps } from '../internals/models/validation'; -import { TimezoneProps } from '../models'; +import { PickerValidDate, TimezoneProps } from '../models'; export interface ExportedMonthCalendarProps { /** @@ -11,7 +11,7 @@ export interface ExportedMonthCalendarProps { */ monthsPerRow?: 3 | 4; } -export interface MonthCalendarProps<TDate> +export interface MonthCalendarProps<TDate extends PickerValidDate> extends ExportedMonthCalendarProps, MonthValidationProps<TDate>, BaseDateValidationProps<TDate>, diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx index 0f4fbe64df7ba..3aae2c8dcb262 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx @@ -17,7 +17,7 @@ import { MultiSectionDigitalClockViewProps, } from './MultiSectionDigitalClock.types'; import { getHourSectionOptions, getTimeSectionOptions } from './MultiSectionDigitalClock.utils'; -import { TimeStepOptions, TimeView } from '../models'; +import { PickerValidDate, TimeStepOptions, TimeView } from '../models'; import { TimeViewWithMeridiem } from '../internals/models'; import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone'; import { singleItemValueManager } from '../internals/utils/valueManagers'; @@ -44,7 +44,7 @@ const MultiSectionDigitalClockRoot = styled(PickerViewRoot, { borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, })); -type MultiSectionDigitalClockComponent = (<TDate>( +type MultiSectionDigitalClockComponent = (<TDate extends PickerValidDate>( props: MultiSectionDigitalClockProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -59,7 +59,7 @@ type MultiSectionDigitalClockComponent = (<TDate>( * - [MultiSectionDigitalClock API](https://mui.com/x/api/date-pickers/multi-section-digital-clock/) */ export const MultiSectionDigitalClock = React.forwardRef(function MultiSectionDigitalClock< - TDate extends unknown, + TDate extends PickerValidDate, >(inProps: MultiSectionDigitalClockProps<TDate>, ref: React.Ref<HTMLDivElement>) { const utils = useUtils<TDate>(); @@ -455,7 +455,7 @@ MultiSectionDigitalClock.propTypes = { * The default selected value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the picker views and text field are disabled. * @default false @@ -484,12 +484,12 @@ MultiSectionDigitalClock.propTypes = { * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -532,7 +532,7 @@ MultiSectionDigitalClock.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid time using the validation props, except callbacks such as `shouldDisableTime`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Disable specific time. * @template TDate @@ -586,7 +586,7 @@ MultiSectionDigitalClock.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts index 13fe496fa09fd..31f2ac1d1d73e 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts @@ -1,3 +1,4 @@ +import * as React from 'react'; import { SlotComponentProps } from '@mui/base/utils'; import MenuItem from '@mui/material/MenuItem'; import { MultiSectionDigitalClockClasses } from './multiSectionDigitalClockClasses'; @@ -8,6 +9,7 @@ import { } from '../internals/models/props/clock'; import { MultiSectionDigitalClockSectionProps } from './MultiSectionDigitalClockSection'; import { TimeViewWithMeridiem } from '../internals/models'; +import { PickerValidDate } from '../models'; export interface MultiSectionDigitalClockOption<TValue> { isDisabled?: (value: TValue) => boolean; @@ -18,7 +20,7 @@ export interface MultiSectionDigitalClockOption<TValue> { ariaLabel: string; } -export interface ExportedMultiSectionDigitalClockProps<TDate> +export interface ExportedMultiSectionDigitalClockProps<TDate extends PickerValidDate> extends ExportedBaseClockProps<TDate>, MultiSectionDigitalClockOnlyProps {} @@ -37,7 +39,7 @@ export interface MultiSectionDigitalClockSlotProps { digitalClockSectionItem?: SlotComponentProps<typeof MenuItem, {}, Record<string, any>>; } -export interface MultiSectionDigitalClockProps<TDate> +export interface MultiSectionDigitalClockProps<TDate extends PickerValidDate> extends ExportedMultiSectionDigitalClockProps<TDate>, BaseClockProps<TDate, TimeViewWithMeridiem> { /** diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.utils.ts b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.utils.ts index 660f2a7cf9dff..643fcb5e0c180 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.utils.ts +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.utils.ts @@ -1,7 +1,7 @@ -import { MuiPickersAdapter } from '../models'; +import { MuiPickersAdapter, PickerValidDate } from '../models'; import { MultiSectionDigitalClockOption } from './MultiSectionDigitalClock.types'; -interface IGetHoursSectionOptions<TDate> { +interface IGetHoursSectionOptions<TDate extends PickerValidDate> { now: TDate; value: TDate | null; utils: MuiPickersAdapter<TDate>; @@ -12,7 +12,7 @@ interface IGetHoursSectionOptions<TDate> { valueOrReferenceDate: TDate; } -export const getHourSectionOptions = <TDate>({ +export const getHourSectionOptions = <TDate extends PickerValidDate>({ now, value, utils, @@ -66,7 +66,7 @@ export const getHourSectionOptions = <TDate>({ return result; }; -interface IGetTimeSectionOptions<TDate> { +interface IGetTimeSectionOptions<TDate extends PickerValidDate> { value: number | null; utils: MuiPickersAdapter<TDate>; isDisabled: (value: number) => boolean; @@ -76,7 +76,7 @@ interface IGetTimeSectionOptions<TDate> { resolveAriaLabel: (value: string) => string; } -export const getTimeSectionOptions = <TDate>({ +export const getTimeSectionOptions = <TDate extends PickerValidDate>({ value, utils, isDisabled, diff --git a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx index d3367326fca6f..4edc2507e7390 100644 --- a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx +++ b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx @@ -22,6 +22,7 @@ import { PickersCalendarHeaderOwnerState, PickersCalendarHeaderProps, } from './PickersCalendarHeader.types'; +import { PickerValidDate } from '../models'; const useUtilityClasses = (ownerState: PickersCalendarHeaderOwnerState<any>) => { const { classes } = ownerState; @@ -105,7 +106,7 @@ const PickersCalendarHeaderSwitchViewIcon = styled(ArrowDropDownIcon, { transform: 'rotate(0deg)', })); -type PickersCalendarHeaderComponent = (<TDate>( +type PickersCalendarHeaderComponent = (<TDate extends PickerValidDate>( props: PickersCalendarHeaderProps<TDate> & React.RefAttributes<HTMLButtonElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -120,10 +121,9 @@ type PickersCalendarHeaderComponent = (<TDate>( * * - [PickersCalendarHeader API](https://mui.com/x/api/date-pickers/pickers-calendar-header/) */ -const PickersCalendarHeader = React.forwardRef(function PickersCalendarHeader<TDate>( - inProps: PickersCalendarHeaderProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const PickersCalendarHeader = React.forwardRef(function PickersCalendarHeader< + TDate extends PickerValidDate, +>(inProps: PickersCalendarHeaderProps<TDate>, ref: React.Ref<HTMLDivElement>) { const localeText = useLocaleText<TDate>(); const utils = useUtils<TDate>(); @@ -267,7 +267,7 @@ PickersCalendarHeader.propTypes = { */ classes: PropTypes.object, className: PropTypes.string, - currentMonth: PropTypes.any.isRequired, + currentMonth: PropTypes.object.isRequired, disabled: PropTypes.bool, disableFuture: PropTypes.bool, disablePast: PropTypes.bool, @@ -277,8 +277,8 @@ PickersCalendarHeader.propTypes = { */ format: PropTypes.string, labelId: PropTypes.string, - maxDate: PropTypes.any.isRequired, - minDate: PropTypes.any.isRequired, + maxDate: PropTypes.object.isRequired, + minDate: PropTypes.object.isRequired, onMonthChange: PropTypes.func.isRequired, onViewChange: PropTypes.func, reduceAnimations: PropTypes.bool.isRequired, diff --git a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.types.ts b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.types.ts index 506e6d4ce821f..c2270d128f8e8 100644 --- a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.types.ts +++ b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.types.ts @@ -1,3 +1,4 @@ +import * as React from 'react'; import { SlotComponentProps } from '@mui/base/utils'; import IconButton from '@mui/material/IconButton'; import SvgIcon from '@mui/material/SvgIcon'; @@ -8,7 +9,7 @@ import { PickersArrowSwitcherSlotProps, } from '../internals/components/PickersArrowSwitcher'; import { MonthValidationOptions } from '../internals/hooks/date-helpers-hooks'; -import { DateView } from '../models/views'; +import { PickerValidDate, DateView } from '../models'; import { SlideDirection } from '../DateCalendar/PickersSlideTransition'; import { PickersCalendarHeaderClasses } from './pickersCalendarHeaderClasses'; @@ -28,9 +29,11 @@ export interface PickersCalendarHeaderSlots extends PickersArrowSwitcherSlots { // We keep the interface to allow module augmentation export interface PickersCalendarHeaderSlotPropsOverrides {} -export type PickersCalendarHeaderOwnerState<TDate> = PickersCalendarHeaderProps<TDate>; +export type PickersCalendarHeaderOwnerState<TDate extends PickerValidDate> = + PickersCalendarHeaderProps<TDate>; -export interface PickersCalendarHeaderSlotProps<TDate> extends PickersArrowSwitcherSlotProps { +export interface PickersCalendarHeaderSlotProps<TDate extends PickerValidDate> + extends PickersArrowSwitcherSlotProps { switchViewButton?: SlotComponentProps< typeof IconButton, PickersCalendarHeaderSlotPropsOverrides, @@ -44,7 +47,7 @@ export interface PickersCalendarHeaderSlotProps<TDate> extends PickersArrowSwitc >; } -export interface PickersCalendarHeaderProps<TDate> +export interface PickersCalendarHeaderProps<TDate extends PickerValidDate> extends ExportedPickersArrowSwitcherProps, MonthValidationOptions<TDate> { /** @@ -76,7 +79,7 @@ export interface PickersCalendarHeaderProps<TDate> sx?: SxProps<Theme>; } -export type ExportedPickersCalendarHeaderProps<TDate> = Pick< +export type ExportedPickersCalendarHeaderProps<TDate extends PickerValidDate> = Pick< PickersCalendarHeaderProps<TDate>, 'classes' | 'slots' | 'slotProps' >; diff --git a/packages/x-date-pickers/src/PickersDay/PickersDay.tsx b/packages/x-date-pickers/src/PickersDay/PickersDay.tsx index b226938bc31d7..b0ed7b3ac0eb7 100644 --- a/packages/x-date-pickers/src/PickersDay/PickersDay.tsx +++ b/packages/x-date-pickers/src/PickersDay/PickersDay.tsx @@ -18,6 +18,7 @@ import { getPickersDayUtilityClass, pickersDayClasses, } from './pickersDayClasses'; +import { PickerValidDate } from '../models'; export interface ExportedPickersDayProps { /** @@ -38,7 +39,7 @@ export interface ExportedPickersDayProps { showDaysOutsideCurrentMonth?: boolean; } -export interface PickersDayProps<TDate> +export interface PickersDayProps<TDate extends PickerValidDate> extends ExportedPickersDayProps, Omit< ExtendMui<ButtonBaseProps>, @@ -221,11 +222,11 @@ const PickersDayFiller = styled('div', { const noop = () => {}; -type PickersDayComponent = (<TDate>( +type PickersDayComponent = (<TDate extends PickerValidDate>( props: PickersDayProps<TDate> & React.RefAttributes<HTMLButtonElement>, ) => React.JSX.Element) & { propTypes?: any }; -const PickersDayRaw = React.forwardRef(function PickersDay<TDate>( +const PickersDayRaw = React.forwardRef(function PickersDay<TDate extends PickerValidDate>( inProps: PickersDayProps<TDate>, forwardedRef: React.Ref<HTMLButtonElement>, ) { @@ -373,7 +374,7 @@ PickersDayRaw.propTypes = { /** * The date to show. */ - day: PropTypes.any.isRequired, + day: PropTypes.object.isRequired, /** * If `true`, renders as disabled. * @default false diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx index 4247d58b2f8ab..c76b350f092fb 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx @@ -7,6 +7,7 @@ import { PickersLayoutProps } from './PickersLayout.types'; import { pickersLayoutClasses, getPickersLayoutUtilityClass } from './pickersLayoutClasses'; import usePickerLayout from './usePickerLayout'; import { DateOrTimeViewWithMeridiem } from '../internals/models'; +import { PickerValidDate } from '../models'; const useUtilityClasses = (ownerState: PickersLayoutProps<any, any, any>) => { const { isLandscape, classes } = ownerState; @@ -81,7 +82,7 @@ export const PickersLayoutContentWrapper = styled('div', { */ const PickersLayout = function PickersLayout< TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, >(inProps: PickersLayoutProps<TValue, TDate, TView>) { const props = useThemeProps({ props: inProps, name: 'MuiPickersLayout' }); diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.types.ts b/packages/x-date-pickers/src/PickersLayout/PickersLayout.types.ts index 40e699fc58dc0..27b0b042aae56 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.types.ts +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.types.ts @@ -9,10 +9,11 @@ import { PickersLayoutClasses } from './pickersLayoutClasses'; import { DateOrTimeViewWithMeridiem, WrapperVariant } from '../internals/models/common'; import { PickersShortcutsProps } from '../PickersShortcuts'; import { ExportedPickersShortcutProps } from '../PickersShortcuts/PickersShortcuts'; +import { PickerValidDate } from '../models'; export interface ExportedPickersLayoutSlots< TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, > { /** @@ -34,8 +35,11 @@ export interface ExportedPickersLayoutSlots< >; } -interface PickersLayoutActionBarOwnerState<TValue, TDate, TView extends DateOrTimeViewWithMeridiem> - extends PickersLayoutProps<TValue, TDate, TView> { +interface PickersLayoutActionBarOwnerState< + TValue, + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends PickersLayoutProps<TValue, TDate, TView> { wrapperVariant: WrapperVariant; } @@ -45,7 +49,7 @@ interface PickersShortcutsOwnerState<TValue> extends PickersShortcutsProps<TValu export interface ExportedPickersLayoutSlotProps< TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, > { /** @@ -72,8 +76,11 @@ export interface ExportedPickersLayoutSlotProps< layout?: Partial<PickersLayoutProps<TValue, TDate, TView>>; } -export interface PickersLayoutSlots<TValue, TDate, TView extends DateOrTimeViewWithMeridiem> - extends ExportedPickersLayoutSlots<TValue, TDate, TView> { +export interface PickersLayoutSlots< + TValue, + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends ExportedPickersLayoutSlots<TValue, TDate, TView> { /** * Tabs enabling toggling between views. */ @@ -85,8 +92,11 @@ export interface PickersLayoutSlots<TValue, TDate, TView extends DateOrTimeViewW toolbar?: React.JSXElementConstructor<BaseToolbarProps<TValue, TView>>; } -export interface PickersLayoutSlotProps<TValue, TDate, TView extends DateOrTimeViewWithMeridiem> - extends ExportedPickersLayoutSlotProps<TValue, TDate, TView> { +export interface PickersLayoutSlotProps< + TValue, + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends ExportedPickersLayoutSlotProps<TValue, TDate, TView> { /** * Props passed down to the tabs component. */ @@ -97,8 +107,11 @@ export interface PickersLayoutSlotProps<TValue, TDate, TView extends DateOrTimeV toolbar?: ExportedBaseToolbarProps; } -export interface PickersLayoutProps<TValue, TDate, TView extends DateOrTimeViewWithMeridiem> - extends Omit<UsePickerLayoutPropsResponseLayoutProps<TValue, TView>, 'value'> { +export interface PickersLayoutProps< + TValue, + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends Omit<UsePickerLayoutPropsResponseLayoutProps<TValue, TView>, 'value'> { value?: TValue; className?: string; children?: React.ReactNode; diff --git a/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx b/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx index 8ba6c1afa4f5e..186649d43cd7d 100644 --- a/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx @@ -7,6 +7,7 @@ import { getPickersLayoutUtilityClass } from './pickersLayoutClasses'; import { PickersShortcuts } from '../PickersShortcuts'; import { BaseToolbarProps } from '../internals/models/props/toolbar'; import { DateOrTimeViewWithMeridiem } from '../internals/models'; +import { PickerValidDate } from '../models'; function toolbarHasView<TValue, TView extends DateOrTimeViewWithMeridiem>( toolbarProps: BaseToolbarProps<TValue, TView> | any, @@ -31,14 +32,18 @@ const useUtilityClasses = (ownerState: PickersLayoutProps<any, any, any>) => { interface PickersLayoutPropsWithValueRequired< TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, > extends PickersLayoutProps<TValue, TDate, TView> { value: TValue; } interface UsePickerLayoutResponse<TValue> extends SubComponents<TValue> {} -const usePickerLayout = <TValue, TDate, TView extends DateOrTimeViewWithMeridiem>( +const usePickerLayout = < + TValue, + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +>( props: PickersLayoutProps<TValue, TDate, TView>, ): UsePickerLayoutResponse<TValue> => { const { diff --git a/packages/x-date-pickers/src/StaticDatePicker/StaticDatePicker.tsx b/packages/x-date-pickers/src/StaticDatePicker/StaticDatePicker.tsx index f15751cb36d15..fe7afbb4b72fc 100644 --- a/packages/x-date-pickers/src/StaticDatePicker/StaticDatePicker.tsx +++ b/packages/x-date-pickers/src/StaticDatePicker/StaticDatePicker.tsx @@ -5,11 +5,11 @@ import { useDatePickerDefaultizedProps } from '../DatePicker/shared'; import { renderDateViewCalendar } from '../dateViewRenderers'; import { useStaticPicker } from '../internals/hooks/useStaticPicker'; import { validateDate } from '../internals/utils/validation/validateDate'; -import { DateView } from '../models'; +import { DateView, PickerValidDate } from '../models'; import { singleItemValueManager } from '../internals/utils/valueManagers'; import { PickerViewRendererLookup } from '../internals/hooks/usePicker/usePickerViews'; -type StaticDatePickerComponent = (<TDate>( +type StaticDatePickerComponent = (<TDate extends PickerValidDate>( props: StaticDatePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -23,7 +23,7 @@ type StaticDatePickerComponent = (<TDate>( * * - [StaticDatePicker API](https://mui.com/x/api/date-pickers/static-date-picker/) */ -const StaticDatePicker = React.forwardRef(function StaticDatePicker<TDate>( +const StaticDatePicker = React.forwardRef(function StaticDatePicker<TDate extends PickerValidDate>( inProps: StaticDatePickerProps<TDate>, ref: React.Ref<HTMLDivElement>, ) { @@ -91,7 +91,7 @@ StaticDatePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the picker and text field are disabled. * @default false @@ -141,11 +141,11 @@ StaticDatePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Months rendered per row. * @default 3 @@ -219,7 +219,7 @@ StaticDatePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component displaying when passed `loading` true. * @returns {React.ReactNode} The node to render when loading. @@ -291,7 +291,7 @@ StaticDatePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/StaticDatePicker/StaticDatePicker.types.ts b/packages/x-date-pickers/src/StaticDatePicker/StaticDatePicker.types.ts index de183ec323e96..64a84459d9b4e 100644 --- a/packages/x-date-pickers/src/StaticDatePicker/StaticDatePicker.types.ts +++ b/packages/x-date-pickers/src/StaticDatePicker/StaticDatePicker.types.ts @@ -9,17 +9,17 @@ import { UseStaticPickerSlotProps, } from '../internals/hooks/useStaticPicker'; import { MakeOptional } from '../internals/models/helpers'; -import { DateView } from '../models'; +import { DateView, PickerValidDate } from '../models'; -export interface StaticDatePickerSlots<TDate> +export interface StaticDatePickerSlots<TDate extends PickerValidDate> extends BaseDatePickerSlots<TDate>, UseStaticPickerSlots<TDate, DateView> {} -export interface StaticDatePickerSlotProps<TDate> +export interface StaticDatePickerSlotProps<TDate extends PickerValidDate> extends BaseDatePickerSlotProps<TDate>, UseStaticPickerSlotProps<TDate, DateView> {} -export interface StaticDatePickerProps<TDate> +export interface StaticDatePickerProps<TDate extends PickerValidDate> extends BaseDatePickerProps<TDate>, MakeOptional<StaticOnlyPickerProps, 'displayStaticWrapperAs'> { /** diff --git a/packages/x-date-pickers/src/StaticDateTimePicker/StaticDateTimePicker.tsx b/packages/x-date-pickers/src/StaticDateTimePicker/StaticDateTimePicker.tsx index 7e60ab686782c..e47845d169c97 100644 --- a/packages/x-date-pickers/src/StaticDateTimePicker/StaticDateTimePicker.tsx +++ b/packages/x-date-pickers/src/StaticDateTimePicker/StaticDateTimePicker.tsx @@ -6,11 +6,11 @@ import { renderTimeViewClock } from '../timeViewRenderers'; import { renderDateViewCalendar } from '../dateViewRenderers'; import { singleItemValueManager } from '../internals/utils/valueManagers'; import { useStaticPicker } from '../internals/hooks/useStaticPicker'; -import { DateOrTimeView } from '../models'; +import { DateOrTimeView, PickerValidDate } from '../models'; import { validateDateTime } from '../internals/utils/validation/validateDateTime'; import { PickerViewRendererLookup } from '../internals/hooks/usePicker/usePickerViews'; -type StaticDateTimePickerComponent = (<TDate>( +type StaticDateTimePickerComponent = (<TDate extends PickerValidDate>( props: StaticDateTimePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -24,10 +24,9 @@ type StaticDateTimePickerComponent = (<TDate>( * * - [StaticDateTimePicker API](https://mui.com/x/api/date-pickers/static-date-time-picker/) */ -const StaticDateTimePicker = React.forwardRef(function StaticDateTimePicker<TDate>( - inProps: StaticDateTimePickerProps<TDate>, - ref: React.Ref<HTMLDivElement>, -) { +const StaticDateTimePicker = React.forwardRef(function StaticDateTimePicker< + TDate extends PickerValidDate, +>(inProps: StaticDateTimePickerProps<TDate>, ref: React.Ref<HTMLDivElement>) { const defaultizedProps = useDateTimePickerDefaultizedProps< TDate, DateOrTimeView, @@ -113,7 +112,7 @@ StaticDateTimePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the picker and text field are disabled. * @default false @@ -168,29 +167,29 @@ StaticDateTimePicker.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Maximal selectable moment of time with binding to date, to set max time in each day use `maxTime`. */ - maxDateTime: PropTypes.any, + maxDateTime: PropTypes.object, /** * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Minimal selectable moment of time with binding to date, to set min time in each day use `minTime`. */ - minDateTime: PropTypes.any, + minDateTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -269,7 +268,7 @@ StaticDateTimePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Component displaying when passed `loading` true. * @returns {React.ReactNode} The node to render when loading. @@ -349,7 +348,7 @@ StaticDateTimePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/StaticDateTimePicker/StaticDateTimePicker.types.ts b/packages/x-date-pickers/src/StaticDateTimePicker/StaticDateTimePicker.types.ts index ead81f65a0387..e154e31b80982 100644 --- a/packages/x-date-pickers/src/StaticDateTimePicker/StaticDateTimePicker.types.ts +++ b/packages/x-date-pickers/src/StaticDateTimePicker/StaticDateTimePicker.types.ts @@ -9,17 +9,17 @@ import { UseStaticPickerSlotProps, } from '../internals/hooks/useStaticPicker'; import { MakeOptional } from '../internals/models/helpers'; -import { DateOrTimeView } from '../models'; +import { DateOrTimeView, PickerValidDate } from '../models'; -export interface StaticDateTimePickerSlots<TDate> +export interface StaticDateTimePickerSlots<TDate extends PickerValidDate> extends BaseDateTimePickerSlots<TDate>, UseStaticPickerSlots<TDate, DateOrTimeView> {} -export interface StaticDateTimePickerSlotProps<TDate> +export interface StaticDateTimePickerSlotProps<TDate extends PickerValidDate> extends BaseDateTimePickerSlotProps<TDate>, UseStaticPickerSlotProps<TDate, DateOrTimeView> {} -export interface StaticDateTimePickerProps<TDate> +export interface StaticDateTimePickerProps<TDate extends PickerValidDate> extends BaseDateTimePickerProps<TDate, DateOrTimeView>, MakeOptional<StaticOnlyPickerProps, 'displayStaticWrapperAs'> { /** diff --git a/packages/x-date-pickers/src/StaticTimePicker/StaticTimePicker.tsx b/packages/x-date-pickers/src/StaticTimePicker/StaticTimePicker.tsx index a5b99754c2eaf..aaf03d7301f18 100644 --- a/packages/x-date-pickers/src/StaticTimePicker/StaticTimePicker.tsx +++ b/packages/x-date-pickers/src/StaticTimePicker/StaticTimePicker.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { TimeView } from '../models'; +import { PickerValidDate, TimeView } from '../models'; import { StaticTimePickerProps } from './StaticTimePicker.types'; import { useTimePickerDefaultizedProps } from '../TimePicker/shared'; import { renderTimeViewClock } from '../timeViewRenderers'; @@ -9,7 +9,7 @@ import { useStaticPicker } from '../internals/hooks/useStaticPicker'; import { validateTime } from '../internals/utils/validation/validateTime'; import { PickerViewRendererLookup } from '../internals/hooks/usePicker/usePickerViews'; -type StaticTimePickerComponent = (<TDate>( +type StaticTimePickerComponent = (<TDate extends PickerValidDate>( props: StaticTimePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -23,7 +23,7 @@ type StaticTimePickerComponent = (<TDate>( * * - [StaticTimePicker API](https://mui.com/x/api/date-pickers/static-time-picker/) */ -const StaticTimePicker = React.forwardRef(function StaticTimePicker<TDate>( +const StaticTimePicker = React.forwardRef(function StaticTimePicker<TDate extends PickerValidDate>( inProps: StaticTimePickerProps<TDate>, ref: React.Ref<HTMLDivElement>, ) { @@ -97,7 +97,7 @@ StaticTimePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the picker and text field are disabled. * @default false @@ -132,12 +132,12 @@ StaticTimePicker.propTypes = { * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -199,7 +199,7 @@ StaticTimePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Disable specific time. * @template TDate @@ -238,7 +238,7 @@ StaticTimePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/StaticTimePicker/StaticTimePicker.types.ts b/packages/x-date-pickers/src/StaticTimePicker/StaticTimePicker.types.ts index b55a15bd0714a..70d04cbe841af 100644 --- a/packages/x-date-pickers/src/StaticTimePicker/StaticTimePicker.types.ts +++ b/packages/x-date-pickers/src/StaticTimePicker/StaticTimePicker.types.ts @@ -9,17 +9,17 @@ import { UseStaticPickerSlotProps, } from '../internals/hooks/useStaticPicker'; import { MakeOptional } from '../internals/models/helpers'; -import { TimeView } from '../models'; +import { PickerValidDate, TimeView } from '../models'; -export interface StaticTimePickerSlots<TDate> +export interface StaticTimePickerSlots<TDate extends PickerValidDate> extends BaseTimePickerSlots<TDate>, UseStaticPickerSlots<TDate, TimeView> {} -export interface StaticTimePickerSlotProps<TDate> +export interface StaticTimePickerSlotProps<TDate extends PickerValidDate> extends BaseTimePickerSlotProps, UseStaticPickerSlotProps<TDate, TimeView> {} -export interface StaticTimePickerProps<TDate> +export interface StaticTimePickerProps<TDate extends PickerValidDate> extends BaseTimePickerProps<TDate, TimeView>, MakeOptional<StaticOnlyPickerProps, 'displayStaticWrapperAs'> { /** diff --git a/packages/x-date-pickers/src/TimeClock/Clock.tsx b/packages/x-date-pickers/src/TimeClock/Clock.tsx index b4080f100f6d3..8b15624405619 100644 --- a/packages/x-date-pickers/src/TimeClock/Clock.tsx +++ b/packages/x-date-pickers/src/TimeClock/Clock.tsx @@ -12,11 +12,12 @@ import { useLocaleText, useUtils } from '../internals/hooks/useUtils'; import type { PickerSelectionState } from '../internals/hooks/usePicker'; import { useMeridiemMode } from '../internals/hooks/date-helpers-hooks'; import { CLOCK_HOUR_WIDTH, getHours, getMinutes } from './shared'; -import { TimeView } from '../models'; +import { PickerValidDate, TimeView } from '../models'; import { ClockClasses, getClockUtilityClass } from './clockClasses'; import { formatMeridiem } from '../internals/utils/date-utils'; -export interface ClockProps<TDate> extends ReturnType<typeof useMeridiemMode> { +export interface ClockProps<TDate extends PickerValidDate> + extends ReturnType<typeof useMeridiemMode> { ampm: boolean; ampmInClock: boolean; autoFocus?: boolean; @@ -195,7 +196,7 @@ const ClockMeridiemText = styled(Typography, { /** * @ignore - internal component. */ -export function Clock<TDate>(inProps: ClockProps<TDate>) { +export function Clock<TDate extends PickerValidDate>(inProps: ClockProps<TDate>) { const props = useThemeProps({ props: inProps, name: 'MuiClock' }); const { ampm, diff --git a/packages/x-date-pickers/src/TimeClock/ClockNumbers.tsx b/packages/x-date-pickers/src/TimeClock/ClockNumbers.tsx index 19188dad42796..28c34d15caf5b 100644 --- a/packages/x-date-pickers/src/TimeClock/ClockNumbers.tsx +++ b/packages/x-date-pickers/src/TimeClock/ClockNumbers.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import { ClockNumber } from './ClockNumber'; -import { MuiPickersAdapter } from '../models'; +import { MuiPickersAdapter, PickerValidDate } from '../models'; import type { PickerSelectionState } from '../internals/hooks/usePicker'; -interface GetHourNumbersOptions<TDate> { +interface GetHourNumbersOptions<TDate extends PickerValidDate> { ampm: boolean; value: TDate | null; getClockNumberText: (hour: string) => string; @@ -20,7 +20,7 @@ interface GetHourNumbersOptions<TDate> { /** * @ignore - internal component. */ -export const getHourNumbers = <TDate extends unknown>({ +export const getHourNumbers = <TDate extends PickerValidDate>({ ampm, value, getClockNumberText, @@ -79,7 +79,7 @@ export const getHourNumbers = <TDate extends unknown>({ return hourNumbers; }; -export const getMinutesNumbers = <TDate extends unknown>({ +export const getMinutesNumbers = <TDate extends PickerValidDate>({ utils, value, isDisabled, diff --git a/packages/x-date-pickers/src/TimeClock/TimeClock.tsx b/packages/x-date-pickers/src/TimeClock/TimeClock.tsx index 93b8e6625af79..2e2e4186fe2da 100644 --- a/packages/x-date-pickers/src/TimeClock/TimeClock.tsx +++ b/packages/x-date-pickers/src/TimeClock/TimeClock.tsx @@ -9,7 +9,7 @@ import { convertValueToMeridiem, createIsAfterIgnoreDatePart } from '../internal import { useViews } from '../internals/hooks/useViews'; import type { PickerSelectionState } from '../internals/hooks/usePicker'; import { useMeridiemMode } from '../internals/hooks/date-helpers-hooks'; -import { TimeView } from '../models'; +import { PickerValidDate, TimeView } from '../models'; import { PickerViewRoot } from '../internals/components/PickerViewRoot'; import { getTimeClockUtilityClass } from './timeClockClasses'; import { Clock, ClockProps } from './Clock'; @@ -49,7 +49,7 @@ const TimeClockArrowSwitcher = styled(PickersArrowSwitcher, { top: 15, }); -type TimeClockComponent = (<TDate>( +type TimeClockComponent = (<TDate extends PickerValidDate>( props: TimeClockProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -65,7 +65,7 @@ const TIME_CLOCK_DEFAULT_VIEWS: TimeView[] = ['hours', 'minutes']; * * - [TimeClock API](https://mui.com/x/api/date-pickers/time-clock/) */ -export const TimeClock = React.forwardRef(function TimeClock<TDate extends unknown>( +export const TimeClock = React.forwardRef(function TimeClock<TDate extends PickerValidDate>( inProps: TimeClockProps<TDate>, ref: React.Ref<HTMLDivElement>, ) { @@ -417,7 +417,7 @@ TimeClock.propTypes = { * The default selected value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the picker views and text field are disabled. * @default false @@ -446,12 +446,12 @@ TimeClock.propTypes = { * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -494,7 +494,7 @@ TimeClock.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid time using the validation props, except callbacks such as `shouldDisableTime`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Disable specific time. * @template TDate @@ -534,7 +534,7 @@ TimeClock.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/TimeClock/TimeClock.types.ts b/packages/x-date-pickers/src/TimeClock/TimeClock.types.ts index afb3a935e5531..fda54930f817a 100644 --- a/packages/x-date-pickers/src/TimeClock/TimeClock.types.ts +++ b/packages/x-date-pickers/src/TimeClock/TimeClock.types.ts @@ -4,10 +4,11 @@ import { PickersArrowSwitcherSlotProps, } from '../internals/components/PickersArrowSwitcher'; import { BaseClockProps, ExportedBaseClockProps } from '../internals/models/props/clock'; -import { TimeView } from '../models'; +import { PickerValidDate, TimeView } from '../models'; import { TimeViewWithMeridiem } from '../internals/models'; -export interface ExportedTimeClockProps<TDate> extends ExportedBaseClockProps<TDate> { +export interface ExportedTimeClockProps<TDate extends PickerValidDate> + extends ExportedBaseClockProps<TDate> { /** * Display ampm controls under the clock (instead of in the toolbar). * @default false @@ -19,8 +20,10 @@ export interface TimeClockSlots extends PickersArrowSwitcherSlots {} export interface TimeClockSlotProps extends PickersArrowSwitcherSlotProps {} -export interface TimeClockProps<TDate, TView extends TimeViewWithMeridiem = TimeView> - extends ExportedTimeClockProps<TDate>, +export interface TimeClockProps< + TDate extends PickerValidDate, + TView extends TimeViewWithMeridiem = TimeView, +> extends ExportedTimeClockProps<TDate>, BaseClockProps<TDate, TView> { /** * Available views. diff --git a/packages/x-date-pickers/src/TimeField/TimeField.tsx b/packages/x-date-pickers/src/TimeField/TimeField.tsx index 495ae41d528ec..612df5b2f35a2 100644 --- a/packages/x-date-pickers/src/TimeField/TimeField.tsx +++ b/packages/x-date-pickers/src/TimeField/TimeField.tsx @@ -8,8 +8,9 @@ import { TimeFieldProps, TimeFieldSlotProps } from './TimeField.types'; import { useTimeField } from './useTimeField'; import { useClearableField } from '../hooks'; import { convertFieldResponseIntoMuiTextFieldProps } from '../internals/utils/convertFieldResponseIntoMuiTextFieldProps'; +import { PickerValidDate } from '../models'; -type TimeFieldComponent = (<TDate>( +type TimeFieldComponent = (<TDate extends PickerValidDate>( props: TimeFieldProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -23,7 +24,7 @@ type TimeFieldComponent = (<TDate>( * * - [TimeField API](https://mui.com/x/api/date-pickers/time-field/) */ -const TimeField = React.forwardRef(function TimeField<TDate>( +const TimeField = React.forwardRef(function TimeField<TDate extends PickerValidDate>( inProps: TimeFieldProps<TDate>, inRef: React.Ref<HTMLDivElement>, ) { @@ -100,7 +101,7 @@ TimeField.propTypes = { /** * The default value. Use when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true`, the component is disabled. * @default false @@ -193,12 +194,12 @@ TimeField.propTypes = { * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -246,7 +247,7 @@ TimeField.propTypes = { * For example, on time fields it will be used to determine the date to set. * @default The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * If `true`, the label is displayed as required and the `input` element is required. * @default false @@ -342,7 +343,7 @@ TimeField.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The variant to use. * @default 'outlined' diff --git a/packages/x-date-pickers/src/TimeField/TimeField.types.ts b/packages/x-date-pickers/src/TimeField/TimeField.types.ts index 46c7b4659e5b2..b78ed842f6f30 100644 --- a/packages/x-date-pickers/src/TimeField/TimeField.types.ts +++ b/packages/x-date-pickers/src/TimeField/TimeField.types.ts @@ -5,10 +5,10 @@ import { UseFieldInternalProps } from '../internals/hooks/useField'; import { DefaultizedProps, MakeOptional } from '../internals/models/helpers'; import { BaseTimeValidationProps, TimeValidationProps } from '../internals/models/validation'; import { FieldsTextFieldProps } from '../internals/models/fields'; -import { FieldSection, TimeValidationError } from '../models'; +import { FieldSection, PickerValidDate, TimeValidationError } from '../models'; import { UseClearableFieldSlots, UseClearableFieldSlotProps } from '../hooks/useClearableField'; -export interface UseTimeFieldProps<TDate> +export interface UseTimeFieldProps<TDate extends PickerValidDate> extends MakeOptional< UseFieldInternalProps<TDate | null, TDate, FieldSection, TimeValidationError>, 'format' @@ -22,18 +22,17 @@ export interface UseTimeFieldProps<TDate> ampm?: boolean; } -export type UseTimeFieldDefaultizedProps<TDate> = DefaultizedProps< +export type UseTimeFieldDefaultizedProps<TDate extends PickerValidDate> = DefaultizedProps< UseTimeFieldProps<TDate>, keyof BaseTimeValidationProps | 'format' >; -export type UseTimeFieldComponentProps<TDate, TChildProps extends {}> = Omit< - TChildProps, - keyof UseTimeFieldProps<TDate> -> & - UseTimeFieldProps<TDate>; +export type UseTimeFieldComponentProps< + TDate extends PickerValidDate, + TChildProps extends {}, +> = Omit<TChildProps, keyof UseTimeFieldProps<TDate>> & UseTimeFieldProps<TDate>; -export interface TimeFieldProps<TDate> +export interface TimeFieldProps<TDate extends PickerValidDate> extends UseTimeFieldComponentProps<TDate, FieldsTextFieldProps> { /** * Overridable component slots. @@ -47,7 +46,7 @@ export interface TimeFieldProps<TDate> slotProps?: TimeFieldSlotProps<TDate>; } -export type TimeFieldOwnerState<TDate> = TimeFieldProps<TDate>; +export type TimeFieldOwnerState<TDate extends PickerValidDate> = TimeFieldProps<TDate>; export interface TimeFieldSlots extends UseClearableFieldSlots { /** @@ -58,6 +57,7 @@ export interface TimeFieldSlots extends UseClearableFieldSlots { textField?: React.ElementType; } -export interface TimeFieldSlotProps<TDate> extends UseClearableFieldSlotProps { +export interface TimeFieldSlotProps<TDate extends PickerValidDate> + extends UseClearableFieldSlotProps { textField?: SlotComponentProps<typeof TextField, {}, TimeFieldOwnerState<TDate>>; } diff --git a/packages/x-date-pickers/src/TimeField/useTimeField.ts b/packages/x-date-pickers/src/TimeField/useTimeField.ts index fdaf7485cbf8a..1c6cf0089253e 100644 --- a/packages/x-date-pickers/src/TimeField/useTimeField.ts +++ b/packages/x-date-pickers/src/TimeField/useTimeField.ts @@ -11,8 +11,9 @@ import { import { validateTime } from '../internals/utils/validation/validateTime'; import { useUtils } from '../internals/hooks/useUtils'; import { splitFieldInternalAndForwardedProps } from '../internals/utils/fields'; +import { PickerValidDate } from '../models'; -const useDefaultizedTimeField = <TDate, AdditionalProps extends {}>( +const useDefaultizedTimeField = <TDate extends PickerValidDate, AdditionalProps extends {}>( props: UseTimeFieldProps<TDate>, ): AdditionalProps & UseTimeFieldDefaultizedProps<TDate> => { const utils = useUtils<TDate>(); @@ -28,7 +29,7 @@ const useDefaultizedTimeField = <TDate, AdditionalProps extends {}>( } as any; }; -export const useTimeField = <TDate, TChildProps extends {}>( +export const useTimeField = <TDate extends PickerValidDate, TChildProps extends {}>( inProps: UseTimeFieldComponentProps<TDate, TChildProps>, ) => { const props = useDefaultizedTimeField<TDate, TChildProps>(inProps); diff --git a/packages/x-date-pickers/src/TimePicker/TimePicker.tsx b/packages/x-date-pickers/src/TimePicker/TimePicker.tsx index b78288e0e7872..0928d469cc9c8 100644 --- a/packages/x-date-pickers/src/TimePicker/TimePicker.tsx +++ b/packages/x-date-pickers/src/TimePicker/TimePicker.tsx @@ -7,8 +7,9 @@ import { DesktopTimePicker } from '../DesktopTimePicker'; import { MobileTimePicker, MobileTimePickerProps } from '../MobileTimePicker'; import { TimePickerProps } from './TimePicker.types'; import { DEFAULT_DESKTOP_MODE_MEDIA_QUERY } from '../internals/utils/utils'; +import { PickerValidDate } from '../models'; -type TimePickerComponent = (<TDate>( +type TimePickerComponent = (<TDate extends PickerValidDate>( props: TimePickerProps<TDate> & React.RefAttributes<HTMLDivElement>, ) => React.JSX.Element) & { propTypes?: any }; @@ -22,7 +23,7 @@ type TimePickerComponent = (<TDate>( * * - [TimePicker API](https://mui.com/x/api/date-pickers/time-picker/) */ -const TimePicker = React.forwardRef(function TimePicker<TDate>( +const TimePicker = React.forwardRef(function TimePicker<TDate extends PickerValidDate>( inProps: TimePickerProps<TDate>, ref: React.Ref<HTMLDivElement>, ) { @@ -72,7 +73,7 @@ TimePicker.propTypes = { * The default value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * CSS media query when `Mobile` mode will be changed to `Desktop`. * @default '@media (pointer: fine)' @@ -132,12 +133,12 @@ TimePicker.propTypes = { * Maximal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxTime: PropTypes.any, + maxTime: PropTypes.object, /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minTime: PropTypes.any, + minTime: PropTypes.object, /** * Step over minutes. * @default 1 @@ -217,7 +218,7 @@ TimePicker.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * The currently selected sections. * This prop accept four formats: @@ -305,7 +306,7 @@ TimePicker.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * The visible view. * Used when the component view is controlled. diff --git a/packages/x-date-pickers/src/TimePicker/TimePicker.types.ts b/packages/x-date-pickers/src/TimePicker/TimePicker.types.ts index 3bf24d7725e1b..5561198004888 100644 --- a/packages/x-date-pickers/src/TimePicker/TimePicker.types.ts +++ b/packages/x-date-pickers/src/TimePicker/TimePicker.types.ts @@ -9,16 +9,17 @@ import { MobileTimePickerSlots, MobileTimePickerSlotProps, } from '../MobileTimePicker'; +import { PickerValidDate } from '../models'; -export interface TimePickerSlots<TDate> +export interface TimePickerSlots<TDate extends PickerValidDate> extends DesktopTimePickerSlots<TDate>, MobileTimePickerSlots<TDate, TimeViewWithMeridiem> {} -export interface TimePickerSlotProps<TDate> +export interface TimePickerSlotProps<TDate extends PickerValidDate> extends DesktopTimePickerSlotProps<TDate>, MobileTimePickerSlotProps<TDate, TimeViewWithMeridiem> {} -export interface TimePickerProps<TDate> +export interface TimePickerProps<TDate extends PickerValidDate> extends DesktopTimePickerProps<TDate>, Omit<MobileTimePickerProps<TDate, TimeViewWithMeridiem>, 'views'> { /** diff --git a/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx b/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx index 89151a022a9e5..78614cdb22f21 100644 --- a/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx +++ b/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx @@ -16,8 +16,9 @@ import { } from './timePickerToolbarClasses'; import { TimeViewWithMeridiem } from '../internals/models'; import { formatMeridiem } from '../internals/utils/date-utils'; +import { PickerValidDate } from '../models'; -export interface TimePickerToolbarProps<TDate> +export interface TimePickerToolbarProps<TDate extends PickerValidDate> extends BaseToolbarProps<TDate | null, TimeViewWithMeridiem> { ampm?: boolean; ampmInClock?: boolean; @@ -153,7 +154,7 @@ TimePickerToolbarAmPmSelection.propTypes = { * * - [TimePickerToolbar API](https://mui.com/x/api/date-pickers/time-picker-toolbar/) */ -function TimePickerToolbar<TDate extends unknown>(inProps: TimePickerToolbarProps<TDate>) { +function TimePickerToolbar<TDate extends PickerValidDate>(inProps: TimePickerToolbarProps<TDate>) { const props = useThemeProps({ props: inProps, name: 'MuiTimePickerToolbar' }); const { ampm, @@ -302,7 +303,7 @@ TimePickerToolbar.propTypes = { * @default "––" */ toolbarPlaceholder: PropTypes.node, - value: PropTypes.any, + value: PropTypes.object, /** * Currently visible picker view. */ diff --git a/packages/x-date-pickers/src/TimePicker/shared.tsx b/packages/x-date-pickers/src/TimePicker/shared.tsx index b1812f13fb69e..763948a3398ad 100644 --- a/packages/x-date-pickers/src/TimePicker/shared.tsx +++ b/packages/x-date-pickers/src/TimePicker/shared.tsx @@ -11,14 +11,14 @@ import { ExportedTimePickerToolbarProps, TimePickerToolbar, } from './TimePickerToolbar'; -import { TimeValidationError } from '../models'; +import { PickerValidDate, TimeValidationError } from '../models'; import { PickerViewRendererLookup } from '../internals/hooks/usePicker/usePickerViews'; import { TimeViewRendererProps } from '../timeViewRenderers'; import { applyDefaultViewProps } from '../internals/utils/views'; import { BaseClockProps, ExportedBaseClockProps } from '../internals/models/props/clock'; import { TimeViewWithMeridiem } from '../internals/models'; -export interface BaseTimePickerSlots<TDate> extends TimeClockSlots { +export interface BaseTimePickerSlots<TDate extends PickerValidDate> extends TimeClockSlots { /** * Custom component for the toolbar rendered above the views. * @default TimePickerToolbar @@ -30,8 +30,10 @@ export interface BaseTimePickerSlotProps extends TimeClockSlotProps { toolbar?: ExportedTimePickerToolbarProps; } -export interface BaseTimePickerProps<TDate, TView extends TimeViewWithMeridiem> - extends BasePickerInputProps<TDate | null, TDate, TView, TimeValidationError>, +export interface BaseTimePickerProps< + TDate extends PickerValidDate, + TView extends TimeViewWithMeridiem, +> extends BasePickerInputProps<TDate | null, TDate, TView, TimeValidationError>, ExportedBaseClockProps<TDate> { /** * Display ampm controls under the clock (instead of in the toolbar). @@ -64,7 +66,7 @@ export interface BaseTimePickerProps<TDate, TView extends TimeViewWithMeridiem> } type UseTimePickerDefaultizedProps< - TDate, + TDate extends PickerValidDate, TView extends TimeViewWithMeridiem, Props extends BaseTimePickerProps<TDate, TView>, > = LocalizedComponent< @@ -73,7 +75,7 @@ type UseTimePickerDefaultizedProps< >; export function useTimePickerDefaultizedProps< - TDate, + TDate extends PickerValidDate, TView extends TimeViewWithMeridiem, Props extends BaseTimePickerProps<TDate, TView>, >(props: Props, name: string): UseTimePickerDefaultizedProps<TDate, TView, Props> { diff --git a/packages/x-date-pickers/src/YearCalendar/YearCalendar.tsx b/packages/x-date-pickers/src/YearCalendar/YearCalendar.tsx index d7e5ef3dfaa82..678c512bad34e 100644 --- a/packages/x-date-pickers/src/YearCalendar/YearCalendar.tsx +++ b/packages/x-date-pickers/src/YearCalendar/YearCalendar.tsx @@ -19,6 +19,7 @@ import { singleItemValueManager } from '../internals/utils/valueManagers'; import { SECTION_TYPE_GRANULARITY } from '../internals/utils/getDefaultReferenceDate'; import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone'; import { DIALOG_WIDTH, MAX_CALENDAR_HEIGHT } from '../internals/constants/dimensions'; +import { PickerValidDate } from '../models'; const useUtilityClasses = (ownerState: YearCalendarProps<any>) => { const { classes } = ownerState; @@ -30,7 +31,7 @@ const useUtilityClasses = (ownerState: YearCalendarProps<any>) => { return composeClasses(slots, getYearCalendarUtilityClass, classes); }; -function useYearCalendarDefaultizedProps<TDate>( +function useYearCalendarDefaultizedProps<TDate extends PickerValidDate>( props: YearCalendarProps<TDate>, name: string, ): DefaultizedProps< @@ -72,7 +73,9 @@ const YearCalendarRoot = styled('div', { position: 'relative', }); -type YearCalendarComponent = (<TDate>(props: YearCalendarProps<TDate>) => React.JSX.Element) & { +type YearCalendarComponent = (<TDate extends PickerValidDate>( + props: YearCalendarProps<TDate>, +) => React.JSX.Element) & { propTypes?: any; }; @@ -85,7 +88,7 @@ type YearCalendarComponent = (<TDate>(props: YearCalendarProps<TDate>) => React. * * - [YearCalendar API](https://mui.com/x/api/date-pickers/year-calendar/) */ -export const YearCalendar = React.forwardRef(function YearCalendar<TDate>( +export const YearCalendar = React.forwardRef(function YearCalendar<TDate extends PickerValidDate>( inProps: YearCalendarProps<TDate>, ref: React.Ref<HTMLDivElement>, ) { @@ -331,7 +334,7 @@ YearCalendar.propTypes = { * The default selected value. * Used when the component is not controlled. */ - defaultValue: PropTypes.any, + defaultValue: PropTypes.object, /** * If `true` picker is disabled */ @@ -356,11 +359,11 @@ YearCalendar.propTypes = { /** * Maximal selectable date. */ - maxDate: PropTypes.any, + maxDate: PropTypes.object, /** * Minimal selectable date. */ - minDate: PropTypes.any, + minDate: PropTypes.object, /** * Callback fired when the value changes. * @template TDate @@ -377,7 +380,7 @@ YearCalendar.propTypes = { * The date used to generate the new value when both `value` and `defaultValue` are empty. * @default The closest valid year using the validation props, except callbacks such as `shouldDisableYear`. */ - referenceDate: PropTypes.any, + referenceDate: PropTypes.object, /** * Disable specific year. * @template TDate @@ -405,7 +408,7 @@ YearCalendar.propTypes = { * The selected value. * Used when the component is controlled. */ - value: PropTypes.any, + value: PropTypes.object, /** * Years rendered per row. * @default 3 diff --git a/packages/x-date-pickers/src/YearCalendar/YearCalendar.types.ts b/packages/x-date-pickers/src/YearCalendar/YearCalendar.types.ts index 6b2cd9de038a9..ae45c7a04f960 100644 --- a/packages/x-date-pickers/src/YearCalendar/YearCalendar.types.ts +++ b/packages/x-date-pickers/src/YearCalendar/YearCalendar.types.ts @@ -2,7 +2,7 @@ import { SxProps } from '@mui/system'; import { Theme } from '@mui/material/styles'; import { YearCalendarClasses } from './yearCalendarClasses'; import { BaseDateValidationProps, YearValidationProps } from '../internals/models/validation'; -import { TimezoneProps } from '../models'; +import { PickerValidDate, TimezoneProps } from '../models'; export interface ExportedYearCalendarProps { /** @@ -12,7 +12,7 @@ export interface ExportedYearCalendarProps { yearsPerRow?: 3 | 4; } -export interface YearCalendarProps<TDate> +export interface YearCalendarProps<TDate extends PickerValidDate> extends ExportedYearCalendarProps, YearValidationProps<TDate>, BaseDateValidationProps<TDate>, diff --git a/packages/x-date-pickers/src/dateTimeViewRenderers/dateTimeViewRenderers.tsx b/packages/x-date-pickers/src/dateTimeViewRenderers/dateTimeViewRenderers.tsx index 7e9d4340e0571..80ea74129e606 100644 --- a/packages/x-date-pickers/src/dateTimeViewRenderers/dateTimeViewRenderers.tsx +++ b/packages/x-date-pickers/src/dateTimeViewRenderers/dateTimeViewRenderers.tsx @@ -17,8 +17,9 @@ import { } from '../timeViewRenderers'; import { digitalClockClasses } from '../DigitalClock'; import { VIEW_HEIGHT } from '../internals/constants/dimensions'; +import { PickerValidDate } from '../models'; -export interface DateTimeViewRendererProps<TDate> +export interface DateTimeViewRendererProps<TDate extends PickerValidDate> extends Omit< DateCalendarProps<TDate> & MultiSectionDigitalClockProps<TDate>, 'views' | 'openTo' | 'view' | 'onViewChange' | 'focusedView' | 'slots' | 'slotProps' @@ -32,7 +33,7 @@ export interface DateTimeViewRendererProps<TDate> shouldRenderTimeInASingleColumn: boolean; } -export const renderDesktopDateTimeView = <TDate extends unknown>({ +export const renderDesktopDateTimeView = <TDate extends PickerValidDate>({ view, onViewChange, views, diff --git a/packages/x-date-pickers/src/dateViewRenderers/dateViewRenderers.tsx b/packages/x-date-pickers/src/dateViewRenderers/dateViewRenderers.tsx index a2014f4bc8cd8..fa043429c5999 100644 --- a/packages/x-date-pickers/src/dateViewRenderers/dateViewRenderers.tsx +++ b/packages/x-date-pickers/src/dateViewRenderers/dateViewRenderers.tsx @@ -1,11 +1,13 @@ import * as React from 'react'; import { DateCalendar, DateCalendarProps } from '../DateCalendar'; -import { DateView } from '../models'; +import { DateView, PickerValidDate } from '../models'; import { DateOrTimeViewWithMeridiem } from '../internals/models'; import { isDatePickerView } from '../internals/utils/date-utils'; -export interface DateViewRendererProps<TDate, TView extends DateOrTimeViewWithMeridiem> - extends Omit< +export interface DateViewRendererProps< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends Omit< DateCalendarProps<TDate>, 'views' | 'openTo' | 'view' | 'onViewChange' | 'focusedView' > { @@ -15,7 +17,7 @@ export interface DateViewRendererProps<TDate, TView extends DateOrTimeViewWithMe focusedView: TView | null; } -export const renderDateViewCalendar = <TDate extends unknown>({ +export const renderDateViewCalendar = <TDate extends PickerValidDate>({ view, onViewChange, views, diff --git a/packages/x-date-pickers/src/internals/hooks/date-helpers-hooks.tsx b/packages/x-date-pickers/src/internals/hooks/date-helpers-hooks.tsx index e4f299d8ae139..7fcdcba1b2c97 100644 --- a/packages/x-date-pickers/src/internals/hooks/date-helpers-hooks.tsx +++ b/packages/x-date-pickers/src/internals/hooks/date-helpers-hooks.tsx @@ -3,9 +3,9 @@ import { useUtils } from './useUtils'; import { PickerOnChangeFn } from './useViews'; import { getMeridiem, convertToMeridiem } from '../utils/time-utils'; import { PickerSelectionState } from './usePicker'; -import { PickersTimezone } from '../../models'; +import { PickersTimezone, PickerValidDate } from '../../models'; -export interface MonthValidationOptions<TDate> { +export interface MonthValidationOptions<TDate extends PickerValidDate> { disablePast?: boolean; disableFuture?: boolean; minDate: TDate; @@ -13,7 +13,7 @@ export interface MonthValidationOptions<TDate> { timezone: PickersTimezone; } -export function useNextMonthDisabled<TDate>( +export function useNextMonthDisabled<TDate extends PickerValidDate>( month: TDate, { disableFuture, @@ -31,7 +31,7 @@ export function useNextMonthDisabled<TDate>( }, [disableFuture, maxDate, month, utils, timezone]); } -export function usePreviousMonthDisabled<TDate>( +export function usePreviousMonthDisabled<TDate extends PickerValidDate>( month: TDate, { disablePast, @@ -50,7 +50,7 @@ export function usePreviousMonthDisabled<TDate>( }, [disablePast, minDate, month, utils, timezone]); } -export function useMeridiemMode<TDate>( +export function useMeridiemMode<TDate extends PickerValidDate>( date: TDate | null, ampm: boolean | undefined, onChange: PickerOnChangeFn<TDate>, diff --git a/packages/x-date-pickers/src/internals/hooks/useClockReferenceDate.ts b/packages/x-date-pickers/src/internals/hooks/useClockReferenceDate.ts index f7f4062bad211..03afe046d50c6 100644 --- a/packages/x-date-pickers/src/internals/hooks/useClockReferenceDate.ts +++ b/packages/x-date-pickers/src/internals/hooks/useClockReferenceDate.ts @@ -1,10 +1,10 @@ import * as React from 'react'; -import { MuiPickersAdapter, PickersTimezone } from '../../models'; +import { MuiPickersAdapter, PickersTimezone, PickerValidDate } from '../../models'; import { singleItemValueManager } from '../utils/valueManagers'; import { getTodayDate } from '../utils/date-utils'; import { SECTION_TYPE_GRANULARITY } from '../utils/getDefaultReferenceDate'; -export const useClockReferenceDate = <TDate, TProps extends {}>({ +export const useClockReferenceDate = <TDate extends PickerValidDate, TProps extends {}>({ value, referenceDate: referenceDateProp, utils, diff --git a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx index 7c6a84ddec528..52418e14d0ac6 100644 --- a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx +++ b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx @@ -15,7 +15,7 @@ import { usePicker } from '../usePicker'; import { LocalizationProvider } from '../../../LocalizationProvider'; import { PickersLayout } from '../../../PickersLayout'; import { InferError } from '../useValidation'; -import { FieldSection, BaseSingleInputFieldProps } from '../../../models'; +import { FieldSection, BaseSingleInputFieldProps, PickerValidDate } from '../../../models'; import { DateOrTimeViewWithMeridiem } from '../../models'; import { UsePickerValueFieldResponse } from '../usePicker/usePickerValue.types'; @@ -26,7 +26,7 @@ import { UsePickerValueFieldResponse } from '../usePicker/usePickerValue.types'; * - DesktopTimePicker */ export const useDesktopPicker = < - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseDesktopPickerProps<TDate, TView, any, TExternalProps>, >({ diff --git a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.types.ts b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.types.ts index 3c661b0c11f52..64118161d17d8 100644 --- a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.types.ts @@ -10,7 +10,12 @@ import { } from '../../models/props/basePickerProps'; import { PickersPopperSlots, PickersPopperSlotProps } from '../../components/PickersPopper'; import { UsePickerParams, UsePickerProps } from '../usePicker'; -import { BaseSingleInputFieldProps, FieldSection, MuiPickersAdapter } from '../../../models'; +import { + BaseSingleInputFieldProps, + FieldSection, + MuiPickersAdapter, + PickerValidDate, +} from '../../../models'; import { ExportedPickersLayoutSlots, ExportedPickersLayoutSlotProps, @@ -24,8 +29,10 @@ import { UseClearableFieldSlotProps, } from '../../../hooks/useClearableField'; -export interface UseDesktopPickerSlots<TDate, TView extends DateOrTimeViewWithMeridiem> - extends Pick< +export interface UseDesktopPickerSlots< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends Pick< PickersPopperSlots, 'desktopPaper' | 'desktopTransition' | 'desktopTrapFocus' | 'popper' >, @@ -57,12 +64,16 @@ export interface UseDesktopPickerSlots<TDate, TView extends DateOrTimeViewWithMe openPickerIcon: React.ElementType; } -export interface UseDesktopPickerSlotProps<TDate, TView extends DateOrTimeViewWithMeridiem> - extends ExportedUseDesktopPickerSlotProps<TDate, TView>, +export interface UseDesktopPickerSlotProps< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends ExportedUseDesktopPickerSlotProps<TDate, TView>, Pick<PickersLayoutSlotProps<TDate | null, TDate, TView>, 'toolbar'> {} -export interface ExportedUseDesktopPickerSlotProps<TDate, TView extends DateOrTimeViewWithMeridiem> - extends PickersPopperSlotProps, +export interface ExportedUseDesktopPickerSlotProps< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends PickersPopperSlotProps, ExportedPickersLayoutSlotProps<TDate | null, TDate, TView>, UseClearableFieldSlotProps { field?: SlotComponentProps< @@ -80,7 +91,7 @@ export interface ExportedUseDesktopPickerSlotProps<TDate, TView extends DateOrTi openPickerIcon?: Record<string, any>; } -export interface DesktopOnlyPickerProps<TDate> +export interface DesktopOnlyPickerProps<TDate extends PickerValidDate> extends BaseNonStaticPickerProps, BaseNonRangeNonStaticPickerProps, UsePickerValueNonStaticProps<TDate | null, FieldSection>, @@ -92,7 +103,7 @@ export interface DesktopOnlyPickerProps<TDate> } export interface UseDesktopPickerProps< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TError, TExternalProps extends UsePickerViewsProps<any, any, TView, any, any>, @@ -111,7 +122,7 @@ export interface UseDesktopPickerProps< } export interface UseDesktopPickerParams< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseDesktopPickerProps<TDate, TView, any, TExternalProps>, > extends Pick< diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.ts index 6afb33b07eb22..740054ce131d7 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.ts @@ -16,11 +16,11 @@ import { adjustSectionValue, isAndroid, cleanString, getSectionOrder } from './u import { useFieldState } from './useFieldState'; import { useFieldCharacterEditing } from './useFieldCharacterEditing'; import { getActiveElement } from '../../utils/utils'; -import { FieldSection } from '../../../models'; +import { FieldSection, PickerValidDate } from '../../../models'; export const useField = < TValue, - TDate, + TDate extends PickerValidDate, TSection extends FieldSection, TForwardedProps extends UseFieldForwardedProps, TInternalProps extends UseFieldInternalProps<any, any, any, any> & { minutesStep?: number }, diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts index cf0e3de7ea40c..6bfc7d3580935 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts @@ -8,13 +8,14 @@ import { FieldSectionContentType, FieldValueType, PickersTimezone, + PickerValidDate, } from '../../../models'; import type { PickerValueManager } from '../usePicker'; import { InferError, Validator } from '../useValidation'; export interface UseFieldParams< TValue, - TDate, + TDate extends PickerValidDate, TSection extends FieldSection, TForwardedProps extends UseFieldForwardedProps, TInternalProps extends UseFieldInternalProps<any, any, any, any>, @@ -32,8 +33,12 @@ export interface UseFieldParams< valueType: FieldValueType; } -export interface UseFieldInternalProps<TValue, TDate, TSection extends FieldSection, TError> - extends TimezoneProps { +export interface UseFieldInternalProps< + TValue, + TDate extends PickerValidDate, + TSection extends FieldSection, + TError, +> extends TimezoneProps { /** * The selected value. * Used when the component is controlled. @@ -183,12 +188,15 @@ export type FieldSectionWithoutPosition<TSection extends FieldSection = FieldSec 'start' | 'end' | 'startInInput' | 'endInInput' >; -export type FieldSectionValueBoundaries<TDate, SectionType extends FieldSectionType> = { +export type FieldSectionValueBoundaries< + TDate extends PickerValidDate, + SectionType extends FieldSectionType, +> = { minimum: number; maximum: number; } & (SectionType extends 'day' ? { longestMonth: TDate } : {}); -export type FieldSectionsValueBoundaries<TDate> = { +export type FieldSectionsValueBoundaries<TDate extends PickerValidDate> = { [SectionType in FieldSectionType]: (params: { currentDate: TDate | null; format: string; @@ -209,7 +217,11 @@ export interface FieldChangeHandlerContext<TError> { * Object used to access and update the active date (i.e: the date containing the active section). * Mainly useful in the range fields where we need to update the date containing the active section without impacting the other one. */ -interface FieldActiveDateManager<TValue, TDate, TSection extends FieldSection> { +interface FieldActiveDateManager< + TValue, + TDate extends PickerValidDate, + TSection extends FieldSection, +> { /** * Active date from `state.value`. */ @@ -245,7 +257,11 @@ export type FieldSelectedSectionsIndexes = { shouldSelectBoundarySelectors: boolean; }; -export interface FieldValueManager<TValue, TDate, TSection extends FieldSection> { +export interface FieldValueManager< + TValue, + TDate extends PickerValidDate, + TSection extends FieldSection, +> { /** * Creates the section list from the current value. * The `prevSections` are used on the range fields to avoid losing the sections of a partially filled date when editing the other date. diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.utils.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.utils.ts index cfbea21b8f719..2f6ad0ab5b404 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.utils.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.utils.ts @@ -13,11 +13,12 @@ import { MuiPickersAdapter, FieldSectionContentType, PickersTimezone, + PickerValidDate, } from '../../../models'; import { PickersLocaleText } from '../../../locales/utils/pickersLocaleTextApi'; import { getMonthsInYear } from '../../utils/date-utils'; -export const getDateSectionConfigFromFormatToken = <TDate>( +export const getDateSectionConfigFromFormatToken = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, formatToken: string, ): Pick<FieldSection, 'type' | 'contentType'> & { maxLength: number | undefined } => { @@ -62,7 +63,7 @@ const getDeltaFromKeyCode = (keyCode: Omit<AvailableAdjustKeyCode, 'Home' | 'End } }; -export const getDaysInWeekStr = <TDate>( +export const getDaysInWeekStr = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, timezone: PickersTimezone, format: string, @@ -82,7 +83,7 @@ export const getDaysInWeekStr = <TDate>( return elements.map((weekDay) => utils.formatByString(weekDay, format)); }; -export const getLetterEditingOptions = <TDate>( +export const getLetterEditingOptions = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, timezone: PickersTimezone, sectionType: FieldSectionType, @@ -118,7 +119,9 @@ export const FORMAT_SECONDS_NO_LEADING_ZEROS = 's'; const NON_LOCALIZED_DIGITS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; -export const getLocalizedDigits = <TDate>(utils: MuiPickersAdapter<TDate>) => { +export const getLocalizedDigits = <TDate extends PickerValidDate>( + utils: MuiPickersAdapter<TDate>, +) => { const today = utils.date(undefined); const formattedZero = utils.formatByString( utils.setSeconds(today, 0), @@ -188,7 +191,7 @@ export const cleanLeadingZeros = (valueStr: string, size: number) => { return cleanValueStr; }; -export const cleanDigitSectionValue = <TDate>( +export const cleanDigitSectionValue = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, value: number, sectionBoundaries: FieldSectionValueBoundaries<TDate, any>, @@ -231,7 +234,7 @@ export const cleanDigitSectionValue = <TDate>( return applyLocalizedDigits(valueStr, localizedDigits); }; -export const adjustSectionValue = <TDate, TSection extends FieldSection>( +export const adjustSectionValue = <TDate extends PickerValidDate, TSection extends FieldSection>( utils: MuiPickersAdapter<TDate>, timezone: PickersTimezone, section: TSection, @@ -417,7 +420,7 @@ export const addPositionPropertiesToSections = <TSection extends FieldSection>( return newSections; }; -const getSectionPlaceholder = <TDate>( +const getSectionPlaceholder = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, timezone: PickersTimezone, localeText: PickersLocaleText<TDate>, @@ -472,7 +475,7 @@ const getSectionPlaceholder = <TDate>( } }; -export const changeSectionValueFormat = <TDate>( +export const changeSectionValueFormat = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, valueStr: string, currentFormat: string, @@ -487,13 +490,13 @@ export const changeSectionValueFormat = <TDate>( return utils.formatByString(utils.parse(valueStr, currentFormat)!, newFormat); }; -const isFourDigitYearFormat = <TDate>( +const isFourDigitYearFormat = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, timezone: PickersTimezone, format: string, ) => utils.formatByString(utils.date(undefined, timezone), format).length === 4; -export const doesSectionFormatHaveLeadingZeros = <TDate>( +export const doesSectionFormatHaveLeadingZeros = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, timezone: PickersTimezone, contentType: FieldSectionContentType, @@ -548,7 +551,10 @@ export const doesSectionFormatHaveLeadingZeros = <TDate>( } }; -const getEscapedPartsFromFormat = <TDate>(utils: MuiPickersAdapter<TDate>, format: string) => { +const getEscapedPartsFromFormat = <TDate extends PickerValidDate>( + utils: MuiPickersAdapter<TDate>, + format: string, +) => { const escapedParts: { start: number; end: number }[] = []; const { start: startChar, end: endChar } = utils.escapedCharacters; const regExp = new RegExp(`(\\${startChar}[^\\${endChar}]*\\${endChar})+`, 'g'); @@ -562,7 +568,7 @@ const getEscapedPartsFromFormat = <TDate>(utils: MuiPickersAdapter<TDate>, forma return escapedParts; }; -export const splitFormatIntoSections = <TDate>( +export const splitFormatIntoSections = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, timezone: PickersTimezone, localeText: PickersLocaleText<TDate>, @@ -743,7 +749,7 @@ export const splitFormatIntoSections = <TDate>( * Some date libraries like `dayjs` don't support parsing from date with escaped characters. * To make sure that the parsing works, we are building a format and a date without any separator. */ -export const getDateFromDateSections = <TDate>( +export const getDateFromDateSections = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, sections: FieldSection[], localizedDigits: string[], @@ -800,7 +806,7 @@ export const createDateStrForInputFromSections = ( return `\u2066${dateStr}\u2069`; }; -export const getSectionsBoundaries = <TDate>( +export const getSectionsBoundaries = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, localizedDigits: string[], timezone: PickersTimezone, @@ -929,7 +935,7 @@ export const validateSections = <TSection extends FieldSection>( } }; -const transferDateSectionValue = <TDate>( +const transferDateSectionValue = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, timezone: PickersTimezone, section: FieldSectionWithoutPosition, @@ -1004,7 +1010,7 @@ const reliableSectionModificationOrder: Record<FieldSectionType, number> = { empty: 9, }; -export const mergeDateIntoReferenceDate = <TDate>( +export const mergeDateIntoReferenceDate = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, timezone: PickersTimezone, dateToTransferFrom: TDate, diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useFieldCharacterEditing.ts b/packages/x-date-pickers/src/internals/hooks/useField/useFieldCharacterEditing.ts index 13f7247bdf780..2fc78b739d0d0 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useFieldCharacterEditing.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useFieldCharacterEditing.ts @@ -1,6 +1,6 @@ import * as React from 'react'; import useEventCallback from '@mui/utils/useEventCallback'; -import { FieldSectionType, FieldSection, PickersTimezone } from '../../../models'; +import { FieldSectionType, FieldSection, PickersTimezone, PickerValidDate } from '../../../models'; import { useUtils } from '../useUtils'; import { FieldSectionsValueBoundaries } from './useField.types'; import { @@ -27,7 +27,7 @@ interface ApplyCharacterEditingParams { sectionIndex: number; } -interface UseFieldEditingParams<TDate, TSection extends FieldSection> { +interface UseFieldEditingParams<TDate extends PickerValidDate, TSection extends FieldSection> { sections: TSection[]; updateSectionValue: (params: UpdateSectionValueParams<TSection>) => void; sectionsValueBoundaries: FieldSectionsValueBoundaries<TDate>; @@ -78,7 +78,10 @@ const isQueryResponseWithoutValue = <TSection extends FieldSection>( * 1. The numeric editing when the user presses a digit * 2. The letter editing when the user presses another key */ -export const useFieldCharacterEditing = <TDate, TSection extends FieldSection>({ +export const useFieldCharacterEditing = < + TDate extends PickerValidDate, + TSection extends FieldSection, +>({ sections, updateSectionValue, sectionsValueBoundaries, diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useFieldState.ts b/packages/x-date-pickers/src/internals/hooks/useField/useFieldState.ts index 102bac4d7f7a6..0731be627b7ed 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useFieldState.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useFieldState.ts @@ -20,7 +20,7 @@ import { getLocalizedDigits, } from './useField.utils'; import { InferError } from '../useValidation'; -import { FieldSection, FieldSelectedSections } from '../../../models'; +import { FieldSection, FieldSelectedSections, PickerValidDate } from '../../../models'; import { useValueWithTimezone } from '../useValueWithTimezone'; import { GetDefaultReferenceDateProps, @@ -44,7 +44,7 @@ export interface UpdateSectionValueParams<TSection extends FieldSection> { export const useFieldState = < TValue, - TDate, + TDate extends PickerValidDate, TSection extends FieldSection, TForwardedProps extends UseFieldForwardedProps, TInternalProps extends UseFieldInternalProps<any, any, any, any>, diff --git a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx index a34d914b30449..f39bda9d098bb 100644 --- a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx +++ b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx @@ -10,7 +10,7 @@ import { useUtils } from '../useUtils'; import { LocalizationProvider } from '../../../LocalizationProvider'; import { PickersLayout } from '../../../PickersLayout'; import { InferError } from '../useValidation'; -import { FieldSection, BaseSingleInputFieldProps } from '../../../models'; +import { FieldSection, BaseSingleInputFieldProps, PickerValidDate } from '../../../models'; import { DateOrTimeViewWithMeridiem } from '../../models'; /** @@ -20,7 +20,7 @@ import { DateOrTimeViewWithMeridiem } from '../../models'; * - MobileTimePicker */ export const useMobilePicker = < - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseMobilePickerProps<TDate, TView, any, TExternalProps>, >({ diff --git a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.types.ts b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.types.ts index 91c310fab3859..bbbe33d8521ef 100644 --- a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.types.ts @@ -11,7 +11,12 @@ import { PickersModalDialogSlotProps, } from '../../components/PickersModalDialog'; import { UsePickerParams, UsePickerProps } from '../usePicker'; -import { BaseSingleInputFieldProps, FieldSection, MuiPickersAdapter } from '../../../models'; +import { + BaseSingleInputFieldProps, + FieldSection, + MuiPickersAdapter, + PickerValidDate, +} from '../../../models'; import { ExportedPickersLayoutSlots, ExportedPickersLayoutSlotProps, @@ -21,8 +26,10 @@ import { UsePickerValueNonStaticProps } from '../usePicker/usePickerValue.types' import { UsePickerViewsNonStaticProps, UsePickerViewsProps } from '../usePicker/usePickerViews'; import { DateOrTimeViewWithMeridiem } from '../../models'; -export interface UseMobilePickerSlots<TDate, TView extends DateOrTimeViewWithMeridiem> - extends PickersModalDialogSlots, +export interface UseMobilePickerSlots< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends PickersModalDialogSlots, ExportedPickersLayoutSlots<TDate | null, TDate, TView> { /** * Component used to enter the date with the keyboard. @@ -36,8 +43,10 @@ export interface UseMobilePickerSlots<TDate, TView extends DateOrTimeViewWithMer textField?: React.ElementType<TextFieldProps>; } -export interface ExportedUseMobilePickerSlotProps<TDate, TView extends DateOrTimeViewWithMeridiem> - extends PickersModalDialogSlotProps, +export interface ExportedUseMobilePickerSlotProps< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends PickersModalDialogSlotProps, ExportedPickersLayoutSlotProps<TDate | null, TDate, TView> { field?: SlotComponentProps< React.ElementType<BaseSingleInputFieldProps<TDate | null, TDate, FieldSection, unknown>>, @@ -47,18 +56,20 @@ export interface ExportedUseMobilePickerSlotProps<TDate, TView extends DateOrTim textField?: SlotComponentProps<typeof TextField, {}, Record<string, any>>; } -export interface UseMobilePickerSlotProps<TDate, TView extends DateOrTimeViewWithMeridiem> - extends ExportedUseMobilePickerSlotProps<TDate, TView>, +export interface UseMobilePickerSlotProps< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends ExportedUseMobilePickerSlotProps<TDate, TView>, Pick<PickersLayoutSlotProps<TDate | null, TDate, TView>, 'toolbar'> {} -export interface MobileOnlyPickerProps<TDate> +export interface MobileOnlyPickerProps<TDate extends PickerValidDate> extends BaseNonStaticPickerProps, BaseNonRangeNonStaticPickerProps, UsePickerValueNonStaticProps<TDate | null, FieldSection>, UsePickerViewsNonStaticProps {} export interface UseMobilePickerProps< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TError, TExternalProps extends UsePickerViewsProps<any, any, TView, any, any>, @@ -77,7 +88,7 @@ export interface UseMobilePickerProps< } export interface UseMobilePickerParams< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseMobilePickerProps<TDate, TView, any, TExternalProps>, > extends Pick< diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts index 4e60cf201427f..889aa0eb101b1 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts @@ -4,7 +4,7 @@ import { usePickerViews } from './usePickerViews'; import { usePickerLayoutProps } from './usePickerLayoutProps'; import { InferError } from '../useValidation'; import { buildWarning } from '../../utils/warning'; -import { FieldSection } from '../../../models'; +import { FieldSection, PickerValidDate } from '../../../models'; import { DateOrTimeViewWithMeridiem } from '../../models'; const warnRenderInputIsDefined = buildWarning([ @@ -15,7 +15,7 @@ const warnRenderInputIsDefined = buildWarning([ export const usePicker = < TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TSection extends FieldSection, TExternalProps extends UsePickerProps<TValue, TDate, TView, TSection, any, any, any>, diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts index 5b7e4aeb4ded8..0827fe08cd995 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts @@ -11,7 +11,7 @@ import { UsePickerViewsBaseProps, } from './usePickerViews'; import { UsePickerLayoutProps, UsePickerLayoutPropsResponse } from './usePickerLayoutProps'; -import { FieldSection } from '../../../models'; +import { FieldSection, PickerValidDate } from '../../../models'; import { DateOrTimeViewWithMeridiem } from '../../models'; /** @@ -19,7 +19,7 @@ import { DateOrTimeViewWithMeridiem } from '../../models'; */ export interface UsePickerBaseProps< TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TError, TExternalProps extends UsePickerViewsProps<TValue, TDate, TView, any, any>, @@ -30,7 +30,7 @@ export interface UsePickerBaseProps< export interface UsePickerProps< TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TSection extends FieldSection, TError, @@ -42,7 +42,7 @@ export interface UsePickerProps< export interface UsePickerParams< TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TSection extends FieldSection, TExternalProps extends UsePickerProps<TValue, TDate, TView, TSection, any, any, any>, diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts index 98863c4ebea8b..1e2c0947eef1d 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts @@ -5,7 +5,12 @@ import { useOpenState } from '../useOpenState'; import { useLocalizationContext, useUtils } from '../useUtils'; import { FieldChangeHandlerContext } from '../useField'; import { InferError, useValidation } from '../useValidation'; -import { FieldSection, FieldSelectedSections, PickerChangeHandlerContext } from '../../../models'; +import { + FieldSection, + FieldSelectedSections, + PickerChangeHandlerContext, + PickerValidDate, +} from '../../../models'; import { PickerShortcutChangeImportance, PickersShortcutsItemContext, @@ -147,7 +152,7 @@ const shouldClosePicker = <TValue, TError>( */ export const usePickerValue = < TValue, - TDate, + TDate extends PickerValidDate, TSection extends FieldSection, TExternalProps extends UsePickerValueProps<TValue, TSection, any>, >({ diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts index 959b45b70a337..3546b56d9f51c 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts @@ -10,6 +10,7 @@ import { MuiPickersAdapter, PickersTimezone, PickerChangeHandlerContext, + PickerValidDate, } from '../../../models'; import { GetDefaultReferenceDateProps } from '../../utils/getDefaultReferenceDate'; import { @@ -17,7 +18,7 @@ import { PickersShortcutsItemContext, } from '../../../PickersShortcuts'; -export interface PickerValueManager<TValue, TDate, TError> { +export interface PickerValueManager<TValue, TDate extends PickerValidDate, TError> { /** * Determines if two values are equal. * @template TDate, TValue @@ -249,7 +250,7 @@ export interface UsePickerValueBaseProps<TValue, TError> { */ export interface UsePickerValueNonStaticProps<TValue, TSection extends FieldSection> extends Pick< - UseFieldInternalProps<TValue, unknown, TSection, unknown>, + UseFieldInternalProps<TValue, PickerValidDate, TSection, unknown>, 'selectedSections' | 'onSelectedSectionsChange' > { /** @@ -284,7 +285,7 @@ export interface UsePickerValueProps<TValue, TSection extends FieldSection, TErr export interface UsePickerValueParams< TValue, - TDate, + TDate extends PickerValidDate, TSection extends FieldSection, TExternalProps extends UsePickerValueProps<TValue, TSection, any>, > { @@ -312,7 +313,7 @@ export interface UsePickerValueActions { export type UsePickerValueFieldResponse<TValue, TSection extends FieldSection, TError> = Required< Pick< - UseFieldInternalProps<TValue, unknown, TSection, TError>, + UseFieldInternalProps<TValue, PickerValidDate, TSection, TError>, 'value' | 'onChange' | 'selectedSections' | 'onSelectedSectionsChange' > >; diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts index d70dbe1cdeb58..58768a3877b35 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts @@ -7,7 +7,7 @@ import { useViews, UseViewsOptions } from '../useViews'; import type { UsePickerValueViewsResponse } from './usePickerValue.types'; import { isTimeView } from '../../utils/time-utils'; import { DateOrTimeViewWithMeridiem } from '../../models'; -import { TimezoneProps } from '../../../models'; +import { PickerValidDate, TimezoneProps } from '../../../models'; interface PickerViewsRendererBaseExternalProps<TView extends DateOrTimeViewWithMeridiem> extends Omit<UsePickerViewsProps<any, any, TView, any, any>, 'openTo' | 'viewRenderers'> {} @@ -49,7 +49,7 @@ export type PickerViewRendererLookup< */ export interface UsePickerViewsBaseProps< TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UsePickerViewsProps<TValue, TDate, TView, any, any>, TAdditionalProps extends {}, @@ -93,7 +93,7 @@ export interface UsePickerViewsNonStaticProps { */ export interface UsePickerViewsProps< TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UsePickerViewsProps<TValue, TDate, TView, any, any>, TAdditionalProps extends {}, @@ -105,7 +105,7 @@ export interface UsePickerViewsProps< export interface UsePickerViewParams< TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UsePickerViewsProps< TValue, @@ -163,7 +163,7 @@ export interface UsePickerViewsLayoutResponse<TView extends DateOrTimeViewWithMe */ export const usePickerViews = < TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UsePickerViewsProps<TValue, TDate, TView, any, any>, TAdditionalProps extends {}, diff --git a/packages/x-date-pickers/src/internals/hooks/useStaticPicker/useStaticPicker.tsx b/packages/x-date-pickers/src/internals/hooks/useStaticPicker/useStaticPicker.tsx index 7bd800892bc20..7c6f79c2914d1 100644 --- a/packages/x-date-pickers/src/internals/hooks/useStaticPicker/useStaticPicker.tsx +++ b/packages/x-date-pickers/src/internals/hooks/useStaticPicker/useStaticPicker.tsx @@ -6,7 +6,7 @@ import { usePicker } from '../usePicker'; import { LocalizationProvider } from '../../../LocalizationProvider'; import { PickersLayout } from '../../../PickersLayout'; import { DIALOG_WIDTH } from '../../constants/dimensions'; -import { FieldSection } from '../../../models'; +import { FieldSection, PickerValidDate } from '../../../models'; import { DateOrTimeViewWithMeridiem } from '../../models'; const PickerStaticLayout = styled(PickersLayout)(({ theme }) => ({ @@ -22,7 +22,7 @@ const PickerStaticLayout = styled(PickersLayout)(({ theme }) => ({ * - StaticTimePicker */ export const useStaticPicker = < - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseStaticPickerProps<TDate, TView, any, TExternalProps>, >({ diff --git a/packages/x-date-pickers/src/internals/hooks/useStaticPicker/useStaticPicker.types.ts b/packages/x-date-pickers/src/internals/hooks/useStaticPicker/useStaticPicker.types.ts index 3938bfcdf7187..3ac7db4269d1c 100644 --- a/packages/x-date-pickers/src/internals/hooks/useStaticPicker/useStaticPicker.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/useStaticPicker/useStaticPicker.types.ts @@ -6,14 +6,18 @@ import { import { BasePickerProps } from '../../models/props/basePickerProps'; import { UsePickerParams } from '../usePicker'; import { UsePickerViewsProps } from '../usePicker/usePickerViews'; -import { FieldSection } from '../../../models'; +import { FieldSection, PickerValidDate } from '../../../models'; import { DateOrTimeViewWithMeridiem } from '../../models'; -export interface UseStaticPickerSlots<TDate, TView extends DateOrTimeViewWithMeridiem> - extends ExportedPickersLayoutSlots<TDate | null, TDate, TView> {} +export interface UseStaticPickerSlots< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends ExportedPickersLayoutSlots<TDate | null, TDate, TView> {} -export interface UseStaticPickerSlotProps<TDate, TView extends DateOrTimeViewWithMeridiem> - extends ExportedPickersLayoutSlotProps<TDate | null, TDate, TView> {} +export interface UseStaticPickerSlotProps< + TDate extends PickerValidDate, + TView extends DateOrTimeViewWithMeridiem, +> extends ExportedPickersLayoutSlotProps<TDate | null, TDate, TView> {} export interface StaticOnlyPickerProps { /** @@ -34,7 +38,7 @@ export interface StaticOnlyPickerProps { } export interface UseStaticPickerProps< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TError, TExternalProps extends UsePickerViewsProps<TDate | null, TDate, TView, any, any>, @@ -44,7 +48,7 @@ export interface UseStaticPickerProps< * Overridable component slots. * @default {} */ - slots?: UseStaticPickerSlots<TDate | null, TView>; + slots?: UseStaticPickerSlots<TDate, TView>; /** * The props used for each component slot. * @default {} @@ -53,7 +57,7 @@ export interface UseStaticPickerProps< } export interface UseStaticPickerParams< - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseStaticPickerProps<TDate, TView, any, TExternalProps>, > extends Pick< diff --git a/packages/x-date-pickers/src/internals/hooks/useUtils.ts b/packages/x-date-pickers/src/internals/hooks/useUtils.ts index 9ce0b0102bcdb..2759b1b050785 100644 --- a/packages/x-date-pickers/src/internals/hooks/useUtils.ts +++ b/packages/x-date-pickers/src/internals/hooks/useUtils.ts @@ -5,9 +5,9 @@ import { } from '../../LocalizationProvider/LocalizationProvider'; import { DEFAULT_LOCALE } from '../../locales/enUS'; import { PickersLocaleText } from '../../locales/utils/pickersLocaleTextApi'; -import { PickersTimezone } from '../../models'; +import { PickersTimezone, PickerValidDate } from '../../models'; -export const useLocalizationContext = <TDate>() => { +export const useLocalizationContext = <TDate extends PickerValidDate>() => { const localization = React.useContext(MuiPickersAdapterContext); if (localization === null) { throw new Error( @@ -45,13 +45,15 @@ export const useLocalizationContext = <TDate>() => { ); }; -export const useUtils = <TDate>() => useLocalizationContext<TDate>().utils; +export const useUtils = <TDate extends PickerValidDate>() => useLocalizationContext<TDate>().utils; -export const useDefaultDates = <TDate>() => useLocalizationContext<TDate>().defaultDates; +export const useDefaultDates = <TDate extends PickerValidDate>() => + useLocalizationContext<TDate>().defaultDates; -export const useLocaleText = <TDate>() => useLocalizationContext<TDate>().localeText; +export const useLocaleText = <TDate extends PickerValidDate>() => + useLocalizationContext<TDate>().localeText; -export const useNow = <TDate>(timezone: PickersTimezone): TDate => { +export const useNow = <TDate extends PickerValidDate>(timezone: PickersTimezone): TDate => { const utils = useUtils<TDate>(); const now = React.useRef() as React.MutableRefObject<TDate>; diff --git a/packages/x-date-pickers/src/internals/hooks/useValidation.ts b/packages/x-date-pickers/src/internals/hooks/useValidation.ts index 1742634d63b5b..406dcf61d0db8 100644 --- a/packages/x-date-pickers/src/internals/hooks/useValidation.ts +++ b/packages/x-date-pickers/src/internals/hooks/useValidation.ts @@ -1,6 +1,7 @@ import * as React from 'react'; import { useLocalizationContext } from './useUtils'; import { MuiPickersAdapterContextValue } from '../../LocalizationProvider/LocalizationProvider'; +import { PickerValidDate } from '../../models'; interface ValidationCommonProps<TError, TValue> { /** @@ -27,13 +28,18 @@ export type InferError<TProps> = ? Parameters<Exclude<TProps['onError'], undefined>>[0] : never; -export type Validator<TValue, TDate, TError, TValidationProps> = (params: { +export type Validator<TValue, TDate extends PickerValidDate, TError, TValidationProps> = (params: { adapter: MuiPickersAdapterContextValue<TDate>; value: TValue; props: Omit<TValidationProps, 'value' | 'onError'>; }) => TError; -export function useValidation<TValue, TDate, TError, TValidationProps extends {}>( +export function useValidation< + TValue, + TDate extends PickerValidDate, + TError, + TValidationProps extends {}, +>( props: ValidationProps<TError, TValue, TValidationProps>, validate: Validator<TValue, TDate, TError, TValidationProps>, isSameError: (a: TError, b: TError | null) => boolean, diff --git a/packages/x-date-pickers/src/internals/hooks/useValueWithTimezone.ts b/packages/x-date-pickers/src/internals/hooks/useValueWithTimezone.ts index 3bac13012c37f..dd892c5d1c9da 100644 --- a/packages/x-date-pickers/src/internals/hooks/useValueWithTimezone.ts +++ b/packages/x-date-pickers/src/internals/hooks/useValueWithTimezone.ts @@ -3,14 +3,18 @@ import useEventCallback from '@mui/utils/useEventCallback'; import useControlled from '@mui/utils/useControlled'; import { useUtils } from './useUtils'; import type { PickerValueManager } from './usePicker'; -import { PickersTimezone } from '../../models'; +import { PickersTimezone, PickerValidDate } from '../../models'; /** * Hooks making sure that: * - The value returned by `onChange` always have the timezone of `props.value` or `props.defaultValue` if defined * - The value rendered is always the one from `props.timezone` if defined */ -export const useValueWithTimezone = <TDate, TValue, TChange extends (...params: any[]) => void>({ +export const useValueWithTimezone = < + TDate extends PickerValidDate, + TValue, + TChange extends (...params: any[]) => void, +>({ timezone: timezoneProp, value: valueProp, defaultValue, @@ -60,7 +64,7 @@ export const useValueWithTimezone = <TDate, TValue, TChange extends (...params: * Wrapper around `useControlled` and `useValueWithTimezone` */ export const useControlledValueWithTimezone = < - TDate, + TDate extends PickerValidDate, TValue, TChange extends (...params: any[]) => void, >({ diff --git a/packages/x-date-pickers/src/internals/hooks/useViews.tsx b/packages/x-date-pickers/src/internals/hooks/useViews.tsx index 8f120dde32635..c5c25387d2bf5 100644 --- a/packages/x-date-pickers/src/internals/hooks/useViews.tsx +++ b/packages/x-date-pickers/src/internals/hooks/useViews.tsx @@ -4,8 +4,9 @@ import { unstable_useControlled as useControlled } from '@mui/utils'; import type { PickerSelectionState } from './usePicker'; import { MakeOptional } from '../models/helpers'; import { DateOrTimeViewWithMeridiem } from '../models'; +import { PickerValidDate } from '../../models'; -export type PickerOnChangeFn<TDate> = ( +export type PickerOnChangeFn<TDate extends PickerValidDate> = ( date: TDate | null, selectionState?: PickerSelectionState, ) => void; diff --git a/packages/x-date-pickers/src/internals/models/fields.ts b/packages/x-date-pickers/src/internals/models/fields.ts index 552dfb3bef9d3..f46af981ad9ac 100644 --- a/packages/x-date-pickers/src/internals/models/fields.ts +++ b/packages/x-date-pickers/src/internals/models/fields.ts @@ -1,10 +1,14 @@ import * as React from 'react'; import { TextFieldProps } from '@mui/material/TextField'; import type { UseFieldInternalProps } from '../hooks/useField'; -import type { FieldSection } from '../../models'; +import { FieldSection, PickerValidDate } from '../../models'; -export interface BaseFieldProps<TValue, TDate, TSection extends FieldSection, TError> - extends Omit<UseFieldInternalProps<TValue, TDate, TSection, TError>, 'format'> { +export interface BaseFieldProps< + TValue, + TDate extends PickerValidDate, + TSection extends FieldSection, + TError, +> extends Omit<UseFieldInternalProps<TValue, TDate, TSection, TError>, 'format'> { className?: string; format?: string; disabled?: boolean; diff --git a/packages/x-date-pickers/src/internals/models/props/basePickerProps.tsx b/packages/x-date-pickers/src/internals/models/props/basePickerProps.tsx index ae4f8a9b8d7f9..9d0b473af2dd8 100644 --- a/packages/x-date-pickers/src/internals/models/props/basePickerProps.tsx +++ b/packages/x-date-pickers/src/internals/models/props/basePickerProps.tsx @@ -6,13 +6,14 @@ import { PickersInputComponentLocaleText } from '../../../locales/utils/pickersL import type { UsePickerViewsProps } from '../../hooks/usePicker/usePickerViews'; import { MakeOptional } from '../helpers'; import { DateOrTimeViewWithMeridiem } from '../common'; +import { PickerValidDate } from '../../../models'; /** * Props common to all pickers after applying the default props on each picker. */ export interface BasePickerProps< TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TError, TExternalProps extends UsePickerViewsProps<TValue, TDate, TView, any, any>, @@ -35,7 +36,7 @@ export interface BasePickerProps< */ export interface BasePickerInputProps< TValue, - TDate, + TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, TError, > extends Omit< diff --git a/packages/x-date-pickers/src/internals/models/props/clock.ts b/packages/x-date-pickers/src/internals/models/props/clock.ts index 8c783c1ac3e67..ff5fa599f6cdb 100644 --- a/packages/x-date-pickers/src/internals/models/props/clock.ts +++ b/packages/x-date-pickers/src/internals/models/props/clock.ts @@ -1,12 +1,12 @@ import { SxProps, Theme } from '@mui/material/styles'; import { BaseTimeValidationProps, TimeValidationProps } from '../validation'; -import { TimeStepOptions, TimezoneProps } from '../../../models'; +import { PickerValidDate, TimeStepOptions, TimezoneProps } from '../../../models'; import type { ExportedDigitalClockProps } from '../../../DigitalClock/DigitalClock.types'; import type { ExportedMultiSectionDigitalClockProps } from '../../../MultiSectionDigitalClock/MultiSectionDigitalClock.types'; import type { ExportedUseViewsOptions } from '../../hooks/useViews'; import { TimeViewWithMeridiem } from '../common'; -export interface ExportedBaseClockProps<TDate> +export interface ExportedBaseClockProps<TDate extends PickerValidDate> extends TimeValidationProps<TDate>, BaseTimeValidationProps, TimezoneProps { @@ -17,7 +17,7 @@ export interface ExportedBaseClockProps<TDate> ampm?: boolean; } -export interface BaseClockProps<TDate, TView extends TimeViewWithMeridiem> +export interface BaseClockProps<TDate extends PickerValidDate, TView extends TimeViewWithMeridiem> extends ExportedUseViewsOptions<TView>, ExportedBaseClockProps<TDate> { className?: string; @@ -52,7 +52,7 @@ export interface BaseClockProps<TDate, TView extends TimeViewWithMeridiem> referenceDate?: TDate; } -export interface DesktopOnlyTimePickerProps<TDate> +export interface DesktopOnlyTimePickerProps<TDate extends PickerValidDate> extends Omit<ExportedDigitalClockProps<TDate>, 'timeStep'>, Omit<ExportedMultiSectionDigitalClockProps<TDate>, 'timeSteps'> { /** diff --git a/packages/x-date-pickers/src/internals/models/validation.ts b/packages/x-date-pickers/src/internals/models/validation.ts index d933b83ecb628..aee8f2a3833e9 100644 --- a/packages/x-date-pickers/src/internals/models/validation.ts +++ b/packages/x-date-pickers/src/internals/models/validation.ts @@ -1,4 +1,4 @@ -import { TimeView } from '../../models'; +import { PickerValidDate, TimeView } from '../../models'; interface FutureAndPastValidationProps { /** @@ -22,7 +22,7 @@ export interface BaseTimeValidationProps extends FutureAndPastValidationProps {} /** * Props used to validate a time value. */ -export interface TimeValidationProps<TDate> { +export interface TimeValidationProps<TDate extends PickerValidDate> { /** * Minimal selectable time. * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. @@ -57,7 +57,8 @@ export interface TimeValidationProps<TDate> { * Validation props common to all the date views. * All these props have a default value when used inside a field / picker / calendar. */ -export interface BaseDateValidationProps<TDate> extends FutureAndPastValidationProps { +export interface BaseDateValidationProps<TDate extends PickerValidDate> + extends FutureAndPastValidationProps { /** * Maximal selectable date. */ @@ -71,7 +72,7 @@ export interface BaseDateValidationProps<TDate> extends FutureAndPastValidationP /** * Props used to validate a date value (validates day + month + year). */ -export interface DayValidationProps<TDate> { +export interface DayValidationProps<TDate extends PickerValidDate> { /** * Disable specific date. * @@ -87,7 +88,7 @@ export interface DayValidationProps<TDate> { /** * Props used to validate a month value */ -export interface MonthValidationProps<TDate> { +export interface MonthValidationProps<TDate extends PickerValidDate> { /** * Disable specific month. * @template TDate @@ -100,7 +101,7 @@ export interface MonthValidationProps<TDate> { /** * Props used to validate a year value */ -export interface YearValidationProps<TDate> { +export interface YearValidationProps<TDate extends PickerValidDate> { /** * Disable specific year. * @template TDate @@ -113,7 +114,7 @@ export interface YearValidationProps<TDate> { /** * Props used to validate a date time value. */ -export interface DateTimeValidationProps<TDate> { +export interface DateTimeValidationProps<TDate extends PickerValidDate> { /** * Minimal selectable moment of time with binding to date, to set min time in each day use `minTime`. */ 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 61f4daa693c15..0be0869483c4b 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 @@ -2,6 +2,7 @@ import { DateOrTimeView, DateView, MuiPickersAdapter, + PickerValidDate, TimeStepOptions, TimeView, } from '../../models'; @@ -11,8 +12,8 @@ import { DateOrTimeViewWithMeridiem } from '../models'; import { DesktopOnlyTimePickerProps } from '../models/props/clock'; import { DefaultizedProps } from '../models/helpers'; -export const resolveDateTimeFormat = ( - utils: MuiPickersAdapter<any>, +export const resolveDateTimeFormat = <TDate extends PickerValidDate>( + utils: MuiPickersAdapter<TDate>, { views, format, ...other }: { format?: string; views: readonly DateOrTimeView[]; ampm: boolean }, ) => { if (format) { @@ -58,13 +59,15 @@ const resolveViews = <TView extends DateOrTimeViewWithMeridiem = DateOrTimeViewW const resolveShouldRenderTimeInASingleColumn = (timeSteps: TimeStepOptions, threshold: number) => (24 * 60) / ((timeSteps.hours ?? 1) * (timeSteps.minutes ?? 5)) <= threshold; -interface DefaultizedTimeViewsProps<TDate, TView = DateOrTimeView> +interface DefaultizedTimeViewsProps<TDate extends PickerValidDate, TView = DateOrTimeView> extends DefaultizedProps<DesktopOnlyTimePickerProps<TDate>, 'ampm'> { views: readonly TView[]; } -interface DefaultizedTimeViewsResponse<TDate, TView = DateOrTimeViewWithMeridiem> - extends Required< +interface DefaultizedTimeViewsResponse< + TDate extends PickerValidDate, + TView = DateOrTimeViewWithMeridiem, +> extends Required< Pick< DefaultizedTimeViewsProps<TDate, TView>, 'thresholdToRenderTimeInASingleColumn' | 'timeSteps' | 'views' @@ -74,7 +77,7 @@ interface DefaultizedTimeViewsResponse<TDate, TView = DateOrTimeViewWithMeridiem } export function resolveTimeViewsResponse< - TDate, + TDate extends PickerValidDate, InTView extends DateOrTimeView = DateOrTimeView, OutTView extends DateOrTimeViewWithMeridiem = DateOrTimeViewWithMeridiem, >({ diff --git a/packages/x-date-pickers/src/internals/utils/date-utils.ts b/packages/x-date-pickers/src/internals/utils/date-utils.ts index ea444ec19736a..639332f7dc49e 100644 --- a/packages/x-date-pickers/src/internals/utils/date-utils.ts +++ b/packages/x-date-pickers/src/internals/utils/date-utils.ts @@ -1,8 +1,14 @@ -import { DateView, FieldValueType, MuiPickersAdapter, PickersTimezone } from '../../models'; +import { + DateView, + FieldValueType, + MuiPickersAdapter, + PickersTimezone, + PickerValidDate, +} from '../../models'; import { DateOrTimeViewWithMeridiem } from '../models'; import { areViewsEqual } from './views'; -interface FindClosestDateParams<TDate> { +interface FindClosestDateParams<TDate extends PickerValidDate> { date: TDate; disableFuture?: boolean; disablePast?: boolean; @@ -13,7 +19,7 @@ interface FindClosestDateParams<TDate> { timezone: PickersTimezone; } -export const findClosestEnabledDate = <TDate>({ +export const findClosestEnabledDate = <TDate extends PickerValidDate>({ date, disableFuture, disablePast, @@ -74,12 +80,12 @@ export const findClosestEnabledDate = <TDate>({ return null; }; -export const replaceInvalidDateByNull = <TDate>( +export const replaceInvalidDateByNull = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, value: TDate | null, ) => (value == null || !utils.isValid(value) ? null : value); -export const applyDefaultDate = <TDate>( +export const applyDefaultDate = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, value: TDate | null | undefined, defaultValue: TDate, @@ -91,7 +97,11 @@ export const applyDefaultDate = <TDate>( return value; }; -export const areDatesEqual = <TDate>(utils: MuiPickersAdapter<TDate>, a: TDate, b: TDate) => { +export const areDatesEqual = <TDate extends PickerValidDate>( + utils: MuiPickersAdapter<TDate>, + a: TDate, + b: TDate, +) => { if (!utils.isValid(a) && a != null && !utils.isValid(b) && b != null) { return true; } @@ -99,7 +109,10 @@ export const areDatesEqual = <TDate>(utils: MuiPickersAdapter<TDate>, a: TDate, return utils.isEqual(a, b); }; -export const getMonthsInYear = <TDate>(utils: MuiPickersAdapter<TDate>, year: TDate) => { +export const getMonthsInYear = <TDate extends PickerValidDate>( + utils: MuiPickersAdapter<TDate>, + year: TDate, +) => { const firstMonth = utils.startOfYear(year); const months = [firstMonth]; @@ -111,7 +124,7 @@ export const getMonthsInYear = <TDate>(utils: MuiPickersAdapter<TDate>, year: TD return months; }; -export const mergeDateAndTime = <TDate>( +export const mergeDateAndTime = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, dateParam: TDate, timeParam: TDate, @@ -124,7 +137,7 @@ export const mergeDateAndTime = <TDate>( return mergedDate; }; -export const getTodayDate = <TDate>( +export const getTodayDate = <TDate extends PickerValidDate>( utils: MuiPickersAdapter<TDate>, timezone: PickersTimezone, valueType?: FieldValueType, @@ -133,7 +146,10 @@ export const getTodayDate = <TDate>( ? utils.startOfDay(utils.date(undefined, timezone)) : utils.date(undefined, timezone); -export const formatMeridiem = <TDate>(utils: MuiPickersAdapter<TDate>, meridiem: 'am' | 'pm') => { +export const formatMeridiem = <TDate extends PickerValidDate>( + utils: MuiPickersAdapter<TDate>, + meridiem: 'am' | 'pm', +) => { const date = utils.setHours(utils.date()!, meridiem === 'am' ? 2 : 14); return utils.format(date, 'meridiem'); }; @@ -142,8 +158,8 @@ const dateViews = ['year', 'month', 'day']; export const isDatePickerView = (view: DateOrTimeViewWithMeridiem): view is DateView => dateViews.includes(view); -export const resolveDateFormat = ( - utils: MuiPickersAdapter<any>, +export const resolveDateFormat = <TDate extends PickerValidDate>( + utils: MuiPickersAdapter<TDate>, { format, views }: { format?: string; views: readonly DateView[] }, isInToolbar: boolean, ) => { @@ -184,7 +200,10 @@ export const resolveDateFormat = ( return formats.keyboardDate; }; -export const getWeekdays = <TDate>(utils: MuiPickersAdapter<TDate>, date: TDate) => { +export const getWeekdays = <TDate extends PickerValidDate>( + utils: MuiPickersAdapter<TDate>, + date: TDate, +) => { const start = utils.startOfWeek(date); return [0, 1, 2, 3, 4, 5, 6].map((diff) => utils.addDays(start, diff)); }; diff --git a/packages/x-date-pickers/src/internals/utils/getDefaultReferenceDate.ts b/packages/x-date-pickers/src/internals/utils/getDefaultReferenceDate.ts index c93f2fda56dae..7d31ee708ee08 100644 --- a/packages/x-date-pickers/src/internals/utils/getDefaultReferenceDate.ts +++ b/packages/x-date-pickers/src/internals/utils/getDefaultReferenceDate.ts @@ -1,8 +1,8 @@ import { createIsAfterIgnoreDatePart } from './time-utils'; import { mergeDateAndTime, getTodayDate } from './date-utils'; -import { FieldSection, MuiPickersAdapter, PickersTimezone } from '../../models'; +import { FieldSection, MuiPickersAdapter, PickersTimezone, PickerValidDate } from '../../models'; -export interface GetDefaultReferenceDateProps<TDate> { +export interface GetDefaultReferenceDateProps<TDate extends PickerValidDate> { maxDate?: TDate; minDate?: TDate; minTime?: TDate; @@ -28,7 +28,11 @@ export const getSectionTypeGranularity = (sections: FieldSection[]) => ), ); -const roundDate = <TDate>(utils: MuiPickersAdapter<TDate>, granularity: number, date: TDate) => { +const roundDate = <TDate extends PickerValidDate>( + utils: MuiPickersAdapter<TDate>, + granularity: number, + date: TDate, +) => { if (granularity === SECTION_TYPE_GRANULARITY.year) { return utils.startOfYear(date); } @@ -54,7 +58,7 @@ const roundDate = <TDate>(utils: MuiPickersAdapter<TDate>, granularity: number, return roundedDate; }; -export const getDefaultReferenceDate = <TDate>({ +export const getDefaultReferenceDate = <TDate extends PickerValidDate>({ props, utils, granularity, diff --git a/packages/x-date-pickers/src/internals/utils/time-utils.ts b/packages/x-date-pickers/src/internals/utils/time-utils.ts index 133ce1080c6a6..01faa1cf78626 100644 --- a/packages/x-date-pickers/src/internals/utils/time-utils.ts +++ b/packages/x-date-pickers/src/internals/utils/time-utils.ts @@ -1,4 +1,4 @@ -import { MuiPickersAdapter, TimeView } from '../../models'; +import { MuiPickersAdapter, PickerValidDate, TimeView } from '../../models'; import { DateOrTimeViewWithMeridiem, TimeViewWithMeridiem } from '../models'; import { areViewsEqual } from './views'; @@ -11,7 +11,7 @@ export const isInternalTimeView = ( export type Meridiem = 'am' | 'pm'; -export const getMeridiem = <TDate>( +export const getMeridiem = <TDate extends PickerValidDate>( date: TDate | null, utils: MuiPickersAdapter<TDate>, ): Meridiem | null => { @@ -33,7 +33,7 @@ export const convertValueToMeridiem = (value: number, meridiem: Meridiem | null, return value; }; -export const convertToMeridiem = <TDate>( +export const convertToMeridiem = <TDate extends PickerValidDate>( time: TDate, meridiem: Meridiem, ampm: boolean, @@ -43,12 +43,18 @@ export const convertToMeridiem = <TDate>( return utils.setHours(time, newHoursAmount); }; -export const getSecondsInDay = <TDate>(date: TDate, utils: MuiPickersAdapter<TDate>) => { +export const getSecondsInDay = <TDate extends PickerValidDate>( + date: TDate, + utils: MuiPickersAdapter<TDate>, +) => { return utils.getHours(date) * 3600 + utils.getMinutes(date) * 60 + utils.getSeconds(date); }; export const createIsAfterIgnoreDatePart = - <TDate>(disableIgnoringDatePartForTimeValidation: boolean, utils: MuiPickersAdapter<TDate>) => + <TDate extends PickerValidDate>( + disableIgnoringDatePartForTimeValidation: boolean, + utils: MuiPickersAdapter<TDate>, + ) => (dateLeft: TDate, dateRight: TDate) => { if (disableIgnoringDatePartForTimeValidation) { return utils.isAfter(dateLeft, dateRight); @@ -57,8 +63,8 @@ export const createIsAfterIgnoreDatePart = return getSecondsInDay(dateLeft, utils) > getSecondsInDay(dateRight, utils); }; -export const resolveTimeFormat = ( - utils: MuiPickersAdapter<any>, +export const resolveTimeFormat = <TDate extends PickerValidDate>( + utils: MuiPickersAdapter<TDate>, { format, views, ampm }: { format?: string; views: readonly TimeView[]; ampm: boolean }, ) => { if (format != null) { diff --git a/packages/x-date-pickers/src/internals/utils/validation/validateDate.ts b/packages/x-date-pickers/src/internals/utils/validation/validateDate.ts index 6cd8b41ff7c63..363b13a96f70c 100644 --- a/packages/x-date-pickers/src/internals/utils/validation/validateDate.ts +++ b/packages/x-date-pickers/src/internals/utils/validation/validateDate.ts @@ -5,11 +5,11 @@ import { MonthValidationProps, YearValidationProps, } from '../../models/validation'; -import { DateValidationError, TimezoneProps } from '../../../models'; +import { DateValidationError, PickerValidDate, TimezoneProps } from '../../../models'; import { applyDefaultDate } from '../date-utils'; import { DefaultizedProps } from '../../models/helpers'; -export interface DateComponentValidationProps<TDate> +export interface DateComponentValidationProps<TDate extends PickerValidDate> extends DayValidationProps<TDate>, MonthValidationProps<TDate>, YearValidationProps<TDate>, diff --git a/packages/x-date-pickers/src/internals/utils/validation/validateDateTime.ts b/packages/x-date-pickers/src/internals/utils/validation/validateDateTime.ts index 30a39602fb47b..ff14f93ac1eb4 100644 --- a/packages/x-date-pickers/src/internals/utils/validation/validateDateTime.ts +++ b/packages/x-date-pickers/src/internals/utils/validation/validateDateTime.ts @@ -1,9 +1,9 @@ import { Validator } from '../../hooks/useValidation'; import { validateDate, DateComponentValidationProps } from './validateDate'; import { validateTime, TimeComponentValidationProps } from './validateTime'; -import { DateTimeValidationError } from '../../../models'; +import { DateTimeValidationError, PickerValidDate } from '../../../models'; -export interface DateTimeComponentValidationProps<TDate> +export interface DateTimeComponentValidationProps<TDate extends PickerValidDate> extends DateComponentValidationProps<TDate>, TimeComponentValidationProps<TDate> {} diff --git a/packages/x-date-pickers/src/internals/utils/validation/validateTime.ts b/packages/x-date-pickers/src/internals/utils/validation/validateTime.ts index e21efee801c33..c3d109e7ec0f9 100644 --- a/packages/x-date-pickers/src/internals/utils/validation/validateTime.ts +++ b/packages/x-date-pickers/src/internals/utils/validation/validateTime.ts @@ -1,10 +1,10 @@ import { createIsAfterIgnoreDatePart } from '../time-utils'; import { Validator } from '../../hooks/useValidation'; import { BaseTimeValidationProps, TimeValidationProps } from '../../models/validation'; -import { TimeValidationError, TimezoneProps } from '../../../models'; +import { PickerValidDate, TimeValidationError, TimezoneProps } from '../../../models'; import { DefaultizedProps } from '../../models/helpers'; -export interface TimeComponentValidationProps<TDate> +export interface TimeComponentValidationProps<TDate extends PickerValidDate> extends Required<BaseTimeValidationProps>, TimeValidationProps<TDate>, DefaultizedProps<TimezoneProps, 'timezone'> {} diff --git a/packages/x-date-pickers/src/internals/utils/valueManagers.ts b/packages/x-date-pickers/src/internals/utils/valueManagers.ts index 02efbeafe40e3..e00437056044e 100644 --- a/packages/x-date-pickers/src/internals/utils/valueManagers.ts +++ b/packages/x-date-pickers/src/internals/utils/valueManagers.ts @@ -4,6 +4,7 @@ import { TimeValidationError, DateTimeValidationError, FieldSection, + PickerValidDate, } from '../../models'; import type { FieldValueManager } from '../hooks/useField'; import { areDatesEqual, getTodayDate, replaceInvalidDateByNull } from './date-utils'; @@ -15,7 +16,7 @@ import { export type SingleItemPickerValueManager< TValue = any, - TDate = any, + TDate extends PickerValidDate = any, TError extends DateValidationError | TimeValidationError | DateTimeValidationError = any, > = PickerValueManager<TValue, TDate, TError>; diff --git a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts index cb738d79bb873..6e0aca44083b1 100644 --- a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts +++ b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts @@ -1,5 +1,11 @@ import { TimeViewWithMeridiem } from '../../internals/models'; -import { DateView, TimeView, MuiPickersAdapter, FieldSectionContentType } from '../../models'; +import { + DateView, + TimeView, + MuiPickersAdapter, + FieldSectionContentType, + PickerValidDate, +} from '../../models'; export interface PickersComponentSpecificLocaleText { /** @@ -24,7 +30,7 @@ export interface PickersComponentSpecificLocaleText { dateRangePickerToolbarTitle: string; } -export interface PickersComponentAgnosticLocaleText<TDate> { +export interface PickersComponentAgnosticLocaleText<TDate extends PickerValidDate> { // Calendar navigation previousMonth: string; nextMonth: string; @@ -91,18 +97,20 @@ export interface PickersComponentAgnosticLocaleText<TDate> { fieldMeridiemPlaceholder: (params: { format: string }) => string; } -export interface PickersLocaleText<TDate> +export interface PickersLocaleText<TDate extends PickerValidDate> extends PickersComponentAgnosticLocaleText<TDate>, PickersComponentSpecificLocaleText {} -export type PickersInputLocaleText<TDate> = Partial<PickersLocaleText<TDate>>; +export type PickersInputLocaleText<TDate extends PickerValidDate> = Partial< + PickersLocaleText<TDate> +>; /** * Translations that can be provided directly to the picker components. * It contains some generic translations like `toolbarTitle` * which will be dispatched to various translations keys in `PickersLocaleText`, depending on the pickers received them. */ -export interface PickersInputComponentLocaleText<TDate> +export interface PickersInputComponentLocaleText<TDate extends PickerValidDate> extends Partial<PickersComponentAgnosticLocaleText<TDate>> { /** * Title displayed in the toolbar of this picker. @@ -114,6 +122,6 @@ export interface PickersInputComponentLocaleText<TDate> export type PickersTranslationKeys = keyof PickersLocaleText<any>; export type LocalizedComponent< - TDate, + TDate extends PickerValidDate, Props extends { localeText?: PickersInputComponentLocaleText<TDate> }, > = Omit<Props, 'localeText'> & { localeText?: PickersInputLocaleText<TDate> }; diff --git a/packages/x-date-pickers/src/models/adapters.ts b/packages/x-date-pickers/src/models/adapters.ts index 199ec3bd03811..ae4cf04ddff23 100644 --- a/packages/x-date-pickers/src/models/adapters.ts +++ b/packages/x-date-pickers/src/models/adapters.ts @@ -1,5 +1,6 @@ import { FieldSectionContentType, FieldSectionType } from './fields'; import { PickersTimezone } from './timezone'; +import { PickerValidDate } from './pickers'; export interface AdapterFormats { // Token formats @@ -153,7 +154,7 @@ export type DateBuilderReturnType<T extends string | null | undefined, TDate> = ? null : TDate; -export interface MuiPickersAdapter<TDate, TLocale = any> { +export interface MuiPickersAdapter<TDate extends PickerValidDate, TLocale = any> { /** * A boolean confirming that the adapter used is an MUI adapter. */ diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index a49895354f1ec..8f88dc742f3b9 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -1,5 +1,6 @@ import * as React from 'react'; import type { BaseFieldProps } from '../internals/models/fields'; +import { PickerValidDate } from './pickers'; export type FieldSectionType = | 'year' @@ -125,10 +126,14 @@ export type FieldSelectedSections = /** * Props the single input field can receive when used inside a picker. - * Only contains what the MUI component are passing to the field, not what users can pass using the `props.slotProps.field`. + * Only contains what the MUI components are passing to the field, not what users can pass using the `props.slotProps.field`. */ -export interface BaseSingleInputFieldProps<TValue, TDate, TSection extends FieldSection, TError> - extends BaseFieldProps<TValue, TDate, TSection, TError> { +export interface BaseSingleInputFieldProps< + TValue, + TDate extends PickerValidDate, + TSection extends FieldSection, + TError, +> extends BaseFieldProps<TValue, TDate, TSection, TError> { label?: React.ReactNode; id?: string; name?: string; diff --git a/packages/x-date-pickers/src/models/pickers.ts b/packages/x-date-pickers/src/models/pickers.ts index a51d9b1bff8ac..f093acb08b6f9 100644 --- a/packages/x-date-pickers/src/models/pickers.ts +++ b/packages/x-date-pickers/src/models/pickers.ts @@ -8,3 +8,7 @@ export interface PickerChangeHandlerContext<TError> { */ shortcut?: PickersShortcutsItemContext; } + +export interface PickerValidDateLookup {} + +export type PickerValidDate = PickerValidDateLookup[keyof PickerValidDateLookup]; diff --git a/packages/x-date-pickers/src/tests/fieldKeyboardInteraction.test.tsx b/packages/x-date-pickers/src/tests/fieldKeyboardInteraction.test.tsx index 948853ed504fd..b2fdefc1e22d9 100644 --- a/packages/x-date-pickers/src/tests/fieldKeyboardInteraction.test.tsx +++ b/packages/x-date-pickers/src/tests/fieldKeyboardInteraction.test.tsx @@ -12,7 +12,7 @@ import { expectInputValue, } from 'test/utils/pickers'; import { DateTimeField } from '@mui/x-date-pickers/DateTimeField'; -import { FieldSectionType, MuiPickersAdapter } from '@mui/x-date-pickers/models'; +import { FieldSectionType, MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models'; import { getDateSectionConfigFromFormatToken, cleanLeadingZeros, @@ -20,7 +20,7 @@ import { const testDate = '2018-05-15T09:35:10'; -function updateDate<TDate>( +function updateDate<TDate extends PickerValidDate>( date: TDate, adapter: MuiPickersAdapter<TDate>, sectionType: FieldSectionType, @@ -182,7 +182,7 @@ adapterToTest.forEach((adapterName) => { return valueStr; }; - const testKeyPress = <TDate extends unknown>({ + const testKeyPress = <TDate extends PickerValidDate>({ key, format, initialValue, diff --git a/packages/x-date-pickers/src/themeAugmentation/props.d.ts b/packages/x-date-pickers/src/themeAugmentation/props.d.ts index 84feaf48aab51..066a1d694b3ec 100644 --- a/packages/x-date-pickers/src/themeAugmentation/props.d.ts +++ b/packages/x-date-pickers/src/themeAugmentation/props.d.ts @@ -17,7 +17,7 @@ import { PickerPopperProps } from '../internals/components/PickersPopper'; import { PickersToolbarProps } from '../internals/components/PickersToolbar'; import { PickersToolbarButtonProps } from '../internals/components/PickersToolbarButton'; import { ExportedPickersToolbarTextProps } from '../internals/components/PickersToolbarText'; -import { DateOrTimeView } from '../models'; +import { DateOrTimeView, PickerValidDate } from '../models'; import { DatePickerProps, DatePickerToolbarProps } from '../DatePicker'; import { DesktopDatePickerProps } from '../DesktopDatePicker'; @@ -55,25 +55,25 @@ import { import { PickersSectionListProps } from '../PickersSectionList'; export interface PickersComponentsPropsList { - MuiClock: ClockProps<unknown>; + MuiClock: ClockProps<PickerValidDate>; MuiClockNumber: ClockNumberProps; MuiClockPointer: ClockPointerProps; - MuiDateCalendar: DateCalendarProps<unknown>; - MuiDateField: DateFieldProps<unknown>; - MuiDatePickerToolbar: DatePickerToolbarProps<unknown>; - MuiDateTimeField: DateTimeFieldProps<unknown>; + MuiDateCalendar: DateCalendarProps<PickerValidDate>; + MuiDateField: DateFieldProps<PickerValidDate>; + MuiDatePickerToolbar: DatePickerToolbarProps<PickerValidDate>; + MuiDateTimeField: DateTimeFieldProps<PickerValidDate>; MuiDateTimePickerTabs: DateTimePickerTabsProps; - MuiDateTimePickerToolbar: DateTimePickerToolbarProps<unknown>; - MuiDayCalendar: DayCalendarProps<unknown>; + MuiDateTimePickerToolbar: DateTimePickerToolbarProps<PickerValidDate>; + MuiDayCalendar: DayCalendarProps<PickerValidDate>; MuiDayCalendarSkeleton: DayCalendarSkeletonProps; - MuiDigitalClock: ExportedDigitalClockProps<unknown>; - MuiLocalizationProvider: LocalizationProviderProps<unknown, unknown>; - MuiMonthCalendar: MonthCalendarProps<unknown>; - MuiMultiSectionDigitalClock: MultiSectionDigitalClockProps<unknown>; + MuiDigitalClock: ExportedDigitalClockProps<PickerValidDate>; + MuiLocalizationProvider: LocalizationProviderProps<PickerValidDate, unknown>; + MuiMonthCalendar: MonthCalendarProps<PickerValidDate>; + MuiMultiSectionDigitalClock: MultiSectionDigitalClockProps<PickerValidDate>; MuiMultiSectionDigitalClockSection: ExportedMultiSectionDigitalClockSectionProps; MuiPickersArrowSwitcher: ExportedPickersArrowSwitcherProps; - MuiPickersCalendarHeader: ExportedPickersCalendarHeaderProps<unknown>; - MuiPickersDay: PickersDayProps<unknown>; + MuiPickersCalendarHeader: ExportedPickersCalendarHeaderProps<PickerValidDate>; + MuiPickersDay: PickersDayProps<PickerValidDate>; MuiPickersFadeTransitionGroup: PickersFadeTransitionGroupProps; MuiPickersMonth: ExportedPickersMonthProps; MuiPickersPopper: PickerPopperProps; @@ -81,30 +81,30 @@ export interface PickersComponentsPropsList { MuiPickersToolbar: PickersToolbarProps<unknown, DateOrTimeView>; MuiPickersToolbarButton: PickersToolbarButtonProps; MuiPickersToolbarText: ExportedPickersToolbarTextProps; - MuiPickersLayout: PickersLayoutProps<unknown, unknown, DateOrTimeView>; + MuiPickersLayout: PickersLayoutProps<unknown, PickerValidDate, DateOrTimeView>; MuiPickersYear: ExportedPickersYearProps; - MuiTimeClock: TimeClockProps<unknown>; - MuiTimeField: TimeFieldProps<unknown>; - MuiTimePickerToolbar: TimePickerToolbarProps<unknown>; - MuiYearCalendar: YearCalendarProps<unknown>; + MuiTimeClock: TimeClockProps<PickerValidDate>; + MuiTimeField: TimeFieldProps<PickerValidDate>; + MuiTimePickerToolbar: TimePickerToolbarProps<PickerValidDate>; + MuiYearCalendar: YearCalendarProps<PickerValidDate>; // Date Pickers - MuiDatePicker: DatePickerProps<unknown>; - MuiDesktopDatePicker: DesktopDatePickerProps<unknown>; - MuiMobileDatePicker: MobileDatePickerProps<unknown>; - MuiStaticDatePicker: StaticDatePickerProps<unknown>; + MuiDatePicker: DatePickerProps<PickerValidDate>; + MuiDesktopDatePicker: DesktopDatePickerProps<PickerValidDate>; + MuiMobileDatePicker: MobileDatePickerProps<PickerValidDate>; + MuiStaticDatePicker: StaticDatePickerProps<PickerValidDate>; // Time Pickers - MuiTimePicker: TimePickerProps<unknown>; - MuiDesktopTimePicker: DesktopTimePickerProps<unknown>; - MuiMobileTimePicker: MobileTimePickerProps<unknown>; - MuiStaticTimePicker: StaticTimePickerProps<unknown>; + MuiTimePicker: TimePickerProps<PickerValidDate>; + MuiDesktopTimePicker: DesktopTimePickerProps<PickerValidDate>; + MuiMobileTimePicker: MobileTimePickerProps<PickerValidDate>; + MuiStaticTimePicker: StaticTimePickerProps<PickerValidDate>; // Date Time Pickers - MuiDateTimePicker: DateTimePickerProps<unknown>; - MuiDesktopDateTimePicker: DesktopDateTimePickerProps<unknown>; - MuiMobileDateTimePicker: MobileDateTimePickerProps<unknown>; - MuiStaticDateTimePicker: StaticDateTimePickerProps<unknown>; + MuiDateTimePicker: DateTimePickerProps<PickerValidDate>; + MuiDesktopDateTimePicker: DesktopDateTimePickerProps<PickerValidDate>; + MuiMobileDateTimePicker: MobileDateTimePickerProps<PickerValidDate>; + MuiStaticDateTimePicker: StaticDateTimePickerProps<PickerValidDate>; // V7 Picker's TextField MuiPickersTextField: PickersTextFieldProps; diff --git a/packages/x-date-pickers/src/timeViewRenderers/timeViewRenderers.tsx b/packages/x-date-pickers/src/timeViewRenderers/timeViewRenderers.tsx index 568a09abaf841..6d9d631c6d0df 100644 --- a/packages/x-date-pickers/src/timeViewRenderers/timeViewRenderers.tsx +++ b/packages/x-date-pickers/src/timeViewRenderers/timeViewRenderers.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { TimeClock, TimeClockProps } from '../TimeClock'; -import { TimeView } from '../models'; +import { PickerValidDate, TimeView } from '../models'; import { DigitalClock, DigitalClockProps } from '../DigitalClock'; import { BaseClockProps } from '../internals/models/props/clock'; import { @@ -20,7 +20,7 @@ export type TimeViewRendererProps< views: readonly TView[]; }; -export const renderTimeViewClock = <TDate extends unknown>({ +export const renderTimeViewClock = <TDate extends PickerValidDate>({ view, onViewChange, focusedView, @@ -82,7 +82,7 @@ export const renderTimeViewClock = <TDate extends unknown>({ /> ); -export const renderDigitalClockTimeView = <TDate extends unknown>({ +export const renderDigitalClockTimeView = <TDate extends PickerValidDate>({ view, onViewChange, focusedView, @@ -147,7 +147,7 @@ export const renderDigitalClockTimeView = <TDate extends unknown>({ /> ); -export const renderMultiSectionDigitalClockTimeView = <TDate extends unknown>({ +export const renderMultiSectionDigitalClockTimeView = <TDate extends PickerValidDate>({ view, onViewChange, focusedView, diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index 5343b4cafe9bf..e56672a9a27df 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -312,6 +312,8 @@ { "name": "pickersYearClasses", "kind": "Variable" }, { "name": "PickersYearClasses", "kind": "Interface" }, { "name": "PickersYearClassKey", "kind": "TypeAlias" }, + { "name": "PickerValidDate", "kind": "TypeAlias" }, + { "name": "PickerValidDateLookup", "kind": "Interface" }, { "name": "RangeFieldSection", "kind": "Interface" }, { "name": "RangePosition", "kind": "TypeAlias" }, { "name": "renderDateRangeViewCalendar", "kind": "Variable" }, diff --git a/scripts/x-date-pickers.exports.json b/scripts/x-date-pickers.exports.json index e7f8314be788d..db0a05484f4f3 100644 --- a/scripts/x-date-pickers.exports.json +++ b/scripts/x-date-pickers.exports.json @@ -233,6 +233,8 @@ { "name": "pickersYearClasses", "kind": "Variable" }, { "name": "PickersYearClasses", "kind": "Interface" }, { "name": "PickersYearClassKey", "kind": "TypeAlias" }, + { "name": "PickerValidDate", "kind": "TypeAlias" }, + { "name": "PickerValidDateLookup", "kind": "Interface" }, { "name": "renderDateViewCalendar", "kind": "Variable" }, { "name": "renderDigitalClockTimeView", "kind": "Variable" }, { "name": "renderMultiSectionDigitalClockTimeView", "kind": "Variable" }, diff --git a/test/utils/pickers/describeGregorianAdapter/describeGregorianAdapter.ts b/test/utils/pickers/describeGregorianAdapter/describeGregorianAdapter.ts index cf87ef967b2ac..09aa0c0a3ffc3 100644 --- a/test/utils/pickers/describeGregorianAdapter/describeGregorianAdapter.ts +++ b/test/utils/pickers/describeGregorianAdapter/describeGregorianAdapter.ts @@ -1,5 +1,5 @@ import createDescribe from '@mui-internal/test-utils/createDescribe'; -import { MuiPickersAdapter } from '@mui/x-date-pickers/models'; +import { MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models'; import { testCalculations } from './testCalculations'; import { testLocalization } from './testLocalization'; import { testFormat } from './testFormat'; @@ -8,7 +8,7 @@ import { DescribeGregorianAdapterTestSuiteParams, } from './describeGregorianAdapter.types'; -function innerGregorianDescribeAdapter<TDate, TLocale>( +function innerGregorianDescribeAdapter<TDate extends PickerValidDate, TLocale>( Adapter: new (...args: any) => MuiPickersAdapter<TDate>, params: DescribeGregorianAdapterParams<TDate, TLocale>, ) { @@ -42,15 +42,15 @@ function innerGregorianDescribeAdapter<TDate, TLocale>( }); } -type Params<TDate, TLocale> = [ +type Params<TDate extends PickerValidDate, TLocale> = [ Adapter: new (...args: any) => MuiPickersAdapter<TDate>, params: DescribeGregorianAdapterParams<TDate, TLocale>, ]; type DescribeGregorianAdapter = { - <TDate, TLocale>(...args: Params<TDate, TLocale>): void; - skip: <TDate, TLocale>(...args: Params<TDate, TLocale>) => void; - only: <TDate, TLocale>(...args: Params<TDate, TLocale>) => void; + <TDate extends PickerValidDate, TLocale>(...args: Params<TDate, TLocale>): void; + skip: <TDate extends PickerValidDate, TLocale>(...args: Params<TDate, TLocale>) => void; + only: <TDate extends PickerValidDate, TLocale>(...args: Params<TDate, TLocale>) => void; }; export const describeGregorianAdapter = createDescribe( diff --git a/test/utils/pickers/describeGregorianAdapter/describeGregorianAdapter.types.ts b/test/utils/pickers/describeGregorianAdapter/describeGregorianAdapter.types.ts index 052f0a1969422..2f1c49b76d2db 100644 --- a/test/utils/pickers/describeGregorianAdapter/describeGregorianAdapter.types.ts +++ b/test/utils/pickers/describeGregorianAdapter/describeGregorianAdapter.types.ts @@ -1,6 +1,6 @@ -import { MuiPickersAdapter, PickersTimezone } from '@mui/x-date-pickers/models'; +import { MuiPickersAdapter, PickersTimezone, PickerValidDate } from '@mui/x-date-pickers/models'; -export interface DescribeGregorianAdapterParams<TDate, TLocale> { +export interface DescribeGregorianAdapterParams<TDate extends PickerValidDate, TLocale> { prepareAdapter?: (adapter: MuiPickersAdapter<TDate, TLocale>) => void; formatDateTime: string; getLocaleFromDate?: (value: TDate) => string; @@ -9,13 +9,13 @@ export interface DescribeGregorianAdapterParams<TDate, TLocale> { frenchLocale: TLocale; } -export interface DescribeGregorianAdapterTestSuiteParams<TDate, TLocale> +export interface DescribeGregorianAdapterTestSuiteParams<TDate extends PickerValidDate, TLocale> extends Omit<DescribeGregorianAdapterParams<TDate, TLocale>, 'frenchLocale'> { adapter: MuiPickersAdapter<TDate, TLocale>; adapterTZ: MuiPickersAdapter<TDate, TLocale>; adapterFr: MuiPickersAdapter<TDate, TLocale>; } -export type DescribeGregorianAdapterTestSuite = <TDate, TLocale>( +export type DescribeGregorianAdapterTestSuite = <TDate extends PickerValidDate, TLocale>( params: DescribeGregorianAdapterTestSuiteParams<TDate, TLocale>, ) => void; diff --git a/test/utils/pickers/describeGregorianAdapter/testCalculations.ts b/test/utils/pickers/describeGregorianAdapter/testCalculations.ts index d3c4bed0632f6..e27fc0f3b458a 100644 --- a/test/utils/pickers/describeGregorianAdapter/testCalculations.ts +++ b/test/utils/pickers/describeGregorianAdapter/testCalculations.ts @@ -1,16 +1,19 @@ import { expect } from 'chai'; -import { MuiPickersAdapter, PickersTimezone } from '@mui/x-date-pickers/models'; +import { MuiPickersAdapter, PickersTimezone, PickerValidDate } from '@mui/x-date-pickers/models'; import { getDateOffset } from 'test/utils/pickers'; import { DescribeGregorianAdapterTestSuite } from './describeGregorianAdapter.types'; import { TEST_DATE_ISO_STRING, TEST_DATE_LOCALE_STRING } from './describeGregorianAdapter.utils'; /** - * To check if the date has the right offset even after changing it's date parts, + * To check if the date has the right offset even after changing its date parts, * we convert it to a different timezone that always has the same offset, * then we check that both dates have the same hour value. */ // We change to -const expectSameTimeInMonacoTZ = <TDate>(adapter: MuiPickersAdapter<TDate>, value: TDate) => { +const expectSameTimeInMonacoTZ = <TDate extends PickerValidDate>( + adapter: MuiPickersAdapter<TDate>, + value: TDate, +) => { const valueInMonacoTz = adapter.setTimezone(value, 'Europe/Monaco'); expect(adapter.getHours(value)).to.equal(adapter.getHours(valueInMonacoTz)); }; diff --git a/test/utils/pickers/describeHijriAdapter/describeHijriAdapter.ts b/test/utils/pickers/describeHijriAdapter/describeHijriAdapter.ts index 4592a70a605d7..ff5ecb2af047d 100644 --- a/test/utils/pickers/describeHijriAdapter/describeHijriAdapter.ts +++ b/test/utils/pickers/describeHijriAdapter/describeHijriAdapter.ts @@ -1,11 +1,11 @@ import createDescribe from '@mui-internal/test-utils/createDescribe'; -import { MuiPickersAdapter } from '@mui/x-date-pickers'; +import { MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models'; import { testCalculations } from './testCalculations'; import { testLocalization } from './testLocalization'; import { testFormat } from './testFormat'; import { DescribeHijriAdapterParams } from './describeHijriAdapter.types'; -function innerJalaliDescribeAdapter<TDate>( +function innerJalaliDescribeAdapter<TDate extends PickerValidDate>( Adapter: new (...args: any) => MuiPickersAdapter<TDate>, params: DescribeHijriAdapterParams, ) { diff --git a/test/utils/pickers/describeHijriAdapter/describeHijriAdapter.types.ts b/test/utils/pickers/describeHijriAdapter/describeHijriAdapter.types.ts index 30fb1493e7683..09c2da3616a89 100644 --- a/test/utils/pickers/describeHijriAdapter/describeHijriAdapter.types.ts +++ b/test/utils/pickers/describeHijriAdapter/describeHijriAdapter.types.ts @@ -1,10 +1,10 @@ -import { MuiPickersAdapter } from '@mui/x-date-pickers/models'; +import { MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models'; export interface DescribeHijriAdapterParams { before?: () => void; after?: () => void; } -export type DescribeHijriAdapterTestSuite = <TDate>(params: { +export type DescribeHijriAdapterTestSuite = <TDate extends PickerValidDate>(params: { adapter: MuiPickersAdapter<TDate>; }) => void; diff --git a/test/utils/pickers/describeJalaliAdapter/describeJalaliAdapter.ts b/test/utils/pickers/describeJalaliAdapter/describeJalaliAdapter.ts index a0a699b6adf87..a09f6257d4861 100644 --- a/test/utils/pickers/describeJalaliAdapter/describeJalaliAdapter.ts +++ b/test/utils/pickers/describeJalaliAdapter/describeJalaliAdapter.ts @@ -1,11 +1,11 @@ import createDescribe from '@mui-internal/test-utils/createDescribe'; -import { MuiPickersAdapter } from '@mui/x-date-pickers'; +import { MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models'; import { testCalculations } from './testCalculations'; import { testLocalization } from './testLocalization'; import { testFormat } from './testFormat'; import { DescribeJalaliAdapterParams } from './describeJalaliAdapter.types'; -function innerJalaliDescribeAdapter<TDate>( +function innerJalaliDescribeAdapter<TDate extends PickerValidDate>( Adapter: new (...args: any) => MuiPickersAdapter<TDate>, params: DescribeJalaliAdapterParams, ) { diff --git a/test/utils/pickers/describeJalaliAdapter/describeJalaliAdapter.types.ts b/test/utils/pickers/describeJalaliAdapter/describeJalaliAdapter.types.ts index be7b2904119bd..176319483313f 100644 --- a/test/utils/pickers/describeJalaliAdapter/describeJalaliAdapter.types.ts +++ b/test/utils/pickers/describeJalaliAdapter/describeJalaliAdapter.types.ts @@ -1,10 +1,10 @@ -import { MuiPickersAdapter } from '@mui/x-date-pickers/models'; +import { MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models'; export interface DescribeJalaliAdapterParams { before?: () => void; after?: () => void; } -export type DescribeJalaliAdapterTestSuite = <TDate>(params: { +export type DescribeJalaliAdapterTestSuite = <TDate extends PickerValidDate>(params: { adapter: MuiPickersAdapter<TDate>; }) => void; diff --git a/test/utils/pickers/misc.ts b/test/utils/pickers/misc.ts index 97a08af557017..14afbe8208742 100644 --- a/test/utils/pickers/misc.ts +++ b/test/utils/pickers/misc.ts @@ -1,5 +1,5 @@ import sinon from 'sinon'; -import { MuiPickersAdapter } from '@mui/x-date-pickers/models'; +import { MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models'; import { PickerComponentFamily } from './describe.types'; import { OpenPickerParams } from './openPicker'; @@ -48,7 +48,7 @@ export const getExpectedOnChangeCount = ( return getChangeCountForComponentFamily(componentFamily); }; -export const getDateOffset = <TDate extends unknown>( +export const getDateOffset = <TDate extends PickerValidDate>( adapter: MuiPickersAdapter<TDate>, date: TDate, ) => { @@ -57,7 +57,7 @@ export const getDateOffset = <TDate extends unknown>( return cleanUtcHour * 60; }; -export const formatFullTimeValue = <TDate extends unknown>( +export const formatFullTimeValue = <TDate extends PickerValidDate>( adapter: MuiPickersAdapter<TDate>, value: TDate, ) => { From 3b2d0665cdcf6ffdf1e5a7d021f0a07d8b478c7f Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskii <andrew@mui.com> Date: Mon, 5 Feb 2024 13:46:37 +0100 Subject: [PATCH 17/35] [DataGrid] Add support for dialogs in menu actions (#11909) --- .../column-definition/ActionsWithModalGrid.js | 92 ++++++++++++++++ .../ActionsWithModalGrid.tsx | 103 ++++++++++++++++++ .../ActionsWithModalGrid.tsx.preview | 1 + .../column-definition/column-definition.md | 102 +++++++++-------- .../src/components/cell/GridActionsCell.tsx | 14 +-- .../components/cell/GridActionsCellItem.tsx | 47 ++++++-- 6 files changed, 293 insertions(+), 66 deletions(-) create mode 100644 docs/data/data-grid/column-definition/ActionsWithModalGrid.js create mode 100644 docs/data/data-grid/column-definition/ActionsWithModalGrid.tsx create mode 100644 docs/data/data-grid/column-definition/ActionsWithModalGrid.tsx.preview diff --git a/docs/data/data-grid/column-definition/ActionsWithModalGrid.js b/docs/data/data-grid/column-definition/ActionsWithModalGrid.js new file mode 100644 index 0000000000000..7a29da11924c4 --- /dev/null +++ b/docs/data/data-grid/column-definition/ActionsWithModalGrid.js @@ -0,0 +1,92 @@ +import * as React from 'react'; +import { DataGrid, GridActionsCellItem } from '@mui/x-data-grid'; +import DeleteIcon from '@mui/icons-material/Delete'; +import { randomUserName } from '@mui/x-data-grid-generator'; +import Dialog from '@mui/material/Dialog'; +import DialogTitle from '@mui/material/DialogTitle'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogActions from '@mui/material/DialogActions'; +import Button from '@mui/material/Button'; + +const initialRows = [ + { id: 1, name: randomUserName() }, + { id: 2, name: randomUserName() }, + { id: 3, name: randomUserName() }, +]; + +function DeleteUserActionItem({ deleteUser, ...props }) { + const [open, setOpen] = React.useState(false); + + return ( + <React.Fragment> + <GridActionsCellItem {...props} onClick={() => setOpen(true)} /> + <Dialog + open={open} + onClose={() => setOpen(false)} + aria-labelledby="alert-dialog-title" + aria-describedby="alert-dialog-description" + > + <DialogTitle id="alert-dialog-title">Delete this user?</DialogTitle> + <DialogContent> + <DialogContentText id="alert-dialog-description"> + This action cannot be undone. + </DialogContentText> + </DialogContent> + <DialogActions> + <Button onClick={() => setOpen(false)}>Cancel</Button> + <Button + onClick={() => { + setOpen(false); + deleteUser(); + }} + color="warning" + autoFocus + > + Delete + </Button> + </DialogActions> + </Dialog> + </React.Fragment> + ); +} + +export default function ActionsWithModalGrid() { + const [rows, setRows] = React.useState(initialRows); + + const deleteUser = React.useCallback( + (id) => () => { + setTimeout(() => { + setRows((prevRows) => prevRows.filter((row) => row.id !== id)); + }); + }, + [], + ); + + const columns = React.useMemo( + () => [ + { field: 'name', type: 'string' }, + { + field: 'actions', + type: 'actions', + width: 80, + getActions: (params) => [ + <DeleteUserActionItem + label="Delete" + showInMenu + icon={<DeleteIcon />} + deleteUser={deleteUser(params.id)} + closeMenuOnClick={false} + />, + ], + }, + ], + [deleteUser], + ); + + return ( + <div style={{ height: 300, width: '100%' }}> + <DataGrid columns={columns} rows={rows} /> + </div> + ); +} diff --git a/docs/data/data-grid/column-definition/ActionsWithModalGrid.tsx b/docs/data/data-grid/column-definition/ActionsWithModalGrid.tsx new file mode 100644 index 0000000000000..e32fd666d9b75 --- /dev/null +++ b/docs/data/data-grid/column-definition/ActionsWithModalGrid.tsx @@ -0,0 +1,103 @@ +import * as React from 'react'; +import { + DataGrid, + GridActionsCellItem, + GridRowId, + GridColDef, + GridActionsCellItemProps, +} from '@mui/x-data-grid'; +import DeleteIcon from '@mui/icons-material/Delete'; +import { randomUserName } from '@mui/x-data-grid-generator'; +import Dialog from '@mui/material/Dialog'; +import DialogTitle from '@mui/material/DialogTitle'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogActions from '@mui/material/DialogActions'; +import Button from '@mui/material/Button'; + +const initialRows = [ + { id: 1, name: randomUserName() }, + { id: 2, name: randomUserName() }, + { id: 3, name: randomUserName() }, +]; + +function DeleteUserActionItem({ + deleteUser, + ...props +}: GridActionsCellItemProps & { deleteUser: () => void }) { + const [open, setOpen] = React.useState(false); + + return ( + <React.Fragment> + <GridActionsCellItem {...props} onClick={() => setOpen(true)} /> + <Dialog + open={open} + onClose={() => setOpen(false)} + aria-labelledby="alert-dialog-title" + aria-describedby="alert-dialog-description" + > + <DialogTitle id="alert-dialog-title">Delete this user?</DialogTitle> + <DialogContent> + <DialogContentText id="alert-dialog-description"> + This action cannot be undone. + </DialogContentText> + </DialogContent> + <DialogActions> + <Button onClick={() => setOpen(false)}>Cancel</Button> + <Button + onClick={() => { + setOpen(false); + deleteUser(); + }} + color="warning" + autoFocus + > + Delete + </Button> + </DialogActions> + </Dialog> + </React.Fragment> + ); +} + +type Row = (typeof initialRows)[number]; + +export default function ActionsWithModalGrid() { + const [rows, setRows] = React.useState<Row[]>(initialRows); + + const deleteUser = React.useCallback( + (id: GridRowId) => () => { + setTimeout(() => { + setRows((prevRows) => prevRows.filter((row) => row.id !== id)); + }); + }, + [], + ); + + const columns = React.useMemo<GridColDef<Row>[]>( + () => [ + { field: 'name', type: 'string' }, + { + field: 'actions', + type: 'actions', + width: 80, + getActions: (params) => [ + <DeleteUserActionItem + label="Delete" + showInMenu + icon={<DeleteIcon />} + deleteUser={deleteUser(params.id)} + closeMenuOnClick={false} + />, + ], + }, + ], + [deleteUser], + ); + + return ( + <div style={{ height: 300, width: '100%' }}> + <DataGrid columns={columns} rows={rows} /> + </div> + ); +} diff --git a/docs/data/data-grid/column-definition/ActionsWithModalGrid.tsx.preview b/docs/data/data-grid/column-definition/ActionsWithModalGrid.tsx.preview new file mode 100644 index 0000000000000..6f326f7a9cd17 --- /dev/null +++ b/docs/data/data-grid/column-definition/ActionsWithModalGrid.tsx.preview @@ -0,0 +1 @@ +<DataGrid columns={columns} rows={rows} /> \ No newline at end of file diff --git a/docs/data/data-grid/column-definition/column-definition.md b/docs/data/data-grid/column-definition/column-definition.md index dc73721a1e571..0c1ae990eea6f 100644 --- a/docs/data/data-grid/column-definition/column-definition.md +++ b/docs/data/data-grid/column-definition/column-definition.md @@ -230,6 +230,8 @@ The following are the native column types with their required value types: | `'singleSelect'` | A value in `.valueOptions` | | `'actions'` | Not applicable | +{{"demo": "ColumnTypesGrid.js", "bg": "inline"}} + ### Converting types Default methods, such as filtering and sorting, assume that the type of the values will match the type of the column specified in `type`. @@ -249,57 +251,67 @@ If for any reason, your data type is not the correct one, you can use `valueGett To use most of the column types, you only need to define the `type` property in your column definition. However, some types require additional properties to be set to make them work correctly: -- If the column type is `'singleSelect'`, you also need to set the `valueOptions` property in the respective column definition. These values are options used for filtering and editing. +#### Single select - ```tsx - { - field: 'country', - type: 'singleSelect', - valueOptions: ['United Kingdom', 'Spain', 'Brazil'] - } - ``` - - :::warning - When using objects values for `valueOptions` you need to provide the `value` and `label` attributes for each option. - However, you can customize which attribute is used as value and label by using `getOptionValue` and `getOptionLabel`, respectively. - - ```tsx - // Without getOptionValue and getOptionLabel - { - valueOptions: [ - { value: 'BR', label: 'Brazil' }, - { value: 'FR', label: 'France' } - ] - } +If the column type is `'singleSelect'`, you also need to set the `valueOptions` property in the respective column definition. These values are options used for filtering and editing. - // With getOptionValue and getOptionLabel - { - getOptionValue: (value: any) => value.code, - getOptionLabel: (value: any) => value.name, - valueOptions: [ - { code: 'BR', name: 'Brazil' }, - { code: 'FR', name: 'France' } - ] - } - ``` +```tsx +{ + field: 'country', + type: 'singleSelect', + valueOptions: ['United Kingdom', 'Spain', 'Brazil'] +} +``` - ::: +:::warning +When using objects values for `valueOptions` you need to provide the `value` and `label` attributes for each option. +However, you can customize which attribute is used as value and label by using `getOptionValue` and `getOptionLabel`, respectively. -- If the column type is `'actions'`, you need to provide a `getActions` function that returns an array of actions available for each row (React elements). - You can add the `showInMenu` prop on the returned React elements to signal the data grid to group these actions inside a row menu. +```tsx +// Without getOptionValue and getOptionLabel +{ + valueOptions: [ + { value: 'BR', label: 'Brazil' }, + { value: 'FR', label: 'France' } + ] +} - ```tsx - { - field: 'actions', - type: 'actions', - getActions: (params: GridRowParams) => [ - <GridActionsCellItem icon={...} onClick={...} label="Delete" />, - <GridActionsCellItem icon={...} onClick={...} label="Print" showInMenu />, - ] - } - ``` +// With getOptionValue and getOptionLabel +{ + getOptionValue: (value: any) => value.code, + getOptionLabel: (value: any) => value.name, + valueOptions: [ + { code: 'BR', name: 'Brazil' }, + { code: 'FR', name: 'France' } + ] +} +``` -{{"demo": "ColumnTypesGrid.js", "bg": "inline"}} +::: + +#### Actions + +If the column type is `'actions'`, you need to provide a `getActions` function that returns an array of actions available for each row (React elements). +You can add the `showInMenu` prop on the returned React elements to signal the data grid to group these actions inside a row menu. + +```tsx +{ + field: 'actions', + type: 'actions', + getActions: (params: GridRowParams) => [ + <GridActionsCellItem icon={...} onClick={...} label="Delete" />, + <GridActionsCellItem icon={...} onClick={...} label="Print" showInMenu />, + ] +} +``` + +By default, actions shown in the menu will close the menu on click. +But in some cases, you might want to keep the menu open after clicking an action. +You can achieve this by setting the `closeMenuOnClick` prop to `false`. + +In the following example, the "Delete" action opens a confirmation dialog and therefore needs to keep the menu mounted: + +{{"demo": "ActionsWithModalGrid.js", "bg": "inline"}} ### Custom column types diff --git a/packages/grid/x-data-grid/src/components/cell/GridActionsCell.tsx b/packages/grid/x-data-grid/src/components/cell/GridActionsCell.tsx index 08083eab542e8..c3a64881b58a0 100644 --- a/packages/grid/x-data-grid/src/components/cell/GridActionsCell.tsx +++ b/packages/grid/x-data-grid/src/components/cell/GridActionsCell.tsx @@ -180,7 +180,7 @@ function GridActionsCell(props: GridActionsCellProps) { if (event.key === 'Tab') { event.preventDefault(); } - if (['Tab', 'Enter', 'Escape'].includes(event.key)) { + if (['Tab', 'Escape'].includes(event.key)) { hideMenu(); } }; @@ -223,13 +223,7 @@ function GridActionsCell(props: GridActionsCellProps) { )} {menuButtons.length > 0 && ( - <GridMenu - open={open} - target={buttonRef.current} - position={position} - onClose={hideMenu} - onClick={hideMenu} - > + <GridMenu open={open} target={buttonRef.current} position={position} onClose={hideMenu}> <MenuList id={menuId} className={gridClasses.menuList} @@ -238,7 +232,9 @@ function GridActionsCell(props: GridActionsCellProps) { variant="menu" autoFocusItem > - {menuButtons.map((button, index) => React.cloneElement(button, { key: index }))} + {menuButtons.map((button, index) => + React.cloneElement(button, { key: index, closeMenu: hideMenu }), + )} </MenuList> </GridMenu> )} diff --git a/packages/grid/x-data-grid/src/components/cell/GridActionsCellItem.tsx b/packages/grid/x-data-grid/src/components/cell/GridActionsCellItem.tsx index 2d3d5c5307a09..3cb8f38d93b5d 100644 --- a/packages/grid/x-data-grid/src/components/cell/GridActionsCellItem.tsx +++ b/packages/grid/x-data-grid/src/components/cell/GridActionsCellItem.tsx @@ -12,29 +12,35 @@ export type GridActionsCellItemProps = { component?: React.ElementType; } & ( | ({ showInMenu?: false; icon: React.ReactElement } & IconButtonProps) - | ({ showInMenu: true } & MenuItemProps) + | ({ + showInMenu: true; + /** + * If false, the menu will not close when this item is clicked. + * @default true + */ + closeMenuOnClick?: boolean; + closeMenu?: () => void; + } & MenuItemProps) ); -const GridActionsCellItem = React.forwardRef<HTMLButtonElement, GridActionsCellItemProps>( +const GridActionsCellItem = React.forwardRef<HTMLElement, GridActionsCellItemProps>( (props, ref) => { - const { label, icon, showInMenu, onClick, ...other } = props; - const rootProps = useGridRootProps(); - const handleClick = (event: any) => { - if (onClick) { - onClick(event); - } - }; + if (!props.showInMenu) { + const { label, icon, showInMenu, onClick, ...other } = props; + + const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => { + onClick?.(event); + }; - if (!showInMenu) { return ( <rootProps.slots.baseIconButton ref={ref} size="small" role="menuitem" aria-label={label} - {...(other as any)} + {...other} onClick={handleClick} {...rootProps.slotProps?.baseIconButton} > @@ -43,8 +49,25 @@ const GridActionsCellItem = React.forwardRef<HTMLButtonElement, GridActionsCellI ); } + const { + label, + icon, + showInMenu, + onClick, + closeMenuOnClick = true, + closeMenu, + ...other + } = props; + + const handleClick = (event: React.MouseEvent<HTMLLIElement>) => { + onClick?.(event); + if (closeMenuOnClick) { + closeMenu?.(); + } + }; + return ( - <MenuItem ref={ref} {...(other as any)} onClick={onClick}> + <MenuItem ref={ref} {...(other as any)} onClick={handleClick}> {icon && <ListItemIcon>{icon}</ListItemIcon>} {label} </MenuItem> From af046548d4534dcf690efe423e1be0d2acdb91fd Mon Sep 17 00:00:00 2001 From: Lukas <llukas.tyla@gmail.com> Date: Mon, 5 Feb 2024 17:07:30 +0200 Subject: [PATCH 18/35] [pickers] Avoid relying on locale in Luxon `isWithinRange` method (#11936) --- .../x-date-pickers/src/AdapterLuxon/AdapterLuxon.ts | 4 ++-- .../describeGregorianAdapter/testCalculations.ts | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/x-date-pickers/src/AdapterLuxon/AdapterLuxon.ts b/packages/x-date-pickers/src/AdapterLuxon/AdapterLuxon.ts index 295db06c32f41..0118a0025be80 100644 --- a/packages/x-date-pickers/src/AdapterLuxon/AdapterLuxon.ts +++ b/packages/x-date-pickers/src/AdapterLuxon/AdapterLuxon.ts @@ -324,8 +324,8 @@ export class AdapterLuxon implements MuiPickersAdapter<DateTime, string> { public isWithinRange = (value: DateTime, [start, end]: [DateTime, DateTime]) => { return ( - value.equals(start) || - value.equals(end) || + this.isEqual(value, start) || + this.isEqual(value, end) || (this.isAfter(value, start) && this.isBefore(value, end)) ); }; diff --git a/test/utils/pickers/describeGregorianAdapter/testCalculations.ts b/test/utils/pickers/describeGregorianAdapter/testCalculations.ts index e27fc0f3b458a..a8439902d70c0 100644 --- a/test/utils/pickers/describeGregorianAdapter/testCalculations.ts +++ b/test/utils/pickers/describeGregorianAdapter/testCalculations.ts @@ -577,7 +577,7 @@ export const testCalculations: DescribeGregorianAdapterTestSuite = ({ ).to.equal(false); }); - it('should use inclusivity of range', () => { + it('should use inclusiveness of range', () => { expect( adapter.isWithinRange(adapter.date('2019-09-01T00:00:00.000Z')!, [ adapter.date('2019-09-01T00:00:00.000Z')!, @@ -606,6 +606,15 @@ export const testCalculations: DescribeGregorianAdapterTestSuite = ({ ]), ).to.equal(true); }); + + it('should be equal with values in different locales', () => { + expect( + adapter.isWithinRange(adapter.date('2022-04-17'), [ + adapterFr.date('2022-04-17'), + adapterFr.date('2022-04-19'), + ]), + ).to.equal(true); + }); }); it('Method: startOfYear', () => { From c5d5a17962b1347bee77516c741fbe24ee73917f Mon Sep 17 00:00:00 2001 From: Rom Grk <romgrk@users.noreply.github.com> Date: Mon, 5 Feb 2024 10:17:08 -0500 Subject: [PATCH 19/35] [DataGrid] Add slot typings (#11795) Co-authored-by: Andrew Cherniavskyi <andrew@mui.com> Co-authored-by: Bilal Shafi <bilalshafidev@gmail.com> --- .../data-grid/components/CustomColumnMenu.tsx | 3 +- .../components/CustomLoadingOverlayGrid.tsx | 4 +- .../CustomLoadingOverlayGrid.tsx.preview | 2 +- docs/data/data-grid/components/components.md | 18 ++- .../editing/FullFeaturedCrudGrid.tsx | 3 +- .../editing/FullFeaturedCrudGrid.tsx.preview | 2 +- .../data-grid/editing/StartEditButtonGrid.tsx | 3 +- .../filtering/CustomFilterPanelPosition.tsx | 3 +- .../CustomFilterPanelPosition.tsx.preview | 2 +- .../row-updates/InfiniteLoadingGrid.tsx | 4 +- .../InfiniteLoadingGrid.tsx.preview | 2 +- .../state/RestoreStateInitialState.tsx | 3 +- .../RestoreStateInitialState.tsx.preview | 2 +- .../migration-data-grid-v6.md | 1 + .../src/DataGridPremium/DataGridPremium.tsx | 2 + .../src/DataGridPro/DataGridPro.tsx | 2 + .../GridHeaderFilterMenuContainer.tsx | 7 +- .../x-data-grid/src/DataGrid/DataGrid.tsx | 2 + .../src/components/GridPagination.tsx | 2 +- .../x-data-grid/src/components/GridRow.tsx | 2 +- .../components/base/GridFooterPlaceholder.tsx | 4 +- .../GridCellCheckboxRenderer.tsx | 4 +- .../columnSelection/GridHeaderCheckbox.tsx | 2 +- .../panel/filterPanel/GridFilterForm.tsx | 6 +- .../filterPanel/GridFilterInputBoolean.tsx | 4 +- .../GridFilterInputSingleSelect.tsx | 6 +- .../grid/x-data-grid/src/joy/joySlots.tsx | 29 ++-- .../src/models/api/gridLocaleTextApi.ts | 6 +- .../src/models/gridSlotsComponent.ts | 74 +++++------ .../src/models/gridSlotsComponentsProps.ts | 125 ++++++++++-------- .../src/tests/filtering.DataGrid.test.tsx | 5 +- scripts/x-data-grid-premium.exports.json | 8 +- scripts/x-data-grid-pro.exports.json | 8 +- scripts/x-data-grid.exports.json | 8 +- 34 files changed, 208 insertions(+), 150 deletions(-) diff --git a/docs/data/data-grid/components/CustomColumnMenu.tsx b/docs/data/data-grid/components/CustomColumnMenu.tsx index 70275eb92d007..9a0a7fa8d4f3e 100644 --- a/docs/data/data-grid/components/CustomColumnMenu.tsx +++ b/docs/data/data-grid/components/CustomColumnMenu.tsx @@ -10,6 +10,7 @@ import { GridColumnMenuSortItem, useGridApiRef, DataGridPro, + GridSlots, } from '@mui/x-data-grid-pro'; import StarOutlineIcon from '@mui/icons-material/StarOutline'; @@ -119,7 +120,7 @@ export default function CustomColumnMenu() { }, ]} slots={{ - columnMenu: CustomColumnMenuComponent, + columnMenu: CustomColumnMenuComponent as GridSlots['columnMenu'], }} slotProps={{ columnMenu: { color }, diff --git a/docs/data/data-grid/components/CustomLoadingOverlayGrid.tsx b/docs/data/data-grid/components/CustomLoadingOverlayGrid.tsx index fef9a8145a76c..c278f02c68a45 100644 --- a/docs/data/data-grid/components/CustomLoadingOverlayGrid.tsx +++ b/docs/data/data-grid/components/CustomLoadingOverlayGrid.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { DataGrid } from '@mui/x-data-grid'; +import { DataGrid, GridSlots } from '@mui/x-data-grid'; import LinearProgress from '@mui/material/LinearProgress'; import { useDemoData } from '@mui/x-data-grid-generator'; @@ -14,7 +14,7 @@ export default function CustomLoadingOverlayGrid() { <div style={{ height: 400, width: '100%' }}> <DataGrid slots={{ - loadingOverlay: LinearProgress, + loadingOverlay: LinearProgress as GridSlots['loadingOverlay'], }} loading {...data} diff --git a/docs/data/data-grid/components/CustomLoadingOverlayGrid.tsx.preview b/docs/data/data-grid/components/CustomLoadingOverlayGrid.tsx.preview index f9ad726dd2ea2..84c2df95e8387 100644 --- a/docs/data/data-grid/components/CustomLoadingOverlayGrid.tsx.preview +++ b/docs/data/data-grid/components/CustomLoadingOverlayGrid.tsx.preview @@ -1,6 +1,6 @@ <DataGrid slots={{ - loadingOverlay: LinearProgress, + loadingOverlay: LinearProgress as GridSlots['loadingOverlay'], }} loading {...data} diff --git a/docs/data/data-grid/components/components.md b/docs/data/data-grid/components/components.md index f2e7826a07ec0..481d3ce2072a5 100644 --- a/docs/data/data-grid/components/components.md +++ b/docs/data/data-grid/components/components.md @@ -8,16 +8,16 @@ As part of the customization API, the Data Grid allows you to override internal The prop accepts an object of type [`GridSlotsComponent`](/x/api/data-grid/data-grid/#slots). If you wish to pass additional props in a component slot, you can do it using the `slotProps` prop. -This prop is of type `GridSlotsComponentsProps`. +This prop is of type `GridSlotsComponentsProps`. Note that if you do and you use typescript, you'll need to cast your custom component so it can fit in the slot type. As an example, you could override the column menu and pass additional props as below. -```jsx +```tsx <DataGrid rows={rows} columns={columns} slots={{ - columnMenu: MyCustomColumnMenu, + columnMenu: MyCustomColumnMenu as DataGridProps['slots']['columnMenu'], }} slotProps={{ columnMenu: { background: 'red', counter: rows.length }, @@ -25,6 +25,18 @@ As an example, you could override the column menu and pass additional props as b /> ``` +If you want to ensure type safety, you can declare your component using the slot props typings: + +```tsx +import { GridSlotProps } from '@mui/x-data-grid'; + +function MyCustomColumnMenu( + props: GridSlotProps['columnMenu'] & { background: string; counter: number }, +) { + // ... +} +``` + ### Interacting with the data grid The grid exposes two hooks to help you to access the data grid data while overriding component slots. diff --git a/docs/data/data-grid/editing/FullFeaturedCrudGrid.tsx b/docs/data/data-grid/editing/FullFeaturedCrudGrid.tsx index a3f845377b155..ea0680357f04a 100644 --- a/docs/data/data-grid/editing/FullFeaturedCrudGrid.tsx +++ b/docs/data/data-grid/editing/FullFeaturedCrudGrid.tsx @@ -18,6 +18,7 @@ import { GridRowId, GridRowModel, GridRowEditStopReasons, + GridSlots, } from '@mui/x-data-grid'; import { randomCreatedDate, @@ -237,7 +238,7 @@ export default function FullFeaturedCrudGrid() { onRowEditStop={handleRowEditStop} processRowUpdate={processRowUpdate} slots={{ - toolbar: EditToolbar, + toolbar: EditToolbar as GridSlots['toolbar'], }} slotProps={{ toolbar: { setRows, setRowModesModel }, diff --git a/docs/data/data-grid/editing/FullFeaturedCrudGrid.tsx.preview b/docs/data/data-grid/editing/FullFeaturedCrudGrid.tsx.preview index b060ee3cfc323..2693093092106 100644 --- a/docs/data/data-grid/editing/FullFeaturedCrudGrid.tsx.preview +++ b/docs/data/data-grid/editing/FullFeaturedCrudGrid.tsx.preview @@ -7,7 +7,7 @@ onRowEditStop={handleRowEditStop} processRowUpdate={processRowUpdate} slots={{ - toolbar: EditToolbar, + toolbar: EditToolbar as GridSlots['toolbar'], }} slotProps={{ toolbar: { setRows, setRowModesModel }, diff --git a/docs/data/data-grid/editing/StartEditButtonGrid.tsx b/docs/data/data-grid/editing/StartEditButtonGrid.tsx index 6397547acaac8..98f848fd4e14e 100644 --- a/docs/data/data-grid/editing/StartEditButtonGrid.tsx +++ b/docs/data/data-grid/editing/StartEditButtonGrid.tsx @@ -9,6 +9,7 @@ import { GridCellModes, GridEventListener, GridCellModesModel, + GridSlots, } from '@mui/x-data-grid'; import { randomCreatedDate, @@ -147,7 +148,7 @@ export default function StartEditButtonGrid() { onCellEditStop={handleCellEditStop} onCellModesModelChange={(model) => setCellModesModel(model)} slots={{ - toolbar: EditToolbar, + toolbar: EditToolbar as GridSlots['toolbar'], }} slotProps={{ toolbar: { diff --git a/docs/data/data-grid/filtering/CustomFilterPanelPosition.tsx b/docs/data/data-grid/filtering/CustomFilterPanelPosition.tsx index 65f85ed661714..2f686357b240a 100644 --- a/docs/data/data-grid/filtering/CustomFilterPanelPosition.tsx +++ b/docs/data/data-grid/filtering/CustomFilterPanelPosition.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { DataGrid, + GridSlots, GridToolbarContainer, GridToolbarFilterButton, } from '@mui/x-data-grid'; @@ -35,7 +36,7 @@ export default function CustomFilterPanelPosition() { <DataGrid {...data} slots={{ - toolbar: CustomToolbar, + toolbar: CustomToolbar as GridSlots['toolbar'], }} slotProps={{ panel: { diff --git a/docs/data/data-grid/filtering/CustomFilterPanelPosition.tsx.preview b/docs/data/data-grid/filtering/CustomFilterPanelPosition.tsx.preview index a9b9de62d6d60..ded969e1fd1e9 100644 --- a/docs/data/data-grid/filtering/CustomFilterPanelPosition.tsx.preview +++ b/docs/data/data-grid/filtering/CustomFilterPanelPosition.tsx.preview @@ -1,7 +1,7 @@ <DataGrid {...data} slots={{ - toolbar: CustomToolbar, + toolbar: CustomToolbar as GridSlots['toolbar'], }} slotProps={{ panel: { diff --git a/docs/data/data-grid/row-updates/InfiniteLoadingGrid.tsx b/docs/data/data-grid/row-updates/InfiniteLoadingGrid.tsx index f25f0c832f9b2..7ab60d8647492 100644 --- a/docs/data/data-grid/row-updates/InfiniteLoadingGrid.tsx +++ b/docs/data/data-grid/row-updates/InfiniteLoadingGrid.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { DataGridPro, DataGridProProps } from '@mui/x-data-grid-pro'; +import { DataGridPro, DataGridProProps, GridSlots } from '@mui/x-data-grid-pro'; import { useDemoData, getRealGridData, @@ -61,7 +61,7 @@ export default function InfiniteLoadingGrid() { hideFooterPagination onRowsScrollEnd={handleOnRowsScrollEnd} slots={{ - loadingOverlay: LinearProgress, + loadingOverlay: LinearProgress as GridSlots['loadingOverlay'], }} /> </div> diff --git a/docs/data/data-grid/row-updates/InfiniteLoadingGrid.tsx.preview b/docs/data/data-grid/row-updates/InfiniteLoadingGrid.tsx.preview index db0cc47aa7911..d8a614229f5c7 100644 --- a/docs/data/data-grid/row-updates/InfiniteLoadingGrid.tsx.preview +++ b/docs/data/data-grid/row-updates/InfiniteLoadingGrid.tsx.preview @@ -5,6 +5,6 @@ hideFooterPagination onRowsScrollEnd={handleOnRowsScrollEnd} slots={{ - loadingOverlay: LinearProgress, + loadingOverlay: LinearProgress as GridSlots['loadingOverlay'], }} /> \ No newline at end of file diff --git a/docs/data/data-grid/state/RestoreStateInitialState.tsx b/docs/data/data-grid/state/RestoreStateInitialState.tsx index 7e576cec4eb9b..d953a4a8e5a50 100644 --- a/docs/data/data-grid/state/RestoreStateInitialState.tsx +++ b/docs/data/data-grid/state/RestoreStateInitialState.tsx @@ -5,6 +5,7 @@ import Stack from '@mui/material/Stack'; import { DataGridPro, GridInitialState, + GridSlots, GridToolbarContainer, GridToolbarDensitySelector, GridToolbarFilterButton, @@ -62,7 +63,7 @@ export default function RestoreStateInitialState() { <DataGridPro {...data} loading={loading} - slots={{ toolbar: GridCustomToolbar }} + slots={{ toolbar: GridCustomToolbar as GridSlots['toolbar'] }} slotProps={{ toolbar: { syncState } }} /> </Box> diff --git a/docs/data/data-grid/state/RestoreStateInitialState.tsx.preview b/docs/data/data-grid/state/RestoreStateInitialState.tsx.preview index cb7e99c92deb1..a02338eabb0bb 100644 --- a/docs/data/data-grid/state/RestoreStateInitialState.tsx.preview +++ b/docs/data/data-grid/state/RestoreStateInitialState.tsx.preview @@ -2,7 +2,7 @@ <DataGridPro {...data} loading={loading} - slots={{ toolbar: GridCustomToolbar }} + slots={{ toolbar: GridCustomToolbar as GridSlots['toolbar'] }} slotProps={{ toolbar: { syncState } }} /> </Box> diff --git a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md index 907ccdf3398a3..6e9df3de4b2f9 100644 --- a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md +++ b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md @@ -457,5 +457,6 @@ Here's the list of affected features, colDef flags and props to disable them and - The slot `row` has had these props removed: `containerWidth`, `position`. - The slot `row` has typed props now. - The slot `headerFilterCell` has had these props removed: `filterOperators`. +- All slots are now strongly typed, previously were `React.JSXElementConstructor<any>`. <!-- ### Rename `components` to `slots` --> diff --git a/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index e4958093925cb..f013899888d81 100644 --- a/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -23,6 +23,8 @@ import { import { useDataGridPremiumProps } from './useDataGridPremiumProps'; import { getReleaseInfo } from '../utils/releaseInfo'; +export type { GridPremiumSlotsComponent as GridSlots } from '../models'; + const releaseInfo = getReleaseInfo(); const dataGridPremiumPropValidators: PropValidator<DataGridPremiumProcessedProps>[] = [ diff --git a/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index b6623f1c4d26e..e14b2b41380d8 100644 --- a/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -16,6 +16,8 @@ import { useDataGridProProps } from './useDataGridProProps'; import { getReleaseInfo } from '../utils/releaseInfo'; import { propValidatorsDataGridPro } from '../internals/propValidation'; +export type { GridProSlotsComponent as GridSlots } from '../models'; + const releaseInfo = getReleaseInfo(); const DataGridProRaw = React.forwardRef(function DataGridPro<R extends GridValidRowModel>( diff --git a/packages/grid/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterMenuContainer.tsx b/packages/grid/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterMenuContainer.tsx index 4e89cdfd4d6cd..ac8188dd7226f 100644 --- a/packages/grid/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterMenuContainer.tsx +++ b/packages/grid/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterMenuContainer.tsx @@ -53,13 +53,16 @@ function GridHeaderFilterMenuContainer(props: { return null; } + const label = apiRef.current.getLocaleText('filterPanelOperator'); + const labelString = label ? String(label) : undefined; + return ( <React.Fragment> <rootProps.slots.baseIconButton id={buttonId} ref={buttonRef} - aria-label={apiRef.current.getLocaleText('filterPanelOperator')} - title={apiRef.current.getLocaleText('filterPanelOperator')} + aria-label={labelString} + title={labelString} aria-controls={menuId} aria-expanded={open ? 'true' : undefined} aria-haspopup="true" diff --git a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx index 45be6056de0aa..bae5e67639324 100644 --- a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx @@ -12,6 +12,8 @@ import { validateProps, } from '../internals/utils/propValidation'; +export type { GridSlotsComponent as GridSlots } from '../models'; + const propValidators: PropValidator<DataGridProcessedProps>[] = [ ...propValidatorsDataGrid, // Only validate in MIT version diff --git a/packages/grid/x-data-grid/src/components/GridPagination.tsx b/packages/grid/x-data-grid/src/components/GridPagination.tsx index 92c2717b2eae8..f7a45091220cb 100644 --- a/packages/grid/x-data-grid/src/components/GridPagination.tsx +++ b/packages/grid/x-data-grid/src/components/GridPagination.tsx @@ -26,7 +26,7 @@ const GridPaginationRoot = styled(TablePagination)(({ theme }) => ({ }, })) as typeof TablePagination; -export const GridPagination = React.forwardRef<HTMLDivElement, Partial<TablePaginationProps>>( +export const GridPagination = React.forwardRef<unknown, Partial<TablePaginationProps>>( function GridPagination(props, ref) { const apiRef = useGridApiContext(); const rootProps = useGridRootProps(); diff --git a/packages/grid/x-data-grid/src/components/GridRow.tsx b/packages/grid/x-data-grid/src/components/GridRow.tsx index c66b72793ff3e..457218861b733 100644 --- a/packages/grid/x-data-grid/src/components/GridRow.tsx +++ b/packages/grid/x-data-grid/src/components/GridRow.tsx @@ -389,7 +389,7 @@ const GridRow = React.forwardRef<HTMLDivElement, GridRowProps>(function GridRow( width={width} contentWidth={contentWidth} field={column.field} - align={column.align} + align={column.align ?? 'left'} /> ); } diff --git a/packages/grid/x-data-grid/src/components/base/GridFooterPlaceholder.tsx b/packages/grid/x-data-grid/src/components/base/GridFooterPlaceholder.tsx index 5974991f1bf83..d27336afc8653 100644 --- a/packages/grid/x-data-grid/src/components/base/GridFooterPlaceholder.tsx +++ b/packages/grid/x-data-grid/src/components/base/GridFooterPlaceholder.tsx @@ -8,5 +8,7 @@ export function GridFooterPlaceholder() { return null; } - return <rootProps.slots.footer {...rootProps.slotProps?.footer} />; + return ( + <rootProps.slots.footer {...(rootProps.slotProps?.footer as any) /* FIXME: typing error */} /> + ); } diff --git a/packages/grid/x-data-grid/src/components/columnSelection/GridCellCheckboxRenderer.tsx b/packages/grid/x-data-grid/src/components/columnSelection/GridCellCheckboxRenderer.tsx index 7353974fabb98..db1ea9d1d3eb6 100644 --- a/packages/grid/x-data-grid/src/components/columnSelection/GridCellCheckboxRenderer.tsx +++ b/packages/grid/x-data-grid/src/components/columnSelection/GridCellCheckboxRenderer.tsx @@ -49,7 +49,7 @@ const GridCellCheckboxForwardRef = React.forwardRef<HTMLInputElement, GridRender const rootProps = useGridRootProps(); const ownerState = { classes: rootProps.classes }; const classes = useUtilityClasses(ownerState); - const checkboxElement = React.useRef<HTMLInputElement | null>(null); + const checkboxElement = React.useRef<HTMLElement>(null); const rippleRef = React.useRef<TouchRippleActions>(null); const handleRef = useForkRef(checkboxElement, ref); @@ -104,7 +104,7 @@ const GridCellCheckboxForwardRef = React.forwardRef<HTMLInputElement, GridRender inputProps={{ 'aria-label': label }} onKeyDown={handleKeyDown} disabled={!isSelectable} - touchRippleRef={rippleRef} + touchRippleRef={rippleRef as any /* FIXME: typing error */} {...rootProps.slotProps?.baseCheckbox} {...other} /> diff --git a/packages/grid/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx b/packages/grid/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx index b62cc90fed944..215608379c39a 100644 --- a/packages/grid/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx +++ b/packages/grid/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx @@ -27,7 +27,7 @@ const useUtilityClasses = (ownerState: OwnerState) => { return composeClasses(slots, getDataGridUtilityClass, classes); }; -const GridHeaderCheckbox = React.forwardRef<HTMLInputElement, GridColumnHeaderParams>( +const GridHeaderCheckbox = React.forwardRef<HTMLButtonElement, GridColumnHeaderParams>( function GridHeaderCheckbox(props, ref) { const { field, colDef, ...other } = props; const [, forceUpdate] = React.useState(false); diff --git a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx index bc6bfdc1c3549..9ff36187ec42c 100644 --- a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx +++ b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx @@ -316,7 +316,7 @@ const GridFilterForm = React.forwardRef<HTMLDivElement, GridFilterFormProps>( }, [item, currentColumn]); const changeColumn = React.useCallback( - (event: SelectChangeEvent) => { + (event: SelectChangeEvent<any>) => { const field = event.target.value as string; const column = apiRef.current.getColumn(field)!; @@ -369,7 +369,7 @@ const GridFilterForm = React.forwardRef<HTMLDivElement, GridFilterFormProps>( ); const changeOperator = React.useCallback( - (event: SelectChangeEvent) => { + (event: SelectChangeEvent<any>) => { const operator = event.target.value as string; const newOperator = currentColumn?.filterOperators!.find((op) => op.value === operator); @@ -388,7 +388,7 @@ const GridFilterForm = React.forwardRef<HTMLDivElement, GridFilterFormProps>( ); const changeLogicOperator = React.useCallback( - (event: SelectChangeEvent) => { + (event: SelectChangeEvent<any>) => { const logicOperator = (event.target.value as string) === GridLogicOperator.And.toString() ? GridLogicOperator.And diff --git a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputBoolean.tsx b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputBoolean.tsx index 32c79a69e6b76..f8dc457521aa1 100644 --- a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputBoolean.tsx +++ b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputBoolean.tsx @@ -85,7 +85,9 @@ function GridFilterInputBoolean(props: GridFilterInputBooleanProps) { native={isSelectNative} displayEmpty inputProps={{ ref: focusElementRef, tabIndex }} - {...others} + { + ...(others as any) /* FIXME: typing error */ + } {...baseSelectProps} > <rootProps.slots.baseSelectOption diff --git a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputSingleSelect.tsx b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputSingleSelect.tsx index 43994aa5409f8..230971be89b91 100644 --- a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputSingleSelect.tsx +++ b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputSingleSelect.tsx @@ -104,7 +104,7 @@ function GridFilterInputSingleSelect(props: GridFilterInputSingleSelectProps) { }, [resolvedColumn]); const onFilterChange = React.useCallback( - (event: SelectChangeEvent) => { + (event: SelectChangeEvent<any>) => { let value = event.target.value; // NativeSelect casts the value to a string. @@ -146,7 +146,9 @@ function GridFilterInputSingleSelect(props: GridFilterInputSingleSelectProps) { placeholder: placeholder ?? apiRef.current.getLocaleText('filterPanelInputPlaceholder'), }} native={isSelectNative} - {...others} + { + ...(others as any) /* FIXME: typing error */ + } {...rootProps.slotProps?.baseSelect} > {renderSingleSelectOptions({ diff --git a/packages/grid/x-data-grid/src/joy/joySlots.tsx b/packages/grid/x-data-grid/src/joy/joySlots.tsx index 7e245b9180657..7c5819657da0f 100644 --- a/packages/grid/x-data-grid/src/joy/joySlots.tsx +++ b/packages/grid/x-data-grid/src/joy/joySlots.tsx @@ -16,7 +16,7 @@ import JoyCircularProgress from '@mui/joy/CircularProgress'; import JoyTooltip from '@mui/joy/Tooltip'; import { unstable_useForkRef as useForkRef } from '@mui/utils'; import joyIconSlots, { GridKeyboardArrowRight, GridKeyboardArrowLeft } from './icons'; -import type { GridSlotsComponent, GridSlotsComponentsProps } from '../models'; +import type { GridSlotProps, GridSlotsComponent, GridSlotsComponentsProps } from '../models'; import { useGridApiContext } from '../hooks/utils/useGridApiContext'; import { useGridRootProps } from '../hooks/utils/useGridRootProps'; import { gridFilteredTopLevelRowCountSelector, gridPaginationModelSelector } from '../hooks'; @@ -116,10 +116,10 @@ const TextField = React.forwardRef< ); }); -const Button = React.forwardRef< - HTMLButtonElement, - NonNullable<GridSlotsComponentsProps['baseButton']> ->(function Button({ startIcon, color, endIcon, size, sx, variant, ...props }, ref) { +const Button = React.forwardRef<HTMLButtonElement, GridSlotProps['baseButton']>(function Button( + { startIcon, color, endIcon, size, sx, variant, ...props }, + ref, +) { return ( <JoyButton {...props} @@ -150,10 +150,7 @@ const IconButton = React.forwardRef< ); }); -const Switch = React.forwardRef< - HTMLDivElement, - NonNullable<GridSlotsComponentsProps['baseSwitch']> ->(function Switch( +const Switch = React.forwardRef<any, GridSlotProps['baseSwitch']>(function Switch( { name, checkedIcon, @@ -204,10 +201,7 @@ const Switch = React.forwardRef< ); }); -const Select = React.forwardRef< - HTMLButtonElement, - NonNullable<GridSlotsComponentsProps['baseSelect']> ->( +const Select = React.forwardRef<any, GridSlotProps['baseSelect']>( ( { open, @@ -314,10 +308,7 @@ const getLabelDisplayedRowsTo = ({ return pageSize === -1 ? rowCount : Math.min(rowCount, (page + 1) * pageSize); }; -const Pagination = React.forwardRef< - HTMLDivElement, - NonNullable<GridSlotsComponentsProps['pagination']> ->((props, ref) => { +const Pagination = React.forwardRef<any, GridSlotProps['pagination']>((props, ref) => { const apiRef = useGridApiContext(); const rootProps = useGridRootProps(); const paginationModel = gridPaginationModelSelector(apiRef); @@ -443,8 +434,8 @@ const joySlots: Partial<GridSlotsComponent> = { baseSelect: Select, baseSelectOption: Option, baseInputLabel: InputLabel, - baseFormControl: JoyFormControl, - baseTooltip: JoyTooltip, + baseFormControl: JoyFormControl as any /* FIXME: typing error */, + baseTooltip: JoyTooltip as any /* FIXME: typing error */, pagination: Pagination, loadingOverlay: LoadingOverlay, }; diff --git a/packages/grid/x-data-grid/src/models/api/gridLocaleTextApi.ts b/packages/grid/x-data-grid/src/models/api/gridLocaleTextApi.ts index c77fe2f388f9a..b25858988c0a4 100644 --- a/packages/grid/x-data-grid/src/models/api/gridLocaleTextApi.ts +++ b/packages/grid/x-data-grid/src/models/api/gridLocaleTextApi.ts @@ -41,9 +41,9 @@ export interface GridLocaleText { toolbarExportExcel: string; // Columns management text - columnsManagementSearchTitle: React.ReactNode; - columnsManagementNoColumns: React.ReactNode; - columnsManagementShowHideAllText: React.ReactNode; + columnsManagementSearchTitle: string; + columnsManagementNoColumns: string; + columnsManagementShowHideAllText: string; // Filter panel text filterPanelAddFilter: React.ReactNode; diff --git a/packages/grid/x-data-grid/src/models/gridSlotsComponent.ts b/packages/grid/x-data-grid/src/models/gridSlotsComponent.ts index 2fec34e839a47..aedf8ceb29a95 100644 --- a/packages/grid/x-data-grid/src/models/gridSlotsComponent.ts +++ b/packages/grid/x-data-grid/src/models/gridSlotsComponent.ts @@ -1,77 +1,75 @@ import * as React from 'react'; +import type { GridSlotProps } from './gridSlotsComponentsProps'; import type { GridIconSlotsComponent } from './gridIconSlotsComponent'; -import type { GridRowProps } from '../components/GridRow'; -import type { GridDetailPanelsProps } from '../components/GridDetailPanels'; -import type { GridPinnedRowsProps } from '../components/GridPinnedRows'; -import type { GridColumnHeadersProps } from '../components/GridColumnHeaders'; -// TODO: Convert all `any` to `Props & PropsOverrides` +export type { GridSlotProps } from './gridSlotsComponentsProps'; + export interface GridBaseSlots { /** * The custom Checkbox component used in the grid for both header and cells. * @default Checkbox */ - baseCheckbox: React.JSXElementConstructor<any>; + baseCheckbox: React.JSXElementConstructor<GridSlotProps['baseCheckbox']>; /** * The custom Chip component used in the grid. * @default Chip */ - baseChip: React.JSXElementConstructor<any>; + baseChip: React.JSXElementConstructor<GridSlotProps['baseChip']>; /** * The custom InputAdornment component used in the grid. * @default InputAdornment */ - baseInputAdornment: React.JSXElementConstructor<any>; + baseInputAdornment: React.JSXElementConstructor<GridSlotProps['baseInputAdornment']>; /** * The custom TextField component used in the grid. * @default TextField */ - baseTextField: React.JSXElementConstructor<any>; + baseTextField: React.JSXElementConstructor<GridSlotProps['baseTextField']>; /** * The custom FormControl component used in the grid. * @default FormControl */ - baseFormControl: React.JSXElementConstructor<any>; + baseFormControl: React.JSXElementConstructor<GridSlotProps['baseFormControl']>; /** * The custom Select component used in the grid. * @default Select */ - baseSelect: React.JSXElementConstructor<any>; + baseSelect: React.JSXElementConstructor<GridSlotProps['baseSelect']>; /** * The custom Switch component used in the grid. * @default Switch */ - baseSwitch: React.JSXElementConstructor<any>; + baseSwitch: React.JSXElementConstructor<GridSlotProps['baseSwitch']>; /** * The custom Button component used in the grid. * @default Button */ - baseButton: React.JSXElementConstructor<any>; + baseButton: React.JSXElementConstructor<GridSlotProps['baseButton']>; /** * The custom IconButton component used in the grid. * @default IconButton */ - baseIconButton: React.JSXElementConstructor<any>; + baseIconButton: React.JSXElementConstructor<GridSlotProps['baseIconButton']>; /** * The custom Tooltip component used in the grid. * @default Tooltip */ - baseTooltip: React.JSXElementConstructor<any>; + baseTooltip: React.JSXElementConstructor<GridSlotProps['baseTooltip']>; /** * The custom Popper component used in the grid. * @default Popper */ - basePopper: React.JSXElementConstructor<any>; + basePopper: React.JSXElementConstructor<GridSlotProps['basePopper']>; /** * The custom InputLabel component used in the grid. * @default InputLabel */ - baseInputLabel: React.JSXElementConstructor<any>; + baseInputLabel: React.JSXElementConstructor<GridSlotProps['baseInputLabel']>; /** * The custom SelectOption component used in the grid. * @default MenuItem */ - baseSelectOption: React.JSXElementConstructor<any>; + baseSelectOption: React.JSXElementConstructor<GridSlotProps['baseSelectOption']>; } /** @@ -82,87 +80,89 @@ export interface GridSlotsComponent extends GridBaseSlots, GridIconSlotsComponen * The custom Chip component used in the grid. * @default Chip */ - baseChip: React.JSXElementConstructor<any>; + baseChip: React.JSXElementConstructor<GridSlotProps['baseChip']>; /** * Component rendered for each cell. * @default GridCell */ - cell: React.JSXElementConstructor<any>; + cell: React.JSXElementConstructor<GridSlotProps['cell']>; /** * Component rendered for each skeleton cell. * @default GridSkeletonCell */ - skeletonCell: React.JSXElementConstructor<any>; + skeletonCell: React.JSXElementConstructor<GridSlotProps['skeletonCell']>; /** * Filter icon component rendered in each column header. * @default GridColumnHeaderFilterIconButton */ - columnHeaderFilterIconButton: React.JSXElementConstructor<any>; + columnHeaderFilterIconButton: React.JSXElementConstructor< + GridSlotProps['columnHeaderFilterIconButton'] + >; /** * Column menu component rendered by clicking on the 3 dots "kebab" icon in column headers. * @default GridColumnMenu */ - columnMenu: React.JSXElementConstructor<any>; + columnMenu: React.JSXElementConstructor<GridSlotProps['columnMenu']>; /** * Component responsible for rendering the column headers. * @default DataGridColumnHeaders */ - columnHeaders: React.JSXElementConstructor<GridColumnHeadersProps>; + columnHeaders: React.JSXElementConstructor<GridSlotProps['columnHeaders']>; /** * Component responsible for rendering the detail panels. * @default GridDetailPanels */ - detailPanels: React.JSXElementConstructor<GridDetailPanelsProps>; + detailPanels: React.JSXElementConstructor<GridSlotProps['detailPanels']>; /** * Footer component rendered at the bottom of the grid viewport. * @default GridFooter */ - footer: React.JSXElementConstructor<any>; + footer: React.JSXElementConstructor<GridSlotProps['footer']>; /** * Row count component rendered in the footer * @default GridRowCount */ - footerRowCount: React.JSXElementConstructor<any>; + footerRowCount: React.JSXElementConstructor<GridSlotProps['footerRowCount']>; /** * Toolbar component rendered inside the Header component. * @default null */ - toolbar: React.JSXElementConstructor<any> | null; + toolbar: React.JSXElementConstructor<GridSlotProps['toolbar']> | null; /** * Pinned rows container. * @ignore - do not document */ - pinnedRows: React.JSXElementConstructor<GridPinnedRowsProps>; + pinnedRows: React.JSXElementConstructor<GridSlotProps['pinnedRows']>; /** * Loading overlay component rendered when the grid is in a loading state. * @default GridLoadingOverlay */ - loadingOverlay: React.JSXElementConstructor<any>; + loadingOverlay: React.JSXElementConstructor<GridSlotProps['loadingOverlay']>; /** * No results overlay component rendered when the grid has no results after filtering. * @default GridNoResultsOverlay */ - noResultsOverlay: React.JSXElementConstructor<any>; + noResultsOverlay: React.JSXElementConstructor<GridSlotProps['noResultsOverlay']>; /** * No rows overlay component rendered when the grid has no rows. * @default GridNoRowsOverlay */ - noRowsOverlay: React.JSXElementConstructor<any>; + noRowsOverlay: React.JSXElementConstructor<GridSlotProps['noRowsOverlay']>; /** * Pagination component rendered in the grid footer by default. * @default Pagination */ - pagination: React.JSXElementConstructor<any> | null; + pagination: React.JSXElementConstructor<GridSlotProps['pagination']> | null; /** * Filter panel component rendered when clicking the filter button. * @default GridFilterPanel */ - filterPanel: React.JSXElementConstructor<any>; + filterPanel: React.JSXElementConstructor<GridSlotProps['filterPanel']>; /** * GridColumns panel component rendered when clicking the columns button. * @default GridColumnsPanel */ - columnsPanel: React.JSXElementConstructor<any>; + columnsPanel: React.JSXElementConstructor<GridSlotProps['columnsPanel']>; /** * Component used inside Grid Columns panel to manage columns. * @default GridColumnsManagement @@ -172,10 +172,10 @@ export interface GridSlotsComponent extends GridBaseSlots, GridIconSlotsComponen * Panel component wrapping the filters and columns panels. * @default GridPanel */ - panel: React.JSXElementConstructor<any>; + panel: React.JSXElementConstructor<GridSlotProps['panel']>; /** * Component rendered for each row. * @default GridRow */ - row: React.JSXElementConstructor<GridRowProps>; + row: React.JSXElementConstructor<GridSlotProps['row']>; } diff --git a/packages/grid/x-data-grid/src/models/gridSlotsComponentsProps.ts b/packages/grid/x-data-grid/src/models/gridSlotsComponentsProps.ts index b22b600d1c4cc..6623ae5d4483e 100644 --- a/packages/grid/x-data-grid/src/models/gridSlotsComponentsProps.ts +++ b/packages/grid/x-data-grid/src/models/gridSlotsComponentsProps.ts @@ -1,26 +1,31 @@ import * as React from 'react'; -import { CheckboxProps } from '@mui/material/Checkbox'; -import { TextFieldProps } from '@mui/material/TextField'; -import { FormControlProps } from '@mui/material/FormControl'; -import { SelectProps } from '@mui/material/Select'; -import { SwitchProps } from '@mui/material/Switch'; -import { ButtonProps } from '@mui/material/Button'; -import { IconButtonProps } from '@mui/material/IconButton'; -import { TooltipProps } from '@mui/material/Tooltip'; +import type { CheckboxProps } from '@mui/material/Checkbox'; +import type { TextFieldProps } from '@mui/material/TextField'; +import type { FormControlProps } from '@mui/material/FormControl'; +import type { SelectProps } from '@mui/material/Select'; +import type { SwitchProps } from '@mui/material/Switch'; +import type { ButtonProps } from '@mui/material/Button'; +import type { IconButtonProps } from '@mui/material/IconButton'; +import type { InputAdornmentProps } from '@mui/material/InputAdornment'; +import type { TooltipProps } from '@mui/material/Tooltip'; import type { InputLabelProps } from '@mui/material/InputLabel'; -import { PopperProps } from '@mui/material/Popper'; -import { TablePaginationProps } from '@mui/material/TablePagination'; -import { ChipProps } from '@mui/material/Chip'; -import { GridToolbarProps } from '../components/toolbar/GridToolbar'; -import { ColumnHeaderFilterIconButtonProps } from '../components/columnHeaders/GridColumnHeaderFilterIconButton'; -import { GridColumnMenuProps } from '../components/menu/columnMenu/GridColumnMenuProps'; -import { GridColumnsPanelProps } from '../components/panel/GridColumnsPanel'; -import { GridFilterPanelProps } from '../components/panel/filterPanel/GridFilterPanel'; -import { GridFooterContainerProps } from '../components/containers/GridFooterContainer'; -import { GridOverlayProps } from '../components/containers/GridOverlay'; -import { GridPanelProps } from '../components/panel/GridPanel'; +import type { PopperProps } from '@mui/material/Popper'; +import type { TablePaginationProps } from '@mui/material/TablePagination'; +import type { ChipProps } from '@mui/material/Chip'; +import type { GridToolbarProps } from '../components/toolbar/GridToolbar'; +import type { ColumnHeaderFilterIconButtonProps } from '../components/columnHeaders/GridColumnHeaderFilterIconButton'; +import type { GridColumnMenuProps } from '../components/menu/columnMenu/GridColumnMenuProps'; +import type { GridColumnsPanelProps } from '../components/panel/GridColumnsPanel'; +import type { GridFilterPanelProps } from '../components/panel/filterPanel/GridFilterPanel'; +import type { GridFooterContainerProps } from '../components/containers/GridFooterContainer'; +import type { GridOverlayProps } from '../components/containers/GridOverlay'; +import type { GridPanelProps } from '../components/panel/GridPanel'; +import type { GridSkeletonCellProps } from '../components/cell/GridSkeletonCell'; import type { GridRowProps } from '../components/GridRow'; import type { GridCellProps } from '../components/cell/GridCell'; +import type { GridColumnHeadersProps } from '../components/GridColumnHeaders'; +import type { GridDetailPanelsProps } from '../components/GridDetailPanels'; +import type { GridPinnedRowsProps } from '../components/GridPinnedRows'; import type { GridColumnsManagementProps } from '../components/columnsManagement/GridColumnsManagement'; import type { GridRowCountProps } from '../components'; @@ -32,6 +37,7 @@ export interface BaseSelectPropsOverrides {} export interface BaseSwitchPropsOverrides {} export interface BaseButtonPropsOverrides {} export interface BaseIconButtonPropsOverrides {} +export interface BaseInputAdornmentPropsOverrides {} export interface BaseTooltipPropsOverrides {} export interface BasePopperPropsOverrides {} export interface BaseInputLabelPropsOverrides {} @@ -42,6 +48,7 @@ export interface ToolbarPropsOverrides {} export interface ColumnHeaderFilterIconButtonPropsOverrides {} export interface ColumnMenuPropsOverrides {} export interface ColumnsPanelPropsOverrides {} +export interface DetailPanelsPropsOverrides {} export interface ColumnsManagementPropsOverrides {} export interface FilterPanelPropsOverrides {} export interface FooterPropsOverrides {} @@ -51,45 +58,53 @@ export interface LoadingOverlayPropsOverrides {} export interface NoResultsOverlayPropsOverrides {} export interface NoRowsOverlayPropsOverrides {} export interface PanelPropsOverrides {} +export interface PinnedRowsPropsOverrides {} +export interface SkeletonCellPropsOverrides {} export interface RowPropsOverrides {} -type SlotProps<Props, Overrides> = Partial<Props & Overrides>; +export interface GridSlotProps { + baseCheckbox: CheckboxProps & BaseCheckboxPropsOverrides; + baseTextField: TextFieldProps & BaseTextFieldPropsOverrides; + baseFormControl: FormControlProps & BaseFormControlPropsOverrides; + baseSelect: SelectProps & BaseSelectPropsOverrides; + baseSwitch: SwitchProps & BaseSwitchPropsOverrides; + baseButton: ButtonProps & BaseButtonPropsOverrides; + baseIconButton: IconButtonProps & BaseIconButtonPropsOverrides; + basePopper: PopperProps & BasePopperPropsOverrides; + baseTooltip: TooltipProps & BaseTooltipPropsOverrides; + baseInputLabel: InputLabelProps & BaseInputLabelPropsOverrides; + baseInputAdornment: InputAdornmentProps & BaseInputAdornmentPropsOverrides; + baseSelectOption: { + native: boolean; + value: any; + children?: React.ReactNode; + } & BaseSelectOptionPropsOverrides; + baseChip: ChipProps & BaseChipPropsOverrides; + cell: GridCellProps & CellPropsOverrides; + columnHeaders: GridColumnHeadersProps; + columnHeaderFilterIconButton: ColumnHeaderFilterIconButtonProps & + ColumnHeaderFilterIconButtonPropsOverrides; + columnMenu: GridColumnMenuProps & ColumnMenuPropsOverrides; + columnsPanel: GridColumnsPanelProps & ColumnsPanelPropsOverrides; + columnsManagement: GridColumnsManagementProps & ColumnsManagementPropsOverrides; + detailPanels: GridDetailPanelsProps & DetailPanelsPropsOverrides; + filterPanel: GridFilterPanelProps & FilterPanelPropsOverrides; + footer: GridFooterContainerProps & FooterPropsOverrides; + footerRowCount: GridRowCountProps & FooterRowCountOverrides; + loadingOverlay: GridOverlayProps & LoadingOverlayPropsOverrides; + noResultsOverlay: GridOverlayProps & NoResultsOverlayPropsOverrides; + noRowsOverlay: GridOverlayProps & NoRowsOverlayPropsOverrides; + pagination: Partial<TablePaginationProps> & PaginationPropsOverrides; + panel: GridPanelProps & PanelPropsOverrides; + pinnedRows: GridPinnedRowsProps & PinnedRowsPropsOverrides; + row: GridRowProps & RowPropsOverrides; + skeletonCell: GridSkeletonCellProps & SkeletonCellPropsOverrides; + toolbar: GridToolbarProps & ToolbarPropsOverrides; +} /** * Overridable components props dynamically passed to the component at rendering. */ -export interface GridSlotsComponentsProps { - baseCheckbox?: SlotProps<CheckboxProps, BaseCheckboxPropsOverrides>; - baseTextField?: SlotProps<TextFieldProps, BaseTextFieldPropsOverrides>; - baseFormControl?: SlotProps<FormControlProps, BaseFormControlPropsOverrides>; - baseSelect?: SlotProps<SelectProps, BaseSelectPropsOverrides>; - baseSwitch?: SlotProps<SwitchProps, BaseSwitchPropsOverrides>; - baseButton?: SlotProps<ButtonProps, BaseButtonPropsOverrides>; - baseIconButton?: SlotProps<IconButtonProps, BaseIconButtonPropsOverrides>; - basePopper?: SlotProps<PopperProps, BasePopperPropsOverrides>; - baseTooltip?: SlotProps<TooltipProps, BaseTooltipPropsOverrides>; - baseInputLabel?: SlotProps<InputLabelProps, BaseInputLabelPropsOverrides>; - baseSelectOption?: SlotProps< - { native: boolean; value: any; children?: React.ReactNode }, - BaseSelectOptionPropsOverrides - >; - baseChip?: SlotProps<ChipProps, BaseChipPropsOverrides>; - cell?: SlotProps<GridCellProps, CellPropsOverrides>; - columnHeaderFilterIconButton?: SlotProps< - ColumnHeaderFilterIconButtonProps, - ColumnHeaderFilterIconButtonPropsOverrides - >; - columnMenu?: SlotProps<GridColumnMenuProps, ColumnMenuPropsOverrides>; - columnsPanel?: SlotProps<GridColumnsPanelProps, ColumnsPanelPropsOverrides>; - columnsManagement?: SlotProps<GridColumnsManagementProps, ColumnsManagementPropsOverrides>; - filterPanel?: SlotProps<GridFilterPanelProps, FilterPanelPropsOverrides>; - footer?: SlotProps<GridFooterContainerProps, FooterPropsOverrides>; - footerRowCount?: SlotProps<GridRowCountProps, FooterRowCountOverrides>; - loadingOverlay?: SlotProps<GridOverlayProps, LoadingOverlayPropsOverrides>; - noResultsOverlay?: SlotProps<GridOverlayProps, NoResultsOverlayPropsOverrides>; - noRowsOverlay?: SlotProps<GridOverlayProps, NoRowsOverlayPropsOverrides>; - pagination?: SlotProps<TablePaginationProps, PaginationPropsOverrides>; - panel?: SlotProps<GridPanelProps, PanelPropsOverrides>; - row?: SlotProps<GridRowProps, RowPropsOverrides>; - toolbar?: SlotProps<GridToolbarProps, ToolbarPropsOverrides>; -} +export type GridSlotsComponentsProps = Partial<{ + [K in keyof GridSlotProps]: Partial<GridSlotProps[K]>; +}>; diff --git a/packages/grid/x-data-grid/src/tests/filtering.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/filtering.DataGrid.test.tsx index c69bb7331eca5..1c0e44a39cbf9 100644 --- a/packages/grid/x-data-grid/src/tests/filtering.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/filtering.DataGrid.test.tsx @@ -8,6 +8,7 @@ import { GridColDef, GridFilterItem, GridPreferencePanelsValue, + GridSlots, GridToolbar, GridFilterOperator, } from '@mui/x-data-grid'; @@ -1305,7 +1306,7 @@ describe('<DataGrid /> - Filter', () => { type: 'number', }, ]} - slots={{ toolbar: GridToolbarFilterButton }} + slots={{ toolbar: GridToolbarFilterButton as GridSlots['toolbar'] }} />, ); @@ -1369,7 +1370,7 @@ describe('<DataGrid /> - Filter', () => { ] as GridFilterOperator<any, string>[], }, ]} - slots={{ toolbar: GridToolbarFilterButton }} + slots={{ toolbar: GridToolbarFilterButton as GridSlots['toolbar'] }} /> </div>, ); diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index 287b954cc35ce..7093d6eac2ad7 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -4,6 +4,7 @@ { "name": "BaseChipPropsOverrides", "kind": "Interface" }, { "name": "BaseFormControlPropsOverrides", "kind": "Interface" }, { "name": "BaseIconButtonPropsOverrides", "kind": "Interface" }, + { "name": "BaseInputAdornmentPropsOverrides", "kind": "Interface" }, { "name": "BaseInputLabelPropsOverrides", "kind": "Interface" }, { "name": "BasePopperPropsOverrides", "kind": "Interface" }, { "name": "BaseSelectOptionPropsOverrides", "kind": "Interface" }, @@ -28,6 +29,7 @@ { "name": "DataGridPro", "kind": "Function" }, { "name": "DEFAULT_GRID_AUTOSIZE_OPTIONS", "kind": "Variable" }, { "name": "DEFAULT_GRID_COL_TYPE_KEY", "kind": "Variable" }, + { "name": "DetailPanelsPropsOverrides", "kind": "Interface" }, { "name": "ElementSize", "kind": "Interface" }, { "name": "EMPTY_PINNED_COLUMN_FIELDS", "kind": "Variable" }, { "name": "EMPTY_RENDER_CONTEXT", "kind": "Variable" }, @@ -529,8 +531,10 @@ { "name": "GridSkeletonCell", "kind": "Function" }, { "name": "GridSkeletonCellProps", "kind": "Interface" }, { "name": "GridSkeletonRowNode", "kind": "Interface" }, + { "name": "GridSlotProps", "kind": "Interface" }, + { "name": "GridSlots", "kind": "Interface" }, { "name": "GridSlotsComponent", "kind": "Interface" }, - { "name": "GridSlotsComponentsProps", "kind": "Interface" }, + { "name": "GridSlotsComponentsProps", "kind": "TypeAlias" }, { "name": "GridSortApi", "kind": "Interface" }, { "name": "GridSortCellParams", "kind": "Interface" }, { "name": "GridSortColumnLookup", "kind": "TypeAlias" }, @@ -610,6 +614,7 @@ { "name": "OutputSelector", "kind": "Interface" }, { "name": "PaginationPropsOverrides", "kind": "Interface" }, { "name": "PanelPropsOverrides", "kind": "Interface" }, + { "name": "PinnedRowsPropsOverrides", "kind": "Interface" }, { "name": "renderActionsCell", "kind": "Variable" }, { "name": "renderBooleanCell", "kind": "Variable" }, { "name": "renderEditBooleanCell", "kind": "Variable" }, @@ -621,6 +626,7 @@ { "name": "selectedGridRowsSelector", "kind": "Variable" }, { "name": "selectedIdsLookupSelector", "kind": "Variable" }, { "name": "setupExcelExportWebWorker", "kind": "Function" }, + { "name": "SkeletonCellPropsOverrides", "kind": "Interface" }, { "name": "ToolbarPropsOverrides", "kind": "Interface" }, { "name": "unstable_resetCleanupTracking", "kind": "Variable" }, { "name": "useFirstRender", "kind": "Variable" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index 6e1bffb88d86e..7a9543c73818f 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -4,6 +4,7 @@ { "name": "BaseChipPropsOverrides", "kind": "Interface" }, { "name": "BaseFormControlPropsOverrides", "kind": "Interface" }, { "name": "BaseIconButtonPropsOverrides", "kind": "Interface" }, + { "name": "BaseInputAdornmentPropsOverrides", "kind": "Interface" }, { "name": "BaseInputLabelPropsOverrides", "kind": "Interface" }, { "name": "BasePopperPropsOverrides", "kind": "Interface" }, { "name": "BaseSelectOptionPropsOverrides", "kind": "Interface" }, @@ -27,6 +28,7 @@ { "name": "DataGridProProps", "kind": "Interface" }, { "name": "DEFAULT_GRID_AUTOSIZE_OPTIONS", "kind": "Variable" }, { "name": "DEFAULT_GRID_COL_TYPE_KEY", "kind": "Variable" }, + { "name": "DetailPanelsPropsOverrides", "kind": "Interface" }, { "name": "ElementSize", "kind": "Interface" }, { "name": "EMPTY_PINNED_COLUMN_FIELDS", "kind": "Variable" }, { "name": "EMPTY_RENDER_CONTEXT", "kind": "Variable" }, @@ -483,8 +485,10 @@ { "name": "GridSkeletonCell", "kind": "Function" }, { "name": "GridSkeletonCellProps", "kind": "Interface" }, { "name": "GridSkeletonRowNode", "kind": "Interface" }, + { "name": "GridSlotProps", "kind": "Interface" }, + { "name": "GridSlots", "kind": "Interface" }, { "name": "GridSlotsComponent", "kind": "Interface" }, - { "name": "GridSlotsComponentsProps", "kind": "Interface" }, + { "name": "GridSlotsComponentsProps", "kind": "TypeAlias" }, { "name": "GridSortApi", "kind": "Interface" }, { "name": "GridSortCellParams", "kind": "Interface" }, { "name": "GridSortColumnLookup", "kind": "TypeAlias" }, @@ -562,6 +566,7 @@ { "name": "OutputSelector", "kind": "Interface" }, { "name": "PaginationPropsOverrides", "kind": "Interface" }, { "name": "PanelPropsOverrides", "kind": "Interface" }, + { "name": "PinnedRowsPropsOverrides", "kind": "Interface" }, { "name": "renderActionsCell", "kind": "Variable" }, { "name": "renderBooleanCell", "kind": "Variable" }, { "name": "renderEditBooleanCell", "kind": "Variable" }, @@ -572,6 +577,7 @@ { "name": "selectedGridRowsCountSelector", "kind": "Variable" }, { "name": "selectedGridRowsSelector", "kind": "Variable" }, { "name": "selectedIdsLookupSelector", "kind": "Variable" }, + { "name": "SkeletonCellPropsOverrides", "kind": "Interface" }, { "name": "ToolbarPropsOverrides", "kind": "Interface" }, { "name": "unstable_resetCleanupTracking", "kind": "Variable" }, { "name": "useFirstRender", "kind": "Variable" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index a14da1163acf4..f55ecfd6630cc 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -4,6 +4,7 @@ { "name": "BaseChipPropsOverrides", "kind": "Interface" }, { "name": "BaseFormControlPropsOverrides", "kind": "Interface" }, { "name": "BaseIconButtonPropsOverrides", "kind": "Interface" }, + { "name": "BaseInputAdornmentPropsOverrides", "kind": "Interface" }, { "name": "BaseInputLabelPropsOverrides", "kind": "Interface" }, { "name": "BasePopperPropsOverrides", "kind": "Interface" }, { "name": "BaseSelectOptionPropsOverrides", "kind": "Interface" }, @@ -24,6 +25,7 @@ { "name": "DataGrid", "kind": "Variable" }, { "name": "DataGridProps", "kind": "TypeAlias" }, { "name": "DEFAULT_GRID_COL_TYPE_KEY", "kind": "Variable" }, + { "name": "DetailPanelsPropsOverrides", "kind": "Interface" }, { "name": "ElementSize", "kind": "Interface" }, { "name": "EMPTY_PINNED_COLUMN_FIELDS", "kind": "Variable" }, { "name": "EMPTY_RENDER_CONTEXT", "kind": "Variable" }, @@ -438,8 +440,10 @@ { "name": "GridSkeletonCell", "kind": "Function" }, { "name": "GridSkeletonCellProps", "kind": "Interface" }, { "name": "GridSkeletonRowNode", "kind": "Interface" }, + { "name": "GridSlotProps", "kind": "Interface" }, + { "name": "GridSlots", "kind": "Interface" }, { "name": "GridSlotsComponent", "kind": "Interface" }, - { "name": "GridSlotsComponentsProps", "kind": "Interface" }, + { "name": "GridSlotsComponentsProps", "kind": "TypeAlias" }, { "name": "GridSortApi", "kind": "Interface" }, { "name": "GridSortCellParams", "kind": "Interface" }, { "name": "GridSortColumnLookup", "kind": "TypeAlias" }, @@ -515,6 +519,7 @@ { "name": "OutputSelector", "kind": "Interface" }, { "name": "PaginationPropsOverrides", "kind": "Interface" }, { "name": "PanelPropsOverrides", "kind": "Interface" }, + { "name": "PinnedRowsPropsOverrides", "kind": "Interface" }, { "name": "renderActionsCell", "kind": "Variable" }, { "name": "renderBooleanCell", "kind": "Variable" }, { "name": "renderEditBooleanCell", "kind": "Variable" }, @@ -525,6 +530,7 @@ { "name": "selectedGridRowsCountSelector", "kind": "Variable" }, { "name": "selectedGridRowsSelector", "kind": "Variable" }, { "name": "selectedIdsLookupSelector", "kind": "Variable" }, + { "name": "SkeletonCellPropsOverrides", "kind": "Interface" }, { "name": "ToolbarPropsOverrides", "kind": "Interface" }, { "name": "unstable_resetCleanupTracking", "kind": "Variable" }, { "name": "useFirstRender", "kind": "Variable" }, From cc20ad95b43e7b8a8cf29418fac12f151744bf18 Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskii <andrew@mui.com> Date: Mon, 5 Feb 2024 16:58:56 +0100 Subject: [PATCH 20/35] [core] Add `docs:serve` script (#11935) --- docs/package.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/package.json b/docs/package.json index baa9269d03f51..f64c94dbc67da 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,13 +5,13 @@ "author": "MUI Team", "license": "MIT", "scripts": { - "build": "rimraf docs/export && cross-env NODE_ENV=production next build --profile && yarn build-sw", + "build": "rimraf ./export && cross-env NODE_ENV=production next build --profile && yarn build-sw", "build:clean": "rimraf .next && yarn build", "build-sw": "node ./scripts/buildServiceWorker.js", "dev": "next dev --port 3001", "deploy": "git push -f upstream next:docs-next", "icons": "rimraf public/static/icons/* && node ./scripts/buildIcons.js", - "start": "next start", + "serve": "serve ./export -l 3010", "create-playground": "cpy --cwd=scripts playground.template.tsx ../../pages/playground --rename=index.tsx", "typescript": "tsc -p tsconfig.json", "typescript:transpile": "cross-env BABEL_ENV=development babel-node --extensions \".tsx,.ts,.js\" scripts/formattedTSDemos", @@ -52,8 +52,8 @@ "core-js": "^2.6.12", "cross-env": "^7.0.3", "date-fns": "^2.30.0", - "date-fns-v3": "https://registry.npmjs.org/date-fns/-/date-fns-3.2.0.tgz", "date-fns-jalali": "^2.21.3-1", + "date-fns-v3": "https://registry.npmjs.org/date-fns/-/date-fns-3.2.0.tgz", "dayjs": "^1.11.10", "doctrine": "^3.0.0", "exceljs": "^4.4.0", @@ -98,6 +98,7 @@ "@types/stylis": "^4.2.5", "@types/webpack-bundle-analyzer": "^4.6.3", "cpy-cli": "^5.0.0", - "gm": "^1.25.0" + "gm": "^1.25.0", + "serve": "^14.2.1" } } diff --git a/package.json b/package.json index b572a46f3217c..0db7e3d0dabcb 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "scripts": { "start": "yarn && yarn docs:dev", "docs:dev": "yarn workspace docs dev", - "docs:start": "yarn workspace docs start", + "docs:serve": "yarn workspace docs serve", "docs:create-playground": "yarn workspace docs create-playground", "docs:api": "NODE_OPTIONS=--max-old-space-size=4096 yarn docs:api:build && yarn docs:api:buildX", "docs:api:build": "cross-env BABEL_ENV=development babel-node -i \"/node_modules/(?!@mui)/\" -x .ts,.tsx,.js ./scripts/buildApiDocs/index.ts", From 094abbc2ece29e41f50935783af25b4e7ab1838a Mon Sep 17 00:00:00 2001 From: Olivier Tassinari <olivier.tassinari@gmail.com> Date: Tue, 6 Feb 2024 00:19:54 +0100 Subject: [PATCH 21/35] [core] Normalize issue template --- bug-reproductions/x-data-grid/public/index.html | 9 ++++++--- test/e2e/template.html | 4 ++-- test/regressions/template.html | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/bug-reproductions/x-data-grid/public/index.html b/bug-reproductions/x-data-grid/public/index.html index 80363f8fecc8e..9befde78ff8b2 100644 --- a/bug-reproductions/x-data-grid/public/index.html +++ b/bug-reproductions/x-data-grid/public/index.html @@ -1,12 +1,15 @@ -<!doctype html> +<!DOCTYPE html> <html lang="en"> <head> - <title>DataGridProDemo demo — MUI X + DataGrid — MUI X + + + diff --git a/test/e2e/template.html b/test/e2e/template.html index 081f21ed377a0..7d84cc7643adb 100644 --- a/test/e2e/template.html +++ b/test/e2e/template.html @@ -1,9 +1,9 @@ - + Playwright end-to-end test - +