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 DigitalClock to DesktopDateTimePicker #8946

Merged
merged 31 commits into from
May 26, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
89759fb
Add a combined `dateTimeVIewRenderer` and adapt typing
LukasTy May 10, 2023
003ce58
Avoid type casting
LukasTy May 10, 2023
4d5d90a
Use util
LukasTy May 10, 2023
77d5ad4
Avoid passing incorrect `focusedView`
LukasTy May 10, 2023
f3a73a6
Avoid setting view twice and re-setting it in case of DateTimePicker
LukasTy May 10, 2023
914f451
Improve typing
LukasTy May 11, 2023
f34b6d2
Avoid adding a divider when there are no actions
LukasTy May 11, 2023
89a0cda
Add custom `DesktopDateTimePickerToolbar` styling and layout
LukasTy May 12, 2023
c5f05c0
Support desktop toolbar in landscape mode
LukasTy May 15, 2023
141e619
Specify desktop `wrapperVariant`
LukasTy May 15, 2023
b872592
Keep focus and view in sync.
LukasTy May 15, 2023
9be2828
Fix border
LukasTy May 15, 2023
72691df
Avoid rendering `MultiSectionDigitalClock` when there are no `viewRen…
LukasTy May 15, 2023
db355ec
Hiding focus state is evil
LukasTy May 15, 2023
d3d4b2d
Fix tests on `DesktopDateTimePicker`
LukasTy May 16, 2023
36ab70d
Fix time related tests and use more `views` in them
LukasTy May 16, 2023
73f378f
proptypes
LukasTy May 17, 2023
76430b8
Remove no longer relevant condition
LukasTy May 17, 2023
0a5b99e
Update docs
LukasTy May 17, 2023
21e5131
docs:api
LukasTy May 17, 2023
06bcdd8
Merge remote-tracking branch 'origin/master' into digital-clock-in-da…
LukasTy May 17, 2023
b308f7d
Use new renderer only if no custom renderers are provided
LukasTy May 19, 2023
e532ca3
proptypes
LukasTy May 19, 2023
24e70ab
docs:api
LukasTy May 19, 2023
f6d4cee
Merge remote-tracking branch 'origin/master' into digital-clock-in-da…
LukasTy May 19, 2023
632d14d
Code review: Flavien
LukasTy May 22, 2023
ddf3736
Adjust "desktop" toolbar left padding
LukasTy May 25, 2023
b33ca89
Calculate the scroll offset container height based on the parent height
LukasTy May 26, 2023
139146f
Merge remote-tracking branch 'origin/master' into digital-clock-in-da…
LukasTy May 26, 2023
c7894f2
Fix proptypes
LukasTy May 26, 2023
142add2
Merge remote-tracking branch 'origin/master' into digital-clock-in-da…
LukasTy May 26, 2023
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
11 changes: 3 additions & 8 deletions docs/data/date-pickers/date-time-picker/date-time-picker.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,20 @@ materialDesign: https://m2.material.io/components/date-pickers

<p class="description">The Date Time Picker component lets the user select a date and time.</p>

:::info
The component by default currently does not ship with **time** picker view experience on **desktop**.
It was a conscious decision and a first step towards having a more user friendly desktop experience [discussed in #4483](https://github.com/mui/mui-x/issues/4483).
If a desktop view experience is essential, you can revert to it by following the suggestion [in the migration guide](/x/migration/migration-pickers-v5/#stop-rendering-a-clock-on-desktop).
:::

## Basic usage

{{"demo": "BasicDateTimePicker.js"}}

## Component composition

The component is built using the `DateTimeField` for the keyboard editing, the `DateCalendar` for the date view editing and the `TimeClock` for the time view editing.
All the documented props of those three components can also be passed to the Date Time Picker component.
The component is built using the `DateTimeField` for the keyboard editing, the `DateCalendar` for the date view editing, the `DigitalClock` for the desktop view editing, and the `TimeClock` for the mobile time view editing.
All the documented props of those four components can also be passed to the Date Time Picker component.

Check-out their documentation page for more information:

- [Date Field](/x/react-date-pickers/date-field/)
- [Date Calendar](/x/react-date-pickers/date-calendar/)
- [Digital Clock](/x/react-date-pickers/digital-clock/)
- [Time Clock](/x/react-date-pickers/time-clock/)

The value of the component can be uncontrolled or controlled.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ import { DateTime } from 'luxon';
### Stop rendering a clock on desktop

In desktop mode, the `DateTimePicker` and `TimePicker` components will no longer render the [`TimeClock`](/x/react-date-pickers/time-clock/) component.
The `DateTimePicker` component currently has no replacement, but on `TimePicker` a new [`DigitalClock`](/x/react-date-pickers/digital-clock/) component has been introduced instead.
The behavior on mobile mode is still the same.
The `TimeClock` component has been replaced with a new [`DigitalClock`](/x/react-date-pickers/digital-clock/) component instead.
The behavior on `Mobile` and `Static` variants is still the same.
If you were relying on Clock Picker in desktop mode for tests—make sure to check [testing caveats](/x/react-date-pickers/base-concepts/#testing-caveats) to choose the best replacement for it.

You can manually re-enable the previous clock component using the new `viewRenderers` prop.
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/x/api/date-pickers/date-time-picker-tabs.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"view": {
"type": {
"name": "enum",
"description": "'day'<br>&#124;&nbsp;'hours'<br>&#124;&nbsp;'minutes'<br>&#124;&nbsp;'month'<br>&#124;&nbsp;'seconds'<br>&#124;&nbsp;'year'"
"description": "'day'<br>&#124;&nbsp;'hours'<br>&#124;&nbsp;'meridiem'<br>&#124;&nbsp;'minutes'<br>&#124;&nbsp;'month'<br>&#124;&nbsp;'seconds'<br>&#124;&nbsp;'year'"
},
"required": true
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"view": {
"type": {
"name": "enum",
"description": "'day'<br>&#124;&nbsp;'hours'<br>&#124;&nbsp;'minutes'<br>&#124;&nbsp;'month'<br>&#124;&nbsp;'seconds'<br>&#124;&nbsp;'year'"
"description": "'day'<br>&#124;&nbsp;'hours'<br>&#124;&nbsp;'meridiem'<br>&#124;&nbsp;'minutes'<br>&#124;&nbsp;'month'<br>&#124;&nbsp;'seconds'<br>&#124;&nbsp;'year'"
},
"required": true
},
Expand Down
18 changes: 15 additions & 3 deletions docs/pages/x/api/date-pickers/date-time-picker.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"openTo": {
"type": {
"name": "enum",
"description": "'day'<br>&#124;&nbsp;'hours'<br>&#124;&nbsp;'minutes'<br>&#124;&nbsp;'month'<br>&#124;&nbsp;'seconds'<br>&#124;&nbsp;'year'"
"description": "'day'<br>&#124;&nbsp;'hours'<br>&#124;&nbsp;'meridiem'<br>&#124;&nbsp;'minutes'<br>&#124;&nbsp;'month'<br>&#124;&nbsp;'seconds'<br>&#124;&nbsp;'year'"
}
},
"orientation": {
Expand Down Expand Up @@ -103,6 +103,7 @@
"shouldDisableTime": { "type": { "name": "func" } },
"shouldDisableYear": { "type": { "name": "func" } },
"showDaysOutsideCurrentMonth": { "type": { "name": "bool" } },
"skipDisabled": { "type": { "name": "bool" } },
"slotProps": { "type": { "name": "object" }, "default": "{}" },
"slots": { "type": { "name": "object" }, "default": "{}" },
"sx": {
Expand All @@ -111,17 +112,24 @@
"description": "Array&lt;func<br>&#124;&nbsp;object<br>&#124;&nbsp;bool&gt;<br>&#124;&nbsp;func<br>&#124;&nbsp;object"
}
},
"timeSteps": {
"type": {
"name": "shape",
"description": "{ hours?: number, minutes?: number, seconds?: number }"
},
"default": "{ hours: 1, minutes: 5, seconds: 5 }"
},
"value": { "type": { "name": "any" } },
"view": {
"type": {
"name": "enum",
"description": "'day'<br>&#124;&nbsp;'hours'<br>&#124;&nbsp;'minutes'<br>&#124;&nbsp;'month'<br>&#124;&nbsp;'seconds'<br>&#124;&nbsp;'year'"
"description": "'day'<br>&#124;&nbsp;'hours'<br>&#124;&nbsp;'meridiem'<br>&#124;&nbsp;'minutes'<br>&#124;&nbsp;'month'<br>&#124;&nbsp;'seconds'<br>&#124;&nbsp;'year'"
}
},
"viewRenderers": {
"type": {
"name": "shape",
"description": "{ day?: func, hours?: func, minutes?: func, month?: func, seconds?: func, year?: func }"
"description": "{ day?: func, hours?: func, meridiem?: func, minutes?: func, month?: func, seconds?: func, year?: func }"
}
},
"views": {
Expand All @@ -148,6 +156,10 @@
"type": { "name": "elementType" }
},
"Dialog": { "default": "PickersModalDialogRoot", "type": { "name": "elementType" } },
"DigitalClockSectionItem": {
"default": "MenuItem from '@mui/material'",
"type": { "name": "elementType" }
},
"Field": { "type": { "name": "elementType" } },
"InputAdornment": { "default": "InputAdornment", "type": { "name": "elementType" } },
"Layout": { "type": { "name": "elementType" } },
Expand Down
18 changes: 15 additions & 3 deletions docs/pages/x/api/date-pickers/desktop-date-time-picker.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"openTo": {
"type": {
"name": "enum",
"description": "'day'<br>&#124;&nbsp;'hours'<br>&#124;&nbsp;'minutes'<br>&#124;&nbsp;'month'<br>&#124;&nbsp;'seconds'<br>&#124;&nbsp;'year'"
"description": "'day'<br>&#124;&nbsp;'hours'<br>&#124;&nbsp;'meridiem'<br>&#124;&nbsp;'minutes'<br>&#124;&nbsp;'month'<br>&#124;&nbsp;'seconds'<br>&#124;&nbsp;'year'"
}
},
"orientation": {
Expand Down Expand Up @@ -99,6 +99,7 @@
"shouldDisableTime": { "type": { "name": "func" } },
"shouldDisableYear": { "type": { "name": "func" } },
"showDaysOutsideCurrentMonth": { "type": { "name": "bool" } },
"skipDisabled": { "type": { "name": "bool" } },
"slotProps": { "type": { "name": "object" }, "default": "{}" },
"slots": { "type": { "name": "object" }, "default": "{}" },
"sx": {
Expand All @@ -107,17 +108,24 @@
"description": "Array&lt;func<br>&#124;&nbsp;object<br>&#124;&nbsp;bool&gt;<br>&#124;&nbsp;func<br>&#124;&nbsp;object"
}
},
"timeSteps": {
"type": {
"name": "shape",
"description": "{ hours?: number, minutes?: number, seconds?: number }"
},
"default": "{ hours: 1, minutes: 5, seconds: 5 }"
},
"value": { "type": { "name": "any" } },
"view": {
"type": {
"name": "enum",
"description": "'day'<br>&#124;&nbsp;'hours'<br>&#124;&nbsp;'minutes'<br>&#124;&nbsp;'month'<br>&#124;&nbsp;'seconds'<br>&#124;&nbsp;'year'"
"description": "'day'<br>&#124;&nbsp;'hours'<br>&#124;&nbsp;'meridiem'<br>&#124;&nbsp;'minutes'<br>&#124;&nbsp;'month'<br>&#124;&nbsp;'seconds'<br>&#124;&nbsp;'year'"
}
},
"viewRenderers": {
"type": {
"name": "shape",
"description": "{ day?: func, hours?: func, minutes?: func, month?: func, seconds?: func, year?: func }"
"description": "{ day?: func, hours?: func, meridiem?: func, minutes?: func, month?: func, seconds?: func, year?: func }"
}
},
"views": {
Expand All @@ -143,6 +151,10 @@
"default": "TrapFocus from @mui/material",
"type": { "name": "elementType" }
},
"DigitalClockSectionItem": {
"default": "MenuItem from '@mui/material'",
"type": { "name": "elementType" }
},
"Field": { "type": { "name": "elementType" } },
"InputAdornment": { "default": "InputAdornment", "type": { "name": "elementType" } },
"Layout": { "type": { "name": "elementType" } },
Expand Down
3 changes: 3 additions & 0 deletions docs/translations/api-docs/date-pickers/date-time-picker.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@
"shouldDisableTime": "Disable specific time.<br><br><strong>Signature:</strong><br><code>function(value: TDate, view: TimeView) =&gt; boolean</code><br><em>value:</em> The value to check.<br><em>view:</em> The clock type of the timeValue.<br> <em>returns</em> (boolean): If <code>true</code> the time will be disabled.",
"shouldDisableYear": "Disable specific year.<br><br><strong>Signature:</strong><br><code>function(year: TDate) =&gt; boolean</code><br><em>year:</em> The year to test.<br> <em>returns</em> (boolean): If <code>true</code>, the year will be disabled.",
"showDaysOutsideCurrentMonth": "If <code>true</code>, days outside the current month are rendered:<br>- if <code>fixedWeekNumber</code> is defined, renders days to have the weeks requested.<br>- if <code>fixedWeekNumber</code> is not defined, renders day to fill the first and last week of the current month.<br>- ignored if <code>calendars</code> equals more than <code>1</code> on range pickers.",
"skipDisabled": "If <code>true</code>, disabled digital clock items will not be rendered.",
"slotProps": "The props used for each component slot.",
"slots": "Overridable component slots.",
"sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the <a href=\"/system/getting-started/the-sx-prop/\">`sx` page</a> for more details.",
"timeSteps": "The time steps between two time unit options. For example, if <code>timeStep.minutes = 8</code>, then the available minute options will be <code>[0, 8, 16, 24, 32, 40, 48, 56]</code>. When single column time renderer is used, only <code>timeStep.minutes</code> will be used.",
"value": "The selected value. Used when the component is controlled.",
"view": "The visible view. Used when the component view is controlled. Must be a valid option from <code>views</code> list.",
"viewRenderers": "Define custom view renderers for each section. If <code>null</code>, the section will only have field editing. If <code>undefined</code>, internally defined view will be the used.",
Expand All @@ -72,6 +74,7 @@
"DesktopTransition": "Custom component for the desktop popper <a href=\"https://mui.com/material-ui/transitions/\">Transition</a>.",
"DesktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.",
"Dialog": "Custom component for the dialog inside which the views are rendered on mobile.",
"DigitalClockSectionItem": "Component responsible for rendering a single multi section digital clock section item.",
"Field": "Component used to enter the date with the keyboard.",
"InputAdornment": "Component displayed on the start or end input adornment used to open the picker on desktop.",
"Layout": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@
"shouldDisableTime": "Disable specific time.<br><br><strong>Signature:</strong><br><code>function(value: TDate, view: TimeView) =&gt; boolean</code><br><em>value:</em> The value to check.<br><em>view:</em> The clock type of the timeValue.<br> <em>returns</em> (boolean): If <code>true</code> the time will be disabled.",
"shouldDisableYear": "Disable specific year.<br><br><strong>Signature:</strong><br><code>function(year: TDate) =&gt; boolean</code><br><em>year:</em> The year to test.<br> <em>returns</em> (boolean): If <code>true</code>, the year will be disabled.",
"showDaysOutsideCurrentMonth": "If <code>true</code>, days outside the current month are rendered:<br>- if <code>fixedWeekNumber</code> is defined, renders days to have the weeks requested.<br>- if <code>fixedWeekNumber</code> is not defined, renders day to fill the first and last week of the current month.<br>- ignored if <code>calendars</code> equals more than <code>1</code> on range pickers.",
"skipDisabled": "If <code>true</code>, disabled digital clock items will not be rendered.",
"slotProps": "The props used for each component slot.",
"slots": "Overridable component slots.",
"sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the <a href=\"/system/getting-started/the-sx-prop/\">`sx` page</a> for more details.",
"timeSteps": "The time steps between two time unit options. For example, if <code>timeStep.minutes = 8</code>, then the available minute options will be <code>[0, 8, 16, 24, 32, 40, 48, 56]</code>. When single column time renderer is used, only <code>timeStep.minutes</code> will be used.",
"value": "The selected value. Used when the component is controlled.",
"view": "The visible view. Used when the component view is controlled. Must be a valid option from <code>views</code> list.",
"viewRenderers": "Define custom view renderers for each section. If <code>null</code>, the section will only have field editing. If <code>undefined</code>, internally defined view will be the used.",
Expand All @@ -70,6 +72,7 @@
"DesktopPaper": "Custom component for the paper rendered inside the desktop picker&#39;s Popper.",
"DesktopTransition": "Custom component for the desktop popper <a href=\"https://mui.com/material-ui/transitions/\">Transition</a>.",
"DesktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.",
"DigitalClockSectionItem": "Component responsible for rendering a single multi section digital clock section item.",
"Field": "Component used to enter the date with the keyboard.",
"InputAdornment": "Component displayed on the start or end input adornment used to open the picker on desktop.",
"Layout": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.",
Expand Down
4 changes: 2 additions & 2 deletions packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,10 @@ export const DateCalendar = React.forwardRef(function DateCalendar<TDate>(
const handleSelectedDayChange = useEventCallback((day: TDate | null) => {
if (value && day) {
// If there is a date already selected, then we want to keep its time
return setValueAndGoToNextView(mergeDateAndTime(utils, day, value), 'finish');
return handleValueChange(mergeDateAndTime(utils, day, value), 'finish');
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
}

return setValueAndGoToNextView(day, 'finish');
return handleValueChange(day, 'finish');
});

React.useEffect(() => {
Expand Down
25 changes: 21 additions & 4 deletions packages/x-date-pickers/src/DateTimePicker/DateTimePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import useMediaQuery from '@mui/material/useMediaQuery';
import { useThemeProps } from '@mui/material/styles';
import { DesktopDateTimePicker } from '../DesktopDateTimePicker';
import { MobileDateTimePicker } from '../MobileDateTimePicker';
import { MobileDateTimePicker, MobileDateTimePickerProps } from '../MobileDateTimePicker';
import { DateTimePickerProps } from './DateTimePicker.types';
import { DEFAULT_DESKTOP_MODE_MEDIA_QUERY } from '../internals/utils/utils';

Expand All @@ -26,7 +26,7 @@ const DateTimePicker = React.forwardRef(function DateTimePicker<TDate>(
return <DesktopDateTimePicker ref={ref} {...other} />;
}

return <MobileDateTimePicker ref={ref} {...other} />;
return <MobileDateTimePicker ref={ref} {...(other as MobileDateTimePickerProps<TDate>)} />;
}) as DateTimePickerComponent;

DateTimePicker.propTypes = {
Expand Down Expand Up @@ -272,7 +272,7 @@ DateTimePicker.propTypes = {
* Used when the component view is not controlled.
* Must be a valid option from `views` list.
*/
openTo: PropTypes.oneOf(['day', 'hours', 'minutes', 'month', 'seconds', 'year']),
openTo: PropTypes.oneOf(['day', 'hours', 'meridiem', 'minutes', 'month', 'seconds', 'year']),
/**
* Force rendering in particular orientation.
*/
Expand Down Expand Up @@ -364,6 +364,11 @@ DateTimePicker.propTypes = {
* @default false
*/
showDaysOutsideCurrentMonth: PropTypes.bool,
/**
* If `true`, disabled digital clock items will not be rendered.
* @default false
*/
skipDisabled: PropTypes.bool,
/**
* The props used for each component slot.
* @default {}
Expand All @@ -382,6 +387,17 @@ DateTimePicker.propTypes = {
PropTypes.func,
PropTypes.object,
]),
/**
* The time steps between two time unit options.
* For example, if `timeStep.minutes = 8`, then the available minute options will be `[0, 8, 16, 24, 32, 40, 48, 56]`.
* When single column time renderer is used, only `timeStep.minutes` will be used.
* @default{ hours: 1, minutes: 5, seconds: 5 }
*/
timeSteps: PropTypes.shape({
hours: PropTypes.number,
minutes: PropTypes.number,
seconds: PropTypes.number,
}),
/**
* The selected value.
* Used when the component is controlled.
Expand All @@ -392,7 +408,7 @@ DateTimePicker.propTypes = {
* Used when the component view is controlled.
* Must be a valid option from `views` list.
*/
view: PropTypes.oneOf(['day', 'hours', 'minutes', 'month', 'seconds', 'year']),
view: PropTypes.oneOf(['day', 'hours', 'meridiem', 'minutes', 'month', 'seconds', 'year']),
/**
* Define custom view renderers for each section.
* If `null`, the section will only have field editing.
Expand All @@ -401,6 +417,7 @@ DateTimePicker.propTypes = {
viewRenderers: PropTypes.shape({
day: PropTypes.func,
hours: PropTypes.func,
meridiem: PropTypes.func,
minutes: PropTypes.func,
month: PropTypes.func,
seconds: PropTypes.func,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
DesktopDateTimePickerSlotsComponent,
DesktopDateTimePickerSlotsComponentsProps,
} from '../DesktopDateTimePicker';
import { DateOrTimeViewWithMeridiem } from '../internals/models';
import { UncapitalizeObjectKeys } from '../internals/utils/slots-migration';
import {
MobileDateTimePickerProps,
Expand All @@ -12,15 +13,15 @@ import {

export interface DateTimePickerSlotsComponents<TDate>
extends DesktopDateTimePickerSlotsComponent<TDate>,
MobileDateTimePickerSlotsComponent<TDate> {}
MobileDateTimePickerSlotsComponent<TDate, DateOrTimeViewWithMeridiem> {}

export interface DateTimePickerSlotsComponentsProps<TDate>
extends DesktopDateTimePickerSlotsComponentsProps<TDate>,
MobileDateTimePickerSlotsComponentsProps<TDate> {}
MobileDateTimePickerSlotsComponentsProps<TDate, DateOrTimeViewWithMeridiem> {}

export interface DateTimePickerProps<TDate>
extends DesktopDateTimePickerProps<TDate>,
MobileDateTimePickerProps<TDate> {
Omit<MobileDateTimePickerProps<TDate, DateOrTimeViewWithMeridiem>, 'views'> {
/**
* CSS media query when `Mobile` mode will be changed to `Desktop`.
* @default '@media (pointer: fine)'
Expand Down
Loading
Loading