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 all 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 { DatePicker } from '@mui/x-date-pickers/DatePicker';

export default function ReferenceDateDefaultBehavior() {
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DemoContainer components={['DateTimePicker', 'DateTimePicker']}>
<DemoItem label="No validation: uses today">
<DatePicker />
</DemoItem>
<DemoItem label="Validation: uses the day of `maxDate`">
<DatePicker 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 { DatePicker } from '@mui/x-date-pickers/DatePicker';

export default function ReferenceDateDefaultBehavior() {
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DemoContainer components={['DateTimePicker', 'DateTimePicker']}>
<DemoItem label="No validation: uses today">
<DatePicker />
</DemoItem>
<DemoItem label="Validation: uses the day of `maxDate`">
<DatePicker 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">
<DatePicker />
</DemoItem>
<DemoItem label="Validation: uses the day of `maxDate`">
<DatePicker 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} sx={{ minWidth: 305 }}>
<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} sx={{ minWidth: 305 }}>
<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} sx={{ minWidth: 305 }}>
<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} sx={{ minWidth: 305 }}>
<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>
19 changes: 19 additions & 0 deletions docs/data/date-pickers/base-concepts/ReferenceDateUsingValue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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
defaultValue={dayjs('2022-04-17')}
views={['year', 'month', 'day']}
/>
</DemoContainer>
</LocalizationProvider>
);
}
19 changes: 19 additions & 0 deletions docs/data/date-pickers/base-concepts/ReferenceDateUsingValue.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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
defaultValue={dayjs('2022-04-17')}
views={['year', 'month', 'day']}
LukasTy marked this conversation as resolved.
Show resolved Hide resolved
/>
</DemoContainer>
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<DatePicker
defaultValue={dayjs('2022-04-17')}
views={['year', 'month', 'day']}
/>
21 changes: 21 additions & 0 deletions docs/data/date-pickers/base-concepts/base-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,27 @@ 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).
Expand Down
19 changes: 19 additions & 0 deletions docs/data/date-pickers/date-calendar/DateCalendarReferenceDate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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')}
views={['year', 'month', 'day']}
/>
</DemoContainer>
</LocalizationProvider>
);
}
19 changes: 19 additions & 0 deletions docs/data/date-pickers/date-calendar/DateCalendarReferenceDate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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')}
views={['year', 'month', 'day']}
/>
</DemoContainer>
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<DateCalendar
referenceDate={dayjs('2022-04-17')}
views={['year', 'month', 'day']}
/>
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` contain no valid date, the component will try to find a month and year that satisfies the validation rules.

You can override this date using the `referenceDate`, in the example below the calendar renders April 2022 even though no date is visually selected:

{{"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).
:::

## 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)` || `navigator.userAgent` matches Android <10 or iOS <13"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`."
},
"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)` || `navigator.userAgent` matches Android <10 or iOS <13"
},
"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)` || `navigator.userAgent` matches Android <10 or iOS <13"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`."
},
"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)` || `navigator.userAgent` matches Android <10 or iOS <13"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`."
},
"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)` || `navigator.userAgent` matches Android <10 or iOS <13"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`."
},
"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)` || `navigator.userAgent` matches Android <10 or iOS <13"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`."
},
"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)` || `navigator.userAgent` matches Android <10 or iOS <13"
},
"referenceDate": {
"type": { "name": "any" },
"default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`."
},
"renderLoading": {
"type": { "name": "func" },
"default": "() => <span data-mui-test=\"loading-progress\">...</span>",
Expand Down
Loading