From 51bcf00468ab8c6da7aba586aefd2c000e1cc3a4 Mon Sep 17 00:00:00 2001 From: delangle Date: Fri, 31 May 2024 13:26:34 +0200 Subject: [PATCH] [pickers] Allow to customize the month and the year buttons --- .../custom-components/custom-components.md | 30 +---------- .../CalendarHeaderComponent.js | 0 .../CalendarHeaderComponent.tsx | 0 .../CalendarHeaderComponent.tsx.preview | 0 .../CalendarHeaderComponentProps.js | 0 .../CalendarHeaderComponentProps.tsx | 0 .../CalendarHeaderComponentProps.tsx.preview | 0 .../CalendarHeaderComponentRange.js | 0 .../CalendarHeaderComponentRange.tsx | 0 .../CalendarHeaderComponentRange.tsx.preview | 0 .../custom-views/MonthButtonComponent.js | 26 ++++++++++ .../custom-views/MonthButtonComponent.tsx | 26 ++++++++++ .../MonthButtonComponent.tsx.preview | 5 ++ .../custom-views/MonthButtonComponentProps.js | 23 ++++++++ .../MonthButtonComponentProps.tsx | 23 ++++++++ .../MonthButtonComponentProps.tsx.preview | 9 ++++ .../date-pickers/custom-views/custom-views.md | 51 ++++++++++++++++++ docs/data/pages.ts | 1 + .../x/api/date-pickers/date-calendar.json | 6 +++ .../pages/x/api/date-pickers/date-picker.json | 6 +++ .../x/api/date-pickers/date-time-picker.json | 6 +++ .../api/date-pickers/desktop-date-picker.json | 6 +++ .../desktop-date-time-picker.json | 6 +++ .../api/date-pickers/mobile-date-picker.json | 6 +++ .../date-pickers/mobile-date-time-picker.json | 6 +++ .../x/api/date-pickers/month-calendar.json | 14 +++++ .../date-pickers/pickers-calendar-header.json | 2 +- .../pickers-range-calendar-header.json | 2 +- .../api/date-pickers/static-date-picker.json | 6 +++ .../date-pickers/static-date-time-picker.json | 6 +++ .../x/react-date-pickers/custom-views.js | 7 +++ .../date-calendar/date-calendar.json | 1 + .../date-pickers/date-picker/date-picker.json | 1 + .../date-time-picker/date-time-picker.json | 1 + .../desktop-date-picker.json | 1 + .../desktop-date-time-picker.json | 1 + .../mobile-date-picker.json | 1 + .../mobile-date-time-picker.json | 1 + .../month-calendar/month-calendar.json | 7 ++- .../static-date-picker.json | 1 + .../static-date-time-picker.json | 1 + .../src/DateCalendar/DateCalendar.tsx | 2 + .../src/DateCalendar/DateCalendar.types.ts | 12 +++-- .../src/DateCalendar/DayCalendar.tsx | 8 +-- .../src/MonthCalendar/MonthCalendar.tsx | 16 +++++- .../src/MonthCalendar/MonthCalendar.types.ts | 25 +++++++++ .../src/MonthCalendar/PickersMonth.tsx | 52 ++++++++++++------- .../x-date-pickers/src/MonthCalendar/index.ts | 7 ++- scripts/x-date-pickers-pro.exports.json | 3 ++ scripts/x-date-pickers.exports.json | 3 ++ 50 files changed, 356 insertions(+), 61 deletions(-) rename docs/data/date-pickers/{custom-components => custom-views}/CalendarHeaderComponent.js (100%) rename docs/data/date-pickers/{custom-components => custom-views}/CalendarHeaderComponent.tsx (100%) rename docs/data/date-pickers/{custom-components => custom-views}/CalendarHeaderComponent.tsx.preview (100%) rename docs/data/date-pickers/{custom-components => custom-views}/CalendarHeaderComponentProps.js (100%) rename docs/data/date-pickers/{custom-components => custom-views}/CalendarHeaderComponentProps.tsx (100%) rename docs/data/date-pickers/{custom-components => custom-views}/CalendarHeaderComponentProps.tsx.preview (100%) rename docs/data/date-pickers/{custom-components => custom-views}/CalendarHeaderComponentRange.js (100%) rename docs/data/date-pickers/{custom-components => custom-views}/CalendarHeaderComponentRange.tsx (100%) rename docs/data/date-pickers/{custom-components => custom-views}/CalendarHeaderComponentRange.tsx.preview (100%) create mode 100644 docs/data/date-pickers/custom-views/MonthButtonComponent.js create mode 100644 docs/data/date-pickers/custom-views/MonthButtonComponent.tsx create mode 100644 docs/data/date-pickers/custom-views/MonthButtonComponent.tsx.preview create mode 100644 docs/data/date-pickers/custom-views/MonthButtonComponentProps.js create mode 100644 docs/data/date-pickers/custom-views/MonthButtonComponentProps.tsx create mode 100644 docs/data/date-pickers/custom-views/MonthButtonComponentProps.tsx.preview create mode 100644 docs/data/date-pickers/custom-views/custom-views.md create mode 100644 docs/pages/x/react-date-pickers/custom-views.js diff --git a/docs/data/date-pickers/custom-components/custom-components.md b/docs/data/date-pickers/custom-components/custom-components.md index 3ecf81afeb3c7..ce8429820e7bb 100644 --- a/docs/data/date-pickers/custom-components/custom-components.md +++ b/docs/data/date-pickers/custom-components/custom-components.md @@ -1,7 +1,7 @@ --- productId: x-date-pickers title: Date and Time Pickers - Custom slots and subcomponents -components: DateTimePickerTabs, PickersActionBar, DatePickerToolbar, TimePickerToolbar, DateTimePickerToolbar, PickersCalendarHeader, PickersRangeCalendarHeader, PickersShortcuts, DateRangePickerToolbar +components: DateTimePickerTabs, PickersActionBar, DatePickerToolbar, TimePickerToolbar, DateTimePickerToolbar, PickersShortcuts, DateRangePickerToolbar --- # Custom slots and subcomponents @@ -219,34 +219,6 @@ Each component comes with its own toolbar (`DatePickerToolbar`, `TimePickerToolb {{"demo": "ToolbarComponent.js"}} -## Calendar header - -The calendar header is available on any component that renders a calendar to select a date or a range of dates. -It allows the user to navigate through months and to switch to the month and year views when available. - -### Component props - -You can pass props to the calendar header as shown below: - -{{"demo": "CalendarHeaderComponentProps.js", "defaultCodeOpen": false}} - -### Component - -You can pass custom components to replace the header, as shown below: - -{{"demo": "CalendarHeaderComponent.js", "defaultCodeOpen": false}} - -When used with a date range component, -you receive three additional props to let you handle scenarios where multiple months are rendered: - -- `calendars`: The number of calendars rendered -- `month`: The month used for the header being rendered -- `monthIndex`: The index of the month used for the header being rendered - -The demo below shows how to navigate the months two by two: - -{{"demo": "CalendarHeaderComponentRange.js", "defaultCodeOpen": false}} - ## Arrow switcher The following slots let you customize how to render the buttons and icons for an arrow switcher component—the component diff --git a/docs/data/date-pickers/custom-components/CalendarHeaderComponent.js b/docs/data/date-pickers/custom-views/CalendarHeaderComponent.js similarity index 100% rename from docs/data/date-pickers/custom-components/CalendarHeaderComponent.js rename to docs/data/date-pickers/custom-views/CalendarHeaderComponent.js diff --git a/docs/data/date-pickers/custom-components/CalendarHeaderComponent.tsx b/docs/data/date-pickers/custom-views/CalendarHeaderComponent.tsx similarity index 100% rename from docs/data/date-pickers/custom-components/CalendarHeaderComponent.tsx rename to docs/data/date-pickers/custom-views/CalendarHeaderComponent.tsx diff --git a/docs/data/date-pickers/custom-components/CalendarHeaderComponent.tsx.preview b/docs/data/date-pickers/custom-views/CalendarHeaderComponent.tsx.preview similarity index 100% rename from docs/data/date-pickers/custom-components/CalendarHeaderComponent.tsx.preview rename to docs/data/date-pickers/custom-views/CalendarHeaderComponent.tsx.preview diff --git a/docs/data/date-pickers/custom-components/CalendarHeaderComponentProps.js b/docs/data/date-pickers/custom-views/CalendarHeaderComponentProps.js similarity index 100% rename from docs/data/date-pickers/custom-components/CalendarHeaderComponentProps.js rename to docs/data/date-pickers/custom-views/CalendarHeaderComponentProps.js diff --git a/docs/data/date-pickers/custom-components/CalendarHeaderComponentProps.tsx b/docs/data/date-pickers/custom-views/CalendarHeaderComponentProps.tsx similarity index 100% rename from docs/data/date-pickers/custom-components/CalendarHeaderComponentProps.tsx rename to docs/data/date-pickers/custom-views/CalendarHeaderComponentProps.tsx diff --git a/docs/data/date-pickers/custom-components/CalendarHeaderComponentProps.tsx.preview b/docs/data/date-pickers/custom-views/CalendarHeaderComponentProps.tsx.preview similarity index 100% rename from docs/data/date-pickers/custom-components/CalendarHeaderComponentProps.tsx.preview rename to docs/data/date-pickers/custom-views/CalendarHeaderComponentProps.tsx.preview diff --git a/docs/data/date-pickers/custom-components/CalendarHeaderComponentRange.js b/docs/data/date-pickers/custom-views/CalendarHeaderComponentRange.js similarity index 100% rename from docs/data/date-pickers/custom-components/CalendarHeaderComponentRange.js rename to docs/data/date-pickers/custom-views/CalendarHeaderComponentRange.js diff --git a/docs/data/date-pickers/custom-components/CalendarHeaderComponentRange.tsx b/docs/data/date-pickers/custom-views/CalendarHeaderComponentRange.tsx similarity index 100% rename from docs/data/date-pickers/custom-components/CalendarHeaderComponentRange.tsx rename to docs/data/date-pickers/custom-views/CalendarHeaderComponentRange.tsx diff --git a/docs/data/date-pickers/custom-components/CalendarHeaderComponentRange.tsx.preview b/docs/data/date-pickers/custom-views/CalendarHeaderComponentRange.tsx.preview similarity index 100% rename from docs/data/date-pickers/custom-components/CalendarHeaderComponentRange.tsx.preview rename to docs/data/date-pickers/custom-views/CalendarHeaderComponentRange.tsx.preview diff --git a/docs/data/date-pickers/custom-views/MonthButtonComponent.js b/docs/data/date-pickers/custom-views/MonthButtonComponent.js new file mode 100644 index 0000000000000..8f0c336d4b22b --- /dev/null +++ b/docs/data/date-pickers/custom-views/MonthButtonComponent.js @@ -0,0 +1,26 @@ +import * as React from 'react'; +import { styled } from '@mui/material/styles'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { DateCalendar } from '@mui/x-date-pickers/DateCalendar'; + +const CustomMonthButton = styled('button')({ + margin: '8px 0', + height: 36, + width: 72, +}); + +export default function MonthButtonComponent() { + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/custom-views/MonthButtonComponent.tsx b/docs/data/date-pickers/custom-views/MonthButtonComponent.tsx new file mode 100644 index 0000000000000..8f0c336d4b22b --- /dev/null +++ b/docs/data/date-pickers/custom-views/MonthButtonComponent.tsx @@ -0,0 +1,26 @@ +import * as React from 'react'; +import { styled } from '@mui/material/styles'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { DateCalendar } from '@mui/x-date-pickers/DateCalendar'; + +const CustomMonthButton = styled('button')({ + margin: '8px 0', + height: 36, + width: 72, +}); + +export default function MonthButtonComponent() { + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/custom-views/MonthButtonComponent.tsx.preview b/docs/data/date-pickers/custom-views/MonthButtonComponent.tsx.preview new file mode 100644 index 0000000000000..8659099c00834 --- /dev/null +++ b/docs/data/date-pickers/custom-views/MonthButtonComponent.tsx.preview @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/docs/data/date-pickers/custom-views/MonthButtonComponentProps.js b/docs/data/date-pickers/custom-views/MonthButtonComponentProps.js new file mode 100644 index 0000000000000..ee4e0dbfda7e4 --- /dev/null +++ b/docs/data/date-pickers/custom-views/MonthButtonComponentProps.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { DateCalendar } from '@mui/x-date-pickers/DateCalendar'; + +export default function MonthButtonComponentProps() { + return ( + + + ({ + title: ownerState['aria-label'], + }), + }} + views={['month', 'day']} + openTo="month" + /> + + + ); +} diff --git a/docs/data/date-pickers/custom-views/MonthButtonComponentProps.tsx b/docs/data/date-pickers/custom-views/MonthButtonComponentProps.tsx new file mode 100644 index 0000000000000..ee4e0dbfda7e4 --- /dev/null +++ b/docs/data/date-pickers/custom-views/MonthButtonComponentProps.tsx @@ -0,0 +1,23 @@ +import * as React from 'react'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { DateCalendar } from '@mui/x-date-pickers/DateCalendar'; + +export default function MonthButtonComponentProps() { + return ( + + + ({ + title: ownerState['aria-label'], + }), + }} + views={['month', 'day']} + openTo="month" + /> + + + ); +} diff --git a/docs/data/date-pickers/custom-views/MonthButtonComponentProps.tsx.preview b/docs/data/date-pickers/custom-views/MonthButtonComponentProps.tsx.preview new file mode 100644 index 0000000000000..eabc994bc2200 --- /dev/null +++ b/docs/data/date-pickers/custom-views/MonthButtonComponentProps.tsx.preview @@ -0,0 +1,9 @@ + ({ + title: ownerState['aria-label'], + }), + }} + views={['month', 'day']} + openTo="month" +/> \ No newline at end of file diff --git a/docs/data/date-pickers/custom-views/custom-views.md b/docs/data/date-pickers/custom-views/custom-views.md new file mode 100644 index 0000000000000..3e459e9473631 --- /dev/null +++ b/docs/data/date-pickers/custom-views/custom-views.md @@ -0,0 +1,51 @@ +--- +productId: x-date-pickers +title: Date and Time Pickers - Custom views +components: PickersCalendarHeader, PickersRangeCalendarHeader, PickersMonth +--- + +# Custom views + +

