From bde94669aa4ea8372e335965b1f63f227326fafb Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE Date: Tue, 29 Oct 2024 13:58:36 +0100 Subject: [PATCH] [docs] Apply the new DX to the Button Field demos (#14860) Signed-off-by: Michel Engelen <32863416+michelengelen@users.noreply.github.com> Signed-off-by: Gene Arch Signed-off-by: Flavien DELANGLE Co-authored-by: Michel Engelen <32863416+michelengelen@users.noreply.github.com> Co-authored-by: Olivier Tassinari Co-authored-by: Gene Arch Co-authored-by: Rom Grk Co-authored-by: Lukas Tyla Co-authored-by: Sycamore <71297412+samuelsycamore@users.noreply.github.com> --- .../DateRangePickerWithButtonField.js | 72 --------------- .../DateRangePickerWithButtonField.tsx | 91 ------------------- ...DateRangePickerWithButtonField.tsx.preview | 11 --- .../custom-field/PickerWithButtonField.js | 59 ------------ .../custom-field/PickerWithButtonField.tsx | 79 ---------------- .../PickerWithButtonField.tsx.preview | 5 - .../behavior-button/MaterialDatePicker.js | 73 +++++++++++++++ .../behavior-button/MaterialDatePicker.tsx | 77 ++++++++++++++++ .../MaterialDatePicker.tsx.preview | 1 + .../MaterialDateRangePicker.js | 82 +++++++++++++++++ .../MaterialDateRangePicker.tsx | 86 ++++++++++++++++++ .../MaterialDateRangePicker.tsx.preview | 1 + .../MaskedMaterialTextField.js | 0 .../MaskedMaterialTextField.tsx | 0 .../MaskedMaterialTextField.tsx.preview | 0 .../MaterialDatePicker.js} | 2 +- .../MaterialDatePicker.tsx} | 2 +- .../MaterialDatePicker.tsx.preview} | 0 .../date-pickers/custom-field/custom-field.md | 25 +++-- .../DateRangePicker/DateRangePicker.types.ts | 27 +++++- .../src/DateRangePicker/index.ts | 1 + .../DateTimeRangePicker.types.ts | 32 ++++++- .../src/DateTimeRangePicker/index.ts | 1 + .../DesktopDateRangePicker.tsx | 5 +- .../MobileDateRangePicker.tsx | 5 +- .../src/DatePicker/DatePicker.types.ts | 6 +- .../DateTimePicker/DateTimePicker.types.ts | 5 +- .../src/TimePicker/TimePicker.types.ts | 6 +- .../x-date-pickers/src/internals/index.ts | 7 +- .../src/internals/models/fields.ts | 3 +- scripts/x-date-pickers-pro.exports.json | 2 + 31 files changed, 420 insertions(+), 346 deletions(-) delete mode 100644 docs/data/date-pickers/custom-field/DateRangePickerWithButtonField.js delete mode 100644 docs/data/date-pickers/custom-field/DateRangePickerWithButtonField.tsx delete mode 100644 docs/data/date-pickers/custom-field/DateRangePickerWithButtonField.tsx.preview delete mode 100644 docs/data/date-pickers/custom-field/PickerWithButtonField.js delete mode 100644 docs/data/date-pickers/custom-field/PickerWithButtonField.tsx delete mode 100644 docs/data/date-pickers/custom-field/PickerWithButtonField.tsx.preview create mode 100644 docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.js create mode 100644 docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx create mode 100644 docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx.preview create mode 100644 docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.js create mode 100644 docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx create mode 100644 docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx.preview rename docs/data/date-pickers/custom-field/{custom-behavior => behavior-masked-text-field}/MaskedMaterialTextField.js (100%) rename docs/data/date-pickers/custom-field/{custom-behavior => behavior-masked-text-field}/MaskedMaterialTextField.tsx (100%) rename docs/data/date-pickers/custom-field/{custom-behavior => behavior-masked-text-field}/MaskedMaterialTextField.tsx.preview (100%) rename docs/data/date-pickers/custom-field/{custom-behavior/ReadOnlyMaterialTextField.js => behavior-read-only-text-field/MaterialDatePicker.js} (97%) rename docs/data/date-pickers/custom-field/{custom-behavior/ReadOnlyMaterialTextField.tsx => behavior-read-only-text-field/MaterialDatePicker.tsx} (97%) rename docs/data/date-pickers/custom-field/{custom-behavior/ReadOnlyMaterialTextField.tsx.preview => behavior-read-only-text-field/MaterialDatePicker.tsx.preview} (100%) diff --git a/docs/data/date-pickers/custom-field/DateRangePickerWithButtonField.js b/docs/data/date-pickers/custom-field/DateRangePickerWithButtonField.js deleted file mode 100644 index 7180636a94dd..000000000000 --- a/docs/data/date-pickers/custom-field/DateRangePickerWithButtonField.js +++ /dev/null @@ -1,72 +0,0 @@ -import * as React from 'react'; - -import Button from '@mui/material/Button'; -import useForkRef from '@mui/utils/useForkRef'; - -import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; -import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; -import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker'; - -const DateRangeButtonField = React.forwardRef((props, ref) => { - const { - setOpen, - label, - id, - disabled, - InputProps: { ref: containerRef } = {}, - inputProps: { 'aria-label': ariaLabel } = {}, - } = props; - - const handleRef = useForkRef(ref, containerRef); - - return ( - - ); -}); - -DateRangeButtonField.fieldType = 'single-input'; - -const ButtonDateRangePicker = React.forwardRef((props, ref) => { - const [open, setOpen] = React.useState(false); - - return ( - setOpen(false)} - onOpen={() => setOpen(true)} - /> - ); -}); - -export default function DateRangePickerWithButtonField() { - const [value, setValue] = React.useState([null, null]); - - return ( - - (date ? date.format('MM/DD/YYYY') : 'null')) - .join(' - ') - } - value={value} - onChange={(newValue) => setValue(newValue)} - /> - - ); -} diff --git a/docs/data/date-pickers/custom-field/DateRangePickerWithButtonField.tsx b/docs/data/date-pickers/custom-field/DateRangePickerWithButtonField.tsx deleted file mode 100644 index 1b894f55e6a1..000000000000 --- a/docs/data/date-pickers/custom-field/DateRangePickerWithButtonField.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import * as React from 'react'; -import { Dayjs } from 'dayjs'; -import Button from '@mui/material/Button'; -import useForkRef from '@mui/utils/useForkRef'; -import { DateRange, FieldType } from '@mui/x-date-pickers-pro/models'; -import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; -import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; -import { - DateRangePicker, - DateRangePickerProps, -} from '@mui/x-date-pickers-pro/DateRangePicker'; -import { SingleInputDateRangeFieldProps } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; - -interface DateRangeButtonFieldProps extends SingleInputDateRangeFieldProps { - setOpen?: React.Dispatch>; -} - -type DateRangeButtonFieldComponent = (( - props: DateRangeButtonFieldProps & React.RefAttributes, -) => React.JSX.Element) & { fieldType?: FieldType }; - -const DateRangeButtonField = React.forwardRef( - (props: DateRangeButtonFieldProps, ref: React.Ref) => { - const { - setOpen, - label, - id, - disabled, - InputProps: { ref: containerRef } = {}, - inputProps: { 'aria-label': ariaLabel } = {}, - } = props; - - const handleRef = useForkRef(ref, containerRef); - - return ( - - ); - }, -) as DateRangeButtonFieldComponent; - -DateRangeButtonField.fieldType = 'single-input'; - -const ButtonDateRangePicker = React.forwardRef( - ( - props: Omit, 'open' | 'onOpen' | 'onClose'>, - ref: React.Ref, - ) => { - const [open, setOpen] = React.useState(false); - - return ( - setOpen(false)} - onOpen={() => setOpen(true)} - /> - ); - }, -); - -export default function DateRangePickerWithButtonField() { - const [value, setValue] = React.useState>([null, null]); - - return ( - - (date ? date.format('MM/DD/YYYY') : 'null')) - .join(' - ') - } - value={value} - onChange={(newValue) => setValue(newValue)} - /> - - ); -} diff --git a/docs/data/date-pickers/custom-field/DateRangePickerWithButtonField.tsx.preview b/docs/data/date-pickers/custom-field/DateRangePickerWithButtonField.tsx.preview deleted file mode 100644 index 3a8d6daacd70..000000000000 --- a/docs/data/date-pickers/custom-field/DateRangePickerWithButtonField.tsx.preview +++ /dev/null @@ -1,11 +0,0 @@ - (date ? date.format('MM/DD/YYYY') : 'null')) - .join(' - ') - } - value={value} - onChange={(newValue) => setValue(newValue)} -/> \ No newline at end of file diff --git a/docs/data/date-pickers/custom-field/PickerWithButtonField.js b/docs/data/date-pickers/custom-field/PickerWithButtonField.js deleted file mode 100644 index f13ca0315b2b..000000000000 --- a/docs/data/date-pickers/custom-field/PickerWithButtonField.js +++ /dev/null @@ -1,59 +0,0 @@ -import * as React from 'react'; - -import Button from '@mui/material/Button'; -import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; -import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; -import { DatePicker } from '@mui/x-date-pickers/DatePicker'; - -function ButtonField(props) { - const { - setOpen, - label, - id, - disabled, - InputProps: { ref } = {}, - inputProps: { 'aria-label': ariaLabel } = {}, - } = props; - - return ( - - ); -} - -function ButtonDatePicker(props) { - const [open, setOpen] = React.useState(false); - - return ( - setOpen(false)} - onOpen={() => setOpen(true)} - /> - ); -} - -export default function PickerWithButtonField() { - const [value, setValue] = React.useState(null); - - return ( - - setValue(newValue)} - /> - - ); -} diff --git a/docs/data/date-pickers/custom-field/PickerWithButtonField.tsx b/docs/data/date-pickers/custom-field/PickerWithButtonField.tsx deleted file mode 100644 index 8acbab77d7c4..000000000000 --- a/docs/data/date-pickers/custom-field/PickerWithButtonField.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import * as React from 'react'; -import { Dayjs } from 'dayjs'; -import Button from '@mui/material/Button'; -import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; -import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; -import { DatePicker, DatePickerProps } from '@mui/x-date-pickers/DatePicker'; -import { UseDateFieldProps } from '@mui/x-date-pickers/DateField'; -import { - BaseSingleInputFieldProps, - DateValidationError, - FieldSection, -} from '@mui/x-date-pickers/models'; - -interface ButtonFieldProps - extends UseDateFieldProps, - BaseSingleInputFieldProps< - Dayjs | null, - Dayjs, - FieldSection, - true, - DateValidationError - > { - setOpen?: React.Dispatch>; -} - -function ButtonField(props: ButtonFieldProps) { - const { - setOpen, - label, - id, - disabled, - InputProps: { ref } = {}, - inputProps: { 'aria-label': ariaLabel } = {}, - } = props; - - return ( - - ); -} - -function ButtonDatePicker( - props: Omit, 'open' | 'onOpen' | 'onClose'>, -) { - const [open, setOpen] = React.useState(false); - - return ( - setOpen(false)} - onOpen={() => setOpen(true)} - /> - ); -} - -export default function PickerWithButtonField() { - const [value, setValue] = React.useState(null); - - return ( - - setValue(newValue)} - /> - - ); -} diff --git a/docs/data/date-pickers/custom-field/PickerWithButtonField.tsx.preview b/docs/data/date-pickers/custom-field/PickerWithButtonField.tsx.preview deleted file mode 100644 index 173a0ba16962..000000000000 --- a/docs/data/date-pickers/custom-field/PickerWithButtonField.tsx.preview +++ /dev/null @@ -1,5 +0,0 @@ - setValue(newValue)} -/> \ No newline at end of file diff --git a/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.js b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.js new file mode 100644 index 000000000000..11da4bc2ba23 --- /dev/null +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.js @@ -0,0 +1,73 @@ +import * as React from 'react'; + +import Button from '@mui/material/Button'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { DatePicker } from '@mui/x-date-pickers/DatePicker'; +import { useValidation, validateDate } from '@mui/x-date-pickers/validation'; +import { + useSplitFieldProps, + useParsedFormat, + usePickersContext, +} from '@mui/x-date-pickers/hooks'; + +function ButtonDateField(props) { + const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date'); + const { value, timezone, format } = internalProps; + const { + InputProps, + slotProps, + slots, + ownerState, + label, + focused, + name, + ...other + } = forwardedProps; + + const pickersContext = usePickersContext(); + + const parsedFormat = useParsedFormat(internalProps); + const { hasValidationError } = useValidation({ + validator: validateDate, + value, + timezone, + props: internalProps, + }); + + const handleTogglePicker = (event) => { + if (pickersContext.open) { + pickersContext.onClose(event); + } else { + pickersContext.onOpen(event); + } + }; + + const valueStr = value == null ? parsedFormat : value.format(format); + + return ( + + ); +} + +function ButtonFieldDatePicker(props) { + return ( + + ); +} + +export default function MaterialDatePicker() { + return ( + + + + ); +} diff --git a/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx new file mode 100644 index 000000000000..1f31f5d63e6a --- /dev/null +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx @@ -0,0 +1,77 @@ +import * as React from 'react'; +import { Dayjs } from 'dayjs'; +import Button from '@mui/material/Button'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { + DatePicker, + DatePickerProps, + DatePickerFieldProps, +} from '@mui/x-date-pickers/DatePicker'; +import { useValidation, validateDate } from '@mui/x-date-pickers/validation'; +import { + useSplitFieldProps, + useParsedFormat, + usePickersContext, +} from '@mui/x-date-pickers/hooks'; + +function ButtonDateField(props: DatePickerFieldProps) { + const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date'); + const { value, timezone, format } = internalProps; + const { + InputProps, + slotProps, + slots, + ownerState, + label, + focused, + name, + ...other + } = forwardedProps; + + const pickersContext = usePickersContext(); + + const parsedFormat = useParsedFormat(internalProps); + const { hasValidationError } = useValidation({ + validator: validateDate, + value, + timezone, + props: internalProps, + }); + + const handleTogglePicker = (event: React.UIEvent) => { + if (pickersContext.open) { + pickersContext.onClose(event); + } else { + pickersContext.onOpen(event); + } + }; + + const valueStr = value == null ? parsedFormat : value.format(format); + + return ( + + ); +} + +function ButtonFieldDatePicker(props: DatePickerProps) { + return ( + + ); +} + +export default function MaterialDatePicker() { + return ( + + + + ); +} diff --git a/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx.preview b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx.preview new file mode 100644 index 000000000000..5f578e21a1d6 --- /dev/null +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx.preview @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.js b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.js new file mode 100644 index 000000000000..f9fc03f45d57 --- /dev/null +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.js @@ -0,0 +1,82 @@ +import * as React from 'react'; + +import Button from '@mui/material/Button'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker'; +import { useValidation } from '@mui/x-date-pickers/validation'; +import { validateDateRange } from '@mui/x-date-pickers-pro/validation'; +import { + useSplitFieldProps, + useParsedFormat, + usePickersContext, +} from '@mui/x-date-pickers/hooks'; + +function ButtonDateRangeField(props) { + const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date'); + const { value, timezone, format } = internalProps; + const { + InputProps, + slotProps, + slots, + ownerState, + label, + focused, + name, + ...other + } = forwardedProps; + + const pickersContext = usePickersContext(); + + const parsedFormat = useParsedFormat(internalProps); + const { hasValidationError } = useValidation({ + validator: validateDateRange, + value, + timezone, + props: internalProps, + }); + + const handleTogglePicker = (event) => { + if (pickersContext.open) { + pickersContext.onClose(event); + } else { + pickersContext.onOpen(event); + } + }; + + const formattedValue = (value ?? [null, null]) + .map((date) => (date == null ? parsedFormat : date.format(format))) + .join(' – '); + + return ( + + ); +} + +// TODO v8: Will be removed before the end of the alpha since single input will become the default field. +ButtonDateRangeField.fieldType = 'single-input'; + +function ButtonFieldDateRangePicker(props) { + return ( + + ); +} + +export default function MaterialDateRangePicker() { + return ( + + + + ); +} diff --git a/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx new file mode 100644 index 000000000000..bc154d9a2b9f --- /dev/null +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx @@ -0,0 +1,86 @@ +import * as React from 'react'; +import { Dayjs } from 'dayjs'; +import Button from '@mui/material/Button'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { + DateRangePicker, + DateRangePickerProps, + DateRangePickerFieldProps, +} from '@mui/x-date-pickers-pro/DateRangePicker'; +import { useValidation } from '@mui/x-date-pickers/validation'; +import { validateDateRange } from '@mui/x-date-pickers-pro/validation'; +import { + useSplitFieldProps, + useParsedFormat, + usePickersContext, +} from '@mui/x-date-pickers/hooks'; + +function ButtonDateRangeField(props: DateRangePickerFieldProps) { + const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date'); + const { value, timezone, format } = internalProps; + const { + InputProps, + slotProps, + slots, + ownerState, + label, + focused, + name, + ...other + } = forwardedProps; + + const pickersContext = usePickersContext(); + + const parsedFormat = useParsedFormat(internalProps); + const { hasValidationError } = useValidation({ + validator: validateDateRange, + value, + timezone, + props: internalProps, + }); + + const handleTogglePicker = (event: React.UIEvent) => { + if (pickersContext.open) { + pickersContext.onClose(event); + } else { + pickersContext.onOpen(event); + } + }; + + const formattedValue = (value ?? [null, null]) + .map((date) => (date == null ? parsedFormat : date.format(format))) + .join(' – '); + + return ( + + ); +} + +// TODO v8: Will be removed before the end of the alpha since single input will become the default field. +ButtonDateRangeField.fieldType = 'single-input'; + +function ButtonFieldDateRangePicker(props: DateRangePickerProps) { + return ( + + ); +} + +export default function MaterialDateRangePicker() { + return ( + + + + ); +} diff --git a/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx.preview b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx.preview new file mode 100644 index 000000000000..6512674c0bb6 --- /dev/null +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx.preview @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/data/date-pickers/custom-field/custom-behavior/MaskedMaterialTextField.js b/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.js similarity index 100% rename from docs/data/date-pickers/custom-field/custom-behavior/MaskedMaterialTextField.js rename to docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.js diff --git a/docs/data/date-pickers/custom-field/custom-behavior/MaskedMaterialTextField.tsx b/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx similarity index 100% rename from docs/data/date-pickers/custom-field/custom-behavior/MaskedMaterialTextField.tsx rename to docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx diff --git a/docs/data/date-pickers/custom-field/custom-behavior/MaskedMaterialTextField.tsx.preview b/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx.preview similarity index 100% rename from docs/data/date-pickers/custom-field/custom-behavior/MaskedMaterialTextField.tsx.preview rename to docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx.preview diff --git a/docs/data/date-pickers/custom-field/custom-behavior/ReadOnlyMaterialTextField.js b/docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.js similarity index 97% rename from docs/data/date-pickers/custom-field/custom-behavior/ReadOnlyMaterialTextField.js rename to docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.js index b5050747ff1f..5f1cdc46e732 100644 --- a/docs/data/date-pickers/custom-field/custom-behavior/ReadOnlyMaterialTextField.js +++ b/docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.js @@ -58,7 +58,7 @@ function ReadOnlyFieldDatePicker(props) { ); } -export default function ReadOnlyMaterialTextField() { +export default function MaterialDatePicker() { return ( diff --git a/docs/data/date-pickers/custom-field/custom-behavior/ReadOnlyMaterialTextField.tsx b/docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.tsx similarity index 97% rename from docs/data/date-pickers/custom-field/custom-behavior/ReadOnlyMaterialTextField.tsx rename to docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.tsx index 04223bd73a6e..d8a54a2bebdb 100644 --- a/docs/data/date-pickers/custom-field/custom-behavior/ReadOnlyMaterialTextField.tsx +++ b/docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.tsx @@ -62,7 +62,7 @@ function ReadOnlyFieldDatePicker(props: DatePickerProps) { ); } -export default function ReadOnlyMaterialTextField() { +export default function MaterialDatePicker() { return ( diff --git a/docs/data/date-pickers/custom-field/custom-behavior/ReadOnlyMaterialTextField.tsx.preview b/docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.tsx.preview similarity index 100% rename from docs/data/date-pickers/custom-field/custom-behavior/ReadOnlyMaterialTextField.tsx.preview rename to docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.tsx.preview diff --git a/docs/data/date-pickers/custom-field/custom-field.md b/docs/data/date-pickers/custom-field/custom-field.md index 9c4cc5216bb3..31c5ed4bb824 100644 --- a/docs/data/date-pickers/custom-field/custom-field.md +++ b/docs/data/date-pickers/custom-field/custom-field.md @@ -125,36 +125,35 @@ The new accessible DOM structure will become compatible with Joy UI in the futur ## With a custom editing experience -### Using an `Autocomplete` +### Using an Autocomplete -If your user can only select a value in a small list of available dates, -you can replace the field with an `Autocomplete` listing those dates: +If your user can only select a value in a small list of available dates, you can replace the field with the [Autocomplete](/material-ui/react-autocomplete/) component to list those dates: {{"demo": "PickerWithAutocompleteField.js", "defaultCodeOpen": false}} ### Using a masked Text Field -If you want to use a simple mask approach for the field editing instead of the built-in logic, you can replace the default field with a Text Field using a masked input value built with the [rifm](https://github.com/realadvisor/rifm) package. +If you want to use a simple mask approach for the field editing instead of the built-in logic, you can replace the default field with the [TextField](/material-ui/react-text-field/) component using a masked input value built with the [rifm](https://github.com/realadvisor/rifm) package. -{{"demo": "custom-behavior/MaskedMaterialTextField.js", "defaultCodeOpen": false}} +{{"demo": "behavior-masked-text-field/MaskedMaterialTextField.js", "defaultCodeOpen": false}} -### Using a read-only `TextField` +### Using a read-only Text Field If you want users to select a value exclusively through the views -but you still want the UI to look like a `TextField`, you can replace the field with a read-only `TextField`: +but you still want the UI to look like a Text Field, you can replace the field with a read-only [Text Field](/material-ui/react-text-field/) component: -{{"demo": "custom-behavior/ReadOnlyMaterialTextField.js", "defaultCodeOpen": false}} +{{"demo": "behavior-read-only-text-field/MaterialDatePicker.js", "defaultCodeOpen": false}} -### Using a `Button` +### Using a Button If you want users to select a value exclusively through the views -and you don't want the UI to look like a `TextField`, you can replace the field with a `Button`: +and you don't want the UI to look like a Text Field, you can replace the field with the [Button](/material-ui/react-button/) component: -{{"demo": "PickerWithButtonField.js", "defaultCodeOpen": false}} +{{"demo": "behavior-button/MaterialDatePicker.js", "defaultCodeOpen": false}} -The same can be applied to the `DateRangePicker`: +The same logic can be applied to any Range Picker: -{{"demo": "DateRangePickerWithButtonField.js", "defaultCodeOpen": false}} +{{"demo": "behavior-button/MaterialDateRangePicker.js", "defaultCodeOpen": false}} ## How to build a custom field diff --git a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.types.ts b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.types.ts index 95cd8b8a6b63..09d6ca578fe9 100644 --- a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.types.ts @@ -1,4 +1,5 @@ -import { PickerValidDate } from '@mui/x-date-pickers/models'; +import { BaseDateValidationProps, MakeRequired } from '@mui/x-date-pickers/internals'; +import { BaseSingleInputFieldProps, PickerValidDate } from '@mui/x-date-pickers/models'; import { DesktopDateRangePickerProps, DesktopDateRangePickerSlots, @@ -9,6 +10,12 @@ import { MobileDateRangePickerSlots, MobileDateRangePickerSlotProps, } from '../MobileDateRangePicker'; +import { + DateRange, + DateRangeValidationError, + RangeFieldSection, + UseDateRangeFieldProps, +} from '../models'; export interface DateRangePickerSlots extends DesktopDateRangePickerSlots, @@ -42,3 +49,21 @@ export interface DateRangePickerProps< */ slotProps?: DateRangePickerSlotProps; } + +/** + * Props the field can receive when used inside a `DateRangePicker`, `DesktopDateRangePicker` or `MobileDateRangePicker` component. + */ +export type DateRangePickerFieldProps< + TDate extends PickerValidDate, + TEnableAccessibleFieldDOMStructure extends boolean = true, +> = MakeRequired< + UseDateRangeFieldProps, + 'format' | 'timezone' | 'value' | keyof BaseDateValidationProps +> & + BaseSingleInputFieldProps< + DateRange, + TDate, + RangeFieldSection, + false, + DateRangeValidationError + >; diff --git a/packages/x-date-pickers-pro/src/DateRangePicker/index.ts b/packages/x-date-pickers-pro/src/DateRangePicker/index.ts index 4f65679f8be2..561b96d1667c 100644 --- a/packages/x-date-pickers-pro/src/DateRangePicker/index.ts +++ b/packages/x-date-pickers-pro/src/DateRangePicker/index.ts @@ -3,6 +3,7 @@ export type { DateRangePickerProps, DateRangePickerSlots, DateRangePickerSlotProps, + DateRangePickerFieldProps, } from './DateRangePicker.types'; export { DateRangePickerToolbar } from './DateRangePickerToolbar'; diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.types.ts index aaa9942d7bf1..4a1e5d054f52 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.types.ts @@ -1,4 +1,9 @@ -import { PickerValidDate } from '@mui/x-date-pickers/models'; +import { + BaseDateValidationProps, + BaseTimeValidationProps, + MakeRequired, +} from '@mui/x-date-pickers/internals'; +import { BaseSingleInputFieldProps, PickerValidDate } from '@mui/x-date-pickers/models'; import { DesktopDateTimeRangePickerProps, DesktopDateTimeRangePickerSlots, @@ -9,6 +14,8 @@ import { MobileDateTimeRangePickerSlots, MobileDateTimeRangePickerSlotProps, } from '../MobileDateTimeRangePicker'; +import { UseDateTimeRangeFieldProps } from '../internals/models'; +import { DateRange, DateTimeRangeValidationError, RangeFieldSection } from '../models'; export interface DateTimeRangePickerSlots extends DesktopDateTimeRangePickerSlots, @@ -42,3 +49,26 @@ export interface DateTimeRangePickerProps< */ slotProps?: DateTimeRangePickerSlotProps; } + +/** + * Props the field can receive when used inside a `DateTimeRangePicker`, `DesktopDateTimeRangePicker` or `MobileDateTimeRangePicker` component. + */ +export type DateTimeRangePickerFieldProps< + TDate extends PickerValidDate, + TEnableAccessibleFieldDOMStructure extends boolean = true, +> = MakeRequired< + UseDateTimeRangeFieldProps, + | 'format' + | 'timezone' + | 'value' + | 'ampm' + | keyof BaseDateValidationProps + | keyof BaseTimeValidationProps +> & + BaseSingleInputFieldProps< + DateRange, + TDate, + RangeFieldSection, + false, + DateTimeRangeValidationError + >; diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/index.ts b/packages/x-date-pickers-pro/src/DateTimeRangePicker/index.ts index 6f24b2da3829..4de7da316eed 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/index.ts +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/index.ts @@ -3,6 +3,7 @@ export type { DateTimeRangePickerProps, DateTimeRangePickerSlots, DateTimeRangePickerSlotProps, + DateTimeRangePickerFieldProps, } from './DateTimeRangePicker.types'; export { DateTimeRangePickerTabs } from './DateTimeRangePickerTabs'; diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx index 31c9d03e31ff..a395e353576e 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { PickerViewRendererLookup } from '@mui/x-date-pickers/internals'; +import { PickerViewRendererLookup, useUtils } from '@mui/x-date-pickers/internals'; import { extractValidationProps } from '@mui/x-date-pickers/validation'; import { PickerOwnerState, PickerValidDate } from '@mui/x-date-pickers/models'; import resolveComponentProps from '@mui/utils/resolveComponentProps'; @@ -40,6 +40,8 @@ const DesktopDateRangePicker = React.forwardRef(function DesktopDateRangePicker< inProps: DesktopDateRangePickerProps, ref: React.Ref, ) { + const utils = useUtils(); + // Props with the default values common to all date time pickers const defaultizedProps = useDateRangePickerDefaultizedProps< TDate, @@ -54,6 +56,7 @@ const DesktopDateRangePicker = React.forwardRef(function DesktopDateRangePicker< const props = { ...defaultizedProps, viewRenderers, + format: utils.formats.keyboardDate, calendars: defaultizedProps.calendars ?? 2, views: ['day'] as const, openTo: 'day' as const, diff --git a/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx index 9b90d6ccad83..712683c2ef7a 100644 --- a/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { PickerViewRendererLookup } from '@mui/x-date-pickers/internals'; +import { PickerViewRendererLookup, useUtils } from '@mui/x-date-pickers/internals'; import { extractValidationProps } from '@mui/x-date-pickers/validation'; import { PickerOwnerState, PickerValidDate } from '@mui/x-date-pickers/models'; import resolveComponentProps from '@mui/utils/resolveComponentProps'; @@ -40,6 +40,8 @@ const MobileDateRangePicker = React.forwardRef(function MobileDateRangePicker< inProps: MobileDateRangePickerProps, ref: React.Ref, ) { + const utils = useUtils(); + // Props with the default values common to all date time pickers const defaultizedProps = useDateRangePickerDefaultizedProps< TDate, @@ -54,6 +56,7 @@ const MobileDateRangePicker = React.forwardRef(function MobileDateRangePicker< const props = { ...defaultizedProps, viewRenderers, + format: utils.formats.keyboardDate, // Force one calendar on mobile to avoid layout issues calendars: 1, views: ['day'] as const, diff --git a/packages/x-date-pickers/src/DatePicker/DatePicker.types.ts b/packages/x-date-pickers/src/DatePicker/DatePicker.types.ts index 8ba281c9b024..beb26c092ee6 100644 --- a/packages/x-date-pickers/src/DatePicker/DatePicker.types.ts +++ b/packages/x-date-pickers/src/DatePicker/DatePicker.types.ts @@ -4,7 +4,7 @@ import { DesktopDatePickerSlots, DesktopDatePickerSlotProps, } from '../DesktopDatePicker'; -import { DefaultizedProps } from '../internals/models/helpers'; +import { MakeRequired } from '../internals/models/helpers'; import { BaseDateValidationProps } from '../internals/models/validation'; import { MobileDatePickerProps, @@ -62,8 +62,8 @@ export interface DatePickerProps< export type DatePickerFieldProps< TDate extends PickerValidDate, TEnableAccessibleFieldDOMStructure extends boolean = true, -> = DefaultizedProps< +> = MakeRequired< UseDateFieldProps, - 'format' | 'timezone' | keyof BaseDateValidationProps + 'format' | 'timezone' | 'value' | keyof BaseDateValidationProps > & BaseSingleInputFieldProps; diff --git a/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.types.ts b/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.types.ts index a26c276930b4..d71f06ea1fc4 100644 --- a/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.types.ts +++ b/packages/x-date-pickers/src/DateTimePicker/DateTimePicker.types.ts @@ -5,7 +5,7 @@ import { DesktopDateTimePickerSlotProps, } from '../DesktopDateTimePicker'; import { DateOrTimeViewWithMeridiem } from '../internals/models'; -import { DefaultizedProps } from '../internals/models/helpers'; +import { MakeRequired } from '../internals/models/helpers'; import { BaseDateValidationProps, BaseTimeValidationProps } from '../internals/models/validation'; import { MobileDateTimePickerProps, @@ -77,10 +77,11 @@ export interface DateTimePickerProps< export type DateTimePickerFieldProps< TDate extends PickerValidDate, TEnableAccessibleFieldDOMStructure extends boolean = true, -> = DefaultizedProps< +> = MakeRequired< UseDateTimeFieldProps, | 'format' | 'timezone' + | 'value' | 'ampm' | keyof BaseDateValidationProps | keyof BaseTimeValidationProps diff --git a/packages/x-date-pickers/src/TimePicker/TimePicker.types.ts b/packages/x-date-pickers/src/TimePicker/TimePicker.types.ts index a5ba2479c1e8..c8a39b3ce190 100644 --- a/packages/x-date-pickers/src/TimePicker/TimePicker.types.ts +++ b/packages/x-date-pickers/src/TimePicker/TimePicker.types.ts @@ -4,7 +4,7 @@ import { DesktopTimePickerSlotProps, } from '../DesktopTimePicker'; import { TimeViewWithMeridiem } from '../internals/models'; -import { DefaultizedProps } from '../internals/models/helpers'; +import { MakeRequired } from '../internals/models/helpers'; import { BaseTimeValidationProps } from '../internals/models/validation'; import { MobileTimePickerProps, @@ -62,8 +62,8 @@ export interface TimePickerProps< export type TimePickerFieldProps< TDate extends PickerValidDate, TEnableAccessibleFieldDOMStructure extends boolean = true, -> = DefaultizedProps< +> = MakeRequired< UseTimeFieldProps, - 'format' | 'timezone' | 'ampm' | keyof BaseTimeValidationProps + 'format' | 'timezone' | 'value' | 'ampm' | keyof BaseTimeValidationProps > & BaseSingleInputFieldProps; diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index 010b5eda898d..49700d346134 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -104,7 +104,12 @@ export type { export type { BaseClockProps, DesktopOnlyTimePickerProps } from './models/props/clock'; export type { BaseTabsProps, ExportedBaseTabsProps } from './models/props/tabs'; export type { BaseToolbarProps, ExportedBaseToolbarProps } from './models/props/toolbar'; -export type { DefaultizedProps, MakeOptional, SlotComponentPropsFromProps } from './models/helpers'; +export type { + DefaultizedProps, + MakeOptional, + MakeRequired, + SlotComponentPropsFromProps, +} from './models/helpers'; export type { WrapperVariant, TimeViewWithMeridiem, diff --git a/packages/x-date-pickers/src/internals/models/fields.ts b/packages/x-date-pickers/src/internals/models/fields.ts index e02b43315f56..e3097519c27d 100644 --- a/packages/x-date-pickers/src/internals/models/fields.ts +++ b/packages/x-date-pickers/src/internals/models/fields.ts @@ -1,6 +1,6 @@ import * as React from 'react'; import type { UseFieldInternalProps } from '../hooks/useField'; -import { FieldSection, PickerValidDate } from '../../models'; +import { FieldSection, PickerOwnerState, PickerValidDate } from '../../models'; import type { ExportedUseClearableFieldProps } from '../../hooks/useClearableField'; export interface BaseFieldProps< @@ -18,4 +18,5 @@ export interface BaseFieldProps< format?: string; disabled?: boolean; ref?: React.Ref; + ownerState?: PickerOwnerState; } diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index f61085dd248c..581ce00f24b3 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -61,6 +61,7 @@ { "name": "DateRangePickerDayClasses", "kind": "Interface" }, { "name": "DateRangePickerDayClassKey", "kind": "TypeAlias" }, { "name": "DateRangePickerDayProps", "kind": "Interface" }, + { "name": "DateRangePickerFieldProps", "kind": "TypeAlias" }, { "name": "DateRangePickerProps", "kind": "Interface" }, { "name": "DateRangePickerSlotProps", "kind": "Interface" }, { "name": "DateRangePickerSlots", "kind": "Interface" }, @@ -89,6 +90,7 @@ { "name": "DateTimePickerToolbarClassKey", "kind": "TypeAlias" }, { "name": "DateTimePickerToolbarProps", "kind": "Interface" }, { "name": "DateTimeRangePicker", "kind": "Variable" }, + { "name": "DateTimeRangePickerFieldProps", "kind": "TypeAlias" }, { "name": "DateTimeRangePickerProps", "kind": "Interface" }, { "name": "DateTimeRangePickerSlotProps", "kind": "Interface" }, { "name": "DateTimeRangePickerSlots", "kind": "Interface" },