Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pickers] Add referenceDate on picker components (and DateRangeCalendar) #9991

Merged
merged 10 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as React from 'react';
import dayjs from 'dayjs';
import { DemoContainer, DemoItem } from '@mui/x-date-pickers/internals/demo';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';

export default function ReferenceDateDefaultBehavior() {
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DemoContainer components={['DateTimePicker', 'DateTimePicker']}>
<DemoItem label="No validation: uses today">
<DateTimePicker />
</DemoItem>
<DemoItem label="Validation: uses the first day after `maxDate`">
<DateTimePicker maxDate={dayjs('2022-04-17')} />
</DemoItem>
</DemoContainer>
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as React from 'react';
import dayjs from 'dayjs';
import { DemoContainer, DemoItem } from '@mui/x-date-pickers/internals/demo';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';

export default function ReferenceDateDefaultBehavior() {
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DemoContainer components={['DateTimePicker', 'DateTimePicker']}>
<DemoItem label="No validation: uses today">
<DateTimePicker />
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
</DemoItem>
<DemoItem label="Validation: uses the first day after `maxDate`">
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
<DateTimePicker maxDate={dayjs('2022-04-17')} />
</DemoItem>
</DemoContainer>
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<DemoItem label="No validation: uses today">
<DateTimePicker />
</DemoItem>
<DemoItem label="Validation: uses the first day after `maxDate`">
<DateTimePicker maxDate={dayjs('2022-04-17')} />
</DemoItem>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as React from 'react';
import dayjs from 'dayjs';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';

export default function ReferenceDateExplicitDateTimePicker() {
const [value, setValue] = React.useState(null);

return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Stack spacing={2}>
<DateTimePicker
value={value}
onChange={setValue}
referenceDate={dayjs('2022-04-17T15:30')}
/>
<Typography>
Stored value: {value == null ? 'null' : value.format()}
</Typography>
</Stack>
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as React from 'react';
import dayjs, { Dayjs } from 'dayjs';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';

export default function ReferenceDateExplicitDateTimePicker() {
const [value, setValue] = React.useState<Dayjs | null>(null);

return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Stack spacing={2}>
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
<DateTimePicker
value={value}
onChange={setValue}
referenceDate={dayjs('2022-04-17T15:30')}
/>
<Typography>
Stored value: {value == null ? 'null' : value.format()}
</Typography>
</Stack>
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<DateTimePicker
value={value}
onChange={setValue}
referenceDate={dayjs('2022-04-17T15:30')}
/>
<Typography>
Stored value: {value == null ? 'null' : value.format()}
</Typography>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as React from 'react';
import dayjs from 'dayjs';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { TimePicker } from '@mui/x-date-pickers/TimePicker';

export default function ReferenceDateExplicitTimePicker() {
const [value, setValue] = React.useState(null);

return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Stack spacing={2}>
<TimePicker
value={value}
onChange={setValue}
referenceDate={dayjs('2022-04-17')}
/>
<Typography>
Stored value: {value == null ? 'null' : value.format()}
</Typography>
</Stack>
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as React from 'react';
import dayjs, { Dayjs } from 'dayjs';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { TimePicker } from '@mui/x-date-pickers/TimePicker';

export default function ReferenceDateExplicitTimePicker() {
const [value, setValue] = React.useState<Dayjs | null>(null);

return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Stack spacing={2}>
<TimePicker
value={value}
onChange={setValue}
referenceDate={dayjs('2022-04-17')}
/>
<Typography>
Stored value: {value == null ? 'null' : value.format()}
</Typography>
</Stack>
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<TimePicker
value={value}
onChange={setValue}
referenceDate={dayjs('2022-04-17')}
/>
<Typography>
Stored value: {value == null ? 'null' : value.format()}
</Typography>
16 changes: 16 additions & 0 deletions docs/data/date-pickers/base-concepts/ReferenceDateUsingValue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react';
import dayjs from 'dayjs';
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 { DatePicker } from '@mui/x-date-pickers/DatePicker';

export default function ReferenceDateUsingValue() {
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DemoContainer components={['DatePicker']}>
<DatePicker label="Date Picker" defaultValue={dayjs('2022-04-17')} />
</DemoContainer>
</LocalizationProvider>
);
}
16 changes: 16 additions & 0 deletions docs/data/date-pickers/base-concepts/ReferenceDateUsingValue.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react';
import dayjs from 'dayjs';
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 { DatePicker } from '@mui/x-date-pickers/DatePicker';

export default function ReferenceDateUsingValue() {
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DemoContainer components={['DatePicker']}>
<DatePicker label="Date Picker" defaultValue={dayjs('2022-04-17')} />
</DemoContainer>
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<DatePicker label="Date Picker" defaultValue={dayjs('2022-04-17')} />
23 changes: 22 additions & 1 deletion docs/data/date-pickers/base-concepts/base-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,30 @@ There are many components available, each fitting specific use cases. Use the fo

{{"demo": "ComponentExplorerNoSnap.js", "hideToolbar": true}}

## Reference date when no value is defined

If `value` or `defaultValue` contains a valid date, this date will be used to initialize the rendered component.

In the demo below, you can see that the calendar is set to April 2022 on mount:

{{"demo": "ReferenceDateUsingValue.js"}}

When `value` and `defaultValue` contains no valid date, the component will try to find a reference date that passes the validation to initialize its rendering:

{{"demo": "ReferenceDateDefaultBehavior.js"}}

You can override this date using the `referenceDate` prop:

{{"demo": "ReferenceDateExplicitDateTimePicker.js"}}

This can also be useful to set the part of the value that will not be selectable in the component.
For example, in a Time Picker, it allows you to choose the date of your value:

{{"demo": "ReferenceDateExplicitTimePicker.js"}}

## Accessibility

Both `Desktop` and `Mobile` Date and Time Pickers are using `role="dialog"` to display their interactive view parts and thus they should follow [Modal accessibility guidelines](/material-ui/react-modal/#accessibility).
Both `Desktop` and `Mobile` Date and Time Pickers are using `role="dialog"` to display their interactive view parts, and thus they should follow [Modal accessibility guidelines](/material-ui/react-modal/#accessibility).
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
This behavior is automated as much as possible, ensuring that the Date and Time Pickers are accessible in most cases.
A correct `aria-labelledby` value is assigned to the dialog component based on the following rules:

Expand Down
16 changes: 16 additions & 0 deletions docs/data/date-pickers/date-calendar/DateCalendarReferenceDate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react';
import dayjs from 'dayjs';
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 DateCalendarReferenceDate() {
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DemoContainer components={['DateCalendar']}>
<DateCalendar referenceDate={dayjs('2022-04-17')} />
</DemoContainer>
</LocalizationProvider>
);
}
16 changes: 16 additions & 0 deletions docs/data/date-pickers/date-calendar/DateCalendarReferenceDate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react';
import dayjs from 'dayjs';
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 DateCalendarReferenceDate() {
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DemoContainer components={['DateCalendar']}>
<DateCalendar referenceDate={dayjs('2022-04-17')} />
</DemoContainer>
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<DateCalendar referenceDate={dayjs('2022-04-17')} />
13 changes: 13 additions & 0 deletions docs/data/date-pickers/date-calendar/date-calendar.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ Views will appear in the order they're included in the `views` array.

{{"demo": "DateCalendarViews.js"}}

## Choose the initial year / month

If `value` or `defaultValue` contains a valid date, this date will be used to choose which month to render in the `day` view and which year to render in the `month` view.
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
If both `value` and `defaultValue` contains no valid date, the component will try to find a month and year that passes the validation.
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved

You can override this date using the `referenceDate`, in the example below the calendar renders April 2014 when opened even though no date is visually selected:
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved

{{"demo": "DateCalendarReferenceDate.js"}}

:::success
Learn more about the `referenceDate` in the [dedicated doc section](/x/react-date-pickers/base-concepts/#reference-date-when-no-value-is-defined)
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
:::

## Month and Year Calendar

If you only need the `year` view or the `month` view, you can use the `YearCalendar` / `MonthCalendar` components:
Expand Down
4 changes: 4 additions & 0 deletions docs/pages/x/api/date-pickers/date-picker.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@
"type": { "name": "bool" },
"default": "`@media(prefers-reduced-motion: reduce)` || typeof navigator !== 'undefined' && /(android)/i.test(navigator.userAgent)"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date-time using the validation props, except callbacks such as `shouldDisableDate`."
},
"renderLoading": {
"type": { "name": "func" },
"default": "() => <span data-mui-test=\"loading-progress\">...</span>",
Expand Down
4 changes: 4 additions & 0 deletions docs/pages/x/api/date-pickers/date-range-calendar.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@
"type": { "name": "bool" },
"default": "`@media(prefers-reduced-motion: reduce)` || typeof navigator !== 'undefined' && /(android)/i.test(navigator.userAgent)"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date using the validation props, except callbacks such as `shouldDisableDate`."
},
"renderLoading": {
"type": { "name": "func" },
"default": "() => \"...\"",
Expand Down
4 changes: 4 additions & 0 deletions docs/pages/x/api/date-pickers/date-range-picker.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@
"type": { "name": "bool" },
"default": "`@media(prefers-reduced-motion: reduce)` || typeof navigator !== 'undefined' && /(android)/i.test(navigator.userAgent)"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date-time using the validation props, except callbacks such as `shouldDisableDate`."
},
"renderLoading": {
"type": { "name": "func" },
"default": "() => \"...\"",
Expand Down
4 changes: 4 additions & 0 deletions docs/pages/x/api/date-pickers/date-time-picker.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@
"type": { "name": "bool" },
"default": "`@media(prefers-reduced-motion: reduce)` || typeof navigator !== 'undefined' && /(android)/i.test(navigator.userAgent)"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date-time using the validation props, except callbacks such as `shouldDisableDate`."
},
"renderLoading": {
"type": { "name": "func" },
"default": "() => <span data-mui-test=\"loading-progress\">...</span>",
Expand Down
4 changes: 4 additions & 0 deletions docs/pages/x/api/date-pickers/desktop-date-picker.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@
"type": { "name": "bool" },
"default": "`@media(prefers-reduced-motion: reduce)` || typeof navigator !== 'undefined' && /(android)/i.test(navigator.userAgent)"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date-time using the validation props, except callbacks such as `shouldDisableDate`."
},
"renderLoading": {
"type": { "name": "func" },
"default": "() => <span data-mui-test=\"loading-progress\">...</span>",
Expand Down
4 changes: 4 additions & 0 deletions docs/pages/x/api/date-pickers/desktop-date-range-picker.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@
"type": { "name": "bool" },
"default": "`@media(prefers-reduced-motion: reduce)` || typeof navigator !== 'undefined' && /(android)/i.test(navigator.userAgent)"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date-time using the validation props, except callbacks such as `shouldDisableDate`."
},
"renderLoading": {
"type": { "name": "func" },
"default": "() => \"...\"",
Expand Down
4 changes: 4 additions & 0 deletions docs/pages/x/api/date-pickers/desktop-date-time-picker.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@
"type": { "name": "bool" },
"default": "`@media(prefers-reduced-motion: reduce)` || typeof navigator !== 'undefined' && /(android)/i.test(navigator.userAgent)"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date-time using the validation props, except callbacks such as `shouldDisableDate`."
},
"renderLoading": {
"type": { "name": "func" },
"default": "() => <span data-mui-test=\"loading-progress\">...</span>",
Expand Down
4 changes: 4 additions & 0 deletions docs/pages/x/api/date-pickers/desktop-time-picker.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@
"type": { "name": "bool" },
"default": "`@media(prefers-reduced-motion: reduce)` || typeof navigator !== 'undefined' && /(android)/i.test(navigator.userAgent)"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date-time using the validation props, except callbacks such as `shouldDisableDate`."
},
"selectedSections": {
"type": {
"name": "union",
Expand Down
Loading