diff --git a/docs/data/date-pickers/calendar-systems/AdapterHijri.js b/docs/data/date-pickers/calendar-systems/AdapterHijri.js index fa738ee1e6e3..f146aaa31ba3 100644 --- a/docs/data/date-pickers/calendar-systems/AdapterHijri.js +++ b/docs/data/date-pickers/calendar-systems/AdapterHijri.js @@ -46,14 +46,6 @@ function ButtonDateTimeField(props) { props: internalProps, }); - const handleTogglePicker = (event) => { - if (pickerContext.open) { - pickerContext.onClose(event); - } else { - pickerContext.onOpen(event); - } - }; - const valueStr = value == null ? parsedFormat : value.format(format); return ( @@ -62,7 +54,7 @@ function ButtonDateTimeField(props) { variant="outlined" color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={handleTogglePicker} + onClick={pickerContext.onToggleOpening} > {label ? `${label}: ${valueStr}` : valueStr} diff --git a/docs/data/date-pickers/calendar-systems/AdapterHijri.tsx b/docs/data/date-pickers/calendar-systems/AdapterHijri.tsx index aa9b24d67f79..319f93f591ac 100644 --- a/docs/data/date-pickers/calendar-systems/AdapterHijri.tsx +++ b/docs/data/date-pickers/calendar-systems/AdapterHijri.tsx @@ -50,14 +50,6 @@ function ButtonDateTimeField(props: DateTimePickerFieldProps) { props: internalProps, }); - const handleTogglePicker = (event: React.UIEvent) => { - if (pickerContext.open) { - pickerContext.onClose(event); - } else { - pickerContext.onOpen(event); - } - }; - const valueStr = value == null ? parsedFormat : value.format(format); return ( @@ -66,7 +58,7 @@ function ButtonDateTimeField(props: DateTimePickerFieldProps) { variant="outlined" color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={handleTogglePicker} + onClick={pickerContext.onToggleOpening} > {label ? `${label}: ${valueStr}` : valueStr} diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js index a86335cd7dd7..7adc0f2e453a 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js @@ -87,13 +87,6 @@ const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => { const { slots, slotProps, ...other } = props; const pickerContext = usePickerContext(); - const handleTogglePicker = (event) => { - if (pickerContext.open) { - pickerContext.onClose(event); - } else { - pickerContext.onOpen(event); - } - }; const textFieldProps = useSlotProps({ elementType: 'input', @@ -106,7 +99,7 @@ const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => { ...textFieldProps.InputProps, endAdornment: ( - + diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx index 2c1c935104e7..e6e44e9656e4 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx @@ -115,13 +115,6 @@ const BrowserSingleInputDateRangeField = React.forwardRef( const { slots, slotProps, ...other } = props; const pickerContext = usePickerContext(); - const handleTogglePicker = (event: React.UIEvent) => { - if (pickerContext.open) { - pickerContext.onClose(event); - } else { - pickerContext.onOpen(event); - } - }; const textFieldProps: typeof props = useSlotProps({ elementType: 'input', @@ -134,7 +127,7 @@ const BrowserSingleInputDateRangeField = React.forwardRef( ...textFieldProps.InputProps, endAdornment: ( - + diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js index dd5ee96d6f52..95be4b633756 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js @@ -72,13 +72,6 @@ const JoySingleInputDateRangeField = React.forwardRef((props, ref) => { const { slots, slotProps, ...other } = props; const pickerContext = usePickerContext(); - const handleTogglePicker = (event) => { - if (pickerContext.open) { - pickerContext.onClose(event); - } else { - pickerContext.onOpen(event); - } - }; const textFieldProps = useSlotProps({ elementType: FormControl, @@ -105,7 +98,7 @@ const JoySingleInputDateRangeField = React.forwardRef((props, ref) => { ref={ref} endDecorator={ { - if (pickerContext.open) { - pickerContext.onClose(event); - } else { - pickerContext.onOpen(event); - } - }; const textFieldProps: JoySingleInputDateRangeFieldProps = useSlotProps({ elementType: FormControl, @@ -136,7 +129,7 @@ const JoySingleInputDateRangeField = React.forwardRef( ref={ref} endDecorator={ { - if (pickerContext.open) { - pickerContext.onClose(event); - } else { - pickerContext.onOpen(event); - } - }; - const valueStr = value == null ? parsedFormat : value.format(format); return ( @@ -50,7 +42,7 @@ function ButtonDateField(props) { variant="outlined" color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={handleTogglePicker} + onClick={pickerContext.onToggleOpening} > {label ? `${label}: ${valueStr}` : valueStr} diff --git a/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx index ac64ebd3a5f0..d19c72fb95b0 100644 --- a/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx @@ -38,14 +38,6 @@ function ButtonDateField(props: DatePickerFieldProps) { props: internalProps, }); - const handleTogglePicker = (event: React.UIEvent) => { - if (pickerContext.open) { - pickerContext.onClose(event); - } else { - pickerContext.onOpen(event); - } - }; - const valueStr = value == null ? parsedFormat : value.format(format); return ( @@ -54,7 +46,7 @@ function ButtonDateField(props: DatePickerFieldProps) { variant="outlined" color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={handleTogglePicker} + onClick={pickerContext.onToggleOpening} > {label ? `${label}: ${valueStr}` : valueStr} diff --git a/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.js b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.js index 7c56f7a2693a..d2e26d720904 100644 --- a/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.js +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.js @@ -36,14 +36,6 @@ function ButtonDateRangeField(props) { props: internalProps, }); - const handleTogglePicker = (event) => { - if (pickerContext.open) { - pickerContext.onClose(event); - } else { - pickerContext.onOpen(event); - } - }; - const formattedValue = (value ?? [null, null]) .map((date) => (date == null ? parsedFormat : date.format(format))) .join(' – '); @@ -54,7 +46,7 @@ function ButtonDateRangeField(props) { variant="outlined" color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={handleTogglePicker} + onClick={pickerContext.onToggleOpening} > {label ? `${label}: ${formattedValue}` : formattedValue} diff --git a/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx index fbc0cd45c51e..b4a39597513e 100644 --- a/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx @@ -40,14 +40,6 @@ function ButtonDateRangeField(props: DateRangePickerFieldProps) { props: internalProps, }); - const handleTogglePicker = (event: React.UIEvent) => { - if (pickerContext.open) { - pickerContext.onClose(event); - } else { - pickerContext.onOpen(event); - } - }; - const formattedValue = (value ?? [null, null]) .map((date: Dayjs) => (date == null ? parsedFormat : date.format(format))) .join(' – '); @@ -58,7 +50,7 @@ function ButtonDateRangeField(props: DateRangePickerFieldProps) { variant="outlined" color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={handleTogglePicker} + onClick={pickerContext.onToggleOpening} > {label ? `${label}: ${formattedValue}` : formattedValue} diff --git a/docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.js b/docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.js index 1e7d773f6fdf..96e29f79763a 100644 --- a/docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.js +++ b/docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.js @@ -26,14 +26,6 @@ function ReadOnlyDateField(props) { props: internalProps, }); - const handleTogglePicker = (event) => { - if (pickerContext.open) { - pickerContext.onClose(event); - } else { - pickerContext.onOpen(event); - } - }; - return ( ); } diff --git a/docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.tsx b/docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.tsx index 1fd235a77819..cc2b1180fdf7 100644 --- a/docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.tsx +++ b/docs/data/date-pickers/custom-field/behavior-read-only-text-field/MaterialDatePicker.tsx @@ -30,14 +30,6 @@ function ReadOnlyDateField(props: DatePickerFieldProps) { props: internalProps, }); - const handleTogglePicker = (event: React.UIEvent) => { - if (pickerContext.open) { - pickerContext.onClose(event); - } else { - pickerContext.onOpen(event); - } - }; - return ( ); } diff --git a/docs/src/modules/components/overview/mainDemo/PickerButton.tsx b/docs/src/modules/components/overview/mainDemo/PickerButton.tsx index d47d045fb1c6..59043f6ea467 100644 --- a/docs/src/modules/components/overview/mainDemo/PickerButton.tsx +++ b/docs/src/modules/components/overview/mainDemo/PickerButton.tsx @@ -23,14 +23,6 @@ function ButtonDateField(props: DatePickerFieldProps) { props: internalProps, }); - const handleTogglePicker = (event: React.UIEvent) => { - if (pickerContext.open) { - pickerContext.onClose(event); - } else { - pickerContext.onOpen(event); - } - }; - const valueStr = value == null ? parsedFormat : value.format(format); return ( @@ -43,7 +35,7 @@ function ButtonDateField(props: DatePickerFieldProps) { fullWidth color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={handleTogglePicker} + onClick={pickerContext.onToggleOpening} > {label ? `${label}: ${valueStr}` : valueStr} diff --git a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx index 85eeaf1f04d8..4fa7eb07cbf1 100644 --- a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx @@ -54,6 +54,11 @@ export interface PickerContextValue { * @param {React.UIEvent} event The DOM event that triggered the change. */ onClose: (event: React.UIEvent) => void; + /** + * Close the picker if it's open, open it if it's closed. + * @param {React.UIEvent} event The DOM event that triggered the change. + */ + onToggleOpening: (event: React.UIEvent) => void; /** * `true` if the picker is open, `false` otherwise. */ diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts index 92964972c29a..6c4746dbc8b7 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts @@ -1,5 +1,6 @@ import * as React from 'react'; import useEnhancedEffect from '@mui/utils/useEnhancedEffect'; +import useEventCallback from '@mui/utils/useEventCallback'; import { PickerOwnerState } from '../../../models'; import { PickerValueManager, UsePickerValueResponse } from './usePickerValue.types'; import { @@ -67,6 +68,14 @@ export function usePickerProvider( const utils = useUtils(); const orientation = usePickerOrientation(views, props.orientation); + const handleTogglePicker = useEventCallback((event: React.UIEvent) => { + if (pickerValueResponse.open) { + pickerValueResponse.actions.onClose(event); + } else { + pickerValueResponse.actions.onOpen(event); + } + }); + const ownerState = React.useMemo( () => ({ isPickerValueEmpty: valueManager.areValuesEqual( @@ -96,6 +105,7 @@ export function usePickerProvider( () => ({ onOpen: pickerValueResponse.actions.onOpen, onClose: pickerValueResponse.actions.onClose, + onToggleOpening: handleTogglePicker, open: pickerValueResponse.open, disabled: props.disabled ?? false, readOnly: props.readOnly ?? false, @@ -105,6 +115,7 @@ export function usePickerProvider( [ pickerValueResponse.actions.onOpen, pickerValueResponse.actions.onClose, + handleTogglePicker, pickerValueResponse.open, variant, orientation,