Learn how to override the default DOM structure of the views.

+ +## Calendar header + +The calendar header is available on any component that renders a calendar to select a date or a range of dates. +It allows the user to navigate through months and to switch to the month and year views when available. + +### Component props + +You can pass props to the calendar header as shown below: + +{{"demo": "CalendarHeaderComponentProps.js", "defaultCodeOpen": false}} + +### Component + +You can pass custom components to replace the header, as shown below: + +{{"demo": "CalendarHeaderComponent.js", "defaultCodeOpen": false}} + +When used with a date range component, +you receive three additional props to let you handle scenarios where multiple months are rendered: + +- `calendars`: The number of calendars rendered +- `month`: The month used for the header being rendered +- `monthIndex`: The index of the month used for the header being rendered + +The demo below shows how to navigate the months two by two: + +{{"demo": "CalendarHeaderComponentRange.js", "defaultCodeOpen": false}} + +## Month button + +### Component props + +You can pass props to the month button as shown below: + +{{"demo": "MonthButtonComponentProps.js"}} + +### Component + +You can pass custom components to replace the month button, as shown below: + +{{"demo": "MonthButtonComponent.js"}} diff --git a/docs/data/pages.ts b/docs/data/pages.ts index ee4684125d361..83ad68a4614fc 100644 --- a/docs/data/pages.ts +++ b/docs/data/pages.ts @@ -366,6 +366,7 @@ const pages: MuiPage[] = [ title: 'Custom slots and subcomponents', }, { pathname: '/x/react-date-pickers/custom-layout' }, + { pathname: '/x/react-date-pickers/custom-views' }, { pathname: '/x/react-date-pickers/custom-field' }, { pathname: '/x/react-date-pickers/custom-opening-button' }, { pathname: '/x/react-date-pickers/playground', title: 'Customization playground' }, diff --git a/docs/pages/x/api/date-pickers/date-calendar.json b/docs/pages/x/api/date-pickers/date-calendar.json index 68c507d55288a..5000c124cf1fc 100644 --- a/docs/pages/x/api/date-pickers/date-calendar.json +++ b/docs/pages/x/api/date-pickers/date-calendar.json @@ -199,6 +199,12 @@ "description": "Custom component for day.\nCheck the [PickersDay](https://mui.com/x/api/date-pickers/pickers-day/) component.", "default": "PickersDay", "class": null + }, + { + "name": "monthButton", + "description": "Button displayed to render a single month in the \"month\" view .", + "default": "MonthCalendarButton", + "class": null } ], "classes": [ diff --git a/docs/pages/x/api/date-pickers/date-picker.json b/docs/pages/x/api/date-pickers/date-picker.json index ea40f5ecb500c..a3be367e15a85 100644 --- a/docs/pages/x/api/date-pickers/date-picker.json +++ b/docs/pages/x/api/date-pickers/date-picker.json @@ -242,6 +242,12 @@ "default": "PickersDay", "class": null }, + { + "name": "monthButton", + "description": "Button displayed to render a single month in the \"month\" view .", + "default": "MonthCalendarButton", + "class": null + }, { "name": "actionBar", "description": "Custom component for the action bar, it is placed below the picker views.", 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 34a2663633231..a6143362b4b45 100644 --- a/docs/pages/x/api/date-pickers/date-time-picker.json +++ b/docs/pages/x/api/date-pickers/date-time-picker.json @@ -276,6 +276,12 @@ "default": "PickersDay", "class": null }, + { + "name": "monthButton", + "description": "Button displayed to render a single month in the \"month\" view .", + "default": "MonthCalendarButton", + "class": null + }, { "name": "actionBar", "description": "Custom component for the action bar, it is placed below the picker views.", 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 a444cde654f37..2c67b05fda88f 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-picker.json @@ -238,6 +238,12 @@ "default": "PickersDay", "class": null }, + { + "name": "monthButton", + "description": "Button displayed to render a single month in the \"month\" view .", + "default": "MonthCalendarButton", + "class": null + }, { "name": "actionBar", "description": "Custom component for the action bar, it is placed below the picker views.", 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 ab048c18a4229..c816a78026d64 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 @@ -272,6 +272,12 @@ "default": "PickersDay", "class": null }, + { + "name": "monthButton", + "description": "Button displayed to render a single month in the \"month\" view .", + "default": "MonthCalendarButton", + "class": null + }, { "name": "actionBar", "description": "Custom component for the action bar, it is placed below the picker views.", 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 ef656fc6dcee5..fc7f27f31dc9f 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-picker.json @@ -238,6 +238,12 @@ "default": "PickersDay", "class": null }, + { + "name": "monthButton", + "description": "Button displayed to render a single month in the \"month\" view .", + "default": "MonthCalendarButton", + "class": null + }, { "name": "actionBar", "description": "Custom component for the action bar, it is placed below the picker views.", 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 f304519adf060..5cf05d336dcf5 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 @@ -263,6 +263,12 @@ "default": "PickersDay", "class": null }, + { + "name": "monthButton", + "description": "Button displayed to render a single month in the \"month\" view .", + "default": "MonthCalendarButton", + "class": null + }, { "name": "actionBar", "description": "Custom component for the action bar, it is placed below the picker views.", diff --git a/docs/pages/x/api/date-pickers/month-calendar.json b/docs/pages/x/api/date-pickers/month-calendar.json index 2fe02db3fe453..5768efa023d4b 100644 --- a/docs/pages/x/api/date-pickers/month-calendar.json +++ b/docs/pages/x/api/date-pickers/month-calendar.json @@ -29,6 +29,12 @@ "returned": "boolean" } }, + "slotProps": { "type": { "name": "object" }, "default": "{}" }, + "slots": { + "type": { "name": "object" }, + "default": "{}", + "additionalInfo": { "slotsApi": true } + }, "sx": { "type": { "name": "union", @@ -52,6 +58,14 @@ "import { MonthCalendar } from '@mui/x-date-pickers';", "import { MonthCalendar } from '@mui/x-date-pickers-pro';" ], + "slots": [ + { + "name": "monthButton", + "description": "Button displayed to render a single month in the \"month\" view .", + "default": "MonthCalendarButton", + "class": null + } + ], "classes": [ { "key": "root", diff --git a/docs/pages/x/api/date-pickers/pickers-calendar-header.json b/docs/pages/x/api/date-pickers/pickers-calendar-header.json index 498451ad6b8bf..5dfee18c26c07 100644 --- a/docs/pages/x/api/date-pickers/pickers-calendar-header.json +++ b/docs/pages/x/api/date-pickers/pickers-calendar-header.json @@ -86,6 +86,6 @@ "muiName": "MuiPickersCalendarHeader", "filename": "/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx", "inheritance": null, - "demos": "", + "demos": "", "cssComponent": false } diff --git a/docs/pages/x/api/date-pickers/pickers-range-calendar-header.json b/docs/pages/x/api/date-pickers/pickers-range-calendar-header.json index fbf2f5e605c2a..565ea51a21d49 100644 --- a/docs/pages/x/api/date-pickers/pickers-range-calendar-header.json +++ b/docs/pages/x/api/date-pickers/pickers-range-calendar-header.json @@ -65,6 +65,6 @@ "muiName": "MuiPickersRangeCalendarHeader", "filename": "/packages/x-date-pickers-pro/src/PickersRangeCalendarHeader/PickersRangeCalendarHeader.tsx", "inheritance": null, - "demos": "", + "demos": "", "cssComponent": false } 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 a392f5a1d6dc3..775fd642a90b5 100644 --- a/docs/pages/x/api/date-pickers/static-date-picker.json +++ b/docs/pages/x/api/date-pickers/static-date-picker.json @@ -218,6 +218,12 @@ "default": "PickersDay", "class": null }, + { + "name": "monthButton", + "description": "Button displayed to render a single month in the \"month\" view .", + "default": "MonthCalendarButton", + "class": null + }, { "name": "actionBar", "description": "Custom component for the action bar, it is placed below the picker views.", 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 49ea3c3c11650..ec6b6fcae6aa2 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 @@ -243,6 +243,12 @@ "default": "PickersDay", "class": null }, + { + "name": "monthButton", + "description": "Button displayed to render a single month in the \"month\" view .", + "default": "MonthCalendarButton", + "class": null + }, { "name": "actionBar", "description": "Custom component for the action bar, it is placed below the picker views.", diff --git a/docs/pages/x/react-date-pickers/custom-views.js b/docs/pages/x/react-date-pickers/custom-views.js new file mode 100644 index 0000000000000..0a5e49023cde5 --- /dev/null +++ b/docs/pages/x/react-date-pickers/custom-views.js @@ -0,0 +1,7 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import * as pageProps from 'docsx/data/date-pickers/custom-views/custom-views.md?muiMarkdown'; + +export default function Page() { + return ; +} diff --git a/docs/translations/api-docs/date-pickers/date-calendar/date-calendar.json b/docs/translations/api-docs/date-pickers/date-calendar/date-calendar.json index 4fb2face3be80..5d8a823b770bb 100644 --- a/docs/translations/api-docs/date-pickers/date-calendar/date-calendar.json +++ b/docs/translations/api-docs/date-pickers/date-calendar/date-calendar.json @@ -128,6 +128,7 @@ "calendarHeader": "Custom component for calendar header. Check the PickersCalendarHeader component.", "day": "Custom component for day. Check the PickersDay component.", "leftArrowIcon": "Icon displayed in the left view switch button.", + "monthButton": "Button displayed to render a single month in the "month" view .", "nextIconButton": "Button allowing to switch to the right view.", "previousIconButton": "Button allowing to switch to the left view.", "rightArrowIcon": "Icon displayed in the right view switch button.", diff --git a/docs/translations/api-docs/date-pickers/date-picker/date-picker.json b/docs/translations/api-docs/date-pickers/date-picker/date-picker.json index 00f34183a45d2..5a004b16aeb36 100644 --- a/docs/translations/api-docs/date-pickers/date-picker/date-picker.json +++ b/docs/translations/api-docs/date-pickers/date-picker/date-picker.json @@ -175,6 +175,7 @@ "leftArrowIcon": "Icon displayed in the left view switch button.", "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", "mobileTransition": "Custom component for the mobile dialog Transition.", + "monthButton": "Button displayed to render a single month in the "month" view .", "nextIconButton": "Button allowing to switch to the right view.", "openPickerButton": "Button to open the picker on desktop.", "openPickerIcon": "Icon displayed in the open picker button on desktop.", diff --git a/docs/translations/api-docs/date-pickers/date-time-picker/date-time-picker.json b/docs/translations/api-docs/date-pickers/date-time-picker/date-time-picker.json index fa71ce0a4449e..54be8bfb835cd 100644 --- a/docs/translations/api-docs/date-pickers/date-time-picker/date-time-picker.json +++ b/docs/translations/api-docs/date-pickers/date-time-picker/date-time-picker.json @@ -214,6 +214,7 @@ "leftArrowIcon": "Icon displayed in the left view switch button.", "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", "mobileTransition": "Custom component for the mobile dialog Transition.", + "monthButton": "Button displayed to render a single month in the "month" view .", "nextIconButton": "Button allowing to switch to the right view.", "openPickerButton": "Button to open the picker on desktop.", "openPickerIcon": "Icon displayed in the open picker button on desktop.", diff --git a/docs/translations/api-docs/date-pickers/desktop-date-picker/desktop-date-picker.json b/docs/translations/api-docs/date-pickers/desktop-date-picker/desktop-date-picker.json index ef1e3c68ff304..9ffccf4b649c0 100644 --- a/docs/translations/api-docs/date-pickers/desktop-date-picker/desktop-date-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-date-picker/desktop-date-picker.json @@ -169,6 +169,7 @@ "inputAdornment": "Component displayed on the start or end input adornment used to open the picker on desktop.", "layout": "Custom component for wrapping the layout. It wraps the toolbar, views, action bar, and shortcuts.", "leftArrowIcon": "Icon displayed in the left view switch button.", + "monthButton": "Button displayed to render a single month in the "month" view .", "nextIconButton": "Button allowing to switch to the right view.", "openPickerButton": "Button to open the picker on desktop.", "openPickerIcon": "Icon displayed in the open picker button on desktop.", diff --git a/docs/translations/api-docs/date-pickers/desktop-date-time-picker/desktop-date-time-picker.json b/docs/translations/api-docs/date-pickers/desktop-date-time-picker/desktop-date-time-picker.json index b1ad8f362650f..9470bdfd7c410 100644 --- a/docs/translations/api-docs/date-pickers/desktop-date-time-picker/desktop-date-time-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-date-time-picker/desktop-date-time-picker.json @@ -208,6 +208,7 @@ "inputAdornment": "Component displayed on the start or end input adornment used to open the picker on desktop.", "layout": "Custom component for wrapping the layout. It wraps the toolbar, views, action bar, and shortcuts.", "leftArrowIcon": "Icon displayed in the left view switch button.", + "monthButton": "Button displayed to render a single month in the "month" view .", "nextIconButton": "Button allowing to switch to the right view.", "openPickerButton": "Button to open the picker on desktop.", "openPickerIcon": "Icon displayed in the open picker button on desktop.", diff --git a/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json b/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json index 40892fb4d29ed..43715161d8d52 100644 --- a/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json @@ -166,6 +166,7 @@ "leftArrowIcon": "Icon displayed in the left view switch button.", "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", "mobileTransition": "Custom component for the mobile dialog Transition.", + "monthButton": "Button displayed to render a single month in the "month" view .", "nextIconButton": "Button allowing to switch to the right view.", "previousIconButton": "Button allowing to switch to the left view.", "rightArrowIcon": "Icon displayed in the right view switch button.", diff --git a/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json b/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json index da66472874cf9..b740ce67c9141 100644 --- a/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json @@ -194,6 +194,7 @@ "leftArrowIcon": "Icon displayed in the left view switch button.", "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", "mobileTransition": "Custom component for the mobile dialog Transition.", + "monthButton": "Button displayed to render a single month in the "month" view .", "nextIconButton": "Button allowing to switch to the right view.", "previousIconButton": "Button allowing to switch to the left view.", "rightArrowIcon": "Icon displayed in the right view switch button.", diff --git a/docs/translations/api-docs/date-pickers/month-calendar/month-calendar.json b/docs/translations/api-docs/date-pickers/month-calendar/month-calendar.json index 39c44a3cb07e2..757cb8b685b3c 100644 --- a/docs/translations/api-docs/date-pickers/month-calendar/month-calendar.json +++ b/docs/translations/api-docs/date-pickers/month-calendar/month-calendar.json @@ -33,6 +33,8 @@ "boolean": "If true, the month will be disabled." } }, + "slotProps": { "description": "The props used for each component slot." }, + "slots": { "description": "Overridable component slots." }, "sx": { "description": "The system prop that allows defining system overrides as well as additional CSS styles." }, @@ -42,5 +44,8 @@ }, "value": { "description": "The selected value. Used when the component is controlled." } }, - "classDescriptions": { "root": { "description": "Styles applied to the root element." } } + "classDescriptions": { "root": { "description": "Styles applied to the root element." } }, + "slotDescriptions": { + "monthButton": "Button displayed to render a single month in the "month" view ." + } } diff --git a/docs/translations/api-docs/date-pickers/static-date-picker/static-date-picker.json b/docs/translations/api-docs/date-pickers/static-date-picker/static-date-picker.json index 419ab0e226ccf..fe1c6c83ccb28 100644 --- a/docs/translations/api-docs/date-pickers/static-date-picker/static-date-picker.json +++ b/docs/translations/api-docs/date-pickers/static-date-picker/static-date-picker.json @@ -137,6 +137,7 @@ "day": "Custom component for day. Check the PickersDay component.", "layout": "Custom component for wrapping the layout. It wraps the toolbar, views, action bar, and shortcuts.", "leftArrowIcon": "Icon displayed in the left view switch button.", + "monthButton": "Button displayed to render a single month in the "month" view .", "nextIconButton": "Button allowing to switch to the right view.", "previousIconButton": "Button allowing to switch to the left view.", "rightArrowIcon": "Icon displayed in the right view switch button.", diff --git a/docs/translations/api-docs/date-pickers/static-date-time-picker/static-date-time-picker.json b/docs/translations/api-docs/date-pickers/static-date-time-picker/static-date-time-picker.json index 412c84399a302..19ada9b85db12 100644 --- a/docs/translations/api-docs/date-pickers/static-date-time-picker/static-date-time-picker.json +++ b/docs/translations/api-docs/date-pickers/static-date-time-picker/static-date-time-picker.json @@ -165,6 +165,7 @@ "day": "Custom component for day. Check the PickersDay component.", "layout": "Custom component for wrapping the layout. It wraps the toolbar, views, action bar, and shortcuts.", "leftArrowIcon": "Icon displayed in the left view switch button.", + "monthButton": "Button displayed to render a single month in the "month" view .", "nextIconButton": "Button allowing to switch to the right view.", "previousIconButton": "Button allowing to switch to the left view.", "rightArrowIcon": "Icon displayed in the right view switch button.", diff --git a/packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx b/packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx index e8dad041afc22..08f23b1248edb 100644 --- a/packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx +++ b/packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx @@ -368,6 +368,8 @@ export const DateCalendar = React.forwardRef(function DateCalendar setFocusedView('month', isViewFocused)} monthsPerRow={monthsPerRow} referenceDate={referenceDate} + slots={slots} + slotProps={slotProps} /> )} diff --git a/packages/x-date-pickers/src/DateCalendar/DateCalendar.types.ts b/packages/x-date-pickers/src/DateCalendar/DateCalendar.types.ts index c909e8e9e1710..ad69b86addd74 100644 --- a/packages/x-date-pickers/src/DateCalendar/DateCalendar.types.ts +++ b/packages/x-date-pickers/src/DateCalendar/DateCalendar.types.ts @@ -20,11 +20,16 @@ import { ExportedUseViewsOptions } from '../internals/hooks/useViews'; import { DateView, PickerValidDate, TimezoneProps } from '../models'; import { DefaultizedProps } from '../internals/models/helpers'; import { ExportedYearCalendarProps } from '../YearCalendar/YearCalendar.types'; -import { ExportedMonthCalendarProps } from '../MonthCalendar/MonthCalendar.types'; +import { + ExportedMonthCalendarProps, + MonthCalendarSlots, + MonthCalendarSlotProps, +} from '../MonthCalendar/MonthCalendar.types'; export interface DateCalendarSlots extends PickersCalendarHeaderSlots, - DayCalendarSlots { + DayCalendarSlots, + MonthCalendarSlots { /** * Custom component for calendar header. * Check the [PickersCalendarHeader](https://mui.com/x/api/date-pickers/pickers-calendar-header/) component. @@ -35,7 +40,8 @@ export interface DateCalendarSlots export interface DateCalendarSlotProps extends PickersCalendarHeaderSlotProps, - DayCalendarSlotProps { + DayCalendarSlotProps, + MonthCalendarSlotProps { calendarHeader?: SlotComponentProps>; } diff --git a/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx b/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx index de6365bc00afc..7d7961defe94e 100644 --- a/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx +++ b/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import useEventCallback from '@mui/utils/useEventCallback'; import Typography from '@mui/material/Typography'; -import { useSlotProps, SlotComponentProps } from '@mui/base/utils'; +import { useSlotProps } from '@mui/base/utils'; import { styled, useTheme, useThemeProps } from '@mui/material/styles'; import { unstable_composeClasses as composeClasses, @@ -27,7 +27,7 @@ import { useIsDateDisabled } from './useIsDateDisabled'; import { findClosestEnabledDate, getWeekdays } from '../internals/utils/date-utils'; import { DayCalendarClasses, getDayCalendarUtilityClass } from './dayCalendarClasses'; import { PickerValidDate, TimezoneProps } from '../models'; -import { DefaultizedProps } from '../internals/models/helpers'; +import {DefaultizedProps, SlotComponentPropsFromProps} from '../internals/models/helpers'; export interface DayCalendarSlots { /** @@ -39,8 +39,8 @@ export interface DayCalendarSlots { } export interface DayCalendarSlotProps { - day?: SlotComponentProps< - typeof PickersDay, + day?: SlotComponentPropsFromProps< + PickersDayProps, {}, DayCalendarProps & { day: TDate; selected: boolean } >; diff --git a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx index dfe775f65b001..4f18c2c24f9d6 100644 --- a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx +++ b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx @@ -106,6 +106,8 @@ export const MonthCalendar = React.forwardRef(function MonthCalendar {monthText} @@ -374,6 +378,16 @@ MonthCalendar.propTypes = { * @returns {boolean} If `true`, the month will be disabled. */ shouldDisableMonth: PropTypes.func, + /** + * The props used for each component slot. + * @default {} + */ + slotProps: PropTypes.object, + /** + * Overridable component slots. + * @default {} + */ + slots: PropTypes.object, /** * The system prop that allows defining system overrides as well as additional CSS styles. */ diff --git a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.types.ts b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.types.ts index c7a8a148c6f8d..86d7cc602e2b0 100644 --- a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.types.ts +++ b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.types.ts @@ -1,8 +1,23 @@ +import * as React from 'react'; import { SxProps } from '@mui/system'; import { Theme } from '@mui/material/styles'; +import { SlotComponentProps } from '@mui/base/utils'; import { MonthCalendarClasses } from './monthCalendarClasses'; import { BaseDateValidationProps, MonthValidationProps } from '../internals/models/validation'; import { PickerValidDate, TimezoneProps } from '../models'; +import type { PickersMonthProps } from './PickersMonth'; + +export interface MonthCalendarSlots { + /** + * Button displayed to render a single month in the "month" view . + * @default MonthCalendarButton + */ + monthButton?: React.ElementType, 'button'>; +} + +export interface MonthCalendarSlotProps { + monthButton?: SlotComponentProps<'button', {}, PickersMonthProps>; +} export interface ExportedMonthCalendarProps { /** @@ -22,6 +37,16 @@ export interface MonthCalendarProps * Override or extend the styles applied to the component. */ classes?: Partial; + /** + * Overridable component slots. + * @default {} + */ + slots?: MonthCalendarSlots; + /** + * The props used for each component slot. + * @default {} + */ + slotProps?: MonthCalendarSlotProps; /** * The system prop that allows defining system overrides as well as additional CSS styles. */ diff --git a/packages/x-date-pickers/src/MonthCalendar/PickersMonth.tsx b/packages/x-date-pickers/src/MonthCalendar/PickersMonth.tsx index daae053f66c4d..fea845693e4a0 100644 --- a/packages/x-date-pickers/src/MonthCalendar/PickersMonth.tsx +++ b/packages/x-date-pickers/src/MonthCalendar/PickersMonth.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { styled, alpha, useThemeProps } from '@mui/material/styles'; +import { useSlotProps } from '@mui/base/utils'; import { unstable_composeClasses as composeClasses, unstable_useEnhancedEffect as useEnhancedEffect, @@ -9,6 +10,7 @@ import { pickersMonthClasses, PickersMonthClasses, } from './pickersMonthClasses'; +import { MonthCalendarSlotProps, MonthCalendarSlots } from './MonthCalendar.types'; export interface ExportedPickersMonthProps { classes?: Partial; @@ -28,6 +30,8 @@ export interface PickersMonthProps extends ExportedPickersMonthProps { value: number; tabIndex: number; monthsPerRow: 3 | 4; + slots?: MonthCalendarSlots; + slotProps?: MonthCalendarSlotProps; } const useUtilityClasses = (ownerState: PickersMonthProps) => { @@ -55,7 +59,7 @@ const PickersMonthRoot = styled('div', { variants: [{ props: { monthsPerRow: 4 }, style: { flexBasis: '25%' } }], }); -const PickersMonthButton = styled('button', { +export const PickersMonthButton = styled('button', { name: 'MuiPickersMonth', slot: 'MonthButton', overridesResolver: (_, styles) => [ @@ -64,7 +68,7 @@ const PickersMonthButton = styled('button', { { [`&.${pickersMonthClasses.selected}`]: styles.selected }, ], })<{ - ownerState: PickersMonthProps; + ownerState?: PickersMonthProps; }>(({ theme }) => ({ color: 'unset', backgroundColor: 'transparent', @@ -125,6 +129,8 @@ export const PickersMonth = React.memo(function PickersMonth(inProps: PickersMon 'aria-label': ariaLabel, // We don't want to forward this prop to the root element monthsPerRow, + slots, + slotProps, ...other } = props; @@ -137,26 +143,32 @@ export const PickersMonth = React.memo(function PickersMonth(inProps: PickersMon } }, [autoFocus]); + const MonthButton = slots?.monthButton ?? PickersMonthButton; + const monthButtonProps = useSlotProps({ + elementType: MonthButton, + externalSlotProps: slotProps?.monthButton, + additionalProps: { + children, + disabled, + tabIndex, + ref, + type: 'button' as const, + role: 'radio', + 'aria-current': ariaCurrent, + 'aria-checked': selected, + 'aria-label': ariaLabel, + onClick: (event: React.MouseEvent) => onClick(event, value), + onKeyDown: (event: React.KeyboardEvent) => onKeyDown(event, value), + onFocus: (event: React.FocusEvent) => onFocus(event, value), + onBlur: (event: React.FocusEvent) => onBlur(event, value), + }, + ownerState: props, + className: classes.monthButton, + }); + return ( - onClick(event, value)} - onKeyDown={(event) => onKeyDown(event, value)} - onFocus={(event) => onFocus(event, value)} - onBlur={(event) => onBlur(event, value)} - className={classes.monthButton} - ownerState={props} - > - {children} - + ); }); diff --git a/packages/x-date-pickers/src/MonthCalendar/index.ts b/packages/x-date-pickers/src/MonthCalendar/index.ts index 034b808b06aa9..873d7b77b34c6 100644 --- a/packages/x-date-pickers/src/MonthCalendar/index.ts +++ b/packages/x-date-pickers/src/MonthCalendar/index.ts @@ -1,9 +1,14 @@ export { MonthCalendar } from './MonthCalendar'; -export type { MonthCalendarProps } from './MonthCalendar.types'; +export type { + MonthCalendarProps, + MonthCalendarSlots, + MonthCalendarSlotProps, +} from './MonthCalendar.types'; export { monthCalendarClasses, getMonthCalendarUtilityClass } from './monthCalendarClasses'; export type { MonthCalendarClasses, MonthCalendarClassKey } from './monthCalendarClasses'; export { pickersMonthClasses } from './pickersMonthClasses'; export type { PickersMonthClassKey, PickersMonthClasses } from './pickersMonthClasses'; +export { PickersMonthButton } from './PickersMonth'; export type { ExportedPickersMonthProps } from './PickersMonth'; diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index 689039bc85958..315080b7a21d7 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -213,6 +213,8 @@ { "name": "MonthCalendarClasses", "kind": "Interface" }, { "name": "MonthCalendarClassKey", "kind": "TypeAlias" }, { "name": "MonthCalendarProps", "kind": "Interface" }, + { "name": "MonthCalendarSlotProps", "kind": "Interface" }, + { "name": "MonthCalendarSlots", "kind": "Interface" }, { "name": "MuiPickersAdapter", "kind": "Interface" }, { "name": "MuiPickersAdapterContext", "kind": "Variable" }, { "name": "MultiInputDateRangeField", "kind": "Variable" }, @@ -289,6 +291,7 @@ { "name": "PickersLayoutSlotProps", "kind": "Interface" }, { "name": "PickersLayoutSlots", "kind": "Interface" }, { "name": "PickersLocaleText", "kind": "Interface" }, + { "name": "PickersMonthButton", "kind": "Variable" }, { "name": "pickersMonthClasses", "kind": "Variable" }, { "name": "PickersMonthClasses", "kind": "Interface" }, { "name": "PickersMonthClassKey", "kind": "TypeAlias" }, diff --git a/scripts/x-date-pickers.exports.json b/scripts/x-date-pickers.exports.json index 63ae47de5f992..b0ffa1ade36e0 100644 --- a/scripts/x-date-pickers.exports.json +++ b/scripts/x-date-pickers.exports.json @@ -143,6 +143,8 @@ { "name": "MonthCalendarClasses", "kind": "Interface" }, { "name": "MonthCalendarClassKey", "kind": "TypeAlias" }, { "name": "MonthCalendarProps", "kind": "Interface" }, + { "name": "MonthCalendarSlotProps", "kind": "Interface" }, + { "name": "MonthCalendarSlots", "kind": "Interface" }, { "name": "MuiPickersAdapter", "kind": "Interface" }, { "name": "MuiPickersAdapterContext", "kind": "Variable" }, { "name": "MultiSectionDigitalClock", "kind": "Variable" }, @@ -204,6 +206,7 @@ { "name": "PickersLayoutSlotProps", "kind": "Interface" }, { "name": "PickersLayoutSlots", "kind": "Interface" }, { "name": "PickersLocaleText", "kind": "Interface" }, + { "name": "PickersMonthButton", "kind": "Variable" }, { "name": "pickersMonthClasses", "kind": "Variable" }, { "name": "PickersMonthClasses", "kind": "Interface" }, { "name": "PickersMonthClassKey", "kind": "TypeAlias" },