diff --git a/.eslintrc.js b/.eslintrc.js index fac05b6d0e35d..cfe5dc375f20b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -264,6 +264,7 @@ module.exports = { 'useDateTimePickerDefaultizedProps', 'useDateRangePickerDefaultizedProps', 'useDateTimeRangePickerDefaultizedProps', + 'useTimeRangePickerDefaultizedProps', 'useDateCalendarDefaultizedProps', 'useMonthCalendarDefaultizedProps', 'useYearCalendarDefaultizedProps', diff --git a/docs/data/date-pickers/localization/data.json b/docs/data/date-pickers/localization/data.json index fb6709dc7b2ef..657f65aab33b7 100644 --- a/docs/data/date-pickers/localization/data.json +++ b/docs/data/date-pickers/localization/data.json @@ -3,304 +3,304 @@ "languageTag": "eu", "importName": "eu", "localeName": "Basque", - "missingKeysCount": 13, - "totalKeysCount": 50, + "missingKeysCount": 14, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/eu.ts" }, { "languageTag": "be-BY", "importName": "beBY", "localeName": "Belarusian", - "missingKeysCount": 15, - "totalKeysCount": 50, + "missingKeysCount": 16, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/beBY.ts" }, { "languageTag": "bg-BG", "importName": "bgBG", "localeName": "Bulgarian", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/bgBG.ts" }, { "languageTag": "ca-ES", "importName": "caES", "localeName": "Catalan", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/caES.ts" }, { "languageTag": "zh-HK", "importName": "zhHK", "localeName": "Chinese (Hong Kong)", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/zhHK.ts" }, { "languageTag": "zh-CN", "importName": "zhCN", "localeName": "Chinese (Simplified)", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/zhCN.ts" }, { "languageTag": "zh-TW", "importName": "zhTW", "localeName": "Chinese (Taiwan)", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/zhTW.ts" }, { "languageTag": "hr-HR", "importName": "hrHR", "localeName": "Croatian", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/hrHR.ts" }, { "languageTag": "cs-CZ", "importName": "csCZ", "localeName": "Czech", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/csCZ.ts" }, { "languageTag": "da-DK", "importName": "daDK", "localeName": "Danish", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/daDK.ts" }, { "languageTag": "nl-NL", "importName": "nlNL", "localeName": "Dutch", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/nlNL.ts" }, { "languageTag": "fi-FI", "importName": "fiFI", "localeName": "Finnish", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/fiFI.ts" }, { "languageTag": "fr-FR", "importName": "frFR", "localeName": "French", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/frFR.ts" }, { "languageTag": "de-DE", "importName": "deDE", "localeName": "German", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/deDE.ts" }, { "languageTag": "el-GR", "importName": "elGR", "localeName": "Greek", - "missingKeysCount": 6, - "totalKeysCount": 50, + "missingKeysCount": 7, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/elGR.ts" }, { "languageTag": "he-IL", "importName": "heIL", "localeName": "Hebrew", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/heIL.ts" }, { "languageTag": "hu-HU", "importName": "huHU", "localeName": "Hungarian", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/huHU.ts" }, { "languageTag": "is-IS", "importName": "isIS", "localeName": "Icelandic", - "missingKeysCount": 14, - "totalKeysCount": 50, + "missingKeysCount": 15, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/isIS.ts" }, { "languageTag": "it-IT", "importName": "itIT", "localeName": "Italian", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/itIT.ts" }, { "languageTag": "ja-JP", "importName": "jaJP", "localeName": "Japanese", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/jaJP.ts" }, { "languageTag": "kz-KZ", "importName": "kzKZ", "localeName": "Kazakh", - "missingKeysCount": 15, - "totalKeysCount": 50, + "missingKeysCount": 16, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/kzKZ.ts" }, { "languageTag": "ko-KR", "importName": "koKR", "localeName": "Korean", - "missingKeysCount": 1, - "totalKeysCount": 50, + "missingKeysCount": 2, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/koKR.ts" }, { "languageTag": "mk", "importName": "mk", "localeName": "Macedonian", - "missingKeysCount": 13, - "totalKeysCount": 50, + "missingKeysCount": 14, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/mk.ts" }, { "languageTag": "nb-NO", "importName": "nbNO", "localeName": "Norwegian (Bokmål)", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/nbNO.ts" }, { "languageTag": "nn-NO", "importName": "nnNO", "localeName": "Norwegian (Nynorsk)", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/nnNO.ts" }, { "languageTag": "fa-IR", "importName": "faIR", "localeName": "Persian", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/faIR.ts" }, { "languageTag": "pl-PL", "importName": "plPL", "localeName": "Polish", - "missingKeysCount": 10, - "totalKeysCount": 50, + "missingKeysCount": 11, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/plPL.ts" }, { "languageTag": "pt-PT", "importName": "ptPT", "localeName": "Portuguese", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ptPT.ts" }, { "languageTag": "pt-BR", "importName": "ptBR", "localeName": "Portuguese (Brazil)", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ptBR.ts" }, { "languageTag": "ro-RO", "importName": "roRO", "localeName": "Romanian", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/roRO.ts" }, { "languageTag": "ru-RU", "importName": "ruRU", "localeName": "Russian", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ruRU.ts" }, { "languageTag": "sk-SK", "importName": "skSK", "localeName": "Slovak", - "missingKeysCount": 15, - "totalKeysCount": 50, + "missingKeysCount": 16, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/skSK.ts" }, { "languageTag": "es-ES", "importName": "esES", "localeName": "Spanish", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/esES.ts" }, { "languageTag": "sv-SE", "importName": "svSE", "localeName": "Swedish", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/svSE.ts" }, { "languageTag": "tr-TR", "importName": "trTR", "localeName": "Turkish", - "missingKeysCount": 14, - "totalKeysCount": 50, + "missingKeysCount": 15, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/trTR.ts" }, { "languageTag": "uk-UA", "importName": "ukUA", "localeName": "Ukrainian", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ukUA.ts" }, { "languageTag": "ur-PK", "importName": "urPK", "localeName": "Urdu (Pakistan)", - "missingKeysCount": 22, - "totalKeysCount": 50, + "missingKeysCount": 23, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/urPK.ts" }, { "languageTag": "vi-VN", "importName": "viVN", "localeName": "Vietnamese", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/viVN.ts" } ] diff --git a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js new file mode 100644 index 0000000000000..10df879e6592c --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js @@ -0,0 +1,15 @@ +import * as React from 'react'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { LocalizationProvider } from '@mui/x-date-pickers-pro/LocalizationProvider'; +import { AdapterDayjs } from '@mui/x-date-pickers-pro/AdapterDayjs'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; + +export default function BasicTimeRangePicker() { + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx new file mode 100644 index 0000000000000..10df879e6592c --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx @@ -0,0 +1,15 @@ +import * as React from 'react'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { LocalizationProvider } from '@mui/x-date-pickers-pro/LocalizationProvider'; +import { AdapterDayjs } from '@mui/x-date-pickers-pro/AdapterDayjs'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; + +export default function BasicTimeRangePicker() { + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx.preview b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx.preview new file mode 100644 index 0000000000000..b06e812ca6771 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx.preview @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.js b/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.js new file mode 100644 index 0000000000000..05857cde3ae34 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.js @@ -0,0 +1,59 @@ +import * as React from 'react'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; +import { SingleInputTimeRangeField } from '@mui/x-date-pickers-pro/SingleInputTimeRangeField'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { DigitalClockItem } from '@mui/x-date-pickers/DigitalClock'; + +function CustomDigitalClockItem(props) { + const { rangePosition, selectedValue, formattedValue, itemValue, ...other } = + props; + if (selectedValue[0] && rangePosition === 'end') { + const timeDifference = itemValue.diff(selectedValue[0], ['minutes']); + const timeDifferenceLabel = + timeDifference.minutes < 60 + ? timeDifference.toHuman() + : timeDifference.shiftTo('hours').toHuman(); + return ( + + {formattedValue} ({timeDifferenceLabel}) + + ); + } + return ; +} + +export default function CustomizedBehaviorTimeRangePicker() { + const [rangePosition, setRangePosition] = React.useState('start'); + const [value, setValue] = React.useState([null, null]); + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.tsx b/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.tsx new file mode 100644 index 0000000000000..9ff7d20a99e20 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.tsx @@ -0,0 +1,69 @@ +import * as React from 'react'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; +import { SingleInputTimeRangeField } from '@mui/x-date-pickers-pro/SingleInputTimeRangeField'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { + DigitalClockItem, + DigitalClockItemProps, +} from '@mui/x-date-pickers/DigitalClock'; +import { DateTime } from 'luxon'; +import { DateRange, RangePosition } from '@mui/x-date-pickers-pro/models'; + +function CustomDigitalClockItem( + props: DigitalClockItemProps & { + rangePosition: RangePosition; + selectedValue: DateRange; + }, +) { + const { rangePosition, selectedValue, formattedValue, itemValue, ...other } = + props; + if (selectedValue[0] && rangePosition === 'end') { + const timeDifference = itemValue.diff(selectedValue[0], ['minutes']); + const timeDifferenceLabel = + timeDifference.minutes < 60 + ? timeDifference.toHuman() + : timeDifference.shiftTo('hours').toHuman(); + return ( + + {formattedValue} ({timeDifferenceLabel}) + + ); + } + return ; +} + +export default function CustomizedBehaviorTimeRangePicker() { + const [rangePosition, setRangePosition] = React.useState('start'); + const [value, setValue] = React.useState>([null, null]); + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.js b/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.js new file mode 100644 index 0000000000000..e3d2728ea9302 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.js @@ -0,0 +1,20 @@ +import * as React from 'react'; +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 { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; + +export default function FormPropsTimeRangePickers() { + return ( + + + + + + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx b/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx new file mode 100644 index 0000000000000..e3d2728ea9302 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; +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 { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; + +export default function FormPropsTimeRangePickers() { + return ( + + + + + + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx.preview b/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx.preview new file mode 100644 index 0000000000000..c2dacbc862092 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx.preview @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js new file mode 100644 index 0000000000000..39019af1b4763 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js @@ -0,0 +1,38 @@ +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 { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; +import { MobileTimeRangePicker } from '@mui/x-date-pickers-pro/MobileTimeRangePicker'; +import { DesktopTimeRangePicker } from '@mui/x-date-pickers-pro/DesktopTimeRangePicker'; + +export default function ResponsiveTimeRangePickers() { + return ( + + + + + + + + + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx new file mode 100644 index 0000000000000..39019af1b4763 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx @@ -0,0 +1,38 @@ +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 { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; +import { MobileTimeRangePicker } from '@mui/x-date-pickers-pro/MobileTimeRangePicker'; +import { DesktopTimeRangePicker } from '@mui/x-date-pickers-pro/DesktopTimeRangePicker'; + +export default function ResponsiveTimeRangePickers() { + return ( + + + + + + + + + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx.preview b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx.preview new file mode 100644 index 0000000000000..f1fa97d72d143 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx.preview @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.js b/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.js new file mode 100644 index 0000000000000..aafc5fbc882b7 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.js @@ -0,0 +1,16 @@ +import * as React from 'react'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; +import { SingleInputTimeRangeField } from '@mui/x-date-pickers-pro/SingleInputTimeRangeField'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; + +export default function SingleInputTimeRangePicker() { + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx b/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx new file mode 100644 index 0000000000000..aafc5fbc882b7 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; +import { SingleInputTimeRangeField } from '@mui/x-date-pickers-pro/SingleInputTimeRangeField'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; + +export default function SingleInputTimeRangePicker() { + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx.preview b/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx.preview new file mode 100644 index 0000000000000..26a29226e182d --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx.preview @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.js b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.js new file mode 100644 index 0000000000000..5dde2e2df763c --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.js @@ -0,0 +1,32 @@ +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 { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; + +export default function TimeRangePickerValue() { + const [value, setValue] = React.useState([ + dayjs('2022-04-17T15:30'), + dayjs('2022-04-17T18:30'), + ]); + + return ( + + + + + + + setValue(newValue)} + /> + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx new file mode 100644 index 0000000000000..8c590ae31ab8f --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx @@ -0,0 +1,32 @@ +import * as React from 'react'; +import dayjs, { 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 { DateRange } from '@mui/x-date-pickers-pro/models'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; + +export default function TimeRangePickerValue() { + const [value, setValue] = React.useState>([ + dayjs('2022-04-17T15:30'), + dayjs('2022-04-17T18:30'), + ]); + + return ( + + + + + + + setValue(newValue)} + /> + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx.preview b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx.preview new file mode 100644 index 0000000000000..dd3b16e70f9c3 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx.preview @@ -0,0 +1,11 @@ + + + + + setValue(newValue)} + /> + \ No newline at end of file diff --git a/docs/data/date-pickers/time-range-picker/time-range-picker.md b/docs/data/date-pickers/time-range-picker/time-range-picker.md index b54ff358d4c05..2a407a8c7d0b5 100644 --- a/docs/data/date-pickers/time-range-picker/time-range-picker.md +++ b/docs/data/date-pickers/time-range-picker/time-range-picker.md @@ -1,18 +1,96 @@ --- productId: x-date-pickers title: React Time Range Picker component +components: TimeRangePicker, DesktopTimeRangePicker, MobileTimeRangePicker, DigitalClock, MultiSectionDigitalClock, TimeRangePickerTabs, TimeRangePickerToolbar githubLabel: 'component: TimeRangePicker' packageName: '@mui/x-date-pickers-pro' materialDesign: https://m2.material.io/components/date-pickers --- -# Time Range Picker [](/x/introduction/licensing/#pro-plan 'Pro plan')🚧 +# Time Range Picker [](/x/introduction/licensing/#pro-plan 'Pro plan')

The Time Range Picker lets users select a range of time values.

+## Basic usage + +{{"demo": "BasicTimeRangePicker.js"}} + +## Component composition + +The component is built using the `MultiInputTimeRangeField` for the keyboard editing, the `DigitalClock` for the desktop view editing, and the `TimeClock` for the mobile view editing. + +Check-out their documentation page for more information: + +- [Time Range Field](/x/react-date-pickers/time-range-field/) +- [Digital Clock](/x/react-date-pickers/digital-clock/) +- [Time Clock](/x/react-date-pickers/time-clock/) + +## Uncontrolled vs. controlled value + +The value of the component can be uncontrolled or controlled. + +{{"demo": "TimeRangePickerValue.js"}} + +:::info + +- The value is **controlled** when its parent manages it by providing a `value` prop. +- The value is **uncontrolled** when it is managed by the component's own internal state. This state can be initialized using the `defaultValue` prop. + +Learn more about the _Controlled and uncontrolled_ pattern in the [React documentation](https://react.dev/learn/sharing-state-between-components#controlled-and-uncontrolled-components). +::: + +## Available components + +:::warning +NOT READY +::: + +The component is available in four variants: + +- The `DesktopTimeRangePicker` component which works best for mouse devices and large screens. + It renders the views inside a popover and allows editing values directly inside the field. + +- The `MobileTimeRangePicker` component which works best for touch devices and small screens. + It renders the view inside a modal and does not allow editing values directly inside the field. + +- The `TimeRangePicker` component which renders `DesktopTimeRangePicker` or `MobileTimeRangePicker` depending on the device it runs on. + +{{"demo": "ResponsiveTimeRangePickers.js"}} + +By default, the `TimeRangePicker` component renders the desktop version if the media query [`@media (pointer: fine)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer) matches. +This can be customized with the `desktopModeMediaQuery` prop. + :::warning -This component isn't available yet, but it is planned—you can 👍 upvote [this GitHub issue](https://github.com/mui/mui-x/issues/4460) to help us prioritize it. -Please don't hesitate to leave a comment there to describe your needs, especially if you have a use case we should address or you're facing specific pain points with your current solution. +Responsive components can suffer some inconsistencies between testing environments if media query is not supported. +Please refer to [this section](/x/react-date-pickers/base-concepts/#testing-caveats) for solutions. ::: -The Time Range Picker would let users select a range of time values. +## Form props + +The component can be disabled or read-only. + +{{"demo": "FormPropsTimeRangePickers.js"}} + +## Customization + +### Use a single input field + +:::warning +NOT READY +::: + +You can pass the `SingleInputTimeRangeField` component to the Time Range Picker to use it for keyboard editing: + +{{"demo": "SingleInputTimeRangePicker.js"}} + +:::info +For more information, check out the [Custom field](/x/react-date-pickers/custom-field/#use-single-input-fields-on-range-pickers) page. +::: + +### Change end time label + +{{"demo": "CustomizedBehaviorTimeRangePicker.js"}} + +## Validation + +You can find the documentation in the [Validation page](/x/react-date-pickers/validation/). diff --git a/docs/data/datePickersApiPages.ts b/docs/data/datePickersApiPages.ts index 339472cbea73d..1efe4f86c55e0 100644 --- a/docs/data/datePickersApiPages.ts +++ b/docs/data/datePickersApiPages.ts @@ -94,6 +94,11 @@ const datePickersApiPages: MuiPage[] = [ pathname: '/x/api/date-pickers/desktop-time-picker', title: 'DesktopTimePicker', }, + { + pathname: '/x/api/date-pickers/desktop-time-range-picker', + title: 'DesktopTimeRangePicker', + plan: 'pro', + }, { pathname: '/x/api/date-pickers/digital-clock', title: 'DigitalClock', @@ -124,6 +129,11 @@ const datePickersApiPages: MuiPage[] = [ pathname: '/x/api/date-pickers/mobile-time-picker', title: 'MobileTimePicker', }, + { + pathname: '/x/api/date-pickers/mobile-time-range-picker', + title: 'MobileTimeRangePicker', + plan: 'pro', + }, { pathname: '/x/api/date-pickers/month-calendar', title: 'MonthCalendar', @@ -228,6 +238,21 @@ const datePickersApiPages: MuiPage[] = [ pathname: '/x/api/date-pickers/time-picker-toolbar', title: 'TimePickerToolbar', }, + { + pathname: '/x/api/date-pickers/time-range-picker', + title: 'TimeRangePicker', + plan: 'pro', + }, + { + pathname: '/x/api/date-pickers/time-range-picker-tabs', + title: 'TimeRangePickerTabs', + plan: 'pro', + }, + { + pathname: '/x/api/date-pickers/time-range-picker-toolbar', + title: 'TimeRangePickerToolbar', + plan: 'pro', + }, { pathname: '/x/api/date-pickers/year-calendar', title: 'YearCalendar', diff --git a/docs/data/pages.ts b/docs/data/pages.ts index 5def15ccecfdc..87aa4182ea6fc 100644 --- a/docs/data/pages.ts +++ b/docs/data/pages.ts @@ -334,7 +334,7 @@ const pages: MuiPage[] = [ { pathname: '/x/react-date-pickers/time-range-picker', title: 'Time Range Picker', - planned: true, + newFeature: true, }, { pathname: '/x/react-date-pickers/time-range-field', diff --git a/docs/pages/x/api/date-pickers/desktop-time-range-picker.js b/docs/pages/x/api/date-pickers/desktop-time-range-picker.js new file mode 100644 index 0000000000000..a732e098e9de6 --- /dev/null +++ b/docs/pages/x/api/date-pickers/desktop-time-range-picker.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import ApiPage from 'docs/src/modules/components/ApiPage'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './desktop-time-range-picker.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ; +} + +Page.getInitialProps = () => { + const req = require.context( + 'docsx/translations/api-docs/date-pickers/desktop-time-range-picker', + false, + /\.\/desktop-time-range-picker.*.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json new file mode 100644 index 0000000000000..5893436b93af6 --- /dev/null +++ b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json @@ -0,0 +1,283 @@ +{ + "props": { + "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, + "autoFocus": { "type": { "name": "bool" } }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, + "defaultRangePosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'start'" + }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, + "disabled": { "type": { "name": "bool" }, "default": "false" }, + "disableFuture": { "type": { "name": "bool" }, "default": "false" }, + "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" }, "default": "false" }, + "disableOpenPicker": { "type": { "name": "bool" }, "default": "false" }, + "disablePast": { "type": { "name": "bool" }, "default": "false" }, + "format": { "type": { "name": "string" } }, + "formatDensity": { + "type": { "name": "enum", "description": "'dense'
| 'spacious'" }, + "default": "\"dense\"" + }, + "inputRef": { + "type": { "name": "union", "description": "func
| { current?: object }" } + }, + "label": { "type": { "name": "node" } }, + "localeText": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, + "minutesStep": { "type": { "name": "number" }, "default": "1" }, + "name": { "type": { "name": "string" } }, + "onAccept": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } + }, + "onChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } + }, + "onClose": { "type": { "name": "func" } }, + "onError": { + "type": { "name": "func" }, + "signature": { + "type": "function(error: TError, value: TValue) => void", + "describedArgs": ["error", "value"] + } + }, + "onOpen": { "type": { "name": "func" } }, + "onRangePositionChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(rangePosition: RangePosition) => void", + "describedArgs": ["rangePosition"] + } + }, + "onSelectedSectionsChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(newValue: FieldSelectedSections) => void", + "describedArgs": ["newValue"] + } + }, + "onViewChange": { + "type": { "name": "func" }, + "signature": { "type": "function(view: TView) => void", "describedArgs": ["view"] } + }, + "open": { "type": { "name": "bool" }, "default": "false" }, + "openTo": { + "type": { + "name": "enum", + "description": "'hours'
| 'minutes'
| 'seconds'" + } + }, + "rangePosition": { "type": { "name": "enum", "description": "'end'
| 'start'" } }, + "readOnly": { "type": { "name": "bool" }, "default": "false" }, + "reduceAnimations": { + "type": { "name": "bool" }, + "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" + }, + "referenceDate": { + "type": { "name": "object" }, + "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." + }, + "selectedSections": { + "type": { + "name": "union", + "description": "'all'
| 'day'
| 'empty'
| 'hours'
| 'meridiem'
| 'minutes'
| 'month'
| 'seconds'
| 'weekDay'
| 'year'
| number" + } + }, + "shouldDisableTime": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: PickerValidDate, view: TimeView) => boolean", + "describedArgs": ["value", "view"], + "returned": "boolean" + } + }, + "skipDisabled": { "type": { "name": "bool" }, "default": "false" }, + "slotProps": { "type": { "name": "object" }, "default": "{}" }, + "slots": { + "type": { "name": "object" }, + "default": "{}", + "additionalInfo": { "slotsApi": true } + }, + "sx": { + "type": { + "name": "union", + "description": "Array<func
| object
| bool>
| func
| object" + }, + "additionalInfo": { "sx": true } + }, + "thresholdToRenderTimeInASingleColumn": { "type": { "name": "number" }, "default": "24" }, + "timeSteps": { + "type": { + "name": "shape", + "description": "{ hours?: number, minutes?: number, seconds?: number }" + }, + "default": "{ hours: 1, minutes: 5, seconds: 5 }" + }, + "timezone": { + "type": { "name": "string" }, + "default": "The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise.", + "seeMoreLink": { + "url": "https://mui.com/x/react-date-pickers/timezone/", + "text": "timezones documentation" + } + }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, + "view": { + "type": { + "name": "enum", + "description": "'hours'
| 'meridiem'
| 'minutes'
| 'seconds'" + } + }, + "viewRenderers": { + "type": { + "name": "shape", + "description": "{ hours?: func, meridiem?: func, minutes?: func, seconds?: func }" + } + }, + "views": { + "type": { + "name": "arrayOf", + "description": "Array<'hours'
| 'minutes'
| 'seconds'>" + } + } + }, + "name": "DesktopTimeRangePicker", + "imports": [ + "import { DesktopTimeRangePicker } from '@mui/x-date-pickers-pro/DesktopTimeRangePicker';", + "import { DesktopTimeRangePicker } from '@mui/x-date-pickers-pro';" + ], + "slots": [ + { + "name": "actionBar", + "description": "Custom component for the action bar, it is placed below the picker views.", + "default": "PickersActionBar", + "class": null + }, + { + "name": "clearButton", + "description": "Button to clear the value.", + "default": "IconButton", + "class": null + }, + { + "name": "clearIcon", + "description": "Icon to display inside the clear button.", + "default": "ClearIcon", + "class": null + }, + { + "name": "desktopPaper", + "description": "Custom component for the paper rendered inside the desktop picker's Popper.", + "default": "PickersPopperPaper", + "class": null + }, + { + "name": "desktopTransition", + "description": "Custom component for the desktop popper [Transition](https://mui.com/material-ui/transitions/).", + "default": "Grow or Fade from '@mui/material' when `reduceAnimations` is `true`.", + "class": null + }, + { + "name": "desktopTrapFocus", + "description": "Custom component for trapping the focus inside the views on desktop.", + "default": "TrapFocus from '@mui/material'.", + "class": null + }, + { + "name": "digitalClockItem", + "description": "Component responsible for rendering a single digital clock item.", + "default": "MenuItem from '@mui/material'", + "class": null + }, + { + "name": "digitalClockSectionItem", + "description": "Component responsible for rendering a single multi section digital clock section item.", + "default": "MenuItem from '@mui/material'", + "class": null + }, + { "name": "field", "description": "", "class": null }, + { + "name": "fieldRoot", + "description": "Element rendered at the root.\nIgnored if the field has only one input.", + "class": null + }, + { + "name": "fieldSeparator", + "description": "Element rendered between the two inputs.\nIgnored if the field has only one input.", + "class": null + }, + { + "name": "layout", + "description": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", + "class": null + }, + { + "name": "leftArrowIcon", + "description": "Icon displayed in the left view switch button.", + "default": "ArrowLeft", + "class": null + }, + { + "name": "nextIconButton", + "description": "Button allowing to switch to the right view.", + "default": "IconButton", + "class": null + }, + { + "name": "popper", + "description": "Custom component for the popper inside which the views are rendered on desktop.", + "default": "Popper from '@mui/material'.", + "class": null + }, + { + "name": "previousIconButton", + "description": "Button allowing to switch to the left view.", + "default": "IconButton", + "class": null + }, + { + "name": "rightArrowIcon", + "description": "Icon displayed in the right view switch button.", + "default": "ArrowRight", + "class": null + }, + { + "name": "shortcuts", + "description": "Custom component for the shortcuts.", + "default": "PickersShortcuts", + "class": null + }, + { + "name": "tabs", + "description": "Tabs enabling toggling between start and end time.", + "default": "TimeRangePickerTabs", + "class": null + }, + { + "name": "textField", + "description": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.", + "default": "TextField from '@mui/material' or PickersTextField if `enableAccessibleFieldDOMStructure` is `true`.", + "class": null + }, + { + "name": "Toolbar", + "description": "Custom component for the toolbar rendered above the views.", + "default": "TimeRangePickerToolbar", + "class": null + } + ], + "classes": [], + "muiName": "MuiDesktopTimeRangePicker", + "filename": "/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx", + "inheritance": null, + "demos": "", + "cssComponent": false +} diff --git a/docs/pages/x/api/date-pickers/digital-clock.json b/docs/pages/x/api/date-pickers/digital-clock.json index 1d06e31bfb380..2ff1c1ded9f85 100644 --- a/docs/pages/x/api/date-pickers/digital-clock.json +++ b/docs/pages/x/api/date-pickers/digital-clock.json @@ -114,6 +114,6 @@ "forwardsRefTo": "HTMLDivElement", "filename": "/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx", "inheritance": null, - "demos": "", + "demos": "", "cssComponent": false } diff --git a/docs/pages/x/api/date-pickers/index.md b/docs/pages/x/api/date-pickers/index.md index b7a2c00147dd9..4a0cf73b291cb 100644 --- a/docs/pages/x/api/date-pickers/index.md +++ b/docs/pages/x/api/date-pickers/index.md @@ -34,6 +34,12 @@ - [MobileDateRangePicker](/x/api/date-pickers/mobile-date-range-picker/) - [StaticDateRangePicker](/x/api/date-pickers/static-date-range-picker/) +#### Time Range Pickers + +- [TimeRangePicker](/x/api/date-pickers/time-range-picker/) +- [DesktopTimeRangePicker](/x/api/date-pickers/desktop-time-range-picker/) +- [MobileTimeRangePicker](/x/api/date-pickers/mobile-time-range-picker/) + #### Date Time Range Pickers - [DateTimeRangePicker](/x/api/date-pickers/date-time-range-picker/) @@ -71,12 +77,14 @@ - [TimePickerToolbar](/x/api/date-pickers/time-picker-toolbar/) - [DateTimePickerToolbar](/x/api/date-pickers/date-time-picker-toolbar/) - [DateRangePickerToolbar](/x/api/date-pickers/date-range-picker-toolbar/) +- [TimeRangePickerToolbar](/x/api/date-pickers/time-range-picker-toolbar/) - [DateTimeRangePickerToolbar](/x/api/date-pickers/date-time-range-picker-toolbar/) ### Others - [DateRangePickerDay](/x/api/date-pickers/date-range-picker-day/) - [DateTimePickerTabs](/x/api/date-pickers/date-time-picker-tabs/) +- [TimeRangePickerTabs](/x/api/date-pickers/time-range-picker-tabs/) - [DateTimeRangePickerTabs](/x/api/date-pickers/date-time-range-picker-tabs/) - [DayCalendarSkeleton](/x/api/date-pickers/day-calendar-skeleton/) - [LocalizationProvider](/x/api/date-pickers/localization-provider/) diff --git a/docs/pages/x/api/date-pickers/mobile-time-range-picker.js b/docs/pages/x/api/date-pickers/mobile-time-range-picker.js new file mode 100644 index 0000000000000..6a03412f5f29d --- /dev/null +++ b/docs/pages/x/api/date-pickers/mobile-time-range-picker.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import ApiPage from 'docs/src/modules/components/ApiPage'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './mobile-time-range-picker.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ; +} + +Page.getInitialProps = () => { + const req = require.context( + 'docsx/translations/api-docs/date-pickers/mobile-time-range-picker', + false, + /\.\/mobile-time-range-picker.*.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json new file mode 100644 index 0000000000000..942d4bc67ec50 --- /dev/null +++ b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json @@ -0,0 +1,274 @@ +{ + "props": { + "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, + "autoFocus": { "type": { "name": "bool" } }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, + "defaultRangePosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'start'" + }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, + "disabled": { "type": { "name": "bool" }, "default": "false" }, + "disableFuture": { "type": { "name": "bool" }, "default": "false" }, + "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" }, "default": "false" }, + "disableOpenPicker": { "type": { "name": "bool" }, "default": "false" }, + "disablePast": { "type": { "name": "bool" }, "default": "false" }, + "format": { "type": { "name": "string" } }, + "formatDensity": { + "type": { "name": "enum", "description": "'dense'
| 'spacious'" }, + "default": "\"dense\"" + }, + "inputRef": { "type": { "name": "custom", "description": "ref" } }, + "label": { "type": { "name": "node" } }, + "localeText": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, + "minutesStep": { "type": { "name": "number" }, "default": "1" }, + "name": { "type": { "name": "string" } }, + "onAccept": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } + }, + "onChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } + }, + "onClose": { "type": { "name": "func" } }, + "onError": { + "type": { "name": "func" }, + "signature": { + "type": "function(error: TError, value: TValue) => void", + "describedArgs": ["error", "value"] + } + }, + "onOpen": { "type": { "name": "func" } }, + "onRangePositionChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(rangePosition: RangePosition) => void", + "describedArgs": ["rangePosition"] + } + }, + "onSelectedSectionsChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(newValue: FieldSelectedSections) => void", + "describedArgs": ["newValue"] + } + }, + "onViewChange": { + "type": { "name": "func" }, + "signature": { "type": "function(view: TView) => void", "describedArgs": ["view"] } + }, + "open": { "type": { "name": "bool" }, "default": "false" }, + "openTo": { + "type": { + "name": "enum", + "description": "'hours'
| 'minutes'
| 'seconds'" + } + }, + "rangePosition": { "type": { "name": "enum", "description": "'end'
| 'start'" } }, + "readOnly": { "type": { "name": "bool" }, "default": "false" }, + "reduceAnimations": { + "type": { "name": "bool" }, + "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" + }, + "referenceDate": { + "type": { "name": "object" }, + "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." + }, + "selectedSections": { + "type": { + "name": "union", + "description": "'all'
| 'day'
| 'empty'
| 'hours'
| 'meridiem'
| 'minutes'
| 'month'
| 'seconds'
| 'weekDay'
| 'year'
| number" + } + }, + "shouldDisableTime": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: PickerValidDate, view: TimeView) => boolean", + "describedArgs": ["value", "view"], + "returned": "boolean" + } + }, + "slotProps": { "type": { "name": "object" }, "default": "{}" }, + "slots": { + "type": { "name": "object" }, + "default": "{}", + "additionalInfo": { "slotsApi": true } + }, + "sx": { + "type": { + "name": "union", + "description": "Array<func
| object
| bool>
| func
| object" + }, + "additionalInfo": { "sx": true } + }, + "thresholdToRenderTimeInASingleColumn": { "type": { "name": "number" }, "default": "24" }, + "timeSteps": { + "type": { + "name": "shape", + "description": "{ hours?: number, minutes?: number, seconds?: number }" + }, + "default": "{ hours: 1, minutes: 5, seconds: 5 }" + }, + "timezone": { + "type": { "name": "string" }, + "default": "The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise.", + "seeMoreLink": { + "url": "https://mui.com/x/react-date-pickers/timezone/", + "text": "timezones documentation" + } + }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, + "view": { + "type": { + "name": "enum", + "description": "'hours'
| 'meridiem'
| 'minutes'
| 'seconds'" + } + }, + "viewRenderers": { + "type": { + "name": "shape", + "description": "{ hours?: func, meridiem?: func, minutes?: func, seconds?: func }" + } + }, + "views": { + "type": { + "name": "arrayOf", + "description": "Array<'hours'
| 'minutes'
| 'seconds'>" + } + } + }, + "name": "MobileTimeRangePicker", + "imports": [ + "import { MobileTimeRangePicker } from '@mui/x-date-pickers-pro/MobileTimeRangePicker';", + "import { MobileTimeRangePicker } from '@mui/x-date-pickers-pro';" + ], + "slots": [ + { + "name": "actionBar", + "description": "Custom component for the action bar, it is placed below the picker views.", + "default": "PickersActionBar", + "class": null + }, + { + "name": "clearButton", + "description": "Button to clear the value.", + "default": "IconButton", + "class": null + }, + { + "name": "clearIcon", + "description": "Icon to display inside the clear button.", + "default": "ClearIcon", + "class": null + }, + { + "name": "dialog", + "description": "Custom component for the dialog inside which the views are rendered on mobile.", + "default": "PickersModalDialogRoot", + "class": null + }, + { + "name": "digitalClockItem", + "description": "Component responsible for rendering a single digital clock item.", + "default": "MenuItem from '@mui/material'", + "class": null + }, + { + "name": "digitalClockSectionItem", + "description": "Component responsible for rendering a single multi section digital clock section item.", + "default": "MenuItem from '@mui/material'", + "class": null + }, + { "name": "field", "description": "", "class": null }, + { + "name": "fieldRoot", + "description": "Element rendered at the root.\nIgnored if the field has only one input.", + "class": null + }, + { + "name": "fieldSeparator", + "description": "Element rendered between the two inputs.\nIgnored if the field has only one input.", + "class": null + }, + { + "name": "layout", + "description": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", + "class": null + }, + { + "name": "leftArrowIcon", + "description": "Icon displayed in the left view switch button.", + "default": "ArrowLeft", + "class": null + }, + { + "name": "mobilePaper", + "description": "Custom component for the paper rendered inside the mobile picker's Dialog.", + "default": "Paper from '@mui/material'.", + "class": null + }, + { + "name": "mobileTransition", + "description": "Custom component for the mobile dialog [Transition](https://mui.com/material-ui/transitions/).", + "default": "Fade from '@mui/material'.", + "class": null + }, + { + "name": "nextIconButton", + "description": "Button allowing to switch to the right view.", + "default": "IconButton", + "class": null + }, + { + "name": "previousIconButton", + "description": "Button allowing to switch to the left view.", + "default": "IconButton", + "class": null + }, + { + "name": "rightArrowIcon", + "description": "Icon displayed in the right view switch button.", + "default": "ArrowRight", + "class": null + }, + { + "name": "shortcuts", + "description": "Custom component for the shortcuts.", + "default": "PickersShortcuts", + "class": null + }, + { + "name": "tabs", + "description": "Tabs enabling toggling between start and end time.", + "default": "TimeRangePickerTabs", + "class": null + }, + { + "name": "textField", + "description": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.", + "default": "TextField from '@mui/material' or PickersTextField if `enableAccessibleFieldDOMStructure` is `true`.", + "class": null + }, + { + "name": "Toolbar", + "description": "Custom component for the toolbar rendered above the views.", + "default": "TimeRangePickerToolbar", + "class": null + } + ], + "classes": [], + "muiName": "MuiMobileTimeRangePicker", + "filename": "/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx", + "inheritance": null, + "demos": "", + "cssComponent": false +} diff --git a/docs/pages/x/api/date-pickers/multi-section-digital-clock.json b/docs/pages/x/api/date-pickers/multi-section-digital-clock.json index d2b097c5e7635..cb85caa721c29 100644 --- a/docs/pages/x/api/date-pickers/multi-section-digital-clock.json +++ b/docs/pages/x/api/date-pickers/multi-section-digital-clock.json @@ -126,6 +126,6 @@ "forwardsRefTo": "HTMLDivElement", "filename": "/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx", "inheritance": null, - "demos": "", + "demos": "", "cssComponent": false } diff --git a/docs/pages/x/api/date-pickers/time-range-picker-tabs.js b/docs/pages/x/api/date-pickers/time-range-picker-tabs.js new file mode 100644 index 0000000000000..da2c4d34521e4 --- /dev/null +++ b/docs/pages/x/api/date-pickers/time-range-picker-tabs.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import ApiPage from 'docs/src/modules/components/ApiPage'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './time-range-picker-tabs.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ; +} + +Page.getInitialProps = () => { + const req = require.context( + 'docsx/translations/api-docs/date-pickers/time-range-picker-tabs', + false, + /\.\/time-range-picker-tabs.*.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/x/api/date-pickers/time-range-picker-tabs.json b/docs/pages/x/api/date-pickers/time-range-picker-tabs.json new file mode 100644 index 0000000000000..b806436219386 --- /dev/null +++ b/docs/pages/x/api/date-pickers/time-range-picker-tabs.json @@ -0,0 +1,41 @@ +{ + "props": { + "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, + "hidden": { + "type": { "name": "bool" }, + "default": "`window.innerHeight < 667` for `DesktopTimeRangePicker` and `MobileTimeRangePicker`, `displayStaticWrapperAs === 'desktop'` for `StaticTimeRangePicker`" + }, + "sx": { + "type": { + "name": "union", + "description": "Array<func
| object
| bool>
| func
| object" + }, + "additionalInfo": { "sx": true } + }, + "timeIcon": { "type": { "name": "node" }, "default": "Time" } + }, + "name": "TimeRangePickerTabs", + "imports": [ + "import { TimeRangePickerTabs } from '@mui/x-date-pickers-pro/TimeRangePicker';", + "import { TimeRangePickerTabs } from '@mui/x-date-pickers-pro';" + ], + "classes": [ + { + "key": "root", + "className": "MuiTimeRangePickerTabs-root", + "description": "Styles applied to the root element.", + "isGlobal": false + }, + { + "key": "tab", + "className": "MuiTimeRangePickerTabs-tab", + "description": "Styles applied to the tab element.", + "isGlobal": false + } + ], + "muiName": "MuiTimeRangePickerTabs", + "filename": "/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx", + "inheritance": null, + "demos": "", + "cssComponent": false +} diff --git a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.js b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.js new file mode 100644 index 0000000000000..fe42474b8b397 --- /dev/null +++ b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import ApiPage from 'docs/src/modules/components/ApiPage'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './time-range-picker-toolbar.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ; +} + +Page.getInitialProps = () => { + const req = require.context( + 'docsx/translations/api-docs/date-pickers/time-range-picker-toolbar', + false, + /\.\/time-range-picker-toolbar.*.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json new file mode 100644 index 0000000000000..c82a7d9699e8f --- /dev/null +++ b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json @@ -0,0 +1,50 @@ +{ + "props": { + "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, + "hidden": { "type": { "name": "bool" }, "default": "`true` for Desktop, `false` for Mobile." }, + "sx": { + "type": { + "name": "union", + "description": "Array<func
| object
| bool>
| func
| object" + }, + "additionalInfo": { "sx": true } + }, + "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"––\"" } + }, + "name": "TimeRangePickerToolbar", + "imports": [ + "import { TimeRangePickerToolbar } from '@mui/x-date-pickers-pro/TimeRangePicker';", + "import { TimeRangePickerToolbar } from '@mui/x-date-pickers-pro';" + ], + "classes": [ + { + "key": "container", + "className": "MuiTimeRangePickerToolbar-container", + "description": "Styles applied to the container element.", + "isGlobal": false + }, + { + "key": "root", + "className": "MuiTimeRangePickerToolbar-root", + "description": "Styles applied to the root element.", + "isGlobal": false + }, + { + "key": "separator", + "className": "MuiTimeRangePickerToolbar-separator", + "description": "Styles applied to the separator element.", + "isGlobal": false + }, + { + "key": "timeContainer", + "className": "MuiTimeRangePickerToolbar-timeContainer", + "description": "Styles applied to the time container element.", + "isGlobal": false + } + ], + "muiName": "MuiTimeRangePickerToolbar", + "filename": "/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx", + "inheritance": null, + "demos": "", + "cssComponent": false +} diff --git a/docs/pages/x/api/date-pickers/time-range-picker.js b/docs/pages/x/api/date-pickers/time-range-picker.js new file mode 100644 index 0000000000000..78026529f20b6 --- /dev/null +++ b/docs/pages/x/api/date-pickers/time-range-picker.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import ApiPage from 'docs/src/modules/components/ApiPage'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './time-range-picker.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ; +} + +Page.getInitialProps = () => { + const req = require.context( + 'docsx/translations/api-docs/date-pickers/time-range-picker', + false, + /\.\/time-range-picker.*.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/x/api/date-pickers/time-range-picker.json b/docs/pages/x/api/date-pickers/time-range-picker.json new file mode 100644 index 0000000000000..09abd76060674 --- /dev/null +++ b/docs/pages/x/api/date-pickers/time-range-picker.json @@ -0,0 +1,303 @@ +{ + "props": { + "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, + "autoFocus": { "type": { "name": "bool" } }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, + "defaultRangePosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'start'" + }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<object>" } }, + "desktopModeMediaQuery": { + "type": { "name": "string" }, + "default": "'@media (pointer: fine)'" + }, + "disabled": { "type": { "name": "bool" }, "default": "false" }, + "disableFuture": { "type": { "name": "bool" }, "default": "false" }, + "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" }, "default": "false" }, + "disableOpenPicker": { "type": { "name": "bool" }, "default": "false" }, + "disablePast": { "type": { "name": "bool" }, "default": "false" }, + "format": { "type": { "name": "string" } }, + "formatDensity": { + "type": { "name": "enum", "description": "'dense'
| 'spacious'" }, + "default": "\"dense\"" + }, + "inputRef": { "type": { "name": "custom", "description": "ref" } }, + "label": { "type": { "name": "node" } }, + "localeText": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "object" } }, + "minTime": { "type": { "name": "object" } }, + "minutesStep": { "type": { "name": "number" }, "default": "1" }, + "name": { "type": { "name": "string" } }, + "onAccept": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } + }, + "onChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } + }, + "onClose": { "type": { "name": "func" } }, + "onError": { + "type": { "name": "func" }, + "signature": { + "type": "function(error: TError, value: TValue) => void", + "describedArgs": ["error", "value"] + } + }, + "onOpen": { "type": { "name": "func" } }, + "onRangePositionChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(rangePosition: RangePosition) => void", + "describedArgs": ["rangePosition"] + } + }, + "onSelectedSectionsChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(newValue: FieldSelectedSections) => void", + "describedArgs": ["newValue"] + } + }, + "onViewChange": { + "type": { "name": "func" }, + "signature": { "type": "function(view: TView) => void", "describedArgs": ["view"] } + }, + "open": { "type": { "name": "bool" }, "default": "false" }, + "openTo": { + "type": { + "name": "enum", + "description": "'hours'
| 'minutes'
| 'seconds'" + } + }, + "rangePosition": { "type": { "name": "enum", "description": "'end'
| 'start'" } }, + "readOnly": { "type": { "name": "bool" }, "default": "false" }, + "reduceAnimations": { + "type": { "name": "bool" }, + "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" + }, + "referenceDate": { + "type": { "name": "object" }, + "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." + }, + "selectedSections": { + "type": { + "name": "union", + "description": "'all'
| 'day'
| 'empty'
| 'hours'
| 'meridiem'
| 'minutes'
| 'month'
| 'seconds'
| 'weekDay'
| 'year'
| number" + } + }, + "shouldDisableTime": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: PickerValidDate, view: TimeView) => boolean", + "describedArgs": ["value", "view"], + "returned": "boolean" + } + }, + "skipDisabled": { "type": { "name": "bool" }, "default": "false" }, + "slotProps": { "type": { "name": "object" }, "default": "{}" }, + "slots": { + "type": { "name": "object" }, + "default": "{}", + "additionalInfo": { "slotsApi": true } + }, + "sx": { + "type": { + "name": "union", + "description": "Array<func
| object
| bool>
| func
| object" + }, + "additionalInfo": { "sx": true } + }, + "thresholdToRenderTimeInASingleColumn": { "type": { "name": "number" }, "default": "24" }, + "timeSteps": { + "type": { + "name": "shape", + "description": "{ hours?: number, minutes?: number, seconds?: number }" + }, + "default": "{ hours: 1, minutes: 5, seconds: 5 }" + }, + "timezone": { + "type": { "name": "string" }, + "default": "The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise.", + "seeMoreLink": { + "url": "https://mui.com/x/react-date-pickers/timezone/", + "text": "timezones documentation" + } + }, + "value": { "type": { "name": "arrayOf", "description": "Array<object>" } }, + "view": { + "type": { + "name": "enum", + "description": "'hours'
| 'meridiem'
| 'minutes'
| 'seconds'" + } + }, + "viewRenderers": { + "type": { + "name": "shape", + "description": "{ hours?: func, meridiem?: func, minutes?: func, seconds?: func }" + } + }, + "views": { + "type": { + "name": "arrayOf", + "description": "Array<'hours'
| 'minutes'
| 'seconds'>" + } + } + }, + "name": "TimeRangePicker", + "imports": [ + "import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker';", + "import { TimeRangePicker } from '@mui/x-date-pickers-pro';" + ], + "slots": [ + { + "name": "actionBar", + "description": "Custom component for the action bar, it is placed below the picker views.", + "default": "PickersActionBar", + "class": null + }, + { + "name": "clearButton", + "description": "Button to clear the value.", + "default": "IconButton", + "class": null + }, + { + "name": "clearIcon", + "description": "Icon to display inside the clear button.", + "default": "ClearIcon", + "class": null + }, + { + "name": "desktopPaper", + "description": "Custom component for the paper rendered inside the desktop picker's Popper.", + "default": "PickersPopperPaper", + "class": null + }, + { + "name": "desktopTransition", + "description": "Custom component for the desktop popper [Transition](https://mui.com/material-ui/transitions/).", + "default": "Grow or Fade from '@mui/material' when `reduceAnimations` is `true`.", + "class": null + }, + { + "name": "desktopTrapFocus", + "description": "Custom component for trapping the focus inside the views on desktop.", + "default": "TrapFocus from '@mui/material'.", + "class": null + }, + { + "name": "dialog", + "description": "Custom component for the dialog inside which the views are rendered on mobile.", + "default": "PickersModalDialogRoot", + "class": null + }, + { + "name": "digitalClockItem", + "description": "Component responsible for rendering a single digital clock item.", + "default": "MenuItem from '@mui/material'", + "class": null + }, + { + "name": "digitalClockSectionItem", + "description": "Component responsible for rendering a single multi section digital clock section item.", + "default": "MenuItem from '@mui/material'", + "class": null + }, + { "name": "field", "description": "", "class": null }, + { + "name": "fieldRoot", + "description": "Element rendered at the root.\nIgnored if the field has only one input.", + "class": null + }, + { + "name": "fieldSeparator", + "description": "Element rendered between the two inputs.\nIgnored if the field has only one input.", + "class": null + }, + { + "name": "layout", + "description": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", + "class": null + }, + { + "name": "leftArrowIcon", + "description": "Icon displayed in the left view switch button.", + "default": "ArrowLeft", + "class": null + }, + { + "name": "mobilePaper", + "description": "Custom component for the paper rendered inside the mobile picker's Dialog.", + "default": "Paper from '@mui/material'.", + "class": null + }, + { + "name": "mobileTransition", + "description": "Custom component for the mobile dialog [Transition](https://mui.com/material-ui/transitions/).", + "default": "Fade from '@mui/material'.", + "class": null + }, + { + "name": "nextIconButton", + "description": "Button allowing to switch to the right view.", + "default": "IconButton", + "class": null + }, + { + "name": "popper", + "description": "Custom component for the popper inside which the views are rendered on desktop.", + "default": "Popper from '@mui/material'.", + "class": null + }, + { + "name": "previousIconButton", + "description": "Button allowing to switch to the left view.", + "default": "IconButton", + "class": null + }, + { + "name": "rightArrowIcon", + "description": "Icon displayed in the right view switch button.", + "default": "ArrowRight", + "class": null + }, + { + "name": "shortcuts", + "description": "Custom component for the shortcuts.", + "default": "PickersShortcuts", + "class": null + }, + { + "name": "tabs", + "description": "Tabs enabling toggling between start and end time.", + "default": "TimeRangePickerTabs", + "class": null + }, + { + "name": "textField", + "description": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.", + "default": "TextField from '@mui/material' or PickersTextField if `enableAccessibleFieldDOMStructure` is `true`.", + "class": null + }, + { + "name": "Toolbar", + "description": "Custom component for the toolbar rendered above the views.", + "default": "TimeRangePickerToolbar", + "class": null + } + ], + "classes": [], + "muiName": "MuiTimeRangePicker", + "filename": "/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx", + "inheritance": null, + "demos": "", + "cssComponent": false +} diff --git a/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json new file mode 100644 index 0000000000000..5c42a391ac035 --- /dev/null +++ b/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json @@ -0,0 +1,266 @@ +{ + "componentDescription": "", + "propDescriptions": { + "ampm": { + "description": "12h/24h view for hour selection clock.", + "deprecated": "", + "typeDescriptions": {} + }, + "autoFocus": { + "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered.", + "deprecated": "", + "typeDescriptions": {} + }, + "className": { + "description": "Class name applied to the root element.", + "deprecated": "", + "typeDescriptions": {} + }, + "closeOnSelect": { + "description": "If true, the popover or modal will close after submitting the full date.", + "deprecated": "", + "typeDescriptions": {} + }, + "defaultRangePosition": { + "description": "The initial position in the edited date range. Used when the component is not controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "defaultValue": { + "description": "The default value. Used when the component is not controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "disabled": { + "description": "If true, the picker and text field are disabled.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableFuture": { + "description": "If true, disable values after the current date for date components, time for time components and both for date time components.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableIgnoringDatePartForTimeValidation": { + "description": "Do not ignore date part when validating min/max time.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableOpenPicker": { + "description": "If true, the open picker button will not be rendered (renders only the field).", + "deprecated": "", + "typeDescriptions": {} + }, + "disablePast": { + "description": "If true, disable values before the current date for date components, time for time components and both for date time components.", + "deprecated": "", + "typeDescriptions": {} + }, + "format": { + "description": "Format of the date when rendered in the input(s). Defaults to localized format based on the used views.", + "deprecated": "", + "typeDescriptions": {} + }, + "formatDensity": { + "description": "Density of the format when rendered in the input. Setting formatDensity to "spacious" will add a space before and after each /, - and . character.", + "deprecated": "", + "typeDescriptions": {} + }, + "inputRef": { + "description": "Pass a ref to the input element. Ignored if the field has several inputs.", + "deprecated": "", + "typeDescriptions": {} + }, + "label": { + "description": "The label content. Ignored if the field has several inputs.", + "deprecated": "", + "typeDescriptions": {} + }, + "localeText": { + "description": "Locale for components texts. Allows overriding texts coming from LocalizationProvider and theme.", + "deprecated": "", + "typeDescriptions": {} + }, + "maxTime": { + "description": "Maximal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true.", + "deprecated": "", + "typeDescriptions": {} + }, + "minTime": { + "description": "Minimal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true.", + "deprecated": "", + "typeDescriptions": {} + }, + "minutesStep": { + "description": "Step over minutes.", + "deprecated": "", + "typeDescriptions": {} + }, + "onAccept": { + "description": "Callback fired when the value is accepted.", + "deprecated": "", + "typeDescriptions": { "value": "The value that was just accepted." } + }, + "onChange": { + "description": "Callback fired when the value changes.", + "deprecated": "", + "typeDescriptions": { + "value": "The new value.", + "context": "The context containing the validation result of the current value." + } + }, + "onClose": { + "description": "Callback fired when the popup requests to be closed. Use in controlled mode (see open).", + "deprecated": "", + "typeDescriptions": {} + }, + "onError": { + "description": "Callback fired when the error associated to the current value changes. If the error has a non-null value, then the TextField will be rendered in error state.", + "deprecated": "", + "typeDescriptions": { + "error": "The new error describing why the current value is not valid.", + "value": "The value associated to the error." + } + }, + "onOpen": { + "description": "Callback fired when the popup requests to be opened. Use in controlled mode (see open).", + "deprecated": "", + "typeDescriptions": {} + }, + "onRangePositionChange": { + "description": "Callback fired when the range position changes.", + "deprecated": "", + "typeDescriptions": { "rangePosition": "The new range position." } + }, + "onSelectedSectionsChange": { + "description": "Callback fired when the selected sections change.", + "deprecated": "", + "typeDescriptions": { "newValue": "The new selected sections." } + }, + "onViewChange": { + "description": "Callback fired on view change.", + "deprecated": "", + "typeDescriptions": { "view": "The new view." } + }, + "open": { + "description": "Control the popup or dialog open state.", + "deprecated": "", + "typeDescriptions": {} + }, + "openTo": { + "description": "The default visible view. Used when the component view is not controlled. Must be a valid option from views list.", + "deprecated": "", + "typeDescriptions": {} + }, + "rangePosition": { + "description": "The position in the currently edited date range. Used when the component position is controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "reduceAnimations": { + "description": "If true, disable heavy animations.", + "deprecated": "", + "typeDescriptions": {} + }, + "referenceDate": { + "description": "The date used to generate the new value when both value and defaultValue are empty.", + "deprecated": "", + "typeDescriptions": {} + }, + "selectedSections": { + "description": "The currently selected sections. This prop accept four formats: 1. If a number is provided, the section at this index will be selected. 2. If an object with a startIndex and endIndex properties are provided, the sections between those two indexes will be selected. 3. If a string of type FieldSectionType is provided, the first section with that name will be selected. 4. If null is provided, no section will be selected If not provided, the selected sections will be handled internally.", + "deprecated": "", + "typeDescriptions": {} + }, + "shouldDisableClock": { + "description": "Disable specific clock time.", + "deprecated": "", + "typeDescriptions": { + "clockValue": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." + } + }, + "shouldDisableTime": { + "description": "Disable specific time.", + "deprecated": "", + "typeDescriptions": { + "value": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." + } + }, + "skipDisabled": { + "description": "If true, disabled digital clock items will not be rendered.", + "deprecated": "", + "typeDescriptions": {} + }, + "slotProps": { + "description": "The props used for each component slot.", + "deprecated": "", + "typeDescriptions": {} + }, + "slots": { + "description": "Overridable component slots.", + "deprecated": "", + "typeDescriptions": {} + }, + "sx": { + "description": "The system prop that allows defining system overrides as well as additional CSS styles.", + "deprecated": "", + "typeDescriptions": {} + }, + "thresholdToRenderTimeInASingleColumn": { + "description": "Amount of time options below or at which the single column time renderer is used.", + "deprecated": "", + "typeDescriptions": {} + }, + "timeSteps": { + "description": "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.", + "deprecated": "", + "typeDescriptions": {} + }, + "timezone": { + "description": "Choose which timezone to use for the value. Example: "default", "system", "UTC", "America/New_York". If you pass values from other timezones to some props, they will be converted to this timezone before being used.
See the timezones documention for more details.", + "deprecated": "", + "typeDescriptions": {} + }, + "value": { + "description": "The selected value. Used when the component is controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "view": { + "description": "The visible view. Used when the component view is controlled. Must be a valid option from views list.", + "deprecated": "", + "typeDescriptions": {} + }, + "viewRenderers": { + "description": "Define custom view renderers for each section. If null, the section will only have field editing. If undefined, internally defined view will be the used.", + "deprecated": "", + "typeDescriptions": {} + }, + "views": { "description": "Available views.", "deprecated": "", "typeDescriptions": {} } + }, + "classDescriptions": {}, + "slotDescriptions": { + "Toolbar": "Custom component for the toolbar rendered above the views.", + "actionBar": "Custom component for the action bar, it is placed below the picker views.", + "clearButton": "Button to clear the value.", + "clearIcon": "Icon to display inside the clear button.", + "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", + "desktopTransition": "Custom component for the desktop popper Transition.", + "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", + "field": "", + "fieldRoot": "Element rendered at the root. Ignored if the field has only one input.", + "fieldSeparator": "Element rendered between the two inputs. Ignored if the field has only one input.", + "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.", + "nextIconButton": "Button allowing to switch to the right view.", + "popper": "Custom component for the popper inside which the views are rendered on desktop.", + "previousIconButton": "Button allowing to switch to the left view.", + "rightArrowIcon": "Icon displayed in the right view switch button.", + "shortcuts": "Custom component for the shortcuts.", + "textField": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element. Receives the same props as @mui/material/TextField." + } +} diff --git a/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json new file mode 100644 index 0000000000000..be575adaaaa04 --- /dev/null +++ b/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json @@ -0,0 +1,170 @@ +{ + "componentDescription": "", + "propDescriptions": { + "ampm": { "description": "12h/24h view for hour selection clock." }, + "autoFocus": { + "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." + }, + "closeOnSelect": { + "description": "If true, the Picker will close after submitting the full date." + }, + "defaultRangePosition": { + "description": "The initial position in the edited date range. Used when the component is not controlled." + }, + "defaultValue": { + "description": "The default value. Used when the component is not controlled." + }, + "disabled": { + "description": "If true, the component is disabled. When disabled, the value cannot be changed and no interaction is possible." + }, + "disableFuture": { + "description": "If true, disable values after the current date for date components, time for time components and both for date time components." + }, + "disableIgnoringDatePartForTimeValidation": { + "description": "Do not ignore date part when validating min/max time." + }, + "disableOpenPicker": { + "description": "If true, the open picker button will not be rendered (renders only the field)." + }, + "disablePast": { + "description": "If true, disable values before the current date for date components, time for time components and both for date time components." + }, + "format": { + "description": "Format of the date when rendered in the input(s). Defaults to localized format based on the used views." + }, + "formatDensity": { + "description": "Density of the format when rendered in the input. Setting formatDensity to "spacious" will add a space before and after each /, - and . character." + }, + "inputRef": { + "description": "Pass a ref to the input element. Ignored if the field has several inputs." + }, + "label": { "description": "The label content. Ignored if the field has several inputs." }, + "localeText": { + "description": "Locale for components texts. Allows overriding texts coming from LocalizationProvider and theme." + }, + "maxTime": { + "description": "Maximal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true." + }, + "minTime": { + "description": "Minimal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true." + }, + "minutesStep": { "description": "Step over minutes." }, + "name": { + "description": "Name attribute used by the input element in the Field. Ignored if the field has several inputs." + }, + "onAccept": { + "description": "Callback fired when the value is accepted.", + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } + }, + "onChange": { + "description": "Callback fired when the value changes.", + "typeDescriptions": { + "value": "The new value.", + "context": "The context containing the validation result of the current value." + } + }, + "onClose": { + "description": "Callback fired when the popup requests to be closed. Use in controlled mode (see open)." + }, + "onError": { + "description": "Callback fired when the error associated with the current value changes. When a validation error is detected, the error parameter contains a non-null value. This can be used to render an appropriate form error.", + "typeDescriptions": { + "error": "The reason why the current value is not valid.", + "value": "The value associated with the error." + } + }, + "onOpen": { + "description": "Callback fired when the popup requests to be opened. Use in controlled mode (see open)." + }, + "onRangePositionChange": { + "description": "Callback fired when the range position changes.", + "typeDescriptions": { "rangePosition": "The new range position." } + }, + "onSelectedSectionsChange": { + "description": "Callback fired when the selected sections change.", + "typeDescriptions": { "newValue": "The new selected sections." } + }, + "onViewChange": { + "description": "Callback fired on view change.", + "typeDescriptions": { "view": "The new view." } + }, + "open": { "description": "Control the popup or dialog open state." }, + "openTo": { + "description": "The default visible view. Used when the component view is not controlled. Must be a valid option from views list." + }, + "rangePosition": { + "description": "The position in the currently edited date range. Used when the component position is controlled." + }, + "readOnly": { + "description": "If true, the component is read-only. When read-only, the value cannot be changed but the user can interact with the interface." + }, + "reduceAnimations": { "description": "If true, disable heavy animations." }, + "referenceDate": { + "description": "The date used to generate the new value when both value and defaultValue are empty." + }, + "selectedSections": { + "description": "The currently selected sections. This prop accepts four formats: 1. If a number is provided, the section at this index will be selected. 2. If a string of type FieldSectionType is provided, the first section with that name will be selected. 3. If "all" is provided, all the sections will be selected. 4. If null is provided, no section will be selected. If not provided, the selected sections will be handled internally." + }, + "shouldDisableTime": { + "description": "Disable specific time.", + "typeDescriptions": { + "value": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." + } + }, + "skipDisabled": { + "description": "If true, disabled digital clock items will not be rendered." + }, + "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." + }, + "thresholdToRenderTimeInASingleColumn": { + "description": "Amount of time options below or at which the single column time renderer is used." + }, + "timeSteps": { + "description": "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." + }, + "timezone": { + "description": "Choose which timezone to use for the value. Example: "default", "system", "UTC", "America/New_York". If you pass values from other timezones to some props, they will be converted to this timezone before being used.", + "seeMoreText": "See the {{link}} for more details." + }, + "value": { "description": "The selected value. Used when the component is controlled." }, + "view": { + "description": "The visible view. Used when the component view is controlled. Must be a valid option from views list." + }, + "viewRenderers": { + "description": "Define custom view renderers for each section. If null, the section will only have field editing. If undefined, internally defined view will be the used." + }, + "views": { "description": "Available views." } + }, + "classDescriptions": {}, + "slotDescriptions": { + "actionBar": "Custom component for the action bar, it is placed below the picker views.", + "clearButton": "Button to clear the value.", + "clearIcon": "Icon to display inside the clear button.", + "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", + "desktopTransition": "Custom component for the desktop popper Transition.", + "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", + "digitalClockItem": "Component responsible for rendering a single digital clock item.", + "digitalClockSectionItem": "Component responsible for rendering a single multi section digital clock section item.", + "field": "", + "fieldRoot": "Element rendered at the root. Ignored if the field has only one input.", + "fieldSeparator": "Element rendered between the two inputs. Ignored if the field has only one input.", + "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.", + "nextIconButton": "Button allowing to switch to the right view.", + "popper": "Custom component for the popper inside which the views are rendered on desktop.", + "previousIconButton": "Button allowing to switch to the left view.", + "rightArrowIcon": "Icon displayed in the right view switch button.", + "shortcuts": "Custom component for the shortcuts.", + "tabs": "Tabs enabling toggling between start and end time.", + "textField": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element.", + "Toolbar": "Custom component for the toolbar rendered above the views." + } +} diff --git a/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json new file mode 100644 index 0000000000000..56aee57328071 --- /dev/null +++ b/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json @@ -0,0 +1,260 @@ +{ + "componentDescription": "", + "propDescriptions": { + "ampm": { + "description": "12h/24h view for hour selection clock.", + "deprecated": "", + "typeDescriptions": {} + }, + "autoFocus": { + "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered.", + "deprecated": "", + "typeDescriptions": {} + }, + "className": { + "description": "Class name applied to the root element.", + "deprecated": "", + "typeDescriptions": {} + }, + "closeOnSelect": { + "description": "If true, the popover or modal will close after submitting the full date.", + "deprecated": "", + "typeDescriptions": {} + }, + "defaultRangePosition": { + "description": "The initial position in the edited date range. Used when the component is not controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "defaultValue": { + "description": "The default value. Used when the component is not controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "disabled": { + "description": "If true, the picker and text field are disabled.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableFuture": { + "description": "If true, disable values after the current date for date components, time for time components and both for date time components.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableIgnoringDatePartForTimeValidation": { + "description": "Do not ignore date part when validating min/max time.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableOpenPicker": { + "description": "If true, the open picker button will not be rendered (renders only the field).", + "deprecated": "", + "typeDescriptions": {} + }, + "disablePast": { + "description": "If true, disable values before the current date for date components, time for time components and both for date time components.", + "deprecated": "", + "typeDescriptions": {} + }, + "format": { + "description": "Format of the date when rendered in the input(s). Defaults to localized format based on the used views.", + "deprecated": "", + "typeDescriptions": {} + }, + "formatDensity": { + "description": "Density of the format when rendered in the input. Setting formatDensity to "spacious" will add a space before and after each /, - and . character.", + "deprecated": "", + "typeDescriptions": {} + }, + "inputRef": { + "description": "Pass a ref to the input element. Ignored if the field has several inputs.", + "deprecated": "", + "typeDescriptions": {} + }, + "label": { + "description": "The label content. Ignored if the field has several inputs.", + "deprecated": "", + "typeDescriptions": {} + }, + "localeText": { + "description": "Locale for components texts. Allows overriding texts coming from LocalizationProvider and theme.", + "deprecated": "", + "typeDescriptions": {} + }, + "maxTime": { + "description": "Maximal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true.", + "deprecated": "", + "typeDescriptions": {} + }, + "minTime": { + "description": "Minimal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true.", + "deprecated": "", + "typeDescriptions": {} + }, + "minutesStep": { + "description": "Step over minutes.", + "deprecated": "", + "typeDescriptions": {} + }, + "onAccept": { + "description": "Callback fired when the value is accepted.", + "deprecated": "", + "typeDescriptions": { "value": "The value that was just accepted." } + }, + "onChange": { + "description": "Callback fired when the value changes.", + "deprecated": "", + "typeDescriptions": { + "value": "The new value.", + "context": "The context containing the validation result of the current value." + } + }, + "onClose": { + "description": "Callback fired when the popup requests to be closed. Use in controlled mode (see open).", + "deprecated": "", + "typeDescriptions": {} + }, + "onError": { + "description": "Callback fired when the error associated to the current value changes. If the error has a non-null value, then the TextField will be rendered in error state.", + "deprecated": "", + "typeDescriptions": { + "error": "The new error describing why the current value is not valid.", + "value": "The value associated to the error." + } + }, + "onOpen": { + "description": "Callback fired when the popup requests to be opened. Use in controlled mode (see open).", + "deprecated": "", + "typeDescriptions": {} + }, + "onRangePositionChange": { + "description": "Callback fired when the range position changes.", + "deprecated": "", + "typeDescriptions": { "rangePosition": "The new range position." } + }, + "onSelectedSectionsChange": { + "description": "Callback fired when the selected sections change.", + "deprecated": "", + "typeDescriptions": { "newValue": "The new selected sections." } + }, + "onViewChange": { + "description": "Callback fired on view change.", + "deprecated": "", + "typeDescriptions": { "view": "The new view." } + }, + "open": { + "description": "Control the popup or dialog open state.", + "deprecated": "", + "typeDescriptions": {} + }, + "openTo": { + "description": "The default visible view. Used when the component view is not controlled. Must be a valid option from views list.", + "deprecated": "", + "typeDescriptions": {} + }, + "rangePosition": { + "description": "The position in the currently edited date range. Used when the component position is controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "reduceAnimations": { + "description": "If true, disable heavy animations.", + "deprecated": "", + "typeDescriptions": {} + }, + "referenceDate": { + "description": "The date used to generate the new value when both value and defaultValue are empty.", + "deprecated": "", + "typeDescriptions": {} + }, + "selectedSections": { + "description": "The currently selected sections. This prop accept four formats: 1. If a number is provided, the section at this index will be selected. 2. If an object with a startIndex and endIndex properties are provided, the sections between those two indexes will be selected. 3. If a string of type FieldSectionType is provided, the first section with that name will be selected. 4. If null is provided, no section will be selected If not provided, the selected sections will be handled internally.", + "deprecated": "", + "typeDescriptions": {} + }, + "shouldDisableClock": { + "description": "Disable specific clock time.", + "deprecated": "", + "typeDescriptions": { + "clockValue": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." + } + }, + "shouldDisableTime": { + "description": "Disable specific time.", + "deprecated": "", + "typeDescriptions": { + "value": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." + } + }, + "slotProps": { + "description": "The props used for each component slot.", + "deprecated": "", + "typeDescriptions": {} + }, + "slots": { + "description": "Overridable component slots.", + "deprecated": "", + "typeDescriptions": {} + }, + "sx": { + "description": "The system prop that allows defining system overrides as well as additional CSS styles.", + "deprecated": "", + "typeDescriptions": {} + }, + "thresholdToRenderTimeInASingleColumn": { + "description": "Amount of time options below or at which the single column time renderer is used.", + "deprecated": "", + "typeDescriptions": {} + }, + "timeSteps": { + "description": "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.", + "deprecated": "", + "typeDescriptions": {} + }, + "timezone": { + "description": "Choose which timezone to use for the value. Example: "default", "system", "UTC", "America/New_York". If you pass values from other timezones to some props, they will be converted to this timezone before being used.
See the timezones documention for more details.", + "deprecated": "", + "typeDescriptions": {} + }, + "value": { + "description": "The selected value. Used when the component is controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "view": { + "description": "The visible view. Used when the component view is controlled. Must be a valid option from views list.", + "deprecated": "", + "typeDescriptions": {} + }, + "viewRenderers": { + "description": "Define custom view renderers for each section. If null, the section will only have field editing. If undefined, internally defined view will be the used.", + "deprecated": "", + "typeDescriptions": {} + }, + "views": { "description": "Available views.", "deprecated": "", "typeDescriptions": {} } + }, + "classDescriptions": {}, + "slotDescriptions": { + "Toolbar": "Custom component for the toolbar rendered above the views.", + "actionBar": "Custom component for the action bar, it is placed below the picker views.", + "clearButton": "Button to clear the value.", + "clearIcon": "Icon to display inside the clear button.", + "dialog": "Custom component for the dialog inside which the views are rendered on mobile.", + "field": "", + "fieldRoot": "Element rendered at the root. Ignored if the field has only one input.", + "fieldSeparator": "Element rendered between the two inputs. Ignored if the field has only one input.", + "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.", + "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", + "mobileTransition": "Custom component for the mobile dialog Transition.", + "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.", + "shortcuts": "Custom component for the shortcuts.", + "textField": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element. Receives the same props as @mui/material/TextField." + } +} diff --git a/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json new file mode 100644 index 0000000000000..33033b85f885c --- /dev/null +++ b/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json @@ -0,0 +1,166 @@ +{ + "componentDescription": "", + "propDescriptions": { + "ampm": { "description": "12h/24h view for hour selection clock." }, + "autoFocus": { + "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." + }, + "closeOnSelect": { + "description": "If true, the Picker will close after submitting the full date." + }, + "defaultRangePosition": { + "description": "The initial position in the edited date range. Used when the component is not controlled." + }, + "defaultValue": { + "description": "The default value. Used when the component is not controlled." + }, + "disabled": { + "description": "If true, the component is disabled. When disabled, the value cannot be changed and no interaction is possible." + }, + "disableFuture": { + "description": "If true, disable values after the current date for date components, time for time components and both for date time components." + }, + "disableIgnoringDatePartForTimeValidation": { + "description": "Do not ignore date part when validating min/max time." + }, + "disableOpenPicker": { + "description": "If true, the open picker button will not be rendered (renders only the field)." + }, + "disablePast": { + "description": "If true, disable values before the current date for date components, time for time components and both for date time components." + }, + "format": { + "description": "Format of the date when rendered in the input(s). Defaults to localized format based on the used views." + }, + "formatDensity": { + "description": "Density of the format when rendered in the input. Setting formatDensity to "spacious" will add a space before and after each /, - and . character." + }, + "inputRef": { + "description": "Pass a ref to the input element. Ignored if the field has several inputs." + }, + "label": { "description": "The label content. Ignored if the field has several inputs." }, + "localeText": { + "description": "Locale for components texts. Allows overriding texts coming from LocalizationProvider and theme." + }, + "maxTime": { + "description": "Maximal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true." + }, + "minTime": { + "description": "Minimal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true." + }, + "minutesStep": { "description": "Step over minutes." }, + "name": { + "description": "Name attribute used by the input element in the Field. Ignored if the field has several inputs." + }, + "onAccept": { + "description": "Callback fired when the value is accepted.", + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } + }, + "onChange": { + "description": "Callback fired when the value changes.", + "typeDescriptions": { + "value": "The new value.", + "context": "The context containing the validation result of the current value." + } + }, + "onClose": { + "description": "Callback fired when the popup requests to be closed. Use in controlled mode (see open)." + }, + "onError": { + "description": "Callback fired when the error associated with the current value changes. When a validation error is detected, the error parameter contains a non-null value. This can be used to render an appropriate form error.", + "typeDescriptions": { + "error": "The reason why the current value is not valid.", + "value": "The value associated with the error." + } + }, + "onOpen": { + "description": "Callback fired when the popup requests to be opened. Use in controlled mode (see open)." + }, + "onRangePositionChange": { + "description": "Callback fired when the range position changes.", + "typeDescriptions": { "rangePosition": "The new range position." } + }, + "onSelectedSectionsChange": { + "description": "Callback fired when the selected sections change.", + "typeDescriptions": { "newValue": "The new selected sections." } + }, + "onViewChange": { + "description": "Callback fired on view change.", + "typeDescriptions": { "view": "The new view." } + }, + "open": { "description": "Control the popup or dialog open state." }, + "openTo": { + "description": "The default visible view. Used when the component view is not controlled. Must be a valid option from views list." + }, + "rangePosition": { + "description": "The position in the currently edited date range. Used when the component position is controlled." + }, + "readOnly": { + "description": "If true, the component is read-only. When read-only, the value cannot be changed but the user can interact with the interface." + }, + "reduceAnimations": { "description": "If true, disable heavy animations." }, + "referenceDate": { + "description": "The date used to generate the new value when both value and defaultValue are empty." + }, + "selectedSections": { + "description": "The currently selected sections. This prop accepts four formats: 1. If a number is provided, the section at this index will be selected. 2. If a string of type FieldSectionType is provided, the first section with that name will be selected. 3. If "all" is provided, all the sections will be selected. 4. If null is provided, no section will be selected. If not provided, the selected sections will be handled internally." + }, + "shouldDisableTime": { + "description": "Disable specific time.", + "typeDescriptions": { + "value": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time 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." + }, + "thresholdToRenderTimeInASingleColumn": { + "description": "Amount of time options below or at which the single column time renderer is used." + }, + "timeSteps": { + "description": "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." + }, + "timezone": { + "description": "Choose which timezone to use for the value. Example: "default", "system", "UTC", "America/New_York". If you pass values from other timezones to some props, they will be converted to this timezone before being used.", + "seeMoreText": "See the {{link}} for more details." + }, + "value": { "description": "The selected value. Used when the component is controlled." }, + "view": { + "description": "The visible view. Used when the component view is controlled. Must be a valid option from views list." + }, + "viewRenderers": { + "description": "Define custom view renderers for each section. If null, the section will only have field editing. If undefined, internally defined view will be the used." + }, + "views": { "description": "Available views." } + }, + "classDescriptions": {}, + "slotDescriptions": { + "actionBar": "Custom component for the action bar, it is placed below the picker views.", + "clearButton": "Button to clear the value.", + "clearIcon": "Icon to display inside the clear button.", + "dialog": "Custom component for the dialog inside which the views are rendered on mobile.", + "digitalClockItem": "Component responsible for rendering a single digital clock item.", + "digitalClockSectionItem": "Component responsible for rendering a single multi section digital clock section item.", + "field": "", + "fieldRoot": "Element rendered at the root. Ignored if the field has only one input.", + "fieldSeparator": "Element rendered between the two inputs. Ignored if the field has only one input.", + "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.", + "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", + "mobileTransition": "Custom component for the mobile dialog Transition.", + "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.", + "shortcuts": "Custom component for the shortcuts.", + "tabs": "Tabs enabling toggling between start and end time.", + "textField": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element.", + "Toolbar": "Custom component for the toolbar rendered above the views." + } +} diff --git a/docs/translations/api-docs/date-pickers/time-range-picker-tabs/time-range-picker-tabs.json b/docs/translations/api-docs/date-pickers/time-range-picker-tabs/time-range-picker-tabs.json new file mode 100644 index 0000000000000..841ba6bb9bd51 --- /dev/null +++ b/docs/translations/api-docs/date-pickers/time-range-picker-tabs/time-range-picker-tabs.json @@ -0,0 +1,15 @@ +{ + "componentDescription": "", + "propDescriptions": { + "classes": { "description": "Override or extend the styles applied to the component." }, + "hidden": { "description": "Toggles visibility of the tabs allowing view switching." }, + "sx": { + "description": "The system prop that allows defining system overrides as well as additional CSS styles." + }, + "timeIcon": { "description": "Time tab icon." } + }, + "classDescriptions": { + "root": { "description": "Styles applied to the root element." }, + "tab": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the tab element" } + } +} diff --git a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar.json b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar.json new file mode 100644 index 0000000000000..1c1c780fe217f --- /dev/null +++ b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar.json @@ -0,0 +1,43 @@ +{ + "componentDescription": "", + "propDescriptions": { + "className": { + "description": "className applied to the root component.", + "deprecated": "", + "typeDescriptions": {} + }, + "hidden": { + "description": "If true, show the toolbar even in desktop mode.", + "deprecated": "", + "typeDescriptions": {} + }, + "onViewChange": { + "description": "Callback called when a toolbar is clicked", + "deprecated": "", + "typeDescriptions": { "view": "The view to open" } + }, + "toolbarFormat": { + "description": "Toolbar date format.", + "deprecated": "", + "typeDescriptions": {} + }, + "toolbarPlaceholder": { + "description": "Toolbar value placeholder—it is displayed when the value is empty.", + "deprecated": "", + "typeDescriptions": {} + }, + "view": { + "description": "Currently visible picker view.", + "deprecated": "", + "typeDescriptions": {} + } + }, + "classDescriptions": { + "root": { "description": "Styles applied to the root element." }, + "container": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the container element" + } + }, + "slotDescriptions": {} +} diff --git a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json new file mode 100644 index 0000000000000..d659ba6b6e8c2 --- /dev/null +++ b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json @@ -0,0 +1,28 @@ +{ + "componentDescription": "", + "propDescriptions": { + "classes": { "description": "Override or extend the styles applied to the component." }, + "hidden": { "description": "If true, show the toolbar even in desktop mode." }, + "sx": { + "description": "The system prop that allows defining system overrides as well as additional CSS styles." + }, + "toolbarPlaceholder": { + "description": "Toolbar value placeholder—it is displayed when the value is empty." + } + }, + "classDescriptions": { + "container": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the container element" + }, + "root": { "description": "Styles applied to the root element." }, + "separator": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the separator element" + }, + "timeContainer": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the time container element" + } + } +} diff --git a/docs/translations/api-docs/date-pickers/time-range-picker.json b/docs/translations/api-docs/date-pickers/time-range-picker.json new file mode 100644 index 0000000000000..6bef3d7960393 --- /dev/null +++ b/docs/translations/api-docs/date-pickers/time-range-picker.json @@ -0,0 +1,274 @@ +{ + "componentDescription": "", + "propDescriptions": { + "ampm": { + "description": "12h/24h view for hour selection clock.", + "deprecated": "", + "typeDescriptions": {} + }, + "autoFocus": { + "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered.", + "deprecated": "", + "typeDescriptions": {} + }, + "className": { + "description": "Class name applied to the root element.", + "deprecated": "", + "typeDescriptions": {} + }, + "closeOnSelect": { + "description": "If true, the popover or modal will close after submitting the full date.", + "deprecated": "", + "typeDescriptions": {} + }, + "defaultRangePosition": { + "description": "The initial position in the edited date range. Used when the component is not controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "defaultValue": { + "description": "The default value. Used when the component is not controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "desktopModeMediaQuery": { + "description": "CSS media query when Mobile mode will be changed to Desktop.", + "deprecated": "", + "typeDescriptions": {} + }, + "disabled": { + "description": "If true, the picker and text field are disabled.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableFuture": { + "description": "If true, disable values after the current date for date components, time for time components and both for date time components.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableIgnoringDatePartForTimeValidation": { + "description": "Do not ignore date part when validating min/max time.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableOpenPicker": { + "description": "If true, the open picker button will not be rendered (renders only the field).", + "deprecated": "", + "typeDescriptions": {} + }, + "disablePast": { + "description": "If true, disable values before the current date for date components, time for time components and both for date time components.", + "deprecated": "", + "typeDescriptions": {} + }, + "format": { + "description": "Format of the date when rendered in the input(s). Defaults to localized format based on the used views.", + "deprecated": "", + "typeDescriptions": {} + }, + "formatDensity": { + "description": "Density of the format when rendered in the input. Setting formatDensity to "spacious" will add a space before and after each /, - and . character.", + "deprecated": "", + "typeDescriptions": {} + }, + "inputRef": { + "description": "Pass a ref to the input element. Ignored if the field has several inputs.", + "deprecated": "", + "typeDescriptions": {} + }, + "label": { + "description": "The label content. Ignored if the field has several inputs.", + "deprecated": "", + "typeDescriptions": {} + }, + "localeText": { + "description": "Locale for components texts. Allows overriding texts coming from LocalizationProvider and theme.", + "deprecated": "", + "typeDescriptions": {} + }, + "maxTime": { + "description": "Maximal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true.", + "deprecated": "", + "typeDescriptions": {} + }, + "minTime": { + "description": "Minimal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true.", + "deprecated": "", + "typeDescriptions": {} + }, + "minutesStep": { + "description": "Step over minutes.", + "deprecated": "", + "typeDescriptions": {} + }, + "onAccept": { + "description": "Callback fired when the value is accepted.", + "deprecated": "", + "typeDescriptions": { "value": "The value that was just accepted." } + }, + "onChange": { + "description": "Callback fired when the value changes.", + "deprecated": "", + "typeDescriptions": { + "value": "The new value.", + "context": "The context containing the validation result of the current value." + } + }, + "onClose": { + "description": "Callback fired when the popup requests to be closed. Use in controlled mode (see open).", + "deprecated": "", + "typeDescriptions": {} + }, + "onError": { + "description": "Callback fired when the error associated to the current value changes. If the error has a non-null value, then the TextField will be rendered in error state.", + "deprecated": "", + "typeDescriptions": { + "error": "The new error describing why the current value is not valid.", + "value": "The value associated to the error." + } + }, + "onOpen": { + "description": "Callback fired when the popup requests to be opened. Use in controlled mode (see open).", + "deprecated": "", + "typeDescriptions": {} + }, + "onRangePositionChange": { + "description": "Callback fired when the range position changes.", + "deprecated": "", + "typeDescriptions": { "rangePosition": "The new range position." } + }, + "onSelectedSectionsChange": { + "description": "Callback fired when the selected sections change.", + "deprecated": "", + "typeDescriptions": { "newValue": "The new selected sections." } + }, + "onViewChange": { + "description": "Callback fired on view change.", + "deprecated": "", + "typeDescriptions": { "view": "The new view." } + }, + "open": { + "description": "Control the popup or dialog open state.", + "deprecated": "", + "typeDescriptions": {} + }, + "openTo": { + "description": "The default visible view. Used when the component view is not controlled. Must be a valid option from views list.", + "deprecated": "", + "typeDescriptions": {} + }, + "rangePosition": { + "description": "The position in the currently edited date range. Used when the component position is controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "reduceAnimations": { + "description": "If true, disable heavy animations.", + "deprecated": "", + "typeDescriptions": {} + }, + "referenceDate": { + "description": "The date used to generate the new value when both value and defaultValue are empty.", + "deprecated": "", + "typeDescriptions": {} + }, + "selectedSections": { + "description": "The currently selected sections. This prop accept four formats: 1. If a number is provided, the section at this index will be selected. 2. If an object with a startIndex and endIndex properties are provided, the sections between those two indexes will be selected. 3. If a string of type FieldSectionType is provided, the first section with that name will be selected. 4. If null is provided, no section will be selected If not provided, the selected sections will be handled internally.", + "deprecated": "", + "typeDescriptions": {} + }, + "shouldDisableClock": { + "description": "Disable specific clock time.", + "deprecated": "", + "typeDescriptions": { + "clockValue": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." + } + }, + "shouldDisableTime": { + "description": "Disable specific time.", + "deprecated": "", + "typeDescriptions": { + "value": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." + } + }, + "skipDisabled": { + "description": "If true, disabled digital clock items will not be rendered.", + "deprecated": "", + "typeDescriptions": {} + }, + "slotProps": { + "description": "The props used for each component slot.", + "deprecated": "", + "typeDescriptions": {} + }, + "slots": { + "description": "Overridable component slots.", + "deprecated": "", + "typeDescriptions": {} + }, + "sx": { + "description": "The system prop that allows defining system overrides as well as additional CSS styles.", + "deprecated": "", + "typeDescriptions": {} + }, + "thresholdToRenderTimeInASingleColumn": { + "description": "Amount of time options below or at which the single column time renderer is used.", + "deprecated": "", + "typeDescriptions": {} + }, + "timeSteps": { + "description": "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.", + "deprecated": "", + "typeDescriptions": {} + }, + "timezone": { + "description": "Choose which timezone to use for the value. Example: "default", "system", "UTC", "America/New_York". If you pass values from other timezones to some props, they will be converted to this timezone before being used.
See the timezones documention for more details.", + "deprecated": "", + "typeDescriptions": {} + }, + "value": { + "description": "The selected value. Used when the component is controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "view": { + "description": "The visible view. Used when the component view is controlled. Must be a valid option from views list.", + "deprecated": "", + "typeDescriptions": {} + }, + "viewRenderers": { + "description": "Define custom view renderers for each section. If null, the section will only have field editing. If undefined, internally defined view will be the used.", + "deprecated": "", + "typeDescriptions": {} + }, + "views": { "description": "Available views.", "deprecated": "", "typeDescriptions": {} } + }, + "classDescriptions": {}, + "slotDescriptions": { + "Toolbar": "Custom component for the toolbar rendered above the views.", + "actionBar": "Custom component for the action bar, it is placed below the picker views.", + "clearButton": "Button to clear the value.", + "clearIcon": "Icon to display inside the clear button.", + "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", + "desktopTransition": "Custom component for the desktop popper Transition.", + "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.", + "field": "", + "fieldRoot": "Element rendered at the root. Ignored if the field has only one input.", + "fieldSeparator": "Element rendered between the two inputs. Ignored if the field has only one input.", + "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.", + "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", + "mobileTransition": "Custom component for the mobile dialog Transition.", + "nextIconButton": "Button allowing to switch to the right view.", + "popper": "Custom component for the popper inside which the views are rendered on desktop.", + "previousIconButton": "Button allowing to switch to the left view.", + "rightArrowIcon": "Icon displayed in the right view switch button.", + "shortcuts": "Custom component for the shortcuts.", + "textField": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element. Receives the same props as @mui/material/TextField." + } +} diff --git a/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json b/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json new file mode 100644 index 0000000000000..24c6630dfd554 --- /dev/null +++ b/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json @@ -0,0 +1,176 @@ +{ + "componentDescription": "", + "propDescriptions": { + "ampm": { "description": "12h/24h view for hour selection clock." }, + "autoFocus": { + "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." + }, + "closeOnSelect": { + "description": "If true, the Picker will close after submitting the full date." + }, + "defaultRangePosition": { + "description": "The initial position in the edited date range. Used when the component is not controlled." + }, + "defaultValue": { + "description": "The default value. Used when the component is not controlled." + }, + "desktopModeMediaQuery": { + "description": "CSS media query when Mobile mode will be changed to Desktop." + }, + "disabled": { + "description": "If true, the component is disabled. When disabled, the value cannot be changed and no interaction is possible." + }, + "disableFuture": { + "description": "If true, disable values after the current date for date components, time for time components and both for date time components." + }, + "disableIgnoringDatePartForTimeValidation": { + "description": "Do not ignore date part when validating min/max time." + }, + "disableOpenPicker": { + "description": "If true, the open picker button will not be rendered (renders only the field)." + }, + "disablePast": { + "description": "If true, disable values before the current date for date components, time for time components and both for date time components." + }, + "format": { + "description": "Format of the date when rendered in the input(s). Defaults to localized format based on the used views." + }, + "formatDensity": { + "description": "Density of the format when rendered in the input. Setting formatDensity to "spacious" will add a space before and after each /, - and . character." + }, + "inputRef": { + "description": "Pass a ref to the input element. Ignored if the field has several inputs." + }, + "label": { "description": "The label content. Ignored if the field has several inputs." }, + "localeText": { + "description": "Locale for components texts. Allows overriding texts coming from LocalizationProvider and theme." + }, + "maxTime": { + "description": "Maximal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true." + }, + "minTime": { + "description": "Minimal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true." + }, + "minutesStep": { "description": "Step over minutes." }, + "name": { + "description": "Name attribute used by the input element in the Field. Ignored if the field has several inputs." + }, + "onAccept": { + "description": "Callback fired when the value is accepted.", + "typeDescriptions": { + "value": "The value that was just accepted.", + "context": "The context containing the validation result of the current value." + } + }, + "onChange": { + "description": "Callback fired when the value changes.", + "typeDescriptions": { + "value": "The new value.", + "context": "The context containing the validation result of the current value." + } + }, + "onClose": { + "description": "Callback fired when the popup requests to be closed. Use in controlled mode (see open)." + }, + "onError": { + "description": "Callback fired when the error associated with the current value changes. When a validation error is detected, the error parameter contains a non-null value. This can be used to render an appropriate form error.", + "typeDescriptions": { + "error": "The reason why the current value is not valid.", + "value": "The value associated with the error." + } + }, + "onOpen": { + "description": "Callback fired when the popup requests to be opened. Use in controlled mode (see open)." + }, + "onRangePositionChange": { + "description": "Callback fired when the range position changes.", + "typeDescriptions": { "rangePosition": "The new range position." } + }, + "onSelectedSectionsChange": { + "description": "Callback fired when the selected sections change.", + "typeDescriptions": { "newValue": "The new selected sections." } + }, + "onViewChange": { + "description": "Callback fired on view change.", + "typeDescriptions": { "view": "The new view." } + }, + "open": { "description": "Control the popup or dialog open state." }, + "openTo": { + "description": "The default visible view. Used when the component view is not controlled. Must be a valid option from views list." + }, + "rangePosition": { + "description": "The position in the currently edited date range. Used when the component position is controlled." + }, + "readOnly": { + "description": "If true, the component is read-only. When read-only, the value cannot be changed but the user can interact with the interface." + }, + "reduceAnimations": { "description": "If true, disable heavy animations." }, + "referenceDate": { + "description": "The date used to generate the new value when both value and defaultValue are empty." + }, + "selectedSections": { + "description": "The currently selected sections. This prop accepts four formats: 1. If a number is provided, the section at this index will be selected. 2. If a string of type FieldSectionType is provided, the first section with that name will be selected. 3. If "all" is provided, all the sections will be selected. 4. If null is provided, no section will be selected. If not provided, the selected sections will be handled internally." + }, + "shouldDisableTime": { + "description": "Disable specific time.", + "typeDescriptions": { + "value": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." + } + }, + "skipDisabled": { + "description": "If true, disabled digital clock items will not be rendered." + }, + "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." + }, + "thresholdToRenderTimeInASingleColumn": { + "description": "Amount of time options below or at which the single column time renderer is used." + }, + "timeSteps": { + "description": "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." + }, + "timezone": { + "description": "Choose which timezone to use for the value. Example: "default", "system", "UTC", "America/New_York". If you pass values from other timezones to some props, they will be converted to this timezone before being used.", + "seeMoreText": "See the {{link}} for more details." + }, + "value": { "description": "The selected value. Used when the component is controlled." }, + "view": { + "description": "The visible view. Used when the component view is controlled. Must be a valid option from views list." + }, + "viewRenderers": { + "description": "Define custom view renderers for each section. If null, the section will only have field editing. If undefined, internally defined view will be the used." + }, + "views": { "description": "Available views." } + }, + "classDescriptions": {}, + "slotDescriptions": { + "actionBar": "Custom component for the action bar, it is placed below the picker views.", + "clearButton": "Button to clear the value.", + "clearIcon": "Icon to display inside the clear button.", + "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", + "desktopTransition": "Custom component for the desktop popper Transition.", + "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.", + "digitalClockItem": "Component responsible for rendering a single digital clock item.", + "digitalClockSectionItem": "Component responsible for rendering a single multi section digital clock section item.", + "field": "", + "fieldRoot": "Element rendered at the root. Ignored if the field has only one input.", + "fieldSeparator": "Element rendered between the two inputs. Ignored if the field has only one input.", + "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.", + "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", + "mobileTransition": "Custom component for the mobile dialog Transition.", + "nextIconButton": "Button allowing to switch to the right view.", + "popper": "Custom component for the popper inside which the views are rendered on desktop.", + "previousIconButton": "Button allowing to switch to the left view.", + "rightArrowIcon": "Icon displayed in the right view switch button.", + "shortcuts": "Custom component for the shortcuts.", + "tabs": "Tabs enabling toggling between start and end time.", + "textField": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element.", + "Toolbar": "Custom component for the toolbar rendered above the views." + } +} diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx index 25c8b0e3f8a2b..85decb2f679af 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx @@ -34,8 +34,6 @@ const useUtilityClasses = (classes: Partial | return composeClasses(slots, getDateTimeRangePickerToolbarUtilityClass, classes); }; -type DateTimeRangeViews = Exclude; - export interface DateTimeRangePickerToolbarProps extends BaseToolbarProps, ExportedDateTimeRangePickerToolbarProps { @@ -89,7 +87,6 @@ const DateTimeRangePickerToolbar = React.forwardRef(function DateTimeRangePicker const { className, classes: classesProp, - classes: inClasses, ampm, hidden, toolbarFormat, @@ -99,10 +96,8 @@ const DateTimeRangePickerToolbar = React.forwardRef(function DateTimeRangePicker ...other } = props; - const { value, setValue, disabled, readOnly, view, setView, views } = usePickerContext< - PickerRangeValue, - DateTimeRangeViews - >(); + const { value, setValue, disabled, readOnly, view, setView, views } = + usePickerContext(); const translations = usePickerTranslations(); const ownerState = useToolbarOwnerState(); const { rangePosition, setRangePosition } = usePickerRangePositionContext(); diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx index b9a8076df20a5..1bcd76a6e5583 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx @@ -76,7 +76,7 @@ export interface BaseDateTimeRangePickerSlotProps toolbar?: ExportedDateTimeRangePickerToolbarProps; } -export type DateTimeRangePickerRenderers = +type DateTimeRangePickerRenderers = PickerViewRendererLookup< PickerRangeValue, TView, diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx new file mode 100644 index 0000000000000..0ceac76f92dcf --- /dev/null +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -0,0 +1,449 @@ +'use client'; +import * as React from 'react'; +import PropTypes from 'prop-types'; +import resolveComponentProps from '@mui/utils/resolveComponentProps'; +import { + TimeViewWithMeridiem, + useUtils, + resolveTimeFormat, + PickerRangeValue, + PickerRendererInterceptorProps, + PickerViewRendererLookup, +} from '@mui/x-date-pickers/internals'; +import { extractValidationProps } from '@mui/x-date-pickers/validation'; +import { + multiSectionDigitalClockClasses, + multiSectionDigitalClockSectionClasses, +} from '@mui/x-date-pickers/MultiSectionDigitalClock'; +import { digitalClockClasses } from '@mui/x-date-pickers/DigitalClock'; +import { DesktopDateTimePickerLayout } from '@mui/x-date-pickers/DesktopDateTimePicker'; +import { + renderDigitalClockTimeView, + renderMultiSectionDigitalClockTimeView, +} from '@mui/x-date-pickers/timeViewRenderers'; +import { rangeValueManager } from '../internals/utils/valueManagers'; +import { DesktopTimeRangePickerProps } from './DesktopTimeRangePicker.types'; +import { useTimeRangePickerDefaultizedProps } from '../TimeRangePicker/shared'; +import { MultiInputTimeRangeField } from '../MultiInputTimeRangeField'; +import { useDesktopRangePicker } from '../internals/hooks/useDesktopRangePicker'; +import { validateTimeRange } from '../validation/validateTimeRange'; +import { RANGE_VIEW_HEIGHT } from '../internals/constants/dimensions'; +import { TimeRangePickerTimeWrapper } from '../TimeRangePicker/TimeRangePickerTimeWrapper'; + +const rendererInterceptor = function RendererInterceptor( + props: PickerRendererInterceptorProps, +) { + const { viewRenderers, popperView, rendererProps } = props; + const { openTo, ...otherProps } = rendererProps; + const finalProps = { + ...otherProps, + focusedView: null, + sx: [ + { + [`&.${multiSectionDigitalClockClasses.root}`]: { + borderBottom: 0, + }, + [`&.${multiSectionDigitalClockClasses.root}, .${multiSectionDigitalClockSectionClasses.root}, &.${digitalClockClasses.root}`]: + { + maxHeight: RANGE_VIEW_HEIGHT, + }, + }, + ], + }; + const viewRenderer = viewRenderers[popperView]; + return ( + + ); +}; + +type DesktopTimeRangePickerComponent = (( + props: DesktopTimeRangePickerProps & + React.RefAttributes, +) => React.JSX.Element) & { propTypes?: any }; + +const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< + TEnableAccessibleFieldDOMStructure extends boolean = true, +>( + inProps: DesktopTimeRangePickerProps, + ref: React.Ref, +) { + const utils = useUtils(); + + // Props with the default values common to all date time pickers + const defaultizedProps = useTimeRangePickerDefaultizedProps< + DesktopTimeRangePickerProps + >(inProps, 'MuiDesktopTimeRangePicker'); + + const renderTimeRangeView = defaultizedProps.shouldRenderTimeInASingleColumn + ? renderDigitalClockTimeView + : renderMultiSectionDigitalClockTimeView; + + const viewRenderers: PickerViewRendererLookup = { + hours: renderTimeRangeView, + minutes: renderTimeRangeView, + seconds: renderTimeRangeView, + meridiem: renderTimeRangeView, + ...defaultizedProps.viewRenderers, + }; + + const shouldHoursRendererContainMeridiemView = + viewRenderers.hours?.name === renderMultiSectionDigitalClockTimeView.name; + const views = !shouldHoursRendererContainMeridiemView + ? defaultizedProps.views.filter((view) => view !== 'meridiem') + : defaultizedProps.views; + + const props = { + ...defaultizedProps, + views, + viewRenderers, + ampmInClock: true, + format: resolveTimeFormat(utils, defaultizedProps), + slots: { + field: MultiInputTimeRangeField, + layout: DesktopDateTimePickerLayout, + ...defaultizedProps.slots, + }, + slotProps: { + ...defaultizedProps.slotProps, + field: (ownerState: any) => ({ + ...resolveComponentProps(defaultizedProps.slotProps?.field, ownerState), + ...extractValidationProps(defaultizedProps), + ref, + }), + tabs: { + hidden: true, + ...defaultizedProps.slotProps?.tabs, + }, + toolbar: { + hidden: true, + ...defaultizedProps.slotProps?.toolbar, + }, + }, + }; + + const { renderPicker } = useDesktopRangePicker< + TimeViewWithMeridiem, + TEnableAccessibleFieldDOMStructure, + typeof props + >({ + props, + valueManager: rangeValueManager, + valueType: 'time', + validator: validateTimeRange, + rendererInterceptor, + }); + + return renderPicker(); +}) as DesktopTimeRangePickerComponent; + +DesktopTimeRangePicker.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * 12h/24h view for hour selection clock. + * @default utils.is12HourCycleInCurrentLocale() + */ + ampm: PropTypes.bool, + /** + * If `true`, the main element is focused during the first mount. + * This main element is: + * - the element chosen by the visible view if any (i.e: the selected day on the `day` view). + * - the `input` element if there is a field rendered. + */ + autoFocus: PropTypes.bool, + className: PropTypes.string, + /** + * If `true`, the Picker will close after submitting the full date. + * @default false + */ + closeOnSelect: PropTypes.bool, + /** + * The initial position in the edited date range. + * Used when the component is not controlled. + * @default 'start' + */ + defaultRangePosition: PropTypes.oneOf(['end', 'start']), + /** + * The default value. + * Used when the component is not controlled. + */ + defaultValue: PropTypes.arrayOf(PropTypes.object), + /** + * If `true`, the component is disabled. + * When disabled, the value cannot be changed and no interaction is possible. + * @default false + */ + disabled: PropTypes.bool, + /** + * If `true`, disable values after the current date for date components, time for time components and both for date time components. + * @default false + */ + disableFuture: PropTypes.bool, + /** + * Do not ignore date part when validating min/max time. + * @default false + */ + disableIgnoringDatePartForTimeValidation: PropTypes.bool, + /** + * If `true`, the open picker button will not be rendered (renders only the field). + * @default false + */ + disableOpenPicker: PropTypes.bool, + /** + * If `true`, disable values before the current date for date components, time for time components and both for date time components. + * @default false + */ + disablePast: PropTypes.bool, + /** + * @default true + */ + enableAccessibleFieldDOMStructure: PropTypes.any, + /** + * Format of the date when rendered in the input(s). + * Defaults to localized format based on the used `views`. + */ + format: PropTypes.string, + /** + * Density of the format when rendered in the input. + * Setting `formatDensity` to `"spacious"` will add a space before and after each `/`, `-` and `.` character. + * @default "dense" + */ + formatDensity: PropTypes.oneOf(['dense', 'spacious']), + /** + * Pass a ref to the `input` element. + * Ignored if the field has several inputs. + */ + inputRef: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.shape({ + current: PropTypes.object, + }), + ]), + /** + * The label content. + * Ignored if the field has several inputs. + */ + label: PropTypes.node, + /** + * Locale for components texts. + * Allows overriding texts coming from `LocalizationProvider` and `theme`. + */ + localeText: PropTypes.object, + /** + * Maximal selectable time. + * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. + */ + maxTime: PropTypes.object, + /** + * Minimal selectable time. + * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. + */ + minTime: PropTypes.object, + /** + * Step over minutes. + * @default 1 + */ + minutesStep: PropTypes.number, + /** + * Name attribute used by the `input` element in the Field. + * Ignored if the field has several inputs. + */ + name: PropTypes.string, + /** + * Callback fired when the value is accepted. + * @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value. + * @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value. + * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. + */ + onAccept: PropTypes.func, + /** + * Callback fired when the value changes. + * @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value. + * @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value. + * @param {TValue} value The new value. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. + */ + onChange: PropTypes.func, + /** + * Callback fired when the popup requests to be closed. + * Use in controlled mode (see `open`). + */ + onClose: PropTypes.func, + /** + * Callback fired when the error associated with the current value changes. + * When a validation error is detected, the `error` parameter contains a non-null value. + * This can be used to render an appropriate form error. + * @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value. + * @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value. + * @param {TError} error The reason why the current value is not valid. + * @param {TValue} value The value associated with the error. + */ + onError: PropTypes.func, + /** + * Callback fired when the popup requests to be opened. + * Use in controlled mode (see `open`). + */ + onOpen: PropTypes.func, + /** + * Callback fired when the range position changes. + * @param {RangePosition} rangePosition The new range position. + */ + onRangePositionChange: PropTypes.func, + /** + * Callback fired when the selected sections change. + * @param {FieldSelectedSections} newValue The new selected sections. + */ + onSelectedSectionsChange: PropTypes.func, + /** + * Callback fired on view change. + * @template TView + * @param {TView} view The new view. + */ + onViewChange: PropTypes.func, + /** + * Control the popup or dialog open state. + * @default false + */ + open: PropTypes.bool, + /** + * The default visible view. + * Used when the component view is not controlled. + * Must be a valid option from `views` list. + */ + openTo: PropTypes.oneOf(['hours', 'minutes', 'seconds']), + /** + * The position in the currently edited date range. + * Used when the component position is controlled. + */ + rangePosition: PropTypes.oneOf(['end', 'start']), + /** + * If `true`, the component is read-only. + * When read-only, the value cannot be changed but the user can interact with the interface. + * @default false + */ + readOnly: PropTypes.bool, + /** + * If `true`, disable heavy animations. + * @default `@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13 + */ + reduceAnimations: PropTypes.bool, + /** + * The date used to generate the new value when both `value` and `defaultValue` are empty. + * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. + */ + referenceDate: PropTypes.object, + /** + * The currently selected sections. + * This prop accepts four formats: + * 1. If a number is provided, the section at this index will be selected. + * 2. If a string of type `FieldSectionType` is provided, the first section with that name will be selected. + * 3. If `"all"` is provided, all the sections will be selected. + * 4. If `null` is provided, no section will be selected. + * If not provided, the selected sections will be handled internally. + */ + selectedSections: PropTypes.oneOfType([ + PropTypes.oneOf([ + 'all', + 'day', + 'empty', + 'hours', + 'meridiem', + 'minutes', + 'month', + 'seconds', + 'weekDay', + 'year', + ]), + PropTypes.number, + ]), + /** + * Disable specific time. + * @param {PickerValidDate} value The value to check. + * @param {TimeView} view The clock type of the timeValue. + * @returns {boolean} If `true` the time will be disabled. + */ + shouldDisableTime: PropTypes.func, + /** + * If `true`, disabled digital clock items will not be rendered. + * @default false + */ + skipDisabled: PropTypes.bool, + /** + * 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. + */ + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + /** + * Amount of time options below or at which the single column time renderer is used. + * @default 24 + */ + thresholdToRenderTimeInASingleColumn: PropTypes.number, + /** + * 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, + }), + /** + * Choose which timezone to use for the value. + * Example: "default", "system", "UTC", "America/New_York". + * If you pass values from other timezones to some props, they will be converted to this timezone before being used. + * @see See the {@link https://mui.com/x/react-date-pickers/timezone/ timezones documentation} for more details. + * @default The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise. + */ + timezone: PropTypes.string, + /** + * The selected value. + * Used when the component is controlled. + */ + value: PropTypes.arrayOf(PropTypes.object), + /** + * The visible view. + * Used when the component view is controlled. + * Must be a valid option from `views` list. + */ + view: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']), + /** + * Define custom view renderers for each section. + * If `null`, the section will only have field editing. + * If `undefined`, internally defined view will be the used. + */ + viewRenderers: PropTypes.shape({ + hours: PropTypes.func, + meridiem: PropTypes.func, + minutes: PropTypes.func, + seconds: PropTypes.func, + }), + /** + * Available views. + */ + views: PropTypes.arrayOf(PropTypes.oneOf(['hours', 'minutes', 'seconds']).isRequired), +} as any; + +export { DesktopTimeRangePicker }; diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts new file mode 100644 index 0000000000000..9610ba65d33e0 --- /dev/null +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts @@ -0,0 +1,42 @@ +import { MakeOptional } from '@mui/x-internals/types'; +import { TimeView } from '@mui/x-date-pickers/models'; +import { DesktopOnlyTimePickerProps } from '@mui/x-date-pickers/internals'; +import { + UseDesktopRangePickerSlots, + UseDesktopRangePickerSlotProps, + DesktopRangeOnlyPickerProps, +} from '../internals/hooks/useDesktopRangePicker'; +import { + BaseTimeRangePickerProps, + BaseTimeRangePickerSlots, + BaseTimeRangePickerSlotProps, +} from '../TimeRangePicker/shared'; + +export interface DesktopTimeRangePickerSlots + extends BaseTimeRangePickerSlots, + MakeOptional {} + +export interface DesktopTimeRangePickerSlotProps + extends BaseTimeRangePickerSlotProps, + Omit, 'tabs' | 'toolbar'> {} + +export interface DesktopTimeRangePickerProps< + TEnableAccessibleFieldDOMStructure extends boolean = true, +> extends BaseTimeRangePickerProps, + DesktopRangeOnlyPickerProps, + DesktopOnlyTimePickerProps { + /** + * Available views. + */ + views?: readonly TimeView[]; + /** + * Overridable component slots. + * @default {} + */ + slots?: DesktopTimeRangePickerSlots; + /** + * The props used for each component slot. + * @default {} + */ + slotProps?: DesktopTimeRangePickerSlotProps; +} diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/index.ts b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/index.ts new file mode 100644 index 0000000000000..443117180b736 --- /dev/null +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/index.ts @@ -0,0 +1,6 @@ +export { DesktopTimeRangePicker } from './DesktopTimeRangePicker'; +export type { + DesktopTimeRangePickerProps, + DesktopTimeRangePickerSlots, + DesktopTimeRangePickerSlotProps, +} from './DesktopTimeRangePicker.types'; diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx new file mode 100644 index 0000000000000..eb85ee4964781 --- /dev/null +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -0,0 +1,440 @@ +'use client'; +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { + DIALOG_WIDTH, + PickerRangeValue, + PickerRendererInterceptorProps, + PickerViewRendererLookup, + resolveTimeFormat, + TimeViewWithMeridiem, + useUtils, + VIEW_HEIGHT, +} from '@mui/x-date-pickers/internals'; +import resolveComponentProps from '@mui/utils/resolveComponentProps'; +import refType from '@mui/utils/refType'; +import { + multiSectionDigitalClockClasses, + multiSectionDigitalClockSectionClasses, +} from '@mui/x-date-pickers/MultiSectionDigitalClock'; +import { digitalClockClasses } from '@mui/x-date-pickers/DigitalClock'; +import { + renderDigitalClockTimeView, + renderMultiSectionDigitalClockTimeView, +} from '@mui/x-date-pickers/timeViewRenderers'; +import { extractValidationProps } from '@mui/x-date-pickers/validation'; +import { rangeValueManager } from '../internals/utils/valueManagers'; +import { MobileTimeRangePickerProps } from './MobileTimeRangePicker.types'; +import { useTimeRangePickerDefaultizedProps } from '../TimeRangePicker/shared'; +import { MultiInputTimeRangeField } from '../MultiInputTimeRangeField'; +import { useMobileRangePicker } from '../internals/hooks/useMobileRangePicker'; +import { validateTimeRange } from '../validation/validateTimeRange'; +import { RANGE_VIEW_HEIGHT } from '../internals/constants/dimensions'; +import { TimeRangePickerTimeWrapper } from '../TimeRangePicker/TimeRangePickerTimeWrapper'; + +const rendererInterceptor = function rendererInterceptor( + props: PickerRendererInterceptorProps, +) { + const { viewRenderers, popperView, rendererProps } = props; + const finalProps = { + ...rendererProps, + focusedView: null, + sx: [ + { + width: DIALOG_WIDTH, + [`.${multiSectionDigitalClockSectionClasses.root}`]: { + flex: 1, + // account for the border on `MultiSectionDigitalClock` + maxHeight: VIEW_HEIGHT - 1, + [`.${multiSectionDigitalClockSectionClasses.item}`]: { + width: 'auto', + }, + }, + [`&.${digitalClockClasses.root}`]: { + maxHeight: RANGE_VIEW_HEIGHT, + [`.${digitalClockClasses.item}`]: { + justifyContent: 'center', + }, + }, + [`&.${multiSectionDigitalClockClasses.root}, .${multiSectionDigitalClockSectionClasses.root}`]: + { + maxHeight: RANGE_VIEW_HEIGHT - 1, + }, + }, + ], + }; + const viewRenderer = viewRenderers[popperView]; + if (!viewRenderer) { + return null; + } + return ; +}; + +type MobileTimeRangePickerComponent = (( + props: MobileTimeRangePickerProps & + React.RefAttributes, +) => React.JSX.Element) & { propTypes?: any }; + +const MobileTimeRangePicker = React.forwardRef(function MobileTimeRangePicker< + TEnableAccessibleFieldDOMStructure extends boolean = true, +>( + inProps: MobileTimeRangePickerProps, + ref: React.Ref, +) { + const utils = useUtils(); + + // Props with the default values common to all date time pickers + const defaultizedProps = useTimeRangePickerDefaultizedProps< + MobileTimeRangePickerProps + >(inProps, 'MuiMobileTimeRangePicker'); + + const renderTimeView = defaultizedProps.shouldRenderTimeInASingleColumn + ? renderDigitalClockTimeView + : renderMultiSectionDigitalClockTimeView; + + const viewRenderers: PickerViewRendererLookup = { + hours: renderTimeView, + minutes: renderTimeView, + seconds: renderTimeView, + meridiem: renderTimeView, + ...defaultizedProps.viewRenderers, + }; + + const props = { + ...defaultizedProps, + ampmInClock: true, + viewRenderers, + format: resolveTimeFormat(utils, defaultizedProps), + slots: { + field: MultiInputTimeRangeField, + ...defaultizedProps.slots, + }, + slotProps: { + ...defaultizedProps.slotProps, + field: (ownerState: any) => ({ + ...resolveComponentProps(defaultizedProps.slotProps?.field, ownerState), + ...extractValidationProps(defaultizedProps), + ref, + }), + tabs: { + hidden: false, + ...defaultizedProps.slotProps?.tabs, + }, + toolbar: { + hidden: false, + ...defaultizedProps.slotProps?.toolbar, + }, + }, + }; + + const { renderPicker } = useMobileRangePicker< + TimeViewWithMeridiem, + TEnableAccessibleFieldDOMStructure, + typeof props + >({ + props, + valueManager: rangeValueManager, + valueType: 'time', + validator: validateTimeRange, + rendererInterceptor, + }); + + return renderPicker(); +}) as MobileTimeRangePickerComponent; + +MobileTimeRangePicker.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * 12h/24h view for hour selection clock. + * @default utils.is12HourCycleInCurrentLocale() + */ + ampm: PropTypes.bool, + /** + * If `true`, the main element is focused during the first mount. + * This main element is: + * - the element chosen by the visible view if any (i.e: the selected day on the `day` view). + * - the `input` element if there is a field rendered. + */ + autoFocus: PropTypes.bool, + className: PropTypes.string, + /** + * If `true`, the Picker will close after submitting the full date. + * @default false + */ + closeOnSelect: PropTypes.bool, + /** + * The initial position in the edited date range. + * Used when the component is not controlled. + * @default 'start' + */ + defaultRangePosition: PropTypes.oneOf(['end', 'start']), + /** + * The default value. + * Used when the component is not controlled. + */ + defaultValue: PropTypes.arrayOf(PropTypes.object), + /** + * If `true`, the component is disabled. + * When disabled, the value cannot be changed and no interaction is possible. + * @default false + */ + disabled: PropTypes.bool, + /** + * If `true`, disable values after the current date for date components, time for time components and both for date time components. + * @default false + */ + disableFuture: PropTypes.bool, + /** + * Do not ignore date part when validating min/max time. + * @default false + */ + disableIgnoringDatePartForTimeValidation: PropTypes.bool, + /** + * If `true`, the open picker button will not be rendered (renders only the field). + * @default false + */ + disableOpenPicker: PropTypes.bool, + /** + * If `true`, disable values before the current date for date components, time for time components and both for date time components. + * @default false + */ + disablePast: PropTypes.bool, + /** + * @default true + */ + enableAccessibleFieldDOMStructure: PropTypes.any, + /** + * Format of the date when rendered in the input(s). + * Defaults to localized format based on the used `views`. + */ + format: PropTypes.string, + /** + * Density of the format when rendered in the input. + * Setting `formatDensity` to `"spacious"` will add a space before and after each `/`, `-` and `.` character. + * @default "dense" + */ + formatDensity: PropTypes.oneOf(['dense', 'spacious']), + /** + * Pass a ref to the `input` element. + * Ignored if the field has several inputs. + */ + inputRef: refType, + /** + * The label content. + * Ignored if the field has several inputs. + */ + label: PropTypes.node, + /** + * Locale for components texts. + * Allows overriding texts coming from `LocalizationProvider` and `theme`. + */ + localeText: PropTypes.object, + /** + * Maximal selectable time. + * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. + */ + maxTime: PropTypes.object, + /** + * Minimal selectable time. + * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. + */ + minTime: PropTypes.object, + /** + * Step over minutes. + * @default 1 + */ + minutesStep: PropTypes.number, + /** + * Name attribute used by the `input` element in the Field. + * Ignored if the field has several inputs. + */ + name: PropTypes.string, + /** + * Callback fired when the value is accepted. + * @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value. + * @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value. + * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. + */ + onAccept: PropTypes.func, + /** + * Callback fired when the value changes. + * @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value. + * @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value. + * @param {TValue} value The new value. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. + */ + onChange: PropTypes.func, + /** + * Callback fired when the popup requests to be closed. + * Use in controlled mode (see `open`). + */ + onClose: PropTypes.func, + /** + * Callback fired when the error associated with the current value changes. + * When a validation error is detected, the `error` parameter contains a non-null value. + * This can be used to render an appropriate form error. + * @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value. + * @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value. + * @param {TError} error The reason why the current value is not valid. + * @param {TValue} value The value associated with the error. + */ + onError: PropTypes.func, + /** + * Callback fired when the popup requests to be opened. + * Use in controlled mode (see `open`). + */ + onOpen: PropTypes.func, + /** + * Callback fired when the range position changes. + * @param {RangePosition} rangePosition The new range position. + */ + onRangePositionChange: PropTypes.func, + /** + * Callback fired when the selected sections change. + * @param {FieldSelectedSections} newValue The new selected sections. + */ + onSelectedSectionsChange: PropTypes.func, + /** + * Callback fired on view change. + * @template TView + * @param {TView} view The new view. + */ + onViewChange: PropTypes.func, + /** + * Control the popup or dialog open state. + * @default false + */ + open: PropTypes.bool, + /** + * The default visible view. + * Used when the component view is not controlled. + * Must be a valid option from `views` list. + */ + openTo: PropTypes.oneOf(['hours', 'minutes', 'seconds']), + /** + * The position in the currently edited date range. + * Used when the component position is controlled. + */ + rangePosition: PropTypes.oneOf(['end', 'start']), + /** + * If `true`, the component is read-only. + * When read-only, the value cannot be changed but the user can interact with the interface. + * @default false + */ + readOnly: PropTypes.bool, + /** + * If `true`, disable heavy animations. + * @default `@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13 + */ + reduceAnimations: PropTypes.bool, + /** + * The date used to generate the new value when both `value` and `defaultValue` are empty. + * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. + */ + referenceDate: PropTypes.object, + /** + * The currently selected sections. + * This prop accepts four formats: + * 1. If a number is provided, the section at this index will be selected. + * 2. If a string of type `FieldSectionType` is provided, the first section with that name will be selected. + * 3. If `"all"` is provided, all the sections will be selected. + * 4. If `null` is provided, no section will be selected. + * If not provided, the selected sections will be handled internally. + */ + selectedSections: PropTypes.oneOfType([ + PropTypes.oneOf([ + 'all', + 'day', + 'empty', + 'hours', + 'meridiem', + 'minutes', + 'month', + 'seconds', + 'weekDay', + 'year', + ]), + PropTypes.number, + ]), + /** + * Disable specific time. + * @param {PickerValidDate} value The value to check. + * @param {TimeView} view The clock type of the timeValue. + * @returns {boolean} If `true` the time will be disabled. + */ + shouldDisableTime: 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. + */ + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + /** + * Amount of time options below or at which the single column time renderer is used. + * @default 24 + */ + thresholdToRenderTimeInASingleColumn: PropTypes.number, + /** + * 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, + }), + /** + * Choose which timezone to use for the value. + * Example: "default", "system", "UTC", "America/New_York". + * If you pass values from other timezones to some props, they will be converted to this timezone before being used. + * @see See the {@link https://mui.com/x/react-date-pickers/timezone/ timezones documentation} for more details. + * @default The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise. + */ + timezone: PropTypes.string, + /** + * The selected value. + * Used when the component is controlled. + */ + value: PropTypes.arrayOf(PropTypes.object), + /** + * The visible view. + * Used when the component view is controlled. + * Must be a valid option from `views` list. + */ + view: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']), + /** + * Define custom view renderers for each section. + * If `null`, the section will only have field editing. + * If `undefined`, internally defined view will be the used. + */ + viewRenderers: PropTypes.shape({ + hours: PropTypes.func, + meridiem: PropTypes.func, + minutes: PropTypes.func, + seconds: PropTypes.func, + }), + /** + * Available views. + */ + views: PropTypes.arrayOf(PropTypes.oneOf(['hours', 'minutes', 'seconds']).isRequired), +} as any; + +export { MobileTimeRangePicker }; diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts new file mode 100644 index 0000000000000..c010eee10df04 --- /dev/null +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts @@ -0,0 +1,34 @@ +import { MakeOptional } from '@mui/x-internals/types'; +import { + UseMobileRangePickerSlots, + UseMobileRangePickerSlotProps, + MobileRangeOnlyPickerProps, +} from '../internals/hooks/useMobileRangePicker'; +import { + BaseTimeRangePickerProps, + BaseTimeRangePickerSlots, + BaseTimeRangePickerSlotProps, +} from '../TimeRangePicker/shared'; + +export interface MobileTimeRangePickerSlots + extends BaseTimeRangePickerSlots, + MakeOptional {} + +export interface MobileTimeRangePickerSlotProps + extends BaseTimeRangePickerSlotProps, + Omit, 'tabs' | 'toolbar'> {} + +export interface MobileTimeRangePickerProps + extends BaseTimeRangePickerProps, + MobileRangeOnlyPickerProps { + /** + * Overridable component slots. + * @default {} + */ + slots?: MobileTimeRangePickerSlots; + /** + * The props used for each component slot. + * @default {} + */ + slotProps?: MobileTimeRangePickerSlotProps; +} diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/index.ts b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/index.ts new file mode 100644 index 0000000000000..16f4167b8b047 --- /dev/null +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/index.ts @@ -0,0 +1,6 @@ +export { MobileTimeRangePicker } from './MobileTimeRangePicker'; +export type { + MobileTimeRangePickerProps, + MobileTimeRangePickerSlots, + MobileTimeRangePickerSlotProps, +} from './MobileTimeRangePicker.types'; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx new file mode 100644 index 0000000000000..4e710e6091fdf --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx @@ -0,0 +1,352 @@ +'use client'; +import * as React from 'react'; +import PropTypes from 'prop-types'; +import useMediaQuery from '@mui/material/useMediaQuery'; +import { useThemeProps } from '@mui/material/styles'; +import refType from '@mui/utils/refType'; +import { DesktopTimeRangePicker } from '../DesktopTimeRangePicker'; +import { MobileTimeRangePicker } from '../MobileTimeRangePicker'; +import { TimeRangePickerProps } from './TimeRangePicker.types'; + +type TimePickerComponent = (( + props: TimeRangePickerProps & + React.RefAttributes, +) => React.JSX.Element) & { propTypes?: any }; + +/** + * Demos: + * + * - [TimeRangePicker](https://mui.com/x/react-date-pickers/time-range-picker/) + * - [Validation](https://mui.com/x/react-date-pickers/validation/) + * + * API: + * + * - [TimeRangePicker API](https://mui.com/x/api/date-pickers/time-range-picker/) + */ +const TimeRangePicker = React.forwardRef(function TimeRangePicker< + TEnableAccessibleFieldDOMStructure extends boolean = true, +>( + inProps: TimeRangePickerProps, + ref: React.Ref, +) { + const props = useThemeProps({ props: inProps, name: 'MuiTimeRangePicker' }); + + const { desktopModeMediaQuery = '@media (pointer: fine)', ...other } = props; + + // defaults to `true` in environments where `window.matchMedia` would not be available (i.e. test/jsdom) + const isDesktop = useMediaQuery(desktopModeMediaQuery, { defaultMatches: true }); + + if (isDesktop) { + return ; + } + + return ; +}) as TimePickerComponent; + +TimeRangePicker.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * 12h/24h view for hour selection clock. + * @default utils.is12HourCycleInCurrentLocale() + */ + ampm: PropTypes.bool, + /** + * If `true`, the main element is focused during the first mount. + * This main element is: + * - the element chosen by the visible view if any (i.e: the selected day on the `day` view). + * - the `input` element if there is a field rendered. + */ + autoFocus: PropTypes.bool, + className: PropTypes.string, + /** + * If `true`, the Picker will close after submitting the full date. + * @default false + */ + closeOnSelect: PropTypes.bool, + /** + * The initial position in the edited date range. + * Used when the component is not controlled. + * @default 'start' + */ + defaultRangePosition: PropTypes.oneOf(['end', 'start']), + /** + * The default value. + * Used when the component is not controlled. + */ + defaultValue: PropTypes.arrayOf(PropTypes.object), + /** + * CSS media query when `Mobile` mode will be changed to `Desktop`. + * @default '@media (pointer: fine)' + * @example '@media (min-width: 720px)' or theme.breakpoints.up("sm") + */ + desktopModeMediaQuery: PropTypes.string, + /** + * If `true`, the component is disabled. + * When disabled, the value cannot be changed and no interaction is possible. + * @default false + */ + disabled: PropTypes.bool, + /** + * If `true`, disable values after the current date for date components, time for time components and both for date time components. + * @default false + */ + disableFuture: PropTypes.bool, + /** + * Do not ignore date part when validating min/max time. + * @default false + */ + disableIgnoringDatePartForTimeValidation: PropTypes.bool, + /** + * If `true`, the open picker button will not be rendered (renders only the field). + * @default false + */ + disableOpenPicker: PropTypes.bool, + /** + * If `true`, disable values before the current date for date components, time for time components and both for date time components. + * @default false + */ + disablePast: PropTypes.bool, + /** + * @default true + */ + enableAccessibleFieldDOMStructure: PropTypes.any, + /** + * Format of the date when rendered in the input(s). + * Defaults to localized format based on the used `views`. + */ + format: PropTypes.string, + /** + * Density of the format when rendered in the input. + * Setting `formatDensity` to `"spacious"` will add a space before and after each `/`, `-` and `.` character. + * @default "dense" + */ + formatDensity: PropTypes.oneOf(['dense', 'spacious']), + /** + * Pass a ref to the `input` element. + * Ignored if the field has several inputs. + */ + inputRef: refType, + /** + * The label content. + * Ignored if the field has several inputs. + */ + label: PropTypes.node, + /** + * Locale for components texts. + * Allows overriding texts coming from `LocalizationProvider` and `theme`. + */ + localeText: PropTypes.object, + /** + * Maximal selectable time. + * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. + */ + maxTime: PropTypes.object, + /** + * Minimal selectable time. + * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. + */ + minTime: PropTypes.object, + /** + * Step over minutes. + * @default 1 + */ + minutesStep: PropTypes.number, + /** + * Name attribute used by the `input` element in the Field. + * Ignored if the field has several inputs. + */ + name: PropTypes.string, + /** + * Callback fired when the value is accepted. + * @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value. + * @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value. + * @param {TValue} value The value that was just accepted. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. + */ + onAccept: PropTypes.func, + /** + * Callback fired when the value changes. + * @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value. + * @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value. + * @param {TValue} value The new value. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. + */ + onChange: PropTypes.func, + /** + * Callback fired when the popup requests to be closed. + * Use in controlled mode (see `open`). + */ + onClose: PropTypes.func, + /** + * Callback fired when the error associated with the current value changes. + * When a validation error is detected, the `error` parameter contains a non-null value. + * This can be used to render an appropriate form error. + * @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value. + * @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value. + * @param {TError} error The reason why the current value is not valid. + * @param {TValue} value The value associated with the error. + */ + onError: PropTypes.func, + /** + * Callback fired when the popup requests to be opened. + * Use in controlled mode (see `open`). + */ + onOpen: PropTypes.func, + /** + * Callback fired when the range position changes. + * @param {RangePosition} rangePosition The new range position. + */ + onRangePositionChange: PropTypes.func, + /** + * Callback fired when the selected sections change. + * @param {FieldSelectedSections} newValue The new selected sections. + */ + onSelectedSectionsChange: PropTypes.func, + /** + * Callback fired on view change. + * @template TView + * @param {TView} view The new view. + */ + onViewChange: PropTypes.func, + /** + * Control the popup or dialog open state. + * @default false + */ + open: PropTypes.bool, + /** + * The default visible view. + * Used when the component view is not controlled. + * Must be a valid option from `views` list. + */ + openTo: PropTypes.oneOf(['hours', 'minutes', 'seconds']), + /** + * The position in the currently edited date range. + * Used when the component position is controlled. + */ + rangePosition: PropTypes.oneOf(['end', 'start']), + /** + * If `true`, the component is read-only. + * When read-only, the value cannot be changed but the user can interact with the interface. + * @default false + */ + readOnly: PropTypes.bool, + /** + * If `true`, disable heavy animations. + * @default `@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13 + */ + reduceAnimations: PropTypes.bool, + /** + * The date used to generate the new value when both `value` and `defaultValue` are empty. + * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. + */ + referenceDate: PropTypes.object, + /** + * The currently selected sections. + * This prop accepts four formats: + * 1. If a number is provided, the section at this index will be selected. + * 2. If a string of type `FieldSectionType` is provided, the first section with that name will be selected. + * 3. If `"all"` is provided, all the sections will be selected. + * 4. If `null` is provided, no section will be selected. + * If not provided, the selected sections will be handled internally. + */ + selectedSections: PropTypes.oneOfType([ + PropTypes.oneOf([ + 'all', + 'day', + 'empty', + 'hours', + 'meridiem', + 'minutes', + 'month', + 'seconds', + 'weekDay', + 'year', + ]), + PropTypes.number, + ]), + /** + * Disable specific time. + * @param {PickerValidDate} value The value to check. + * @param {TimeView} view The clock type of the timeValue. + * @returns {boolean} If `true` the time will be disabled. + */ + shouldDisableTime: PropTypes.func, + /** + * If `true`, disabled digital clock items will not be rendered. + * @default false + */ + skipDisabled: PropTypes.bool, + /** + * 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. + */ + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + /** + * Amount of time options below or at which the single column time renderer is used. + * @default 24 + */ + thresholdToRenderTimeInASingleColumn: PropTypes.number, + /** + * 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, + }), + /** + * Choose which timezone to use for the value. + * Example: "default", "system", "UTC", "America/New_York". + * If you pass values from other timezones to some props, they will be converted to this timezone before being used. + * @see See the {@link https://mui.com/x/react-date-pickers/timezone/ timezones documentation} for more details. + * @default The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise. + */ + timezone: PropTypes.string, + /** + * The selected value. + * Used when the component is controlled. + */ + value: PropTypes.arrayOf(PropTypes.object), + /** + * The visible view. + * Used when the component view is controlled. + * Must be a valid option from `views` list. + */ + view: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']), + /** + * Define custom view renderers for each section. + * If `null`, the section will only have field editing. + * If `undefined`, internally defined view will be the used. + */ + viewRenderers: PropTypes.shape({ + hours: PropTypes.func, + meridiem: PropTypes.func, + minutes: PropTypes.func, + seconds: PropTypes.func, + }), + /** + * Available views. + */ + views: PropTypes.arrayOf(PropTypes.oneOf(['hours', 'minutes', 'seconds']).isRequired), +} as any; + +export { TimeRangePicker }; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts new file mode 100644 index 0000000000000..de30676d8ab0d --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts @@ -0,0 +1,39 @@ +import { + DesktopTimeRangePickerProps, + DesktopTimeRangePickerSlots, + DesktopTimeRangePickerSlotProps, +} from '../DesktopTimeRangePicker'; +import { + MobileTimeRangePickerProps, + MobileTimeRangePickerSlots, + MobileTimeRangePickerSlotProps, +} from '../MobileTimeRangePicker'; + +export interface TimeRangePickerSlots + extends DesktopTimeRangePickerSlots, + MobileTimeRangePickerSlots {} + +export interface TimeRangePickerSlotProps + extends DesktopTimeRangePickerSlotProps, + MobileTimeRangePickerSlotProps {} + +export interface TimeRangePickerProps + extends DesktopTimeRangePickerProps, + Omit, 'views'> { + /** + * CSS media query when `Mobile` mode will be changed to `Desktop`. + * @default '@media (pointer: fine)' + * @example '@media (min-width: 720px)' or theme.breakpoints.up("sm") + */ + desktopModeMediaQuery?: string; + /** + * Overridable component slots. + * @default {} + */ + slots?: TimeRangePickerSlots; + /** + * The props used for each component slot. + * @default {} + */ + slotProps?: TimeRangePickerSlotProps; +} diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx new file mode 100644 index 0000000000000..fe57a2937b5f7 --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx @@ -0,0 +1,165 @@ +'use client'; +import * as React from 'react'; +import clsx from 'clsx'; +import PropTypes from 'prop-types'; +import Tab from '@mui/material/Tab'; +import Tabs, { tabsClasses } from '@mui/material/Tabs'; +import { styled, useThemeProps } from '@mui/material/styles'; +import composeClasses from '@mui/utils/composeClasses'; +import { TimeIcon } from '@mui/x-date-pickers/icons'; +import { ExportedBaseTabsProps } from '@mui/x-date-pickers/internals'; +import { usePickerContext, usePickerTranslations } from '@mui/x-date-pickers/hooks'; +import { + TimeRangePickerTabsClasses, + getTimeRangePickerTabsUtilityClass, +} from './timeRangePickerTabsClasses'; +import { RangePosition } from '../models'; +import { usePickerRangePositionContext } from '../hooks'; + +export interface ExportedTimeRangePickerTabsProps extends ExportedBaseTabsProps { + /** + * Toggles visibility of the tabs allowing view switching. + * @default `window.innerHeight < 667` for `DesktopTimeRangePicker` and `MobileTimeRangePicker`, `displayStaticWrapperAs === 'desktop'` for `StaticTimeRangePicker` + */ + hidden?: boolean; + /** + * Time tab icon. + * @default Time + */ + timeIcon?: React.ReactNode; + /** + * Override or extend the styles applied to the component. + */ + classes?: Partial; +} + +export interface TimeRangePickerTabsProps extends ExportedTimeRangePickerTabsProps {} + +const useUtilityClasses = (classes: Partial | undefined) => { + const slots = { + root: ['root'], + tab: ['tab'], + }; + + return composeClasses(slots, getTimeRangePickerTabsUtilityClass, classes); +}; + +const TimeRangePickerTabsRoot = styled(Tabs, { + name: 'MuiTimeRangePickerTabs', + slot: 'Root', + overridesResolver: (_, styles) => styles.root, +})(({ theme }) => ({ + boxShadow: `0 -1px 0 0 inset ${(theme.vars || theme).palette.divider}`, + '&:last-child': { + boxShadow: `0 1px 0 0 inset ${(theme.vars || theme).palette.divider}`, + [`& .${tabsClasses.indicator}`]: { + bottom: 'auto', + top: 0, + }, + }, +})); + +const TimeRangePickerTab = styled(Tab, { + name: 'MuiTimeRangePickerTabs', + slot: 'Tab', + overridesResolver: (_, styles) => styles.tab, +})(({ theme }) => ({ + minHeight: '48px', + gap: theme.spacing(1), +})); + +/** + * Demos: + * + * - [TimeRangePicker](https://mui.com/x/react-date-pickers/time-range-picker/) + * - [Custom slots and subcomponents](https://mui.com/x/react-date-pickers/custom-components/) + * + * API: + * + * - [TimeRangePickerTabs API](https://mui.com/x/api/date-pickers/time-range-picker-tabs/) + */ +const TimeRangePickerTabs = function TimeRangePickerTabs(inProps: TimeRangePickerTabsProps) { + const props = useThemeProps({ props: inProps, name: 'MuiTimeRangePickerTabs' }); + const { + timeIcon = , + hidden = typeof window === 'undefined' || window.innerHeight < 667, + className, + sx, + classes: classesProp, + } = props; + + const translations = usePickerTranslations(); + const { view, setView } = usePickerContext(); + const { rangePosition, setRangePosition } = usePickerRangePositionContext(); + const classes = useUtilityClasses(classesProp); + + const handleChange = (event: React.SyntheticEvent, value: RangePosition) => { + if (rangePosition !== value) { + setRangePosition(value); + } + if (view !== 'hours') { + setView('hours'); + } + }; + + if (hidden) { + return null; + } + + return ( + + {timeIcon}} + label={translations.start} + className={classes.tab} + /> + {timeIcon}} + className={classes.tab} + /> + + ); +}; + +TimeRangePickerTabs.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * Override or extend the styles applied to the component. + */ + classes: PropTypes.object, + className: PropTypes.string, + /** + * Toggles visibility of the tabs allowing view switching. + * @default `window.innerHeight < 667` for `DesktopTimeRangePicker` and `MobileTimeRangePicker`, `displayStaticWrapperAs === 'desktop'` for `StaticTimeRangePicker` + */ + hidden: PropTypes.bool, + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + /** + * Time tab icon. + * @default Time + */ + timeIcon: PropTypes.node, +} as any; + +export { TimeRangePickerTabs }; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTimeWrapper.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTimeWrapper.tsx new file mode 100644 index 0000000000000..def2e593593fd --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTimeWrapper.tsx @@ -0,0 +1,94 @@ +import { DefaultizedProps } from '@mui/x-internals/types'; +import { + PickerSelectionState, + PickerViewRenderer, + useUtils, + TimeViewWithMeridiem, + BaseClockProps, + PickerRangeValue, + PickerViewsRendererProps, +} from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; +import { isRangeValid } from '../internals/utils/date-utils'; +import { calculateRangeChange } from '../internals/utils/date-range-manager'; +import { usePickerRangePositionContext } from '../hooks'; + +export type TimeRangePickerTimeWrapperProps< + TComponentProps extends DefaultizedProps< + Omit, 'value' | 'defaultValue' | 'onChange'>, + 'views' + >, +> = Omit< + TComponentProps, + 'views' | 'view' | 'onViewChange' | 'value' | 'defaultValue' | 'onChange' +> & { + view: TimeViewWithMeridiem; + onViewChange?: (view: TimeViewWithMeridiem) => void; + views: readonly TimeViewWithMeridiem[]; + value?: PickerRangeValue; + defaultValue?: PickerRangeValue; + onChange?: ( + value: PickerRangeValue, + selectionState: PickerSelectionState, + selectedView: TimeViewWithMeridiem, + ) => void; + viewRenderer: PickerViewRenderer | null; + openTo?: TimeViewWithMeridiem; +}; + +/** + * @ignore - internal component. + */ +function TimeRangePickerTimeWrapper< + TComponentProps extends DefaultizedProps< + Omit, 'value' | 'defaultValue' | 'onChange'>, + 'views' + >, +>(props: TimeRangePickerTimeWrapperProps) { + const utils = useUtils(); + + const { viewRenderer, value, onChange, defaultValue, onViewChange, views, className, ...other } = + props; + + const { rangePosition, setRangePosition } = usePickerRangePositionContext(); + + if (!viewRenderer) { + return null; + } + + const currentValue = (rangePosition === 'start' ? value?.[0] : value?.[1]) ?? null; + const currentDefaultValue = + (rangePosition === 'start' ? defaultValue?.[0] : defaultValue?.[1]) ?? null; + const handleOnChange = ( + newDate: PickerValidDate | null, + selectionState: PickerSelectionState, + selectedView: TimeViewWithMeridiem, + ) => { + if (!onChange || !value) { + return; + } + const { newRange } = calculateRangeChange({ + newDate, + utils, + range: value, + rangePosition, + }); + const isFullRangeSelected = rangePosition === 'end' && isRangeValid(utils, newRange); + if (selectionState === 'finish') { + setRangePosition(rangePosition === 'start' ? 'end' : 'start'); + onViewChange?.(views[0]); + } + onChange(newRange, isFullRangeSelected ? 'finish' : 'partial', selectedView); + }; + + return viewRenderer({ + ...other, + views, + onViewChange, + value: currentValue, + onChange: handleOnChange, + defaultValue: currentDefaultValue, + } as any as PickerViewsRendererProps); +} + +export { TimeRangePickerTimeWrapper }; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx new file mode 100644 index 0000000000000..bd657231f2794 --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -0,0 +1,355 @@ +'use client'; +import * as React from 'react'; +import PropTypes from 'prop-types'; +import clsx from 'clsx'; +import { styled, useThemeProps } from '@mui/material/styles'; +import { unstable_composeClasses as composeClasses } from '@mui/utils'; +import { MakeRequired } from '@mui/x-internals/types'; +import { MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models'; +import { + PickersToolbar, + PickersToolbarButton, + useUtils, + BaseToolbarProps, + ExportedBaseToolbarProps, + PickerVariant, + TimeViewWithMeridiem, + PickersToolbarText, + getMeridiem, + formatMeridiem, + pickersToolbarClasses, + pickersToolbarTextClasses, + PickerRangeValue, + MULTI_SECTION_CLOCK_SECTION_WIDTH, + UseViewsOptions, + useToolbarOwnerState, + PickerToolbarOwnerState, +} from '@mui/x-date-pickers/internals'; +import { usePickerContext, usePickerTranslations } from '@mui/x-date-pickers/hooks'; +import { + TimeRangePickerToolbarClasses, + getTimeRangePickerToolbarUtilityClass, +} from './timeRangePickerToolbarClasses'; +import { usePickerRangePositionContext } from '../hooks'; + +const useUtilityClasses = ( + classes: Partial | undefined, + ownerState: PickerToolbarOwnerState, +) => { + const { pickerVariant } = ownerState; + const slots = { + root: ['root'], + container: ['container', pickerVariant], + separator: ['separator'], + timeContainer: ['timeContainer'], + }; + + return composeClasses(slots, getTimeRangePickerToolbarUtilityClass, classes); +}; + +export interface TimeRangePickerToolbarProps + extends Omit, + ExportedTimeRangePickerToolbarProps { + ampm: boolean; +} + +export interface ExportedTimeRangePickerToolbarProps + extends Omit { + /** + * Override or extend the styles applied to the component. + */ + classes?: Partial; +} + +const TimeRangePickerToolbarRoot = styled(PickersToolbar, { + name: 'MuiTimeRangePickerToolbar', + slot: 'Root', + overridesResolver: (_, styles) => styles.root, +})<{ ownerState: PickerToolbarOwnerState }>(({ theme }) => ({ + borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, + padding: '12px 0px 8px 0px', + [`& .${pickersToolbarClasses.content} .${pickersToolbarTextClasses.root}[data-selected]`]: { + color: (theme.vars || theme).palette.primary.main, + fontWeight: theme.typography.fontWeightBold, + }, + [`& .${pickersToolbarClasses.title}`]: { + paddingLeft: 12, + }, +})); + +const TimeRangePickerToolbarContainer = styled('div', { + name: 'MuiTimeRangePickerToolbar', + slot: 'Container', + shouldForwardProp: (prop) => prop !== 'pickerVariant', + overridesResolver: (_, styles) => styles.container, +})<{ pickerVariant: PickerVariant }>({ + display: 'flex', + flex: 1, + variants: [ + { + props: { pickerVariant: 'mobile' }, + style: { + flexDirection: 'column', + rowGap: 8, + }, + }, + { + props: { pickerVariant: 'desktop' }, + style: { + flexDirection: 'row', + gap: 1, + }, + }, + ], +}); + +const TimeRangePickerToolbarTimeContainer = styled('div', { + name: 'MuiTimeRangePickerToolbar', + slot: 'TimeContainer', + overridesResolver: (_, styles) => styles.timeContainer, +})({ + display: 'flex', + justifyContent: 'space-around', + flex: 1, +}); + +const TimeRangePickerToolbarSeparator = styled(PickersToolbarText, { + name: 'MuiTimeRangePickerToolbar', + slot: 'Separator', + overridesResolver: (props, styles) => styles.separator, +})({ + cursor: 'default', +}); + +type TimeRangePickerToolbarTimeElementProps = Pick< + TimeRangePickerToolbarProps, + 'ampm' | 'toolbarPlaceholder' +> & + MakeRequired< + Pick< + UseViewsOptions, + 'view' | 'views' | 'onViewChange' + >, + 'onViewChange' + > & { + value: PickerValidDate | null; + utils: MuiPickersAdapter; + separatorClasses: string; + pickerVariant: PickerVariant; + }; + +function TimeRangePickerToolbarTimeElement(props: TimeRangePickerToolbarTimeElementProps) { + const { + value, + ampm, + views, + onViewChange, + view, + utils, + separatorClasses, + toolbarPlaceholder, + pickerVariant, + } = props; + + const formatHours = (time: PickerValidDate) => + ampm ? utils.format(time, 'hours12h') : utils.format(time, 'hours24h'); + const meridiemMode = getMeridiem(value, utils); + const sectionWidth = pickerVariant === 'desktop' ? MULTI_SECTION_CLOCK_SECTION_WIDTH : '100%'; + + return ( + + {views.includes('hours') && ( + + onViewChange('hours')} + selected={view === 'hours'} + value={value ? formatHours(value) : toolbarPlaceholder} + /> + + onViewChange('minutes')} + selected={view === 'minutes' || (!views.includes('minutes') && view === 'hours')} + value={value ? utils.format(value, 'minutes') : toolbarPlaceholder} + disabled={!views.includes('minutes')} + /> + + )} + + {views.includes('seconds') && ( + + + onViewChange('seconds')} + selected={view === 'seconds'} + value={value ? utils.format(value, 'seconds') : toolbarPlaceholder} + /> + + )} + + {ampm && ( + onViewChange('meridiem')} + selected={view === 'meridiem'} + value={value && meridiemMode ? formatMeridiem(utils, meridiemMode) : toolbarPlaceholder} + width={sectionWidth} + /> + )} + + ); +} + +TimeRangePickerToolbarTimeElement.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + ampm: PropTypes.bool.isRequired, + /** + * Callback fired on view change. + * @template TView + * @param {TView} view The new view. + */ + onViewChange: PropTypes.func.isRequired, + pickerVariant: PropTypes.oneOf(['desktop', 'mobile']).isRequired, + separatorClasses: PropTypes.string.isRequired, + /** + * Toolbar value placeholder—it is displayed when the value is empty. + * @default "––" + */ + toolbarPlaceholder: PropTypes.node, + utils: PropTypes.object.isRequired, + value: PropTypes.object, + /** + * The visible view. + * Used when the component view is controlled. + * Must be a valid option from `views` list. + */ + view: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']), + /** + * Available views. + */ + views: PropTypes.arrayOf(PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']).isRequired) + .isRequired, +} as any; + +const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar( + inProps: TimeRangePickerToolbarProps, + ref: React.Ref, +) { + const props = useThemeProps({ props: inProps, name: 'MuiTimeRangePickerToolbar' }); + const utils = useUtils(); + + const { className, ampm, toolbarPlaceholder = '--', classes: classesProp, ...other } = props; + + const { value, view, setView, views } = usePickerContext< + PickerRangeValue, + TimeViewWithMeridiem + >(); + const translations = usePickerTranslations(); + const ownerState = useToolbarOwnerState(); + const { rangePosition, setRangePosition } = usePickerRangePositionContext(); + const classes = useUtilityClasses(classesProp, ownerState); + + const handleStartRangeViewChange = React.useCallback( + (newView: TimeViewWithMeridiem) => { + if (rangePosition !== 'start') { + setRangePosition('start'); + } + setView(newView); + }, + [setRangePosition, setView, rangePosition], + ); + + const handleEndRangeViewChange = React.useCallback( + (newView: TimeViewWithMeridiem) => { + if (rangePosition !== 'end') { + setRangePosition('end'); + } + setView(newView); + }, + [setRangePosition, setView, rangePosition], + ); + + if (!view) { + return null; + } + + return ( + + + + + + + ); +}); + +TimeRangePickerToolbar.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + ampm: PropTypes.bool.isRequired, + /** + * Override or extend the styles applied to the component. + */ + classes: PropTypes.object, + className: PropTypes.string, + /** + * If `true`, show the toolbar even in desktop mode. + * @default `true` for Desktop, `false` for Mobile. + */ + hidden: PropTypes.bool, + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + titleId: PropTypes.string, + /** + * Toolbar value placeholder—it is displayed when the value is empty. + * @default "––" + */ + toolbarPlaceholder: PropTypes.node, +} as any; + +export { TimeRangePickerToolbar }; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts b/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts new file mode 100644 index 0000000000000..09dc5b5ca9bbf --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts @@ -0,0 +1,26 @@ +export { TimeRangePicker } from './TimeRangePicker'; +export type { + TimeRangePickerProps, + TimeRangePickerSlots, + TimeRangePickerSlotProps, +} from './TimeRangePicker.types'; + +export { TimeRangePickerTabs } from './TimeRangePickerTabs'; +export type { ExportedTimeRangePickerTabsProps } from './TimeRangePickerTabs'; + +export { + getTimeRangePickerTabsUtilityClass, + timeRangePickerTabsClasses, +} from './timeRangePickerTabsClasses'; +export type { + TimeRangePickerTabsClasses, + TimeRangePickerTabsClassKey, +} from './timeRangePickerTabsClasses'; + +export { TimeRangePickerToolbar } from './TimeRangePickerToolbar'; +export type { TimeRangePickerToolbarProps } from './TimeRangePickerToolbar'; +export { timeRangePickerToolbarClasses } from './timeRangePickerToolbarClasses'; +export type { + TimeRangePickerToolbarClassKey, + TimeRangePickerToolbarClasses, +} from './timeRangePickerToolbarClasses'; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx new file mode 100644 index 0000000000000..6fc48e7d40962 --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx @@ -0,0 +1,191 @@ +import * as React from 'react'; +import { useThemeProps } from '@mui/material/styles'; +import { DefaultizedProps } from '@mui/x-internals/types'; +import { LocalizedComponent, PickersInputLocaleText } from '@mui/x-date-pickers/locales'; +import { TimeStepOptions, TimeView } from '@mui/x-date-pickers/models'; +import { + BasePickerInputProps, + PickerViewRendererLookup, + BaseTimeValidationProps, + BaseClockProps, + ExportedBaseClockProps, + TimeViewWithMeridiem, + useUtils, + applyDefaultViewProps, + resolveTimeViewsResponse, + UseViewsOptions, + PickerRangeValue, + PickerValue, +} from '@mui/x-date-pickers/internals'; +import { TimeClockSlots, TimeClockSlotProps } from '@mui/x-date-pickers/TimeClock'; +import { DigitalClockSlots, DigitalClockSlotProps } from '@mui/x-date-pickers/DigitalClock'; +import { + MultiSectionDigitalClockSlots, + MultiSectionDigitalClockSlotProps, +} from '@mui/x-date-pickers/MultiSectionDigitalClock'; +import { TimeViewRendererProps } from '@mui/x-date-pickers/timeViewRenderers'; +import { + TimeRangePickerToolbar, + TimeRangePickerToolbarProps, + ExportedTimeRangePickerToolbarProps, +} from './TimeRangePickerToolbar'; +import { TimeRangeValidationError } from '../models'; +import { + ExportedTimeRangePickerTabsProps, + TimeRangePickerTabs, + TimeRangePickerTabsProps, +} from './TimeRangePickerTabs'; + +export interface BaseTimeRangePickerSlots + extends TimeClockSlots, + DigitalClockSlots, + MultiSectionDigitalClockSlots { + /** + * Tabs enabling toggling between start and end time. + * @default TimeRangePickerTabs + */ + tabs?: React.ElementType; + /** + * Custom component for the toolbar rendered above the views. + * @default TimeRangePickerToolbar + */ + Toolbar?: React.JSXElementConstructor; +} + +export interface BaseTimeRangePickerSlotProps + extends TimeClockSlotProps, + DigitalClockSlotProps, + MultiSectionDigitalClockSlotProps { + /** + * Props passed down to the tabs component. + */ + tabs?: ExportedTimeRangePickerTabsProps; + /** + * Props passed down to the toolbar component. + */ + toolbar?: ExportedTimeRangePickerToolbarProps; +} + +export type TimeRangePickerRenderers = PickerViewRendererLookup< + PickerValue, + TimeViewWithMeridiem, + TimeViewRendererProps> & { + view: TimeViewWithMeridiem; + } +>; + +export interface BaseTimeRangePickerProps + extends Omit< + BasePickerInputProps, + 'orientation' | 'views' | 'openTo' + >, + ExportedBaseClockProps, + Partial, 'openTo' | 'views'>> { + /** + * Overridable component slots. + * @default {} + */ + slots?: BaseTimeRangePickerSlots; + /** + * The props used for each component slot. + * @default {} + */ + slotProps?: BaseTimeRangePickerSlotProps; + /** + * Define custom view renderers for each section. + * If `null`, the section will only have field editing. + * If `undefined`, internally defined view will be the used. + */ + viewRenderers?: TimeRangePickerRenderers; + /** + * Amount of time options below or at which the single column time renderer is used. + * @default 24 + */ + thresholdToRenderTimeInASingleColumn?: number; + /** + * 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?: TimeStepOptions; +} + +type UseTimeRangePickerDefaultizedProps = + LocalizedComponent< + Omit< + DefaultizedProps, + 'views' + > + > & { + shouldRenderTimeInASingleColumn: boolean; + views: readonly TimeViewWithMeridiem[]; + }; + +export function useTimeRangePickerDefaultizedProps( + props: Props, + name: string, +): UseTimeRangePickerDefaultizedProps { + const utils = useUtils(); + + const themeProps = useThemeProps({ + props, + name, + }); + + const ampm = themeProps.ampm ?? utils.is12HourCycleInCurrentLocale(); + const { openTo, views: defaultViews } = applyDefaultViewProps({ + views: themeProps.views, + openTo: themeProps.openTo, + defaultViews: ['hours', 'minutes'], + defaultOpenTo: 'hours', + }); + + const localeText = React.useMemo(() => { + if (themeProps.localeText?.toolbarTitle == null) { + return themeProps.localeText; + } + + return { + ...themeProps.localeText, + timeRangePickerToolbarTitle: themeProps.localeText.toolbarTitle, + }; + }, [themeProps.localeText]); + + const { + shouldRenderTimeInASingleColumn, + thresholdToRenderTimeInASingleColumn, + views, + timeSteps, + } = resolveTimeViewsResponse({ + thresholdToRenderTimeInASingleColumn: themeProps.thresholdToRenderTimeInASingleColumn, + ampm, + timeSteps: themeProps.timeSteps, + views: defaultViews, + }); + + return { + ...themeProps, + localeText, + timeSteps, + openTo, + shouldRenderTimeInASingleColumn, + thresholdToRenderTimeInASingleColumn, + views, + ampm, + disableFuture: themeProps.disableFuture ?? false, + disablePast: themeProps.disablePast ?? false, + slots: { + tabs: TimeRangePickerTabs, + toolbar: TimeRangePickerToolbar, + ...themeProps.slots, + }, + slotProps: { + ...themeProps.slotProps, + toolbar: { + ampm, + ...themeProps.slotProps?.toolbar, + }, + }, + }; +} diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerTabsClasses.ts b/packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerTabsClasses.ts new file mode 100644 index 0000000000000..d86a762e3307d --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerTabsClasses.ts @@ -0,0 +1,22 @@ +import { + unstable_generateUtilityClass as generateUtilityClass, + unstable_generateUtilityClasses as generateUtilityClasses, +} from '@mui/utils'; + +export interface TimeRangePickerTabsClasses { + /** Styles applied to the root element. */ + root: string; + /** Styles applied to the tab element. */ + tab: string; +} + +export type TimeRangePickerTabsClassKey = keyof TimeRangePickerTabsClasses; + +export function getTimeRangePickerTabsUtilityClass(slot: string) { + return generateUtilityClass('MuiTimeRangePickerTabs', slot); +} + +export const timeRangePickerTabsClasses: TimeRangePickerTabsClasses = generateUtilityClasses( + 'MuiTimeRagePickerTabs', + ['root', 'tab'], +); diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerToolbarClasses.ts b/packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerToolbarClasses.ts new file mode 100644 index 0000000000000..63d9869594cd2 --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerToolbarClasses.ts @@ -0,0 +1,26 @@ +import { + unstable_generateUtilityClass as generateUtilityClass, + unstable_generateUtilityClasses as generateUtilityClasses, +} from '@mui/utils'; + +export interface TimeRangePickerToolbarClasses { + /** Styles applied to the root element. */ + root: string; + /** Styles applied to the container element. */ + container: string; + /** Styles applied to the separator element. */ + separator: string; + /** Styles applied to the time container element. */ + timeContainer: string; +} + +export type TimeRangePickerToolbarClassKey = keyof TimeRangePickerToolbarClasses; + +export function getTimeRangePickerToolbarUtilityClass(slot: string) { + return generateUtilityClass('MuiTimeRangePickerToolbar', slot); +} + +export const timeRangePickerToolbarClasses: TimeRangePickerToolbarClasses = generateUtilityClasses( + 'MuiTimeRangePickerToolbar', + ['root', 'container', 'separator', 'timeContainer'], +); diff --git a/packages/x-date-pickers-pro/src/index.ts b/packages/x-date-pickers-pro/src/index.ts index 64bee4c2ef0e7..616f418d7a0cf 100644 --- a/packages/x-date-pickers-pro/src/index.ts +++ b/packages/x-date-pickers-pro/src/index.ts @@ -19,6 +19,9 @@ export * from './DateRangePicker'; export * from './DesktopDateRangePicker'; export * from './MobileDateRangePicker'; export * from './StaticDateRangePicker'; +export * from './TimeRangePicker'; +export * from './DesktopTimeRangePicker'; +export * from './MobileTimeRangePicker'; export * from './DateTimeRangePicker'; export * from './DesktopDateTimeRangePicker'; diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx index f2daf37e94384..9c4d6d1a722ea 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx @@ -159,7 +159,12 @@ export const useDesktopRangePicker = < > - + prop !== 'itemValue' && prop !== 'formattedValue', overridesResolver: (props, styles) => styles.item, })(({ theme }) => ({ padding: '8px 16px', @@ -345,25 +346,29 @@ export const DigitalClock = React.forwardRef(function DigitalClock( onKeyDown={handleKeyDown} > {timeOptions.map((option, index) => { - if (skipDisabled && isTimeDisabled(option)) { + const optionDisabled = isTimeDisabled(option); + if (skipDisabled && optionDisabled) { return null; } const isSelected = utils.isEqual(option, value); const formattedValue = utils.format(option, ampm ? 'fullTime12h' : 'fullTime24h'); - const tabIndex = - focusedOptionIndex === index || (focusedOptionIndex === -1 && index === 0) ? 0 : -1; + const isFocused = + focusedOptionIndex === index || (focusedOptionIndex === -1 && index === 0); + const tabIndex = isFocused ? 0 : -1; return ( !readOnly && handleItemSelect(option)} selected={isSelected} - disabled={disabled || isTimeDisabled(option)} + disabled={disabled || optionDisabled} disableRipple={readOnly} role="option" // aria-readonly is not supported here and does not have any effect aria-disabled={readOnly} aria-selected={isSelected} tabIndex={tabIndex} + itemValue={option} + formattedValue={formattedValue} {...clockItemProps} > {formattedValue} diff --git a/packages/x-date-pickers/src/DigitalClock/DigitalClock.types.ts b/packages/x-date-pickers/src/DigitalClock/DigitalClock.types.ts index 2e9768dc22a16..d0c753fd7d772 100644 --- a/packages/x-date-pickers/src/DigitalClock/DigitalClock.types.ts +++ b/packages/x-date-pickers/src/DigitalClock/DigitalClock.types.ts @@ -7,7 +7,7 @@ import { DigitalClockOnlyProps, ExportedBaseClockProps, } from '../internals/models/props/time'; -import { PickerOwnerState, TimeView } from '../models'; +import { PickerOwnerState, TimeView, PickerValidDate } from '../models'; export interface ExportedDigitalClockProps extends ExportedBaseClockProps, DigitalClockOnlyProps {} @@ -16,7 +16,7 @@ export interface DigitalClockSlots { * Component responsible for rendering a single digital clock item. * @default MenuItem from '@mui/material' */ - digitalClockItem?: React.ElementType; + digitalClockItem?: React.JSXElementConstructor; } export interface DigitalClockSlotProps { @@ -53,3 +53,14 @@ export interface DigitalClockOwnerState extends PickerOwnerState { */ hasDigitalClockAlreadyBeenRendered: boolean; } + +export interface DigitalClockItemProps { + itemValue: PickerValidDate; + formattedValue: string; + onClick: () => void; + selected: boolean; + disabled: boolean; + readOnly?: boolean; + tabIndex: number; + [x: `data-${string}`]: string; +} diff --git a/packages/x-date-pickers/src/DigitalClock/index.ts b/packages/x-date-pickers/src/DigitalClock/index.ts index c3d13d39b9c6f..12bb8c3e71ada 100644 --- a/packages/x-date-pickers/src/DigitalClock/index.ts +++ b/packages/x-date-pickers/src/DigitalClock/index.ts @@ -1,9 +1,10 @@ -export { DigitalClock } from './DigitalClock'; +export { DigitalClock, DigitalClockItem } from './DigitalClock'; export type { DigitalClockProps, DigitalClockSlots, DigitalClockSlotProps, ExportedDigitalClockProps, + DigitalClockItemProps, } from './DigitalClock.types'; export { digitalClockClasses, getDigitalClockUtilityClass } from './digitalClockClasses'; diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx index 6f1a8e4233303..6fbcc61ee5a08 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx @@ -81,7 +81,7 @@ export const PickersLayoutContentWrapper = styled('div', { slot: 'ContentWrapper', overridesResolver: (props, styles) => styles.contentWrapper, })<{ ownerState: PickerLayoutOwnerState }>({ - gridColumn: 2, + gridColumn: '2 / 4', gridRow: 2, display: 'flex', flexDirection: 'column', diff --git a/packages/x-date-pickers/src/PickersSectionList/PickersSectionList.tsx b/packages/x-date-pickers/src/PickersSectionList/PickersSectionList.tsx index ac7a86aec5881..e8f09faf77a77 100644 --- a/packages/x-date-pickers/src/PickersSectionList/PickersSectionList.tsx +++ b/packages/x-date-pickers/src/PickersSectionList/PickersSectionList.tsx @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import useSlotProps from '@mui/utils/useSlotProps'; import composeClasses from '@mui/utils/composeClasses'; import useForkRef from '@mui/utils/useForkRef'; -import { styled, useThemeProps } from '@mui/material/styles'; +import { styled, useThemeProps, Theme } from '@mui/material/styles'; import { getPickersSectionListUtilityClass, pickersSectionListClasses, @@ -13,6 +13,19 @@ import { import { PickersSectionListProps, PickersSectionElement } from './PickersSectionList.types'; import { usePickerPrivateContext } from '../internals/hooks/usePickerPrivateContext'; +const underlineStyle = (theme: Theme) => ({ + textDecoration: 'underline transparent', + textDecorationThickness: '3px', + textUnderlineOffset: '100%', + transition: theme.transitions.create('all', { + duration: theme.transitions.duration.standard, + }), + [`[data-active-range-position="start"] &[data-range-position="start"], + [data-active-range-position="end"] &[data-range-position="end"]`]: { + textDecorationColor: (theme.vars || theme).palette.primary.main, + }, +}); + export const PickersSectionListRoot = styled('div', { name: 'MuiPickersSectionList', slot: 'Root', @@ -32,17 +45,19 @@ export const PickersSectionListSectionSeparator = styled('span', { name: 'MuiPickersSectionList', slot: 'SectionSeparator', overridesResolver: (props, styles) => styles.sectionSeparator, -})({ +})(({ theme }) => ({ whiteSpace: 'pre', -}); + ...underlineStyle(theme), +})); export const PickersSectionListSectionContent = styled('span', { name: 'MuiPickersSectionList', slot: 'SectionContent', overridesResolver: (props, styles) => styles.sectionContent, -})({ +})(({ theme }) => ({ outline: 'none', -}); + ...underlineStyle(theme), +})); const useUtilityClasses = (classes: Partial | undefined) => { const slots = { diff --git a/packages/x-date-pickers/src/internals/components/PickersToolbar.tsx b/packages/x-date-pickers/src/internals/components/PickersToolbar.tsx index b956c7d4e3ecf..e3643de9af5b3 100644 --- a/packages/x-date-pickers/src/internals/components/PickersToolbar.tsx +++ b/packages/x-date-pickers/src/internals/components/PickersToolbar.tsx @@ -18,6 +18,7 @@ export interface PickersToolbarProps extends Pick | undefined) => { const slots = { root: ['root'], + title: ['title'], content: ['content'], }; @@ -123,6 +124,7 @@ export const PickersToolbar = React.forwardRef(function PickersToolbar( color="text.secondary" variant="overline" id={titleId} + className={classes.title} > {toolbarTitle} diff --git a/packages/x-date-pickers/src/internals/components/PickersToolbarButton.tsx b/packages/x-date-pickers/src/internals/components/PickersToolbarButton.tsx index 5cd25185bd47f..1cfe9f933ea75 100644 --- a/packages/x-date-pickers/src/internals/components/PickersToolbarButton.tsx +++ b/packages/x-date-pickers/src/internals/components/PickersToolbarButton.tsx @@ -16,7 +16,7 @@ export interface PickersToolbarButtonProps extends ExtendMui; - width?: number; + width?: number | string; } const useUtilityClasses = (classes: Partial | undefined) => { diff --git a/packages/x-date-pickers/src/internals/components/pickersToolbarClasses.ts b/packages/x-date-pickers/src/internals/components/pickersToolbarClasses.ts index 09ecae7d30cee..ed84de81ef44d 100644 --- a/packages/x-date-pickers/src/internals/components/pickersToolbarClasses.ts +++ b/packages/x-date-pickers/src/internals/components/pickersToolbarClasses.ts @@ -6,6 +6,8 @@ import { export interface PickersToolbarClasses { /** Styles applied to the root element. */ root: string; + /** Styles applied to the title element. */ + title: string; /** Styles applied to the content element. */ content: string; } @@ -18,5 +20,6 @@ export function getPickersToolbarUtilityClass(slot: string) { export const pickersToolbarClasses = generateUtilityClasses('MuiPickersToolbar', [ 'root', + 'title', 'content', ]); diff --git a/packages/x-date-pickers/src/internals/components/pickersToolbarTextClasses.ts b/packages/x-date-pickers/src/internals/components/pickersToolbarTextClasses.ts index 1ba8c4341fa01..0440c927650d3 100644 --- a/packages/x-date-pickers/src/internals/components/pickersToolbarTextClasses.ts +++ b/packages/x-date-pickers/src/internals/components/pickersToolbarTextClasses.ts @@ -6,8 +6,6 @@ import { export interface PickersToolbarTextClasses { /** Styles applied to the root element. */ root: string; - /** Styles applied to a selected root element. */ - selected: string; } export type PickersToolbarTextClassKey = keyof PickersToolbarTextClasses; @@ -16,7 +14,4 @@ export function getPickersToolbarTextUtilityClass(slot: string) { return generateUtilityClass('MuiPickersToolbarText', slot); } -export const pickersToolbarTextClasses = generateUtilityClasses('MuiPickersToolbarText', [ - 'root', - 'selected', -]); +export const pickersToolbarTextClasses = generateUtilityClasses('MuiPickersToolbarText', ['root']); diff --git a/packages/x-date-pickers/src/internals/hooks/useField/buildSectionsFromFormat.ts b/packages/x-date-pickers/src/internals/hooks/useField/buildSectionsFromFormat.ts index e4022303b6eea..36b0d59eb48b4 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/buildSectionsFromFormat.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/buildSectionsFromFormat.ts @@ -244,6 +244,7 @@ const buildSections = ( startSeparator += char; } else { sections[sections.length - 1].endSeparator += char; + sections[sections.length - 1].isEndFormatSeparator = true; } } diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useFieldV7TextField.ts b/packages/x-date-pickers/src/internals/hooks/useField/useFieldV7TextField.ts index d59c2ceea4adb..d9056a776482e 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useFieldV7TextField.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useFieldV7TextField.ts @@ -13,6 +13,7 @@ import { getActiveElement } from '../../utils/utils'; import { PickersSectionElement, PickersSectionListRef } from '../../../PickersSectionList'; import { usePickerTranslations } from '../../../hooks/usePickerTranslations'; import { useUtils } from '../useUtils'; +import { FieldRangeSection } from '../../models'; export const useFieldV7TextField: UseFieldTextField = (params) => { const { @@ -421,6 +422,7 @@ export const useFieldV7TextField: UseFieldTextField = (params) => { const elements = React.useMemo(() => { return state.sections.map((section, index) => { const isEditable = !isContainerEditable && !disabled && !readOnly; + const dateRangePosition = (section as FieldRangeSection).dateName || undefined; return { container: { 'data-sectionindex': index, @@ -431,6 +433,7 @@ export const useFieldV7TextField: UseFieldTextField = (params) => { contentEditable: !isContainerEditable && !disabled && !readOnly, role: 'spinbutton', id: `${id}-${section.type}`, + 'data-range-position': dateRangePosition, 'aria-labelledby': `${id}-${section.type}`, 'aria-readonly': readOnly, 'aria-valuenow': getSectionValueNow(section, utils), @@ -460,6 +463,7 @@ export const useFieldV7TextField: UseFieldTextField = (params) => { }, after: { children: section.endSeparator, + 'data-range-position': section.isEndFormatSeparator ? dateRangePosition : undefined, }, }; }); diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index c4a78126f6fe0..e578a37357d2d 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -40,6 +40,7 @@ export type { PickersToolbarButtonClassKey, PickersToolbarButtonClasses, } from './components/pickersToolbarButtonClasses'; +export { PickersToolbarText } from './components/PickersToolbarText'; export type { PickersToolbarTextProps, ExportedPickersToolbarTextProps, @@ -56,7 +57,12 @@ export type { } from './components/PickersArrowSwitcher/pickersArrowSwitcherClasses'; export { PickersToolbarButton } from './components/PickersToolbarButton'; -export { DAY_MARGIN, DIALOG_WIDTH, VIEW_HEIGHT } from './constants/dimensions'; +export { + DAY_MARGIN, + DIALOG_WIDTH, + VIEW_HEIGHT, + MULTI_SECTION_CLOCK_SECTION_WIDTH, +} from './constants/dimensions'; export { useControlledValueWithTimezone } from './hooks/useValueWithTimezone'; export type { DesktopOnlyPickerProps } from './hooks/useDesktopPicker'; @@ -121,7 +127,12 @@ export type { export type { RangePosition } from './models/pickers'; export type { BaseSingleInputFieldProps, FieldRangeSection } from './models/fields'; export type { BasePickerProps, BasePickerInputProps } from './models/props/basePickerProps'; -export type { BaseClockProps, DesktopOnlyTimePickerProps, AmPmProps } from './models/props/time'; +export type { + BaseClockProps, + ExportedBaseClockProps, + DesktopOnlyTimePickerProps, + AmPmProps, +} from './models/props/time'; export type { ExportedBaseTabsProps } from './models/props/tabs'; export type { BaseToolbarProps, ExportedBaseToolbarProps } from './models/props/toolbar'; export type { FormProps } from './models/formProps'; @@ -156,8 +167,9 @@ export { mergeDateAndTime, formatMeridiem, } from './utils/date-utils'; -export { resolveTimeViewsResponse, resolveDateTimeFormat } from './utils/date-time-utils'; export { getDefaultReferenceDate } from './utils/getDefaultReferenceDate'; +export { isTimeView, isInternalTimeView, resolveTimeFormat, getMeridiem } from './utils/time-utils'; +export { resolveTimeViewsResponse, resolveDateTimeFormat } from './utils/date-time-utils'; export { executeInTheNextEventLoopTick, getActiveElement, @@ -179,8 +191,6 @@ export type { export type { ExportedDateCalendarProps } from '../DateCalendar/DateCalendar.types'; export { useCalendarState } from '../DateCalendar/useCalendarState'; -export { isInternalTimeView, isTimeView } from './utils/time-utils'; - export { DateTimePickerToolbarOverrideContext } from '../DateTimePicker/DateTimePickerToolbar'; export { getDateFieldInternalPropsDefaults } from '../managers/useDateManager'; diff --git a/packages/x-date-pickers/src/internals/utils/time-utils.ts b/packages/x-date-pickers/src/internals/utils/time-utils.ts index b833de786fb77..a94ab2c73cd63 100644 --- a/packages/x-date-pickers/src/internals/utils/time-utils.ts +++ b/packages/x-date-pickers/src/internals/utils/time-utils.ts @@ -1,4 +1,4 @@ -import { MuiPickersAdapter, PickerValidDate, TimeView } from '../../models'; +import { MuiPickersAdapter, PickerValidDate } from '../../models'; import { DateOrTimeViewWithMeridiem, TimeViewWithMeridiem } from '../models'; import { areViewsEqual } from './views'; @@ -59,7 +59,11 @@ export const createIsAfterIgnoreDatePart = export const resolveTimeFormat = ( utils: MuiPickersAdapter, - { format, views, ampm }: { format?: string; views: readonly TimeView[]; ampm: boolean }, + { + format, + views, + ampm, + }: { format?: string; views: readonly TimeViewWithMeridiem[]; ampm: boolean }, ) => { if (format != null) { return format; diff --git a/packages/x-date-pickers/src/internals/utils/views.ts b/packages/x-date-pickers/src/internals/utils/views.ts index eec21b1bf666a..b56f0b3db5d2d 100644 --- a/packages/x-date-pickers/src/internals/utils/views.ts +++ b/packages/x-date-pickers/src/internals/utils/views.ts @@ -1,8 +1,7 @@ -import { DateOrTimeView } from '../../models'; import { DateOrTimeViewWithMeridiem } from '../models'; -export const areViewsEqual = ( - views: ReadonlyArray, +export const areViewsEqual = ( + views: ReadonlyArray, expectedViews: TView[], ): views is ReadonlyArray => { if (views.length !== expectedViews.length) { diff --git a/packages/x-date-pickers/src/locales/beBY.ts b/packages/x-date-pickers/src/locales/beBY.ts index ffd1ad340b2c6..a7cfb3d61bc5b 100644 --- a/packages/x-date-pickers/src/locales/beBY.ts +++ b/packages/x-date-pickers/src/locales/beBY.ts @@ -42,6 +42,7 @@ const beBYPickers: Partial = { dateTimePickerToolbarTitle: 'Абраць дату і час', timePickerToolbarTitle: 'Абраць час', dateRangePickerToolbarTitle: 'Абраць каляндарны перыяд', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/bgBG.ts b/packages/x-date-pickers/src/locales/bgBG.ts index d0bdc22949fa3..06e69784550d5 100644 --- a/packages/x-date-pickers/src/locales/bgBG.ts +++ b/packages/x-date-pickers/src/locales/bgBG.ts @@ -41,6 +41,7 @@ const bgBGPickers: Partial = { dateTimePickerToolbarTitle: 'Избери дата и час', timePickerToolbarTitle: 'Избери час', dateRangePickerToolbarTitle: 'Избери времеви период', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/caES.ts b/packages/x-date-pickers/src/locales/caES.ts index 15b212206d21d..73f3a2a1b614a 100644 --- a/packages/x-date-pickers/src/locales/caES.ts +++ b/packages/x-date-pickers/src/locales/caES.ts @@ -41,6 +41,7 @@ const caESPickers: Partial = { dateTimePickerToolbarTitle: 'Seleccionar data i hora', timePickerToolbarTitle: 'Seleccionar hora', dateRangePickerToolbarTitle: 'Seleccionar rang de dates', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/csCZ.ts b/packages/x-date-pickers/src/locales/csCZ.ts index 1c8542f2a1db8..5127d2dbe7eb6 100644 --- a/packages/x-date-pickers/src/locales/csCZ.ts +++ b/packages/x-date-pickers/src/locales/csCZ.ts @@ -42,6 +42,7 @@ const csCZPickers: Partial = { dateTimePickerToolbarTitle: 'Vyberte datum a čas', timePickerToolbarTitle: 'Vyberte čas', dateRangePickerToolbarTitle: 'Vyberete rozmezí dat', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/daDK.ts b/packages/x-date-pickers/src/locales/daDK.ts index 6032cec2aa9a0..f788b8e41ad08 100644 --- a/packages/x-date-pickers/src/locales/daDK.ts +++ b/packages/x-date-pickers/src/locales/daDK.ts @@ -42,6 +42,7 @@ const daDKPickers: Partial = { dateTimePickerToolbarTitle: 'Vælg dato & tidspunkt', timePickerToolbarTitle: 'Vælg tidspunkt', dateRangePickerToolbarTitle: 'Vælg datointerval', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/deDE.ts b/packages/x-date-pickers/src/locales/deDE.ts index b0f492771c02f..b7b664653f312 100644 --- a/packages/x-date-pickers/src/locales/deDE.ts +++ b/packages/x-date-pickers/src/locales/deDE.ts @@ -42,6 +42,7 @@ const deDEPickers: Partial = { dateTimePickerToolbarTitle: 'Datum & Uhrzeit auswählen', timePickerToolbarTitle: 'Uhrzeit auswählen', dateRangePickerToolbarTitle: 'Datumsbereich auswählen', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/elGR.ts b/packages/x-date-pickers/src/locales/elGR.ts index 2effab12a415c..b7812c487ce6f 100644 --- a/packages/x-date-pickers/src/locales/elGR.ts +++ b/packages/x-date-pickers/src/locales/elGR.ts @@ -41,6 +41,7 @@ const elGRPickers: Partial = { dateTimePickerToolbarTitle: 'Επιλέξτε ημερομηνία και ώρα', timePickerToolbarTitle: 'Επιλέξτε ώρα', dateRangePickerToolbarTitle: 'Επιλέξτε εύρος ημερομηνιών', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/enUS.ts b/packages/x-date-pickers/src/locales/enUS.ts index 488a0681602f6..48b69a7b98745 100644 --- a/packages/x-date-pickers/src/locales/enUS.ts +++ b/packages/x-date-pickers/src/locales/enUS.ts @@ -35,6 +35,7 @@ const enUSPickers: PickersLocaleText = { dateTimePickerToolbarTitle: 'Select date & time', timePickerToolbarTitle: 'Select time', dateRangePickerToolbarTitle: 'Select date range', + timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/esES.ts b/packages/x-date-pickers/src/locales/esES.ts index 4ae68d056781b..a36f79e35a046 100644 --- a/packages/x-date-pickers/src/locales/esES.ts +++ b/packages/x-date-pickers/src/locales/esES.ts @@ -41,6 +41,7 @@ const esESPickers: Partial = { dateTimePickerToolbarTitle: 'Seleccionar fecha y hora', timePickerToolbarTitle: 'Seleccionar hora', dateRangePickerToolbarTitle: 'Seleccionar rango de fecha', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/eu.ts b/packages/x-date-pickers/src/locales/eu.ts index 532c9ff4685cb..55748271d8533 100644 --- a/packages/x-date-pickers/src/locales/eu.ts +++ b/packages/x-date-pickers/src/locales/eu.ts @@ -41,6 +41,7 @@ const euPickers: Partial = { dateTimePickerToolbarTitle: 'Data eta ordua aukeratu', timePickerToolbarTitle: 'Ordua aukeratu', dateRangePickerToolbarTitle: 'Data tartea aukeratu', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/faIR.ts b/packages/x-date-pickers/src/locales/faIR.ts index e5f64dc0bc1e2..a3b70e0ed696f 100644 --- a/packages/x-date-pickers/src/locales/faIR.ts +++ b/packages/x-date-pickers/src/locales/faIR.ts @@ -41,6 +41,7 @@ const faIRPickers: Partial = { dateTimePickerToolbarTitle: 'تاریخ و ساعت را انتخاب کنید', timePickerToolbarTitle: 'ساعت را انتخاب کنید', dateRangePickerToolbarTitle: 'محدوده تاریخ را انتخاب کنید', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/fiFI.ts b/packages/x-date-pickers/src/locales/fiFI.ts index 104d5e343ccb0..cb0652d571ea7 100644 --- a/packages/x-date-pickers/src/locales/fiFI.ts +++ b/packages/x-date-pickers/src/locales/fiFI.ts @@ -41,6 +41,7 @@ const fiFIPickers: Partial = { dateTimePickerToolbarTitle: 'Valitse päivä ja aika', timePickerToolbarTitle: 'Valitse aika', dateRangePickerToolbarTitle: 'Valitse aikaväli', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/frFR.ts b/packages/x-date-pickers/src/locales/frFR.ts index 0c80ccbcc8383..587dde7fcca4e 100644 --- a/packages/x-date-pickers/src/locales/frFR.ts +++ b/packages/x-date-pickers/src/locales/frFR.ts @@ -41,6 +41,7 @@ const frFRPickers: Partial = { dateTimePickerToolbarTitle: "Choisir la date et l'heure", timePickerToolbarTitle: "Choisir l'heure", dateRangePickerToolbarTitle: 'Choisir la plage de dates', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/heIL.ts b/packages/x-date-pickers/src/locales/heIL.ts index ed3adcef3f4bc..00d6c8af6a4c6 100644 --- a/packages/x-date-pickers/src/locales/heIL.ts +++ b/packages/x-date-pickers/src/locales/heIL.ts @@ -41,6 +41,7 @@ const heILPickers: Partial = { dateTimePickerToolbarTitle: 'בחירת תאריך ושעה', timePickerToolbarTitle: 'בחירת שעה', dateRangePickerToolbarTitle: 'בחירת טווח תאריכים', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/hrHR.ts b/packages/x-date-pickers/src/locales/hrHR.ts index c1a276282387d..83300d32fce02 100644 --- a/packages/x-date-pickers/src/locales/hrHR.ts +++ b/packages/x-date-pickers/src/locales/hrHR.ts @@ -42,6 +42,7 @@ const hrHRPickers: Partial = { dateTimePickerToolbarTitle: 'Odaberi datum i vrijeme', timePickerToolbarTitle: 'Odaberi vrijeme', dateRangePickerToolbarTitle: 'Odaberi vremenski okvir', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/huHU.ts b/packages/x-date-pickers/src/locales/huHU.ts index 5852e7539d5d0..69af4f171d4c0 100644 --- a/packages/x-date-pickers/src/locales/huHU.ts +++ b/packages/x-date-pickers/src/locales/huHU.ts @@ -42,6 +42,7 @@ const huHUPickers: Partial = { dateTimePickerToolbarTitle: 'Dátum és idő kiválasztása', timePickerToolbarTitle: 'Idő kiválasztása', dateRangePickerToolbarTitle: 'Dátumhatárok kiválasztása', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/isIS.ts b/packages/x-date-pickers/src/locales/isIS.ts index 7484608914db3..0d92255eb2efd 100644 --- a/packages/x-date-pickers/src/locales/isIS.ts +++ b/packages/x-date-pickers/src/locales/isIS.ts @@ -41,6 +41,7 @@ const isISPickers: Partial = { dateTimePickerToolbarTitle: 'Velja dagsetningu og tíma', timePickerToolbarTitle: 'Velja tíma', dateRangePickerToolbarTitle: 'Velja tímabil', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/itIT.ts b/packages/x-date-pickers/src/locales/itIT.ts index 570e6e905fe53..0401cf0063288 100644 --- a/packages/x-date-pickers/src/locales/itIT.ts +++ b/packages/x-date-pickers/src/locales/itIT.ts @@ -41,6 +41,7 @@ const itITPickers: Partial = { dateTimePickerToolbarTitle: 'Seleziona data e orario', timePickerToolbarTitle: 'Seleziona orario', dateRangePickerToolbarTitle: 'Seleziona intervallo di date', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/jaJP.ts b/packages/x-date-pickers/src/locales/jaJP.ts index e76438b6164ae..5fbc7edea4920 100644 --- a/packages/x-date-pickers/src/locales/jaJP.ts +++ b/packages/x-date-pickers/src/locales/jaJP.ts @@ -42,6 +42,7 @@ const jaJPPickers: Partial = { dateTimePickerToolbarTitle: '日時を選択', timePickerToolbarTitle: '時間を選択', dateRangePickerToolbarTitle: '日付の範囲を選択', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/koKR.ts b/packages/x-date-pickers/src/locales/koKR.ts index 52ff53f41fa6d..91f1e66a6c9d7 100644 --- a/packages/x-date-pickers/src/locales/koKR.ts +++ b/packages/x-date-pickers/src/locales/koKR.ts @@ -41,6 +41,7 @@ const koKRPickers: Partial = { dateTimePickerToolbarTitle: '날짜 & 시간 선택하기', timePickerToolbarTitle: '시간 선택하기', dateRangePickerToolbarTitle: '날짜 범위 선택하기', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/kzKZ.ts b/packages/x-date-pickers/src/locales/kzKZ.ts index 1205ba488073e..eaa3b51a23367 100644 --- a/packages/x-date-pickers/src/locales/kzKZ.ts +++ b/packages/x-date-pickers/src/locales/kzKZ.ts @@ -42,6 +42,7 @@ const kzKZPickers: Partial = { dateTimePickerToolbarTitle: 'Күн мен уақытты таңдау', timePickerToolbarTitle: 'Уақытты таңдау', dateRangePickerToolbarTitle: 'Кезеңді таңдаңыз', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/mk.ts b/packages/x-date-pickers/src/locales/mk.ts index bc76dbabce879..889135808d6d8 100644 --- a/packages/x-date-pickers/src/locales/mk.ts +++ b/packages/x-date-pickers/src/locales/mk.ts @@ -35,6 +35,7 @@ const mkPickers: Partial = { dateTimePickerToolbarTitle: 'Избери датум и време', timePickerToolbarTitle: 'Избери време', dateRangePickerToolbarTitle: 'Избери временски опсег', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/nbNO.ts b/packages/x-date-pickers/src/locales/nbNO.ts index 1df1b24bcda5f..6d6c0a70d5fc0 100644 --- a/packages/x-date-pickers/src/locales/nbNO.ts +++ b/packages/x-date-pickers/src/locales/nbNO.ts @@ -41,6 +41,7 @@ const nbNOPickers: Partial = { dateTimePickerToolbarTitle: 'Velg dato & klokkeslett', timePickerToolbarTitle: 'Velg klokkeslett', dateRangePickerToolbarTitle: 'Velg datoperiode', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/nlNL.ts b/packages/x-date-pickers/src/locales/nlNL.ts index 18de679b02f4e..1281d5498245d 100644 --- a/packages/x-date-pickers/src/locales/nlNL.ts +++ b/packages/x-date-pickers/src/locales/nlNL.ts @@ -41,6 +41,7 @@ const nlNLPickers: Partial = { dateTimePickerToolbarTitle: 'Selecteer datum & tijd', timePickerToolbarTitle: 'Selecteer tijd', dateRangePickerToolbarTitle: 'Selecteer datumbereik', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/nnNO.ts b/packages/x-date-pickers/src/locales/nnNO.ts index b801559149581..5a12527d59a6b 100644 --- a/packages/x-date-pickers/src/locales/nnNO.ts +++ b/packages/x-date-pickers/src/locales/nnNO.ts @@ -41,6 +41,7 @@ const nnNOPickers: Partial = { dateTimePickerToolbarTitle: 'Vel dato & klokkeslett', timePickerToolbarTitle: 'Vel klokkeslett', dateRangePickerToolbarTitle: 'Vel datoperiode', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/plPL.ts b/packages/x-date-pickers/src/locales/plPL.ts index 7c8e92d64479d..7baa52e28520c 100644 --- a/packages/x-date-pickers/src/locales/plPL.ts +++ b/packages/x-date-pickers/src/locales/plPL.ts @@ -41,6 +41,7 @@ const plPLPickers: Partial = { dateTimePickerToolbarTitle: 'Wybierz datę i czas', timePickerToolbarTitle: 'Wybierz czas', dateRangePickerToolbarTitle: 'Wybierz zakres dat', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/ptBR.ts b/packages/x-date-pickers/src/locales/ptBR.ts index 2f78696135fa3..2cfa858d0d290 100644 --- a/packages/x-date-pickers/src/locales/ptBR.ts +++ b/packages/x-date-pickers/src/locales/ptBR.ts @@ -41,6 +41,7 @@ const ptBRPickers: Partial = { dateTimePickerToolbarTitle: 'Selecione data e hora', timePickerToolbarTitle: 'Selecione a hora', dateRangePickerToolbarTitle: 'Selecione o intervalo entre datas', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/ptPT.ts b/packages/x-date-pickers/src/locales/ptPT.ts index 0432c7f5821a2..9ed9e5776f4e0 100644 --- a/packages/x-date-pickers/src/locales/ptPT.ts +++ b/packages/x-date-pickers/src/locales/ptPT.ts @@ -41,6 +41,7 @@ const ptPTPickers: Partial = { dateTimePickerToolbarTitle: 'Selecione a data e a hora', timePickerToolbarTitle: 'Selecione a hora', dateRangePickerToolbarTitle: 'Selecione o intervalo de datas', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/roRO.ts b/packages/x-date-pickers/src/locales/roRO.ts index a48ecad511185..01afb0e21eda6 100644 --- a/packages/x-date-pickers/src/locales/roRO.ts +++ b/packages/x-date-pickers/src/locales/roRO.ts @@ -42,6 +42,7 @@ const roROPickers: Partial = { dateTimePickerToolbarTitle: 'Selectați data și ora', timePickerToolbarTitle: 'Selectați ora', dateRangePickerToolbarTitle: 'Selectați intervalul de date', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/ruRU.ts b/packages/x-date-pickers/src/locales/ruRU.ts index 58292619984d9..d5f06e5b3e1f6 100644 --- a/packages/x-date-pickers/src/locales/ruRU.ts +++ b/packages/x-date-pickers/src/locales/ruRU.ts @@ -42,6 +42,7 @@ const ruRUPickers: Partial = { dateTimePickerToolbarTitle: 'Выбрать дату и время', timePickerToolbarTitle: 'Выбрать время', dateRangePickerToolbarTitle: 'Выбрать период', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/skSK.ts b/packages/x-date-pickers/src/locales/skSK.ts index f8d7a4a30016d..e2867ad8f561d 100644 --- a/packages/x-date-pickers/src/locales/skSK.ts +++ b/packages/x-date-pickers/src/locales/skSK.ts @@ -42,6 +42,7 @@ const skSKPickers: Partial = { dateTimePickerToolbarTitle: 'Vyberte dátum a čas', timePickerToolbarTitle: 'Vyberte čas', dateRangePickerToolbarTitle: 'Vyberete rozmedzie dátumov', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/svSE.ts b/packages/x-date-pickers/src/locales/svSE.ts index 31c1c70bf3192..2dee9203e83d4 100644 --- a/packages/x-date-pickers/src/locales/svSE.ts +++ b/packages/x-date-pickers/src/locales/svSE.ts @@ -41,6 +41,7 @@ const svSEPickers: Partial = { dateTimePickerToolbarTitle: 'Välj datum & tid', timePickerToolbarTitle: 'Välj tid', dateRangePickerToolbarTitle: 'Välj datumintervall', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/trTR.ts b/packages/x-date-pickers/src/locales/trTR.ts index 567e42a178300..ed7a8bb6235b7 100644 --- a/packages/x-date-pickers/src/locales/trTR.ts +++ b/packages/x-date-pickers/src/locales/trTR.ts @@ -41,6 +41,7 @@ const trTRPickers: Partial = { dateTimePickerToolbarTitle: 'Tarih & Saat seç', timePickerToolbarTitle: 'Saat seç', dateRangePickerToolbarTitle: 'Tarih aralığı seçin', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/ukUA.ts b/packages/x-date-pickers/src/locales/ukUA.ts index f03f891384083..c896564b76139 100644 --- a/packages/x-date-pickers/src/locales/ukUA.ts +++ b/packages/x-date-pickers/src/locales/ukUA.ts @@ -41,6 +41,7 @@ const ukUAPickers: Partial = { dateTimePickerToolbarTitle: 'Вибрати дату і час', timePickerToolbarTitle: 'Вибрати час', dateRangePickerToolbarTitle: 'Вибрати календарний період', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/urPK.ts b/packages/x-date-pickers/src/locales/urPK.ts index d23d5e37a6da0..e1c5a328f591d 100644 --- a/packages/x-date-pickers/src/locales/urPK.ts +++ b/packages/x-date-pickers/src/locales/urPK.ts @@ -41,6 +41,7 @@ const urPKPickers: Partial = { dateTimePickerToolbarTitle: 'تاریخ اور وقت منتخب کریں', timePickerToolbarTitle: 'وقت منتخب کریں', dateRangePickerToolbarTitle: 'تاریخوں کی رینج منتخب کریں', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts index 902aa019f149a..b7582e073ff94 100644 --- a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts +++ b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts @@ -22,6 +22,11 @@ export interface PickersComponentSpecificLocaleText { * Will be overridden by the `toolbarTitle` translation key passed directly on the picker. */ dateRangePickerToolbarTitle: string; + /** + * Title displayed in the toolbar of the `TimeRangePicker` and its variants. + * Will be overridden by the `toolbarTitle` translation key passed directly on the picker. + */ + timeRangePickerToolbarTitle: string; } export interface PickersComponentAgnosticLocaleText { diff --git a/packages/x-date-pickers/src/locales/viVN.ts b/packages/x-date-pickers/src/locales/viVN.ts index a13d883b082a0..740e4b34a030b 100644 --- a/packages/x-date-pickers/src/locales/viVN.ts +++ b/packages/x-date-pickers/src/locales/viVN.ts @@ -41,6 +41,7 @@ const viVNPickers: Partial = { dateTimePickerToolbarTitle: 'Chọn ngày và giờ', timePickerToolbarTitle: 'Chọn giờ', dateRangePickerToolbarTitle: 'Chọn khoảng ngày', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/zhCN.ts b/packages/x-date-pickers/src/locales/zhCN.ts index d4202d7195359..1b278453849f2 100644 --- a/packages/x-date-pickers/src/locales/zhCN.ts +++ b/packages/x-date-pickers/src/locales/zhCN.ts @@ -39,6 +39,7 @@ const zhCNPickers: Partial = { dateTimePickerToolbarTitle: '选择日期和时间', timePickerToolbarTitle: '选择时间', dateRangePickerToolbarTitle: '选择时间范围', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/zhHK.ts b/packages/x-date-pickers/src/locales/zhHK.ts index d676789838737..43bc4c879b43a 100644 --- a/packages/x-date-pickers/src/locales/zhHK.ts +++ b/packages/x-date-pickers/src/locales/zhHK.ts @@ -39,6 +39,7 @@ const zhHKPickers: Partial = { dateTimePickerToolbarTitle: '選擇日期和時間', timePickerToolbarTitle: '選擇時間', dateRangePickerToolbarTitle: '選擇時間範圍', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/locales/zhTW.ts b/packages/x-date-pickers/src/locales/zhTW.ts index 2c85c8c0bd518..28e844191b481 100644 --- a/packages/x-date-pickers/src/locales/zhTW.ts +++ b/packages/x-date-pickers/src/locales/zhTW.ts @@ -39,6 +39,7 @@ const zhTWPickers: Partial = { dateTimePickerToolbarTitle: '選擇日期和時間', timePickerToolbarTitle: '選擇時間', dateRangePickerToolbarTitle: '選擇時間範圍', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index 2002619cb4e25..05d47a5db5355 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -87,6 +87,10 @@ export interface FieldSection { * For example, on Day.js, the `year` section of the format `[year] YYYY` has a start separator equal to `[year]` */ endSeparator: string; + /** + * If `true`, the `endSeparator` is a format separator (i.e. ":" or "/"). + */ + isEndFormatSeparator?: boolean; } // If `PickerValidDate` contains `any`, then `TValue extends PickerRangeValue` will return true, so we have to handle this edge case first. diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index 9b2c60de65c17..38b8ceacd6a3e 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -139,10 +139,16 @@ { "name": "DesktopTimePickerProps", "kind": "Interface" }, { "name": "DesktopTimePickerSlotProps", "kind": "Interface" }, { "name": "DesktopTimePickerSlots", "kind": "Interface" }, + { "name": "DesktopTimeRangePicker", "kind": "Variable" }, + { "name": "DesktopTimeRangePickerProps", "kind": "Interface" }, + { "name": "DesktopTimeRangePickerSlotProps", "kind": "Interface" }, + { "name": "DesktopTimeRangePickerSlots", "kind": "Interface" }, { "name": "DigitalClock", "kind": "Variable" }, { "name": "digitalClockClasses", "kind": "Variable" }, { "name": "DigitalClockClasses", "kind": "Interface" }, { "name": "DigitalClockClassKey", "kind": "TypeAlias" }, + { "name": "DigitalClockItem", "kind": "Variable" }, + { "name": "DigitalClockItemProps", "kind": "Interface" }, { "name": "DigitalClockProps", "kind": "Interface" }, { "name": "DigitalClockSlotProps", "kind": "Interface" }, { "name": "DigitalClockSlots", "kind": "Interface" }, @@ -156,6 +162,7 @@ { "name": "ExportedPickersRangeCalendarHeaderProps", "kind": "Interface" }, { "name": "ExportedPickersSectionListProps", "kind": "Interface" }, { "name": "ExportedSlideTransitionProps", "kind": "Interface" }, + { "name": "ExportedTimeRangePickerTabsProps", "kind": "Interface" }, { "name": "ExportedUseClearableFieldProps", "kind": "Interface" }, { "name": "extractValidationProps", "kind": "Variable" }, { "name": "FieldFormatTokenMap", "kind": "TypeAlias" }, @@ -188,6 +195,7 @@ { "name": "getPickersSectionListUtilityClass", "kind": "Function" }, { "name": "getPickersTextFieldUtilityClass", "kind": "Function" }, { "name": "getTimeClockUtilityClass", "kind": "Function" }, + { "name": "getTimeRangePickerTabsUtilityClass", "kind": "Function" }, { "name": "getYearCalendarUtilityClass", "kind": "Function" }, { "name": "InferError", "kind": "TypeAlias" }, { "name": "InferFieldSection", "kind": "TypeAlias" }, @@ -214,6 +222,10 @@ { "name": "MobileTimePickerProps", "kind": "Interface" }, { "name": "MobileTimePickerSlotProps", "kind": "Interface" }, { "name": "MobileTimePickerSlots", "kind": "Interface" }, + { "name": "MobileTimeRangePicker", "kind": "Variable" }, + { "name": "MobileTimeRangePickerProps", "kind": "Interface" }, + { "name": "MobileTimeRangePickerSlotProps", "kind": "Interface" }, + { "name": "MobileTimeRangePickerSlots", "kind": "Interface" }, { "name": "MonthCalendar", "kind": "Variable" }, { "name": "monthCalendarClasses", "kind": "Variable" }, { "name": "MonthCalendarClasses", "kind": "Interface" }, @@ -397,6 +409,19 @@ { "name": "TimePickerToolbarClassKey", "kind": "TypeAlias" }, { "name": "TimePickerToolbarProps", "kind": "Interface" }, { "name": "TimeRangeManagerFieldInternalProps", "kind": "Interface" }, + { "name": "TimeRangePicker", "kind": "Variable" }, + { "name": "TimeRangePickerProps", "kind": "Interface" }, + { "name": "TimeRangePickerSlotProps", "kind": "Interface" }, + { "name": "TimeRangePickerSlots", "kind": "Interface" }, + { "name": "TimeRangePickerTabs", "kind": "Variable" }, + { "name": "timeRangePickerTabsClasses", "kind": "Variable" }, + { "name": "TimeRangePickerTabsClasses", "kind": "Interface" }, + { "name": "TimeRangePickerTabsClassKey", "kind": "TypeAlias" }, + { "name": "TimeRangePickerToolbar", "kind": "Variable" }, + { "name": "timeRangePickerToolbarClasses", "kind": "Variable" }, + { "name": "TimeRangePickerToolbarClasses", "kind": "Interface" }, + { "name": "TimeRangePickerToolbarClassKey", "kind": "TypeAlias" }, + { "name": "TimeRangePickerToolbarProps", "kind": "Interface" }, { "name": "TimeRangeValidationError", "kind": "TypeAlias" }, { "name": "TimeStepOptions", "kind": "Interface" }, { "name": "TimeValidationError", "kind": "TypeAlias" }, diff --git a/scripts/x-date-pickers.exports.json b/scripts/x-date-pickers.exports.json index 08c260e8a3783..0f8a03ec10921 100644 --- a/scripts/x-date-pickers.exports.json +++ b/scripts/x-date-pickers.exports.json @@ -92,6 +92,8 @@ { "name": "digitalClockClasses", "kind": "Variable" }, { "name": "DigitalClockClasses", "kind": "Interface" }, { "name": "DigitalClockClassKey", "kind": "TypeAlias" }, + { "name": "DigitalClockItem", "kind": "Variable" }, + { "name": "DigitalClockItemProps", "kind": "Interface" }, { "name": "DigitalClockProps", "kind": "Interface" }, { "name": "DigitalClockSlotProps", "kind": "Interface" }, { "name": "DigitalClockSlots", "kind": "Interface" },