From 5f11d8234d268c456f47deea2040a1d6eef4b186 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 11:26:06 +0100 Subject: [PATCH 01/77] [pickers] Move the field opening logic inside the field components --- .../internals/hooks/models/useRangePicker.ts | 4 +- .../src/DateField/DateField.tsx | 20 +- .../src/DateField/DateField.types.ts | 30 +- .../src/DateField/useDateField.ts | 7 + .../src/DateTimeField/DateTimeField.tsx | 12 +- .../src/DateTimeField/DateTimeField.types.ts | 30 +- .../src/DateTimeField/useDateTimeField.ts | 7 + .../DesktopDatePicker/DesktopDatePicker.tsx | 9 - .../DesktopDateTimePicker.tsx | 9 - .../DesktopTimePicker/DesktopTimePicker.tsx | 9 - .../src/MobileDatePicker/MobileDatePicker.tsx | 9 - .../MobileDateTimePicker.tsx | 9 - .../src/MobileTimePicker/MobileTimePicker.tsx | 9 - .../src/TimeField/TimeField.tsx | 20 +- .../src/TimeField/TimeField.types.ts | 30 +- .../src/TimeField/useTimeField.ts | 7 + .../internals/components/PickerFieldUI.tsx | 320 ++++++++++++++++++ .../internals/components/PickerProvider.tsx | 9 + .../useDesktopPicker/useDesktopPicker.tsx | 73 +--- .../useDesktopPicker.types.ts | 41 +-- .../src/internals/hooks/useField/useField.ts | 2 + .../hooks/useField/useField.types.ts | 5 +- .../hooks/useGetOpenPickerAriaLabel.ts | 18 + .../hooks/useMobilePicker/useMobilePicker.tsx | 24 +- .../useMobilePicker/useMobilePicker.types.ts | 13 +- .../hooks/useNullablePickerContext.ts | 9 + .../internals/hooks/usePicker/usePicker.ts | 2 +- .../hooks/usePicker/usePicker.types.ts | 2 +- .../hooks/usePicker/usePickerProvider.ts | 37 +- .../hooks/usePicker/usePickerViews.ts | 11 - .../x-date-pickers/src/internals/index.ts | 2 +- ...nvertFieldResponseIntoMuiTextFieldProps.ts | 2 +- .../locales/utils/getPickersLocalization.ts | 17 - 33 files changed, 485 insertions(+), 323 deletions(-) create mode 100644 packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx create mode 100644 packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts create mode 100644 packages/x-date-pickers/src/internals/hooks/useNullablePickerContext.ts diff --git a/packages/x-date-pickers-pro/src/internals/hooks/models/useRangePicker.ts b/packages/x-date-pickers-pro/src/internals/hooks/models/useRangePicker.ts index bf22eeb38d5d..9564e78e3c57 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/models/useRangePicker.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/models/useRangePicker.ts @@ -5,7 +5,7 @@ import { UsePickerViewsProps, BaseNonStaticPickerProps, UsePickerValueNonStaticProps, - UsePickerViewsNonStaticProps, + UsePickerProviderNonStaticProps, DateOrTimeViewWithMeridiem, ExportedBaseTabsProps, PickerRangeValue, @@ -37,7 +37,7 @@ export interface UseRangePickerSlotProps< export interface RangeOnlyPickerProps extends BaseNonStaticPickerProps, UsePickerValueNonStaticProps, - UsePickerViewsNonStaticProps, + UsePickerProviderNonStaticProps, BaseRangeNonStaticPickerProps, UseRangePositionProps {} diff --git a/packages/x-date-pickers/src/DateField/DateField.tsx b/packages/x-date-pickers/src/DateField/DateField.tsx index 2d8704ab3310..2b70aae13d9e 100644 --- a/packages/x-date-pickers/src/DateField/DateField.tsx +++ b/packages/x-date-pickers/src/DateField/DateField.tsx @@ -1,16 +1,14 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import MuiTextField from '@mui/material/TextField'; import { useThemeProps } from '@mui/material/styles'; import useSlotProps from '@mui/utils/useSlotProps'; import { refType } from '@mui/utils'; import { DateFieldProps } from './DateField.types'; import { useDateField } from './useDateField'; -import { useClearableField } from '../hooks'; import { PickersTextField } from '../PickersTextField'; -import { convertFieldResponseIntoMuiTextFieldProps } from '../internals/utils/convertFieldResponseIntoMuiTextFieldProps'; import { useFieldOwnerState } from '../internals/hooks/useFieldOwnerState'; +import { PickerFieldUI } from '../internals/components/PickerFieldUI'; type DateFieldComponent = (( props: DateFieldProps & React.RefAttributes, @@ -38,11 +36,10 @@ const DateField = React.forwardRef(function DateField< const ownerState = useFieldOwnerState(themeProps); - const TextField = - slots?.textField ?? - (inProps.enableAccessibleFieldDOMStructure === false ? MuiTextField : PickersTextField); + // The `textField` slot props cannot be handled inside `PickerFieldUI` because it would be a breaking change to not pass the enriched props to `useField`. + // Once the non-accessible DOM structure will be removed, we will be able to remove the `textField` slot and clean this logic. const textFieldProps = useSlotProps({ - elementType: TextField, + elementType: PickersTextField, externalSlotProps: slotProps?.textField, externalForwardedProps: other, additionalProps: { @@ -58,15 +55,8 @@ const DateField = React.forwardRef(function DateField< const fieldResponse = useDateField( textFieldProps, ); - const convertedFieldResponse = convertFieldResponseIntoMuiTextFieldProps(fieldResponse); - const processedFieldProps = useClearableField({ - ...convertedFieldResponse, - slots, - slotProps, - }); - - return ; + return ; }) as DateFieldComponent; DateField.propTypes = { diff --git a/packages/x-date-pickers/src/DateField/DateField.types.ts b/packages/x-date-pickers/src/DateField/DateField.types.ts index 7226c4ac6579..5d462bd8f03b 100644 --- a/packages/x-date-pickers/src/DateField/DateField.types.ts +++ b/packages/x-date-pickers/src/DateField/DateField.types.ts @@ -1,16 +1,10 @@ -import * as React from 'react'; -import type { TextFieldProps } from '@mui/material/TextField'; -import { MakeOptional, SlotComponentPropsFromProps } from '@mui/x-internals/types'; -import { - ExportedUseClearableFieldProps, - UseClearableFieldSlots, - UseClearableFieldSlotProps, -} from '../hooks/useClearableField'; -import { DateValidationError, BuiltInFieldTextFieldProps, FieldOwnerState } from '../models'; +import { MakeOptional } from '@mui/x-internals/types'; +import { ExportedUseClearableFieldProps } from '../hooks/useClearableField'; +import { DateValidationError, BuiltInFieldTextFieldProps } from '../models'; import { UseFieldInternalProps } from '../internals/hooks/useField'; import { ExportedValidateDateProps } from '../validation/validateDate'; -import { PickersTextFieldProps } from '../PickersTextField'; import { PickerValue } from '../internals/models'; +import { PickerFieldUISlotProps, PickerFieldUISlots } from '../internals/components/PickerFieldUI'; export interface UseDateFieldProps extends MakeOptional< @@ -43,18 +37,6 @@ export type DateFieldProps = DateFieldProps; -export interface DateFieldSlots extends UseClearableFieldSlots { - /** - * Form control with an input to render the value. - * @default , or from '@mui/material' if `enableAccessibleFieldDOMStructure` is `false`. - */ - textField?: React.ElementType; -} +export interface DateFieldSlots extends PickerFieldUISlots {} -export interface DateFieldSlotProps extends UseClearableFieldSlotProps { - textField?: SlotComponentPropsFromProps< - PickersTextFieldProps | TextFieldProps, - {}, - FieldOwnerState - >; -} +export interface DateFieldSlotProps extends PickerFieldUISlotProps {} diff --git a/packages/x-date-pickers/src/DateField/useDateField.ts b/packages/x-date-pickers/src/DateField/useDateField.ts index 42d7b01fe3a8..afd4b540aa94 100644 --- a/packages/x-date-pickers/src/DateField/useDateField.ts +++ b/packages/x-date-pickers/src/DateField/useDateField.ts @@ -9,6 +9,7 @@ import { validateDate } from '../validation'; import { useSplitFieldProps } from '../hooks'; import { useDefaultizedDateField } from '../internals/hooks/defaultizedFieldProps'; import { PickerValue } from '../internals/models'; +import { useGetOpenDialogAriaText } from '../internals/hooks/useGetOpenPickerAriaLabel'; export const useDateField = < TEnableAccessibleFieldDOMStructure extends boolean, @@ -23,6 +24,11 @@ export const useDateField = < const { forwardedProps, internalProps } = useSplitFieldProps(props, 'date'); + const getOpenDialogAriaText = useGetOpenDialogAriaText({ + formatKey: 'fullDate', + translationKey: 'openDatePickerDialogue', + }); + return useField< PickerValue, TEnableAccessibleFieldDOMStructure, @@ -35,5 +41,6 @@ export const useDateField = < fieldValueManager: singleItemFieldValueManager, validator: validateDate, valueType: 'date', + getOpenDialogAriaText, }); }; diff --git a/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx b/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx index 876e25f77ed4..1a7d02e7b937 100644 --- a/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx +++ b/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx @@ -7,10 +7,9 @@ import useSlotProps from '@mui/utils/useSlotProps'; import { refType } from '@mui/utils'; import { DateTimeFieldProps } from './DateTimeField.types'; import { useDateTimeField } from './useDateTimeField'; -import { useClearableField } from '../hooks'; import { PickersTextField } from '../PickersTextField'; -import { convertFieldResponseIntoMuiTextFieldProps } from '../internals/utils/convertFieldResponseIntoMuiTextFieldProps'; import { useFieldOwnerState } from '../internals/hooks/useFieldOwnerState'; +import { PickerFieldUI } from '../internals/components/PickerFieldUI'; type DateTimeFieldComponent = (( props: DateTimeFieldProps & @@ -62,15 +61,8 @@ const DateTimeField = React.forwardRef(function DateTimeField< const fieldResponse = useDateTimeField( textFieldProps, ); - const convertedFieldResponse = convertFieldResponseIntoMuiTextFieldProps(fieldResponse); - const processedFieldProps = useClearableField({ - ...convertedFieldResponse, - slots, - slotProps, - }); - - return ; + return ; }) as DateTimeFieldComponent; DateTimeField.propTypes = { diff --git a/packages/x-date-pickers/src/DateTimeField/DateTimeField.types.ts b/packages/x-date-pickers/src/DateTimeField/DateTimeField.types.ts index 2c3964472c39..d52d26722503 100644 --- a/packages/x-date-pickers/src/DateTimeField/DateTimeField.types.ts +++ b/packages/x-date-pickers/src/DateTimeField/DateTimeField.types.ts @@ -1,17 +1,11 @@ -import * as React from 'react'; -import { MakeOptional, SlotComponentPropsFromProps } from '@mui/x-internals/types'; -import { TextFieldProps } from '@mui/material/TextField'; -import { DateTimeValidationError, BuiltInFieldTextFieldProps, FieldOwnerState } from '../models'; +import { MakeOptional } from '@mui/x-internals/types'; +import { DateTimeValidationError, BuiltInFieldTextFieldProps } from '../models'; import { UseFieldInternalProps } from '../internals/hooks/useField'; -import { - ExportedUseClearableFieldProps, - UseClearableFieldSlots, - UseClearableFieldSlotProps, -} from '../hooks/useClearableField'; +import { ExportedUseClearableFieldProps } from '../hooks/useClearableField'; import { ExportedValidateDateTimeProps } from '../validation/validateDateTime'; import { AmPmProps } from '../internals/models/props/time'; import { PickerValue } from '../internals/models'; -import { PickersTextFieldProps } from '../PickersTextField'; +import { PickerFieldUISlotProps, PickerFieldUISlots } from '../internals/components/PickerFieldUI'; export interface UseDateTimeFieldProps extends MakeOptional< @@ -46,18 +40,6 @@ export type DateTimeFieldProps, or from '@mui/material' if `enableAccessibleFieldDOMStructure` is `false`. - */ - textField?: React.ElementType; -} +export interface DateTimeFieldSlots extends PickerFieldUISlots {} -export interface DateTimeFieldSlotProps extends UseClearableFieldSlotProps { - textField?: SlotComponentPropsFromProps< - PickersTextFieldProps | TextFieldProps, - {}, - FieldOwnerState - >; -} +export interface DateTimeFieldSlotProps extends PickerFieldUISlotProps {} diff --git a/packages/x-date-pickers/src/DateTimeField/useDateTimeField.ts b/packages/x-date-pickers/src/DateTimeField/useDateTimeField.ts index bd3b0b585352..fe58b3aff6dd 100644 --- a/packages/x-date-pickers/src/DateTimeField/useDateTimeField.ts +++ b/packages/x-date-pickers/src/DateTimeField/useDateTimeField.ts @@ -9,6 +9,7 @@ import { validateDateTime } from '../validation'; import { useSplitFieldProps } from '../hooks'; import { useDefaultizedDateTimeField } from '../internals/hooks/defaultizedFieldProps'; import { PickerValue } from '../internals/models'; +import { useGetOpenDialogAriaText } from '../internals/hooks/useGetOpenPickerAriaLabel'; export const useDateTimeField = < TEnableAccessibleFieldDOMStructure extends boolean, @@ -23,6 +24,11 @@ export const useDateTimeField = < const { forwardedProps, internalProps } = useSplitFieldProps(props, 'date-time'); + const getOpenDialogAriaText = useGetOpenDialogAriaText({ + formatKey: 'fullDate', + translationKey: 'openDatePickerDialogue', + }); + return useField< PickerValue, TEnableAccessibleFieldDOMStructure, @@ -35,5 +41,6 @@ export const useDateTimeField = < fieldValueManager: singleItemFieldValueManager, validator: validateDateTime, valueType: 'date-time', + getOpenDialogAriaText, }); }; diff --git a/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.tsx b/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.tsx index f5f035ca05f0..c9d5454588f8 100644 --- a/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.tsx +++ b/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.tsx @@ -6,7 +6,6 @@ import { refType } from '@mui/utils'; import { singleItemValueManager } from '../internals/utils/valueManagers'; import { DesktopDatePickerProps } from './DesktopDatePicker.types'; import { DatePickerViewRenderers, useDatePickerDefaultizedProps } from '../DatePicker/shared'; -import { usePickerTranslations } from '../hooks/usePickerTranslations'; import { useUtils } from '../internals/hooks/useUtils'; import { validateDate, extractValidationProps } from '../validation'; import { DateView, PickerOwnerState } from '../models'; @@ -15,7 +14,6 @@ import { CalendarIcon } from '../icons'; import { DateField } from '../DateField'; import { renderDateViewCalendar } from '../dateViewRenderers'; import { resolveDateFormat } from '../internals/utils/date-utils'; -import { buildGetOpenDialogAriaText } from '../locales/utils/getPickersLocalization'; type DesktopDatePickerComponent = (( props: DesktopDatePickerProps & @@ -38,7 +36,6 @@ const DesktopDatePicker = React.forwardRef(function DesktopDatePicker< inProps: DesktopDatePickerProps, ref: React.Ref, ) { - const translations = usePickerTranslations(); const utils = useUtils(); // Props with the default values common to all date pickers @@ -86,12 +83,6 @@ const DesktopDatePicker = React.forwardRef(function DesktopDatePicker< props, valueManager: singleItemValueManager, valueType: 'date', - getOpenDialogAriaText: buildGetOpenDialogAriaText({ - utils, - formatKey: 'fullDate', - contextTranslation: translations.openDatePickerDialogue, - propsTranslation: props.localeText?.openDatePickerDialogue, - }), validator: validateDate, }); diff --git a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx index 3e7ba8dd6635..cd37c8fb0709 100644 --- a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx +++ b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx @@ -13,7 +13,6 @@ import { DateTimePickerViewRenderers, } from '../DateTimePicker/shared'; import { renderDateViewCalendar } from '../dateViewRenderers/dateViewRenderers'; -import { usePickerTranslations } from '../hooks/usePickerTranslations'; import { useUtils } from '../internals/hooks/useUtils'; import { validateDateTime, extractValidationProps } from '../validation'; import { DateOrTimeViewWithMeridiem, PickerValue } from '../internals/models'; @@ -41,7 +40,6 @@ import { VIEW_HEIGHT } from '../internals/constants/dimensions'; import { UsePickerViewsProps } from '../internals/hooks/usePicker/usePickerViews'; import { isInternalTimeView } from '../internals/utils/time-utils'; import { isDatePickerView } from '../internals/utils/date-utils'; -import { buildGetOpenDialogAriaText } from '../locales/utils/getPickersLocalization'; import { PickerLayoutOwnerState } from '../PickersLayout'; const rendererInterceptor = function rendererInterceptor< @@ -130,7 +128,6 @@ const DesktopDateTimePicker = React.forwardRef(function DesktopDateTimePicker< inProps: DesktopDateTimePickerProps, ref: React.Ref, ) { - const translations = usePickerTranslations(); const utils = useUtils(); // Props with the default values common to all date time pickers @@ -220,12 +217,6 @@ const DesktopDateTimePicker = React.forwardRef(function DesktopDateTimePicker< props, valueManager: singleItemValueManager, valueType: 'date-time', - getOpenDialogAriaText: buildGetOpenDialogAriaText({ - utils, - formatKey: 'fullDate', - contextTranslation: translations.openDatePickerDialogue, - propsTranslation: props.localeText?.openDatePickerDialogue, - }), validator: validateDateTime, rendererInterceptor, }); diff --git a/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx b/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx index 75528d45cd42..ebb120ab5e68 100644 --- a/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx +++ b/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx @@ -7,7 +7,6 @@ import { singleItemValueManager } from '../internals/utils/valueManagers'; import { TimeField } from '../TimeField'; import { DesktopTimePickerProps } from './DesktopTimePicker.types'; import { TimePickerViewRenderers, useTimePickerDefaultizedProps } from '../TimePicker/shared'; -import { usePickerTranslations } from '../hooks/usePickerTranslations'; import { useUtils } from '../internals/hooks/useUtils'; import { extractValidationProps, validateTime } from '../validation'; import { ClockIcon } from '../icons'; @@ -21,7 +20,6 @@ import { TimeViewWithMeridiem } from '../internals/models'; import { resolveTimeFormat } from '../internals/utils/time-utils'; import { resolveTimeViewsResponse } from '../internals/utils/date-time-utils'; import { TimeView, PickerOwnerState } from '../models'; -import { buildGetOpenDialogAriaText } from '../locales/utils/getPickersLocalization'; type DesktopTimePickerComponent = (( props: DesktopTimePickerProps & @@ -44,7 +42,6 @@ const DesktopTimePicker = React.forwardRef(function DesktopTimePicker< inProps: DesktopTimePickerProps, ref: React.Ref, ) { - const translations = usePickerTranslations(); const utils = useUtils(); // Props with the default values common to all time pickers @@ -124,12 +121,6 @@ const DesktopTimePicker = React.forwardRef(function DesktopTimePicker< props, valueManager: singleItemValueManager, valueType: 'time', - getOpenDialogAriaText: buildGetOpenDialogAriaText({ - utils, - formatKey: 'fullTime', - contextTranslation: translations.openTimePickerDialogue, - propsTranslation: props.localeText?.openTimePickerDialogue, - }), validator: validateTime, }); diff --git a/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx b/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx index 90e9db74e87d..d6df29951a56 100644 --- a/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx +++ b/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx @@ -6,7 +6,6 @@ import { refType } from '@mui/utils'; import { useMobilePicker } from '../internals/hooks/useMobilePicker'; import { MobileDatePickerProps } from './MobileDatePicker.types'; import { DatePickerViewRenderers, useDatePickerDefaultizedProps } from '../DatePicker/shared'; -import { usePickerTranslations } from '../hooks/usePickerTranslations'; import { useUtils } from '../internals/hooks/useUtils'; import { extractValidationProps, validateDate } from '../validation'; import { DateView, PickerOwnerState } from '../models'; @@ -14,7 +13,6 @@ import { DateField } from '../DateField'; import { singleItemValueManager } from '../internals/utils/valueManagers'; import { renderDateViewCalendar } from '../dateViewRenderers'; import { resolveDateFormat } from '../internals/utils/date-utils'; -import { buildGetOpenDialogAriaText } from '../locales/utils/getPickersLocalization'; type MobileDatePickerComponent = (( props: MobileDatePickerProps & @@ -37,7 +35,6 @@ const MobileDatePicker = React.forwardRef(function MobileDatePicker< inProps: MobileDatePickerProps, ref: React.Ref, ) { - const translations = usePickerTranslations(); const utils = useUtils(); // Props with the default values common to all date pickers @@ -83,12 +80,6 @@ const MobileDatePicker = React.forwardRef(function MobileDatePicker< props, valueManager: singleItemValueManager, valueType: 'date', - getOpenDialogAriaText: buildGetOpenDialogAriaText({ - utils, - formatKey: 'fullDate', - contextTranslation: translations.openDatePickerDialogue, - propsTranslation: props.localeText?.openDatePickerDialogue, - }), validator: validateDate, }); diff --git a/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx b/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx index cdc1c91a5abe..b7da2a82bfed 100644 --- a/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx +++ b/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx @@ -10,7 +10,6 @@ import { DateTimePickerViewRenderers, useDateTimePickerDefaultizedProps, } from '../DateTimePicker/shared'; -import { usePickerTranslations } from '../hooks/usePickerTranslations'; import { useUtils } from '../internals/hooks/useUtils'; import { extractValidationProps, validateDateTime } from '../validation'; import { DateOrTimeView, PickerOwnerState } from '../models'; @@ -18,7 +17,6 @@ import { useMobilePicker } from '../internals/hooks/useMobilePicker'; import { renderDateViewCalendar } from '../dateViewRenderers'; import { renderTimeViewClock } from '../timeViewRenderers'; import { resolveDateTimeFormat } from '../internals/utils/date-time-utils'; -import { buildGetOpenDialogAriaText } from '../locales/utils/getPickersLocalization'; type MobileDateTimePickerComponent = (( props: MobileDateTimePickerProps & @@ -41,7 +39,6 @@ const MobileDateTimePicker = React.forwardRef(function MobileDateTimePicker< inProps: MobileDateTimePickerProps, ref: React.Ref, ) { - const translations = usePickerTranslations(); const utils = useUtils(); // Props with the default values common to all date time pickers @@ -98,12 +95,6 @@ const MobileDateTimePicker = React.forwardRef(function MobileDateTimePicker< props, valueManager: singleItemValueManager, valueType: 'date-time', - getOpenDialogAriaText: buildGetOpenDialogAriaText({ - utils, - formatKey: 'fullDate', - contextTranslation: translations.openDatePickerDialogue, - propsTranslation: props.localeText?.openDatePickerDialogue, - }), validator: validateDateTime, }); diff --git a/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx b/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx index 4428a5c28a14..4f3c8ef317d7 100644 --- a/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx +++ b/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx @@ -7,14 +7,12 @@ import { singleItemValueManager } from '../internals/utils/valueManagers'; import { TimeField } from '../TimeField'; import { MobileTimePickerProps } from './MobileTimePicker.types'; import { TimePickerViewRenderers, useTimePickerDefaultizedProps } from '../TimePicker/shared'; -import { usePickerTranslations } from '../hooks/usePickerTranslations'; import { useUtils } from '../internals/hooks/useUtils'; import { extractValidationProps, validateTime } from '../validation'; import { PickerOwnerState, TimeView } from '../models'; import { useMobilePicker } from '../internals/hooks/useMobilePicker'; import { renderTimeViewClock } from '../timeViewRenderers'; import { resolveTimeFormat } from '../internals/utils/time-utils'; -import { buildGetOpenDialogAriaText } from '../locales/utils/getPickersLocalization'; type MobileTimePickerComponent = (( props: MobileTimePickerProps & @@ -37,7 +35,6 @@ const MobileTimePicker = React.forwardRef(function MobileTimePicker< inProps: MobileTimePickerProps, ref: React.Ref, ) { - const translations = usePickerTranslations(); const utils = useUtils(); // Props with the default values common to all time pickers @@ -87,12 +84,6 @@ const MobileTimePicker = React.forwardRef(function MobileTimePicker< props, valueManager: singleItemValueManager, valueType: 'time', - getOpenDialogAriaText: buildGetOpenDialogAriaText({ - utils, - formatKey: 'fullTime', - contextTranslation: translations.openTimePickerDialogue, - propsTranslation: props.localeText?.openTimePickerDialogue, - }), validator: validateTime, }); diff --git a/packages/x-date-pickers/src/TimeField/TimeField.tsx b/packages/x-date-pickers/src/TimeField/TimeField.tsx index 571fd5c6b723..8217df023b0c 100644 --- a/packages/x-date-pickers/src/TimeField/TimeField.tsx +++ b/packages/x-date-pickers/src/TimeField/TimeField.tsx @@ -1,16 +1,14 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import MuiTextField from '@mui/material/TextField'; import { useThemeProps } from '@mui/material/styles'; import useSlotProps from '@mui/utils/useSlotProps'; import { refType } from '@mui/utils'; import { TimeFieldProps } from './TimeField.types'; import { useTimeField } from './useTimeField'; -import { useClearableField } from '../hooks'; import { PickersTextField } from '../PickersTextField'; -import { convertFieldResponseIntoMuiTextFieldProps } from '../internals/utils/convertFieldResponseIntoMuiTextFieldProps'; import { useFieldOwnerState } from '../internals/hooks/useFieldOwnerState'; +import { PickerFieldUI } from '../internals/components/PickerFieldUI'; type TimeFieldComponent = (( props: TimeFieldProps & React.RefAttributes, @@ -38,11 +36,10 @@ const TimeField = React.forwardRef(function TimeField< const ownerState = useFieldOwnerState(themeProps); - const TextField = - slots?.textField ?? - (inProps.enableAccessibleFieldDOMStructure === false ? MuiTextField : PickersTextField); + // The `textField` slot props cannot be handled inside `PickerFieldUI` because it would be a breaking change to not pass the enriched props to `useField`. + // Once the non-accessible DOM structure will be removed, we will be able to remove the `textField` slot and clean this logic. const textFieldProps = useSlotProps({ - elementType: TextField, + elementType: PickersTextField, externalSlotProps: slotProps?.textField, externalForwardedProps: other, ownerState, @@ -58,15 +55,8 @@ const TimeField = React.forwardRef(function TimeField< const fieldResponse = useTimeField( textFieldProps, ); - const convertedFieldResponse = convertFieldResponseIntoMuiTextFieldProps(fieldResponse); - const processedFieldProps = useClearableField({ - ...convertedFieldResponse, - slots, - slotProps, - }); - - return ; + return ; }) as TimeFieldComponent; TimeField.propTypes = { diff --git a/packages/x-date-pickers/src/TimeField/TimeField.types.ts b/packages/x-date-pickers/src/TimeField/TimeField.types.ts index 819535baa8fb..29621ee51fb2 100644 --- a/packages/x-date-pickers/src/TimeField/TimeField.types.ts +++ b/packages/x-date-pickers/src/TimeField/TimeField.types.ts @@ -1,17 +1,11 @@ -import * as React from 'react'; -import type { TextFieldProps } from '@mui/material/TextField'; -import { MakeOptional, SlotComponentPropsFromProps } from '@mui/x-internals/types'; +import { MakeOptional } from '@mui/x-internals/types'; import { UseFieldInternalProps } from '../internals/hooks/useField'; -import { TimeValidationError, BuiltInFieldTextFieldProps, FieldOwnerState } from '../models'; -import { - ExportedUseClearableFieldProps, - UseClearableFieldSlots, - UseClearableFieldSlotProps, -} from '../hooks/useClearableField'; +import { TimeValidationError, BuiltInFieldTextFieldProps } from '../models'; +import { ExportedUseClearableFieldProps } from '../hooks/useClearableField'; import { ExportedValidateTimeProps } from '../validation/validateTime'; import { AmPmProps } from '../internals/models/props/time'; import { PickerValue } from '../internals/models'; -import { PickersTextFieldProps } from '../PickersTextField'; +import { PickerFieldUISlotProps, PickerFieldUISlots } from '../internals/components/PickerFieldUI'; export interface UseTimeFieldProps extends MakeOptional< @@ -42,18 +36,6 @@ export type TimeFieldProps, or from '@mui/material' if `enableAccessibleFieldDOMStructure` is `false`. - */ - textField?: React.ElementType; -} +export interface TimeFieldSlots extends PickerFieldUISlots {} -export interface TimeFieldSlotProps extends UseClearableFieldSlotProps { - textField?: SlotComponentPropsFromProps< - PickersTextFieldProps | TextFieldProps, - {}, - FieldOwnerState - >; -} +export interface TimeFieldSlotProps extends PickerFieldUISlotProps {} diff --git a/packages/x-date-pickers/src/TimeField/useTimeField.ts b/packages/x-date-pickers/src/TimeField/useTimeField.ts index 51a88016a8dc..8549b49889b2 100644 --- a/packages/x-date-pickers/src/TimeField/useTimeField.ts +++ b/packages/x-date-pickers/src/TimeField/useTimeField.ts @@ -9,6 +9,7 @@ import { validateTime } from '../validation'; import { useSplitFieldProps } from '../hooks'; import { useDefaultizedTimeField } from '../internals/hooks/defaultizedFieldProps'; import { PickerValue } from '../internals/models'; +import { useGetOpenDialogAriaText } from '../internals/hooks/useGetOpenPickerAriaLabel'; export const useTimeField = < TEnableAccessibleFieldDOMStructure extends boolean, @@ -23,6 +24,11 @@ export const useTimeField = < const { forwardedProps, internalProps } = useSplitFieldProps(props, 'time'); + const getOpenDialogAriaText = useGetOpenDialogAriaText({ + formatKey: 'fullTime', + translationKey: 'openTimePickerDialogue', + }); + return useField< PickerValue, TEnableAccessibleFieldDOMStructure, @@ -35,5 +41,6 @@ export const useTimeField = < fieldValueManager: singleItemFieldValueManager, validator: validateTime, valueType: 'time', + getOpenDialogAriaText, }); }; diff --git a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx new file mode 100644 index 000000000000..c6e20cf0c471 --- /dev/null +++ b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx @@ -0,0 +1,320 @@ +import * as React from 'react'; +import MuiTextField, { TextFieldProps } from '@mui/material/TextField'; +import MuiIconButton, { IconButtonProps } from '@mui/material/IconButton'; +import MuiInputAdornment, { InputAdornmentProps } from '@mui/material/InputAdornment'; +import { SvgIconProps } from '@mui/material/SvgIcon'; +import useSlotProps from '@mui/utils/useSlotProps'; +import { SlotComponentPropsFromProps } from '@mui/x-internals/types'; +import { FieldOwnerState } from '../../models'; +import { useFieldOwnerState } from '../hooks/useFieldOwnerState'; +import { usePickerTranslations } from '../../hooks'; +import { ClearIcon as MuiClearIcon } from '../../icons'; +import { useNullablePickerContext } from '../hooks/useNullablePickerContext'; +import { usePickerPrivateContext } from '../hooks/usePickerPrivateContext'; +import { UseFieldResponse } from '../hooks/useField'; +import { PickersTextField, PickersTextFieldProps } from '../../PickersTextField'; + +export const cleanFieldResponse = < + TFieldResponse extends UseFieldResponse, +>({ + enableAccessibleFieldDOMStructure, + ...fieldResponse +}: TFieldResponse): ExportedPickerFieldUIProps & { + openPickerAriaLabel: string; + textFieldProps: TextFieldProps | PickersTextFieldProps; +} => { + if (enableAccessibleFieldDOMStructure) { + const { + InputProps, + readOnly, + onClear, + clearable, + clearButtonPosition, + openPickerButtonPosition, + openPickerAriaLabel, + ...other + } = fieldResponse; + + return { + clearable, + onClear, + clearButtonPosition, + openPickerButtonPosition, + openPickerAriaLabel, + textFieldProps: { + ...other, + InputProps: { ...(InputProps ?? {}), readOnly }, + }, + }; + } + + const { + onPaste, + onKeyDown, + inputMode, + readOnly, + InputProps, + inputProps, + inputRef, + onClear, + clearable, + clearButtonPosition, + openPickerButtonPosition, + openPickerAriaLabel, + ...other + } = fieldResponse; + + return { + clearable, + onClear, + clearButtonPosition, + openPickerButtonPosition, + openPickerAriaLabel, + textFieldProps: { + ...other, + InputProps: { ...(InputProps ?? {}), readOnly }, + inputProps: { ...(inputProps ?? {}), inputMode, onPaste, onKeyDown, ref: inputRef }, + }, + }; +}; + +/** + * @ignore - internal component. + */ +export function PickerFieldUI(props: PickerFieldUIProps) { + const { slots, slotProps, fieldResponse } = props; + + const translations = usePickerTranslations(); + const pickerContext = useNullablePickerContext(); + const { openingUIStatus } = usePickerPrivateContext(); + const { + textFieldProps, + onClear, + clearable, + openPickerAriaLabel, + clearButtonPosition: clearButtonPositionProp = 'end', + openPickerButtonPosition: openPickerButtonPositionProp = 'end', + } = cleanFieldResponse(fieldResponse); + const ownerState = useFieldOwnerState(textFieldProps); + + const handleTogglePicker = (event) => { + if (!pickerContext) { + return; + } + + if (pickerContext.open) { + pickerContext.onClose(event); + } else { + pickerContext.onOpen(event); + } + }; + + const TextField = + slots?.textField ?? + (fieldResponse.enableAccessibleFieldDOMStructure === false ? MuiTextField : PickersTextField); + + const InputAdornment = slots?.inputAdornment ?? MuiInputAdornment; + const { ownerState: startInputAdornmentOwnerState, ...startInputAdornmentProps } = useSlotProps({ + elementType: InputAdornment, + externalSlotProps: slotProps?.inputAdornment, + additionalProps: { + position: 'start' as const, + }, + ownerState: { ...ownerState, position: 'start' }, + }); + const { ownerState: endInputAdornmentOwnerState, ...endInputAdornmentProps } = useSlotProps({ + elementType: InputAdornment, + externalSlotProps: slotProps?.inputAdornment, + additionalProps: { + position: 'end' as const, + }, + ownerState: { ...ownerState, position: 'end' }, + }); + + const OpenPickerButton = slots?.openPickerButton ?? MuiIconButton; + const { ownerState: openPickerButtonOwnerState, ...openPickerButtonProps } = useSlotProps({ + elementType: OpenPickerButton, + externalSlotProps: slotProps?.openPickerButton, + additionalProps: { + disabled: openingUIStatus === 'disabled', + onClick: handleTogglePicker, + 'aria-label': openPickerAriaLabel, + edge: openPickerButtonPositionProp, + }, + ownerState, + }); + + const OpenPickerIcon = slots?.openPickerIcon; + const openPickerIconProps = useSlotProps({ + elementType: OpenPickerIcon, + externalSlotProps: slotProps?.openPickerIcon, + ownerState, + }); + + const ClearButton = slots?.clearButton ?? MuiIconButton; + // The spread is here to avoid this bug mui/material-ui#34056 + const { ownerState: clearButtonOwnerState, ...clearButtonProps } = useSlotProps({ + elementType: ClearButton, + externalSlotProps: slotProps?.clearButton, + className: 'clearButton', + additionalProps: { + title: translations.fieldClearLabel, + tabIndex: -1, + onClick: onClear, + edge: clearButtonPositionProp, + }, + ownerState, + }); + const ClearIcon = slots?.clearIcon ?? MuiClearIcon; + const clearIconProps = useSlotProps({ + elementType: ClearIcon, + externalSlotProps: slotProps?.clearIcon, + additionalProps: { + fontSize: 'small', + }, + ownerState, + }); + + const clearButtonPosition = clearable ? clearButtonPositionProp : null; + const openPickerButtonPosition = + openingUIStatus !== 'hidden' ? openPickerButtonPositionProp : null; + + if (!textFieldProps.InputProps) { + textFieldProps.InputProps = {}; + } + + if (pickerContext) { + textFieldProps.InputProps.ref = pickerContext.triggerRef; + } + + if ( + !textFieldProps.InputProps?.startAdornment && + (clearButtonPosition === 'start' || openPickerButtonPosition === 'start') + ) { + textFieldProps.InputProps.startAdornment = ( + + {openPickerButtonPosition === 'start' && ( + + + + )} + {clearButtonPosition === 'start' && ( + + + + )} + + ); + } + + if ( + !textFieldProps.InputProps?.endAdornment && + (clearButtonPosition === 'end' || openPickerButtonPosition === 'end') + ) { + textFieldProps.InputProps.endAdornment = ( + + {clearButtonPosition === 'end' && ( + + + + )} + {openPickerButtonPosition === 'end' && ( + + + + )} + + ); + } + + return ; +} + +export interface ExportedPickerFieldUIProps { + /** + * If `true`, a clear button will be shown in the field allowing value clearing. + * @default false + */ + clearable?: boolean; + /** + * Callback fired when the clear button is clicked. + */ + onClear?: React.MouseEventHandler; + /** + * The position at which the UI to clear the value should be placed. + * If the field is not clearable, the button will not be rendered. + */ + clearButtonPosition: 'start' | 'end'; + /** + * The position at which the UI to clear the value should be placed. + * If there is no picker to open, the button will not be rendered. + */ + openPickerButtonPosition: 'start' | 'end'; +} + +export interface PickerFieldUIProps { + /** + * Overridable component slots. + * @default {} + */ + slots: PickerFieldUISlots | undefined; + /** + * The props used for each component slot. + * @default {} + */ + slotProps?: PickerFieldUISlotProps | undefined; + fieldResponse: UseFieldResponse; +} + +export interface PickerFieldUISlots { + /** + * Form control with an input to render the value. + * @default , or from '@mui/material' if `enableAccessibleFieldDOMStructure` is `false`. + */ + textField?: React.ElementType; + /** + * Component displayed on the start or end input adornment used to open the picker on desktop. + * @default InputAdornment + */ + inputAdornment?: React.ElementType; + /** + * Button to open the picker on desktop. + * @default IconButton + */ + openPickerButton?: React.ElementType; + /** + * Icon displayed in the open picker button on desktop. + */ + openPickerIcon: React.ElementType; + /** + * Icon to display inside the clear button. + * @default ClearIcon + */ + clearIcon?: React.ElementType; + /** + * Button to clear the value. + * @default IconButton + */ + clearButton?: React.ElementType; +} + +export interface PickerFieldUISlotProps { + textField?: SlotComponentPropsFromProps< + PickersTextFieldProps | TextFieldProps, + {}, + FieldOwnerState + >; + inputAdornment?: SlotComponentPropsFromProps< + InputAdornmentProps, + {}, + FieldInputAdornmentOwnerState + >; + openPickerButton?: SlotComponentPropsFromProps; + openPickerIcon?: SlotComponentPropsFromProps, {}, FieldOwnerState>; + clearIcon?: SlotComponentPropsFromProps; + clearButton?: SlotComponentPropsFromProps; +} + +interface FieldInputAdornmentOwnerState extends FieldOwnerState { + position: 'start' | 'end'; +} diff --git a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx index 85eeaf1f04d8..6b7ba40293a4 100644 --- a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx @@ -15,6 +15,7 @@ export const PickerPrivateContext = React.createContext void; + /** + * The ref that should be attached to the element that triggers the picker opening. + */ + triggerRef: React.RefObject; /** * `true` if the picker is open, `false` otherwise. */ @@ -89,4 +94,8 @@ export interface PickerPrivateContextValue { * The ownerState of the picker. */ ownerState: PickerOwnerState; + /** + * Informs the field if it should render the UI to open the picker. + */ + openingUIStatus: 'hidden' | 'disabled' | 'enabled'; } diff --git a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx index 3ac24e4b6227..fe0e539feb22 100644 --- a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx +++ b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx @@ -1,7 +1,5 @@ import * as React from 'react'; import useSlotProps from '@mui/utils/useSlotProps'; -import MuiInputAdornment from '@mui/material/InputAdornment'; -import IconButton from '@mui/material/IconButton'; import useForkRef from '@mui/utils/useForkRef'; import useId from '@mui/utils/useId'; import { PickersPopper } from '../../components/PickersPopper'; @@ -29,7 +27,6 @@ export const useDesktopPicker = < >, >({ props, - getOpenDialogAriaText, ...pickerParams }: UseDesktopPickerParams) => { const { @@ -53,7 +50,6 @@ export const useDesktopPicker = < reduceAnimations, } = props; - const containerRef = React.useRef(null); const fieldRef = React.useRef>(null); const labelId = useId(); @@ -62,7 +58,6 @@ export const useDesktopPicker = < const { open, actions, - hasUIView, layoutProps, providerProps, renderCurrentView, @@ -79,36 +74,6 @@ export const useDesktopPicker = < variant: 'desktop', }); - const InputAdornment = slots.inputAdornment ?? MuiInputAdornment; - const { ownerState: inputAdornmentOwnerState, ...inputAdornmentProps } = useSlotProps({ - elementType: InputAdornment, - externalSlotProps: innerSlotProps?.inputAdornment, - additionalProps: { - position: 'end' as const, - }, - ownerState, - }); - - const OpenPickerButton = slots.openPickerButton ?? IconButton; - const { ownerState: openPickerButtonOwnerState, ...openPickerButtonProps } = useSlotProps({ - elementType: OpenPickerButton, - externalSlotProps: innerSlotProps?.openPickerButton, - additionalProps: { - disabled: disabled || readOnly, - onClick: open ? actions.onClose : actions.onOpen, - 'aria-label': getOpenDialogAriaText(pickerFieldProps.value), - edge: inputAdornmentProps.position, - }, - ownerState, - }); - - const OpenPickerIcon = slots.openPickerIcon; - const openPickerIconProps = useSlotProps({ - elementType: OpenPickerIcon, - externalSlotProps: innerSlotProps?.openPickerIcon, - ownerState, - }); - const Field = slots.field; const fieldProps: BaseSingleInputFieldProps< PickerValue, @@ -142,30 +107,6 @@ export const useDesktopPicker = < ownerState, }); - // TODO: Move to `useSlotProps` when https://github.com/mui/material-ui/pull/35088 will be merged - if (hasUIView) { - fieldProps.InputProps = { - ...fieldProps.InputProps, - ref: containerRef, - ...(!props.disableOpenPicker && { - [`${inputAdornmentProps.position}Adornment`]: ( - - - - - - ), - }), - } as typeof fieldProps.InputProps; - } - - const slotsForField = { - textField: slots.textField, - clearIcon: slots.clearIcon, - clearButton: slots.clearButton, - ...fieldProps.slots, - }; - const Layout = slots.layout ?? PickersLayout; let labelledById = labelId; @@ -188,6 +129,16 @@ export const useDesktopPicker = < }, }; + const slotsForField = { + ...slots, + ...fieldProps.slots, + }; + + const slotPropsForField = { + ...slotProps, + ...fieldProps.slotProps, + }; + const handleFieldRef = useForkRef(fieldRef, fieldProps.unstableFieldRef); const renderPicker = () => ( @@ -195,13 +146,13 @@ export const useDesktopPicker = < extends Pick< @@ -36,7 +27,7 @@ export interface UseDesktopPickerSlots 'desktopPaper' | 'desktopTransition' | 'desktopTrapFocus' | 'popper' >, ExportedPickersLayoutSlots, - UseClearableFieldSlots { + PickerFieldUISlots { /** * Component used to enter the date with the keyboard. */ @@ -46,20 +37,6 @@ export interface UseDesktopPickerSlots * @default TextField from '@mui/material' or PickersTextField if `enableAccessibleFieldDOMStructure` is `true`. */ textField?: React.ElementType; - /** - * Component displayed on the start or end input adornment used to open the picker on desktop. - * @default InputAdornment - */ - inputAdornment?: React.ElementType; - /** - * Button to open the picker on desktop. - * @default IconButton - */ - openPickerButton?: React.ElementType; - /** - * Icon displayed in the open picker button on desktop. - */ - openPickerIcon: React.ElementType; } export interface UseDesktopPickerSlotProps< @@ -73,7 +50,7 @@ export interface ExportedUseDesktopPickerSlotProps< TEnableAccessibleFieldDOMStructure extends boolean, > extends PickersPopperSlotProps, ExportedPickersLayoutSlotProps, - UseClearableFieldSlotProps { + PickerFieldUISlotProps { field?: SlotComponentPropsFromProps< PickerFieldSlotProps, {}, @@ -84,16 +61,13 @@ export interface ExportedUseDesktopPickerSlotProps< {}, FieldOwnerState >; - inputAdornment?: SlotComponentPropsFromProps; - openPickerButton?: SlotComponentPropsFromProps; - openPickerIcon?: SlotComponentPropsFromProps, {}, PickerOwnerState>; } export interface DesktopOnlyPickerProps extends BaseNonStaticPickerProps, BaseNonRangeNonStaticPickerProps, UsePickerValueNonStaticProps, - UsePickerViewsNonStaticProps { + UsePickerProviderNonStaticProps { /** * If `true`, the `input` element is focused during the first mount. * @default false @@ -134,5 +108,4 @@ export interface UseDesktopPickerParams< 'valueManager' | 'valueType' | 'validator' | 'rendererInterceptor' > { props: TExternalProps; - getOpenDialogAriaText: (date: PickerValidDate | null) => string; } diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.ts index 8bec0c4e9afa..d1d23402edcb 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.ts @@ -52,6 +52,7 @@ export const useField = < fieldValueManager, valueManager, validator, + getOpenDialogAriaText, } = params; const isRtl = useRtl(); @@ -282,6 +283,7 @@ export const useField = < const commonAdditionalProps: UseFieldCommonAdditionalProps = { disabled, readOnly, + openPickerAriaLabel: getOpenDialogAriaText(state.value), }; return { diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts index e28638917817..6fc93a88d3c7 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts @@ -34,6 +34,7 @@ export interface UseFieldParams< fieldValueManager: FieldValueManager; validator: Validator, TInternalProps>; valueType: PickerValueType; + getOpenDialogAriaText: (value: TValue) => string; } export interface UseFieldInternalProps< @@ -122,7 +123,9 @@ export interface UseFieldInternalProps< } export interface UseFieldCommonAdditionalProps - extends Required, 'disabled' | 'readOnly'>> {} + extends Required, 'disabled' | 'readOnly'>> { + openPickerAriaLabel: string; +} export interface UseFieldCommonForwardedProps extends ExportedUseClearableFieldProps { onKeyDown?: React.KeyboardEventHandler; diff --git a/packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts b/packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts new file mode 100644 index 000000000000..1a1efc5a5822 --- /dev/null +++ b/packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts @@ -0,0 +1,18 @@ +import { usePickerTranslations } from '../../hooks'; +import { AdapterFormats, PickerValidDate } from '../../models'; +import { useUtils } from './useUtils'; + +export const useGetOpenDialogAriaText = (params: { + formatKey: keyof AdapterFormats; + translationKey: 'openDatePickerDialogue' | 'openTimePickerDialogue'; +}) => { + const utils = useUtils(); + const translations = usePickerTranslations(); + const { formatKey, translationKey } = params; + + return (value: PickerValidDate | null) => { + const formattedValue = + value !== null && utils.isValid(value) ? utils.format(value, formatKey) : null; + return translations[translationKey](formattedValue); + }; +}; diff --git a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx index fc1ef14d56be..8fd9707a0b06 100644 --- a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx +++ b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx @@ -28,7 +28,6 @@ export const useMobilePicker = < >, >({ props, - getOpenDialogAriaText, ...pickerParams }: UseMobilePickerParams) => { const { @@ -108,17 +107,6 @@ export const useMobilePicker = < ownerState, }); - // TODO: Move to `useSlotProps` when https://github.com/mui/material-ui/pull/35088 will be merged - fieldProps.inputProps = { - ...fieldProps.inputProps, - 'aria-label': getOpenDialogAriaText(pickerFieldProps.value), - } as typeof fieldProps.inputProps; - - const slotsForField = { - textField: slots.textField, - ...fieldProps.slots, - }; - const Layout = slots.layout ?? PickersLayout; let labelledById = labelId; @@ -141,6 +129,16 @@ export const useMobilePicker = < }, }; + const slotsForField = { + ...slots, + ...fieldProps.slots, + }; + + const slotPropsForField = { + ...slotProps, + ...fieldProps.slotProps, + }; + const handleFieldRef = useForkRef(fieldRef, fieldProps.unstableFieldRef); const renderPicker = () => ( @@ -148,7 +146,7 @@ export const useMobilePicker = < diff --git a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.types.ts b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.types.ts index 375a4d0fc551..11436beb1e84 100644 --- a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.types.ts @@ -11,21 +11,17 @@ import { PickersModalDialogSlotProps, } from '../../components/PickersModalDialog'; import { UsePickerParams } from '../usePicker'; -import { - FieldOwnerState, - PickerFieldSlotProps, - PickerOwnerState, - PickerValidDate, -} from '../../../models'; +import { FieldOwnerState, PickerFieldSlotProps, PickerOwnerState } from '../../../models'; import { ExportedPickersLayoutSlots, ExportedPickersLayoutSlotProps, PickersLayoutSlotProps, } from '../../../PickersLayout/PickersLayout.types'; import { UsePickerValueNonStaticProps } from '../usePicker/usePickerValue.types'; -import { UsePickerViewsNonStaticProps, UsePickerViewsProps } from '../usePicker/usePickerViews'; +import { UsePickerViewsProps } from '../usePicker/usePickerViews'; import { DateOrTimeViewWithMeridiem, PickerValue } from '../../models'; import { PickersTextFieldProps } from '../../../PickersTextField'; +import { UsePickerProviderNonStaticProps } from '../usePicker/usePickerProvider'; export interface UseMobilePickerSlots extends PickersModalDialogSlots, @@ -68,7 +64,7 @@ export interface MobileOnlyPickerProps extends BaseNonStaticPickerProps, BaseNonRangeNonStaticPickerProps, UsePickerValueNonStaticProps, - UsePickerViewsNonStaticProps {} + UsePickerProviderNonStaticProps {} export interface UseMobilePickerProps< TView extends DateOrTimeViewWithMeridiem, @@ -103,5 +99,4 @@ export interface UseMobilePickerParams< 'valueManager' | 'valueType' | 'validator' > { props: TExternalProps; - getOpenDialogAriaText: (date: PickerValidDate | null) => string; } diff --git a/packages/x-date-pickers/src/internals/hooks/useNullablePickerContext.ts b/packages/x-date-pickers/src/internals/hooks/useNullablePickerContext.ts new file mode 100644 index 000000000000..a6600ee37c67 --- /dev/null +++ b/packages/x-date-pickers/src/internals/hooks/useNullablePickerContext.ts @@ -0,0 +1,9 @@ +'use client'; +import * as React from 'react'; +import { PickerContext } from '../components/PickerProvider'; + +/** + * Returns the context passed by the picker that wraps the current component. + * If the context is not found, returns `null`. + */ +export const useNullablePickerContext = () => React.useContext(PickerContext); diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts index 30b80061a4af..a4331c78d40a 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts @@ -60,6 +60,7 @@ export const usePicker = < valueManager, variant, views: pickerViewsResponse.views, + hasUIView: pickerViewsResponse.hasUIView, }); return { @@ -70,7 +71,6 @@ export const usePicker = < // Picker views renderCurrentView: pickerViewsResponse.renderCurrentView, - hasUIView: pickerViewsResponse.hasUIView, shouldRestoreFocus: pickerViewsResponse.shouldRestoreFocus, // Picker layout diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts index 37bbb59b667c..a96c34b0ed25 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts @@ -63,7 +63,7 @@ export interface UsePickerResponse< TView extends DateOrTimeViewWithMeridiem, TError, > extends Omit, 'viewProps' | 'layoutProps'>, - Omit, 'layoutProps' | 'views'> { + Omit, 'layoutProps' | 'views' | 'hasUIView'> { ownerState: PickerOwnerState; providerProps: UsePickerProviderReturnValue; layoutProps: UsePickerValueResponse['layoutProps'] & 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..8b8364e1d203 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts @@ -62,10 +62,12 @@ export const usePickerOrientation = ( export function usePickerProvider( parameters: UsePickerProviderParameters, ): UsePickerProviderReturnValue { - const { props, pickerValueResponse, valueManager, localeText, variant, views } = parameters; + const { props, pickerValueResponse, valueManager, localeText, variant, views, hasUIView } = + parameters; const utils = useUtils(); const orientation = usePickerOrientation(views, props.orientation); + const triggerRef = React.useRef(null); const ownerState = React.useMemo( () => ({ @@ -101,6 +103,7 @@ export function usePickerProvider( readOnly: props.readOnly ?? false, variant, orientation, + triggerRef, }), [ pickerValueResponse.actions.onOpen, @@ -113,9 +116,21 @@ export function usePickerProvider( ], ); + const openingUIStatus = React.useMemo(() => { + if (props.disableOpenPicker || !hasUIView) { + return 'hidden'; + } + + if (props.disabled || props.readOnly) { + return 'disabled'; + } + + return 'enabled'; + }, [props.disableOpenPicker, hasUIView, props.disabled, props.readOnly]); + const privateContextValue = React.useMemo( - () => ({ ownerState }), - [ownerState], + () => ({ ownerState, openingUIStatus }), + [ownerState, openingUIStatus], ); return { @@ -127,17 +142,18 @@ export function usePickerProvider( export interface UsePickerProviderParameters extends Pick { - props: UsePickerProps; + props: UsePickerProps & UsePickerProviderNonStaticProps; pickerValueResponse: UsePickerValueResponse; valueManager: PickerValueManager; variant: PickerVariant; views: readonly DateOrTimeViewWithMeridiem[]; + hasUIView: boolean; } export interface UsePickerProviderReturnValue extends Omit {} /** - * Props used to create the private context. + * Props used to create the picker's contexts. * Those props are exposed on all the pickers. */ export interface UsePickerProviderProps extends FormProps { @@ -146,3 +162,14 @@ export interface UsePickerProviderProps extends FormProps { */ orientation?: PickerOrientation; } + +/** + * Props used to create the picker's contexts and that are not available on static pickers. + */ +export interface UsePickerProviderNonStaticProps { + /** + * If `true`, the open picker button will not be rendered (renders only the field). + * @default false + */ + disableOpenPicker?: boolean; +} diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts index fe23fa3eb402..0c32260de8f7 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts @@ -78,17 +78,6 @@ export interface UsePickerViewsBaseProps< referenceDate?: PickerValidDate; } -/** - * Props used to handle the views of the pickers. - */ -export interface UsePickerViewsNonStaticProps { - /** - * If `true`, the open picker button will not be rendered (renders only the field). - * @default false - */ - disableOpenPicker?: boolean; -} - /** * Props used to handle the value of the pickers. */ diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index e7fd05dff8e3..035153425153 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -80,11 +80,11 @@ export type { PickerSelectionState, } from './hooks/usePicker/usePickerValue.types'; export type { - UsePickerViewsNonStaticProps, PickerViewRendererLookup, PickerViewRenderer, UsePickerViewsProps, } from './hooks/usePicker/usePickerViews'; +export type { UsePickerProviderNonStaticProps } from './hooks/usePicker/usePickerProvider'; export { usePickerPrivateContext } from './hooks/usePickerPrivateContext'; export { useStaticPicker } from './hooks/useStaticPicker'; export type { diff --git a/packages/x-date-pickers/src/internals/utils/convertFieldResponseIntoMuiTextFieldProps.ts b/packages/x-date-pickers/src/internals/utils/convertFieldResponseIntoMuiTextFieldProps.ts index 7124c455941a..7cfc387fc6a3 100644 --- a/packages/x-date-pickers/src/internals/utils/convertFieldResponseIntoMuiTextFieldProps.ts +++ b/packages/x-date-pickers/src/internals/utils/convertFieldResponseIntoMuiTextFieldProps.ts @@ -8,7 +8,7 @@ export const convertFieldResponseIntoMuiTextFieldProps = < ...fieldResponse }: TFieldResponse): TextFieldProps => { if (enableAccessibleFieldDOMStructure) { - const { InputProps, readOnly, ...other } = fieldResponse; + const { InputProps, readOnly, value, ...other } = fieldResponse; return { ...other, diff --git a/packages/x-date-pickers/src/locales/utils/getPickersLocalization.ts b/packages/x-date-pickers/src/locales/utils/getPickersLocalization.ts index 598e90d7079e..a6cf8e68da86 100644 --- a/packages/x-date-pickers/src/locales/utils/getPickersLocalization.ts +++ b/packages/x-date-pickers/src/locales/utils/getPickersLocalization.ts @@ -1,4 +1,3 @@ -import { AdapterFormats, MuiPickersAdapter, PickerValidDate } from '../../models'; import { PickersLocaleText } from './pickersLocaleTextApi'; export const getPickersLocalization = (pickersTranslations: Partial) => { @@ -12,19 +11,3 @@ export const getPickersLocalization = (pickersTranslations: Partial string; - propsTranslation: ((formattedValue: string | null) => string) | undefined; -}) => { - const { utils, formatKey, contextTranslation, propsTranslation } = params; - - return (value: PickerValidDate | null) => { - const formattedValue = - value !== null && utils.isValid(value) ? utils.format(value, formatKey) : null; - const translation = propsTranslation ?? contextTranslation; - return translation(formattedValue); - }; -}; From 4f734a82c8ad0d076d366cf99d99827b955430ea Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 12:13:46 +0100 Subject: [PATCH 02/77] Try to support range field --- .../MultiInputDateRangeField.tsx | 9 ++-- .../MultiInputDateTimeRangeField.tsx | 9 ++-- .../MultiInputTimeRangeField.tsx | 9 ++-- .../SingleInputDateRangeField.tsx | 29 +++++----- .../useSingleInputDateRangeField.ts | 7 +++ .../useSingleInputDateTimeRangeField.ts | 7 +++ .../useSingleInputTimeRangeField.ts | 7 +++ .../useDesktopRangePicker.tsx | 5 +- .../hooks/useEnrichedRangePickerFieldProps.ts | 5 -- .../hooks/useGetOpenRangeDialogAriaText.ts | 20 +++++++ .../hooks/useMultiInputRangeField/shared.ts | 12 ----- .../useMultiInputDateRangeField.ts | 6 +-- .../useMultiInputDateTimeRangeField.ts | 6 +-- .../useMultiInputTimeRangeField.ts | 6 +-- .../src/DateField/DateField.tsx | 9 +++- .../src/DateField/DateField.types.ts | 11 ++-- .../src/DateTimeField/DateTimeField.tsx | 9 +++- .../src/DateTimeField/DateTimeField.types.ts | 11 ++-- .../DesktopDatePicker/DesktopDatePicker.tsx | 2 - .../DesktopDateTimePicker.tsx | 2 - .../DesktopTimePicker/DesktopTimePicker.tsx | 2 - .../src/TimeField/TimeField.tsx | 9 +++- .../src/TimeField/TimeField.types.ts | 11 ++-- .../internals/components/PickerFieldUI.tsx | 54 ++++++++++++------- .../useDesktopPicker.types.ts | 4 +- .../hooks/useGetOpenPickerAriaLabel.ts | 5 +- .../hooks/useMobilePicker/useMobilePicker.tsx | 10 ++-- .../x-date-pickers/src/internals/index.ts | 6 ++- packages/x-date-pickers/src/locales/enUS.ts | 30 +++++++++++ .../src/locales/utils/pickersLocaleTextApi.ts | 2 + packages/x-date-pickers/src/models/fields.ts | 8 ++- 31 files changed, 198 insertions(+), 124 deletions(-) create mode 100644 packages/x-date-pickers-pro/src/internals/hooks/useGetOpenRangeDialogAriaText.ts delete mode 100644 packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/shared.ts diff --git a/packages/x-date-pickers-pro/src/MultiInputDateRangeField/MultiInputDateRangeField.tsx b/packages/x-date-pickers-pro/src/MultiInputDateRangeField/MultiInputDateRangeField.tsx index 50cd4f22cbb7..884e069ee3ed 100644 --- a/packages/x-date-pickers-pro/src/MultiInputDateRangeField/MultiInputDateRangeField.tsx +++ b/packages/x-date-pickers-pro/src/MultiInputDateRangeField/MultiInputDateRangeField.tsx @@ -12,10 +12,7 @@ import { unstable_generateUtilityClass as generateUtilityClass, unstable_generateUtilityClasses as generateUtilityClasses, } from '@mui/utils'; -import { - convertFieldResponseIntoMuiTextFieldProps, - useFieldOwnerState, -} from '@mui/x-date-pickers/internals'; +import { cleanFieldResponse, useFieldOwnerState } from '@mui/x-date-pickers/internals'; import { useSplitFieldProps } from '@mui/x-date-pickers/hooks'; import { PickersTextField } from '@mui/x-date-pickers/PickersTextField'; import { @@ -166,8 +163,8 @@ const MultiInputDateRangeField = React.forwardRef(function MultiInputDateRangeFi unstableEndFieldRef, }); - const startDateProps = convertFieldResponseIntoMuiTextFieldProps(fieldResponse.startDate); - const endDateProps = convertFieldResponseIntoMuiTextFieldProps(fieldResponse.endDate); + const { textFieldProps: startDateProps } = cleanFieldResponse(fieldResponse.startDate); + const { textFieldProps: endDateProps } = cleanFieldResponse(fieldResponse.endDate); return ( diff --git a/packages/x-date-pickers-pro/src/MultiInputDateTimeRangeField/MultiInputDateTimeRangeField.tsx b/packages/x-date-pickers-pro/src/MultiInputDateTimeRangeField/MultiInputDateTimeRangeField.tsx index 06b579877035..db9e69a034ee 100644 --- a/packages/x-date-pickers-pro/src/MultiInputDateTimeRangeField/MultiInputDateTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/MultiInputDateTimeRangeField/MultiInputDateTimeRangeField.tsx @@ -12,10 +12,7 @@ import { unstable_generateUtilityClass as generateUtilityClass, unstable_generateUtilityClasses as generateUtilityClasses, } from '@mui/utils'; -import { - convertFieldResponseIntoMuiTextFieldProps, - useFieldOwnerState, -} from '@mui/x-date-pickers/internals'; +import { cleanFieldResponse, useFieldOwnerState } from '@mui/x-date-pickers/internals'; import { useSplitFieldProps } from '@mui/x-date-pickers/hooks'; import { PickersTextField } from '@mui/x-date-pickers/PickersTextField'; import { @@ -164,8 +161,8 @@ const MultiInputDateTimeRangeField = React.forwardRef(function MultiInputDateTim unstableEndFieldRef, }); - const startDateProps = convertFieldResponseIntoMuiTextFieldProps(fieldResponse.startDate); - const endDateProps = convertFieldResponseIntoMuiTextFieldProps(fieldResponse.endDate); + const { textFieldProps: startDateProps } = cleanFieldResponse(fieldResponse.startDate); + const { textFieldProps: endDateProps } = cleanFieldResponse(fieldResponse.endDate); return ( diff --git a/packages/x-date-pickers-pro/src/MultiInputTimeRangeField/MultiInputTimeRangeField.tsx b/packages/x-date-pickers-pro/src/MultiInputTimeRangeField/MultiInputTimeRangeField.tsx index e9e5c24a2ea2..e13e853a49e6 100644 --- a/packages/x-date-pickers-pro/src/MultiInputTimeRangeField/MultiInputTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/MultiInputTimeRangeField/MultiInputTimeRangeField.tsx @@ -12,10 +12,7 @@ import { unstable_generateUtilityClass as generateUtilityClass, unstable_generateUtilityClasses as generateUtilityClasses, } from '@mui/utils'; -import { - convertFieldResponseIntoMuiTextFieldProps, - useFieldOwnerState, -} from '@mui/x-date-pickers/internals'; +import { cleanFieldResponse, useFieldOwnerState } from '@mui/x-date-pickers/internals'; import { useSplitFieldProps } from '@mui/x-date-pickers/hooks'; import { PickersTextField } from '@mui/x-date-pickers/PickersTextField'; import { @@ -167,8 +164,8 @@ const MultiInputTimeRangeField = React.forwardRef(function MultiInputTimeRangeFi unstableEndFieldRef, }); - const startDateProps = convertFieldResponseIntoMuiTextFieldProps(fieldResponse.startDate); - const endDateProps = convertFieldResponseIntoMuiTextFieldProps(fieldResponse.endDate); + const { textFieldProps: startDateProps } = cleanFieldResponse(fieldResponse.startDate); + const { textFieldProps: endDateProps } = cleanFieldResponse(fieldResponse.endDate); return ( diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx index 86707618138f..02f04b9486ae 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx @@ -1,15 +1,11 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import MuiTextField from '@mui/material/TextField'; import { useThemeProps } from '@mui/material/styles'; import useSlotProps from '@mui/utils/useSlotProps'; import { refType } from '@mui/utils'; -import { useClearableField } from '@mui/x-date-pickers/hooks'; -import { - convertFieldResponseIntoMuiTextFieldProps, - useFieldOwnerState, -} from '@mui/x-date-pickers/internals'; +import { CalendarIcon } from '@mui/x-date-pickers/icons'; +import { useFieldOwnerState, PickerFieldUI } from '@mui/x-date-pickers/internals'; import { PickersTextField } from '@mui/x-date-pickers/PickersTextField'; import { SingleInputDateRangeFieldProps } from './SingleInputDateRangeField.types'; import { useSingleInputDateRangeField } from './useSingleInputDateRangeField'; @@ -45,9 +41,9 @@ const SingleInputDateRangeField = React.forwardRef(function SingleInputDateRange const ownerState = useFieldOwnerState(themeProps); - const TextField = - slots?.textField ?? - (inProps.enableAccessibleFieldDOMStructure === false ? MuiTextField : PickersTextField); + // The `textField` slot props cannot be handled inside `PickerFieldUI` because it would be a breaking change to not pass the enriched props to `useField`. + // Once the non-accessible DOM structure will be removed, we will be able to remove the `textField` slot and clean this logic. + const TextField = PickersTextField; const textFieldProps = useSlotProps({ elementType: TextField, externalSlotProps: slotProps?.textField, @@ -66,15 +62,14 @@ const SingleInputDateRangeField = React.forwardRef(function SingleInputDateRange TEnableAccessibleFieldDOMStructure, typeof textFieldProps >(textFieldProps); - const convertedFieldResponse = convertFieldResponseIntoMuiTextFieldProps(fieldResponse); - const processedFieldProps = useClearableField({ - ...convertedFieldResponse, - slots, - slotProps, - }); - - return ; + return ( + + ); }) as DateRangeFieldComponent; SingleInputDateRangeField.fieldType = 'single-input'; diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts index e1b71090039e..f4b93c231fb9 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts @@ -5,6 +5,7 @@ import { useSplitFieldProps } from '@mui/x-date-pickers/hooks'; import { UseSingleInputDateRangeFieldProps } from './SingleInputDateRangeField.types'; import { rangeValueManager, getRangeFieldValueManager } from '../internals/utils/valueManagers'; import { validateDateRange } from '../validation'; +import { useGetOpenRangeDialogAriaText } from '../internals/hooks/useGetOpenRangeDialogAriaText'; export const useSingleInputDateRangeField = < TEnableAccessibleFieldDOMStructure extends boolean, @@ -24,6 +25,11 @@ export const useSingleInputDateRangeField = < [internalProps.dateSeparator], ); + const getOpenDialogAriaText = useGetOpenRangeDialogAriaText({ + formatKey: 'fullDate', + translationKey: 'openDateRangePickerDialogue', + }); + return useField< PickerRangeValue, TEnableAccessibleFieldDOMStructure, @@ -36,5 +42,6 @@ export const useSingleInputDateRangeField = < fieldValueManager, validator: validateDateRange, valueType: 'date', + getOpenDialogAriaText, }); }; diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts index 1fbed22a25d0..0c9f0aeb917d 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts @@ -9,6 +9,7 @@ import { useSplitFieldProps } from '@mui/x-date-pickers/hooks'; import { UseSingleInputDateTimeRangeFieldProps } from './SingleInputDateTimeRangeField.types'; import { rangeValueManager, getRangeFieldValueManager } from '../internals/utils/valueManagers'; import { validateDateTimeRange } from '../validation'; +import { useGetOpenRangeDialogAriaText } from '../internals/hooks/useGetOpenRangeDialogAriaText'; export const useSingleInputDateTimeRangeField = < TEnableAccessibleFieldDOMStructure extends boolean, @@ -28,6 +29,11 @@ export const useSingleInputDateTimeRangeField = < [internalProps.dateSeparator], ); + const getOpenDialogAriaText = useGetOpenRangeDialogAriaText({ + formatKey: 'fullDate', + translationKey: 'openDateRangePickerDialogue', + }); + return useField< PickerRangeValue, TEnableAccessibleFieldDOMStructure, @@ -40,5 +46,6 @@ export const useSingleInputDateTimeRangeField = < fieldValueManager, validator: validateDateTimeRange, valueType: 'date-time', + getOpenDialogAriaText, }); }; diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts index a55e35d42c97..a049219ee1c8 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts @@ -5,6 +5,7 @@ import { useSplitFieldProps } from '@mui/x-date-pickers/hooks'; import { UseSingleInputTimeRangeFieldProps } from './SingleInputTimeRangeField.types'; import { rangeValueManager, getRangeFieldValueManager } from '../internals/utils/valueManagers'; import { validateTimeRange } from '../validation'; +import { useGetOpenRangeDialogAriaText } from '../internals/hooks/useGetOpenRangeDialogAriaText'; export const useSingleInputTimeRangeField = < TEnableAccessibleFieldDOMStructure extends boolean, @@ -24,6 +25,11 @@ export const useSingleInputTimeRangeField = < [internalProps.dateSeparator], ); + const getOpenDialogAriaText = useGetOpenRangeDialogAriaText({ + formatKey: 'fullTime', + translationKey: 'openTimeRangePickerDialogue', + }); + return useField< PickerRangeValue, TEnableAccessibleFieldDOMStructure, @@ -36,5 +42,6 @@ export const useSingleInputTimeRangeField = < fieldValueManager, validator: validateTimeRange, valueType: 'time', + getOpenDialogAriaText, }); }; 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 4dabe621a1e7..a540f77a569f 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 @@ -67,7 +67,6 @@ export const useDesktopRangePicker = < } = props; const fieldContainerRef = React.useRef(null); - const anchorRef = React.useRef(null); const popperRef = React.useRef(null); const startFieldRef = React.useRef>(null); const endFieldRef = React.useRef>(null); @@ -182,7 +181,7 @@ export const useDesktopRangePicker = < pickerSlotProps: slotProps, pickerSlots: slots, fieldProps, - anchorRef, + anchorRef: providerProps.contextValue.triggerRef, startFieldRef, endFieldRef, singleInputFieldRef, @@ -213,7 +212,7 @@ export const useDesktopRangePicker = < role="tooltip" placement="bottom-start" containerRef={popperRef} - anchorEl={anchorRef.current} + anchorEl={providerProps.contextValue.triggerRef.current} onBlur={handleBlur} {...actions} open={open} diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts index a858ae3df40b..a10a6e1d9827 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts @@ -309,7 +309,6 @@ const useSingleInputFieldSlotProps = < pickerSlots, pickerSlotProps, fieldProps, - anchorRef, currentView, }: UseEnrichedRangePickerFieldPropsParams< true, @@ -398,10 +397,6 @@ const useSingleInputFieldSlotProps = < onKeyDown: onSpaceOrEnter(openPicker, fieldProps.onKeyDown), onSelectedSectionsChange: handleSelectedSectionsChange, onBlur, - InputProps: { - ref: anchorRef, - ...fieldProps?.InputProps, - }, focused: open ? true : undefined, ...(labelId != null && { id: labelId }), ...(variant === 'mobile' && { readOnly: true }), diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useGetOpenRangeDialogAriaText.ts b/packages/x-date-pickers-pro/src/internals/hooks/useGetOpenRangeDialogAriaText.ts new file mode 100644 index 000000000000..08b138fa15eb --- /dev/null +++ b/packages/x-date-pickers-pro/src/internals/hooks/useGetOpenRangeDialogAriaText.ts @@ -0,0 +1,20 @@ +import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; +import { PickerRangeValue, useUtils } from '@mui/x-date-pickers/internals'; +import { AdapterFormats } from '@mui/x-date-pickers/models'; + +export const useGetOpenRangeDialogAriaText = (params: { + formatKey: keyof AdapterFormats; + translationKey: 'openDateRangePickerDialogue' | 'openTimeRangePickerDialogue'; +}) => { + const utils = useUtils(); + const translations = usePickerTranslations(); + const { formatKey, translationKey } = params; + + return (value: PickerRangeValue) => { + const formattedValue = [ + value[0] !== null && utils.isValid(value[0]) ? utils.format(value[0], formatKey) : null, + value[1] !== null && utils.isValid(value[1]) ? utils.format(value[1], formatKey) : null, + ] as const; + return translations[translationKey](formattedValue); + }; +}; diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/shared.ts b/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/shared.ts deleted file mode 100644 index f3568f99ad13..000000000000 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/shared.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* TODO: remove this when a clearable behavior for multiple input range fields is implemented */ -export const excludeProps = ( - props: TProps, - excludedProps: Array, -): TProps => { - return (Object.keys(props) as Array).reduce((acc, key) => { - if (!excludedProps.includes(key)) { - acc[key] = props[key]; - } - return acc; - }, {} as TProps); -}; diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateRangeField.ts b/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateRangeField.ts index 081fbf140f0e..724cc8791a36 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateRangeField.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateRangeField.ts @@ -19,7 +19,6 @@ import { validateDateRange } from '../../../validation'; import { rangeValueManager } from '../../utils/valueManagers'; import type { UseMultiInputRangeFieldResponse } from './useMultiInputRangeField.types'; import { DateRangeValidationError } from '../../../models'; -import { excludeProps } from './shared'; import { useMultiInputFieldSelectedSections } from '../useMultiInputFieldSelectedSections'; export const useMultiInputDateRangeField = < @@ -144,9 +143,8 @@ export const useMultiInputDateRangeField = < endFieldProps, ) as UseFieldResponse; - /* TODO: Undo this change when a clearable behavior for multiple input range fields is implemented */ return { - startDate: excludeProps(startDateResponse, ['clearable', 'onClear']), - endDate: excludeProps(endDateResponse, ['clearable', 'onClear']), + startDate: startDateResponse, + endDate: endDateResponse, }; }; diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateTimeRangeField.ts b/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateTimeRangeField.ts index 3a006da7c913..d42bfdc7b867 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateTimeRangeField.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputDateTimeRangeField.ts @@ -19,7 +19,6 @@ import { DateTimeRangeValidationError } from '../../../models'; import { validateDateTimeRange } from '../../../validation'; import { rangeValueManager } from '../../utils/valueManagers'; import type { UseMultiInputRangeFieldResponse } from './useMultiInputRangeField.types'; -import { excludeProps } from './shared'; import { useMultiInputFieldSelectedSections } from '../useMultiInputFieldSelectedSections'; export const useMultiInputDateTimeRangeField = < @@ -145,9 +144,8 @@ export const useMultiInputDateTimeRangeField = < typeof endFieldProps >(endFieldProps) as UseFieldResponse; - /* TODO: Undo this change when a clearable behavior for multiple input range fields is implemented */ return { - startDate: excludeProps(startDateResponse, ['clearable', 'onClear']), - endDate: excludeProps(endDateResponse, ['clearable', 'onClear']), + startDate: startDateResponse, + endDate: endDateResponse, }; }; diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputTimeRangeField.ts b/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputTimeRangeField.ts index 9f8b36291f5f..b8ee4cd81730 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputTimeRangeField.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMultiInputRangeField/useMultiInputTimeRangeField.ts @@ -19,7 +19,6 @@ import type { } from '../../../MultiInputTimeRangeField/MultiInputTimeRangeField.types'; import { rangeValueManager } from '../../utils/valueManagers'; import type { UseMultiInputRangeFieldResponse } from './useMultiInputRangeField.types'; -import { excludeProps } from './shared'; import { useMultiInputFieldSelectedSections } from '../useMultiInputFieldSelectedSections'; export const useMultiInputTimeRangeField = < @@ -144,9 +143,8 @@ export const useMultiInputTimeRangeField = < endFieldProps, ) as UseFieldResponse; - /* TODO: Undo this change when a clearable behavior for multiple input range fields is implemented */ return { - startDate: excludeProps(startDateResponse, ['clearable', 'onClear']), - endDate: excludeProps(endDateResponse, ['clearable', 'onClear']), + startDate: startDateResponse, + endDate: endDateResponse, }; }; diff --git a/packages/x-date-pickers/src/DateField/DateField.tsx b/packages/x-date-pickers/src/DateField/DateField.tsx index 2b70aae13d9e..f65eb0e676be 100644 --- a/packages/x-date-pickers/src/DateField/DateField.tsx +++ b/packages/x-date-pickers/src/DateField/DateField.tsx @@ -9,6 +9,7 @@ import { useDateField } from './useDateField'; import { PickersTextField } from '../PickersTextField'; import { useFieldOwnerState } from '../internals/hooks/useFieldOwnerState'; import { PickerFieldUI } from '../internals/components/PickerFieldUI'; +import { CalendarIcon } from '../icons'; type DateFieldComponent = (( props: DateFieldProps & React.RefAttributes, @@ -56,7 +57,13 @@ const DateField = React.forwardRef(function DateField< textFieldProps, ); - return ; + return ( + + ); }) as DateFieldComponent; DateField.propTypes = { diff --git a/packages/x-date-pickers/src/DateField/DateField.types.ts b/packages/x-date-pickers/src/DateField/DateField.types.ts index 5d462bd8f03b..f401d3c5cc67 100644 --- a/packages/x-date-pickers/src/DateField/DateField.types.ts +++ b/packages/x-date-pickers/src/DateField/DateField.types.ts @@ -1,10 +1,13 @@ import { MakeOptional } from '@mui/x-internals/types'; -import { ExportedUseClearableFieldProps } from '../hooks/useClearableField'; import { DateValidationError, BuiltInFieldTextFieldProps } from '../models'; import { UseFieldInternalProps } from '../internals/hooks/useField'; import { ExportedValidateDateProps } from '../validation/validateDate'; import { PickerValue } from '../internals/models'; -import { PickerFieldUISlotProps, PickerFieldUISlots } from '../internals/components/PickerFieldUI'; +import { + ExportedPickerFieldUIProps, + PickerFieldUISlotProps, + ExportedPickerFieldUISlots, +} from '../internals/components/PickerFieldUI'; export interface UseDateFieldProps extends MakeOptional< @@ -12,7 +15,7 @@ export interface UseDateFieldProps, ExportedValidateDateProps, - ExportedUseClearableFieldProps {} + ExportedPickerFieldUIProps {} export type DateFieldProps = // The hook props @@ -37,6 +40,6 @@ export type DateFieldProps = DateFieldProps; -export interface DateFieldSlots extends PickerFieldUISlots {} +export interface DateFieldSlots extends ExportedPickerFieldUISlots {} export interface DateFieldSlotProps extends PickerFieldUISlotProps {} diff --git a/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx b/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx index 1a7d02e7b937..d92f11d7dbac 100644 --- a/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx +++ b/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx @@ -10,6 +10,7 @@ import { useDateTimeField } from './useDateTimeField'; import { PickersTextField } from '../PickersTextField'; import { useFieldOwnerState } from '../internals/hooks/useFieldOwnerState'; import { PickerFieldUI } from '../internals/components/PickerFieldUI'; +import { CalendarIcon } from '../icons'; type DateTimeFieldComponent = (( props: DateTimeFieldProps & @@ -62,7 +63,13 @@ const DateTimeField = React.forwardRef(function DateTimeField< textFieldProps, ); - return ; + return ( + + ); }) as DateTimeFieldComponent; DateTimeField.propTypes = { diff --git a/packages/x-date-pickers/src/DateTimeField/DateTimeField.types.ts b/packages/x-date-pickers/src/DateTimeField/DateTimeField.types.ts index d52d26722503..f381a5c85711 100644 --- a/packages/x-date-pickers/src/DateTimeField/DateTimeField.types.ts +++ b/packages/x-date-pickers/src/DateTimeField/DateTimeField.types.ts @@ -1,11 +1,14 @@ import { MakeOptional } from '@mui/x-internals/types'; import { DateTimeValidationError, BuiltInFieldTextFieldProps } from '../models'; import { UseFieldInternalProps } from '../internals/hooks/useField'; -import { ExportedUseClearableFieldProps } from '../hooks/useClearableField'; import { ExportedValidateDateTimeProps } from '../validation/validateDateTime'; import { AmPmProps } from '../internals/models/props/time'; import { PickerValue } from '../internals/models'; -import { PickerFieldUISlotProps, PickerFieldUISlots } from '../internals/components/PickerFieldUI'; +import { + ExportedPickerFieldUIProps, + PickerFieldUISlotProps, + ExportedPickerFieldUISlots, +} from '../internals/components/PickerFieldUI'; export interface UseDateTimeFieldProps extends MakeOptional< @@ -17,7 +20,7 @@ export interface UseDateTimeFieldProps, ExportedValidateDateTimeProps, - ExportedUseClearableFieldProps, + ExportedPickerFieldUIProps, AmPmProps {} export type DateTimeFieldProps = @@ -40,6 +43,6 @@ export type DateTimeFieldProps( props: TimeFieldProps & React.RefAttributes, @@ -56,7 +57,13 @@ const TimeField = React.forwardRef(function TimeField< textFieldProps, ); - return ; + return ( + + ); }) as TimeFieldComponent; TimeField.propTypes = { diff --git a/packages/x-date-pickers/src/TimeField/TimeField.types.ts b/packages/x-date-pickers/src/TimeField/TimeField.types.ts index 29621ee51fb2..9c0a273bd0b3 100644 --- a/packages/x-date-pickers/src/TimeField/TimeField.types.ts +++ b/packages/x-date-pickers/src/TimeField/TimeField.types.ts @@ -1,11 +1,14 @@ import { MakeOptional } from '@mui/x-internals/types'; import { UseFieldInternalProps } from '../internals/hooks/useField'; import { TimeValidationError, BuiltInFieldTextFieldProps } from '../models'; -import { ExportedUseClearableFieldProps } from '../hooks/useClearableField'; import { ExportedValidateTimeProps } from '../validation/validateTime'; import { AmPmProps } from '../internals/models/props/time'; import { PickerValue } from '../internals/models'; -import { PickerFieldUISlotProps, PickerFieldUISlots } from '../internals/components/PickerFieldUI'; +import { + ExportedPickerFieldUIProps, + PickerFieldUISlotProps, + ExportedPickerFieldUISlots, +} from '../internals/components/PickerFieldUI'; export interface UseTimeFieldProps extends MakeOptional< @@ -13,7 +16,7 @@ export interface UseTimeFieldProps, ExportedValidateTimeProps, - ExportedUseClearableFieldProps, + ExportedPickerFieldUIProps, AmPmProps {} export type TimeFieldProps = @@ -36,6 +39,6 @@ export type TimeFieldProps; } -export interface PickerFieldUISlots { +interface PickerFieldUISlots { /** * Form control with an input to render the value. * @default , or from '@mui/material' if `enableAccessibleFieldDOMStructure` is `false`. @@ -298,6 +309,9 @@ export interface PickerFieldUISlots { clearButton?: React.ElementType; } +export interface ExportedPickerFieldUISlots + extends MakeOptional {} + export interface PickerFieldUISlotProps { textField?: SlotComponentPropsFromProps< PickersTextFieldProps | TextFieldProps, diff --git a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.types.ts b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.types.ts index 89aff5f45d00..29e462fe2d34 100644 --- a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.types.ts @@ -18,7 +18,7 @@ import { UsePickerValueNonStaticProps } from '../usePicker/usePickerValue.types' import { UsePickerViewsProps } from '../usePicker/usePickerViews'; import { DateOrTimeViewWithMeridiem, PickerValue } from '../../models'; import { PickersTextFieldProps } from '../../../PickersTextField'; -import { PickerFieldUISlots, PickerFieldUISlotProps } from '../../components/PickerFieldUI'; +import { ExportedPickerFieldUISlots, PickerFieldUISlotProps } from '../../components/PickerFieldUI'; import { UsePickerProviderNonStaticProps } from '../usePicker/usePickerProvider'; export interface UseDesktopPickerSlots @@ -27,7 +27,7 @@ export interface UseDesktopPickerSlots 'desktopPaper' | 'desktopTransition' | 'desktopTrapFocus' | 'popper' >, ExportedPickersLayoutSlots, - PickerFieldUISlots { + ExportedPickerFieldUISlots { /** * Component used to enter the date with the keyboard. */ diff --git a/packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts b/packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts index 1a1efc5a5822..a550f3fe9bc0 100644 --- a/packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts +++ b/packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts @@ -1,5 +1,6 @@ import { usePickerTranslations } from '../../hooks'; -import { AdapterFormats, PickerValidDate } from '../../models'; +import { AdapterFormats } from '../../models'; +import { PickerValue } from '../models'; import { useUtils } from './useUtils'; export const useGetOpenDialogAriaText = (params: { @@ -10,7 +11,7 @@ export const useGetOpenDialogAriaText = (params: { const translations = usePickerTranslations(); const { formatKey, translationKey } = params; - return (value: PickerValidDate | null) => { + return (value: PickerValue) => { const formattedValue = value !== null && utils.isValid(value) ? utils.format(value, formatKey) : null; return translations[translationKey](formattedValue); diff --git a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx index 8fd9707a0b06..34dba00cc177 100644 --- a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx +++ b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx @@ -5,7 +5,6 @@ import useId from '@mui/utils/useId'; import { PickersModalDialog } from '../../components/PickersModalDialog'; import { UseMobilePickerParams, UseMobilePickerProps } from './useMobilePicker.types'; import { usePicker } from '../usePicker'; -import { onSpaceOrEnter } from '../../utils/utils'; import { PickersLayout } from '../../../PickersLayout'; import { FieldRef, InferError } from '../../../models'; import { BaseSingleInputFieldProps, DateOrTimeViewWithMeridiem, PickerValue } from '../../models'; @@ -46,6 +45,7 @@ export const useMobilePicker = < inputRef, readOnly, disabled, + autoFocus, localeText, } = props; @@ -82,7 +82,7 @@ export const useMobilePicker = < externalSlotProps: innerSlotProps?.field, additionalProps: { // Internal props - readOnly: readOnly ?? true, + readOnly, disabled, format, formatDensity, @@ -90,6 +90,7 @@ export const useMobilePicker = < selectedSections, onSelectedSectionsChange, timezone, + autoFocus: autoFocus && !props.open, ...pickerFieldProps, // onChange and value // Forwarded props @@ -97,11 +98,8 @@ export const useMobilePicker = < sx, label, name, + focused: open ? true : undefined, ...(isToolbarHidden && { id: labelId }), - ...(!(disabled || readOnly) && { - onClick: actions.onOpen, - onKeyDown: onSpaceOrEnter(actions.onOpen), - }), ...(!!inputRef && { inputRef }), }, ownerState, diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index 035153425153..cf4ebe8da733 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -4,6 +4,11 @@ export type { PickersArrowSwitcherSlots, PickersArrowSwitcherSlotProps, } from './components/PickersArrowSwitcher'; +export { PickerFieldUI, cleanFieldResponse } from './components/PickerFieldUI'; +export type { + ExportedPickerFieldUISlots, + PickerFieldUISlotProps, +} from './components/PickerFieldUI'; export { PickerProvider } from './components/PickerProvider'; export { PickersModalDialog } from './components/PickersModalDialog'; export type { @@ -130,7 +135,6 @@ export type { PickerValidValue, } from './models/value'; -export { convertFieldResponseIntoMuiTextFieldProps } from './utils/convertFieldResponseIntoMuiTextFieldProps'; export { applyDefaultDate, replaceInvalidDateByNull, diff --git a/packages/x-date-pickers/src/locales/enUS.ts b/packages/x-date-pickers/src/locales/enUS.ts index 488a0681602f..4bbe5857a848 100644 --- a/packages/x-date-pickers/src/locales/enUS.ts +++ b/packages/x-date-pickers/src/locales/enUS.ts @@ -57,6 +57,36 @@ const enUSPickers: PickersLocaleText = { formattedDate ? `Choose date, selected date is ${formattedDate}` : 'Choose date', openTimePickerDialogue: (formattedTime) => formattedTime ? `Choose time, selected time is ${formattedTime}` : 'Choose time', + openDateRangePickerDialogue: ([formattedStartDate, formattedEndDate]) => { + if (!formattedStartDate && !formattedEndDate) { + return 'Choose date range'; + } + + if (!formattedStartDate) { + return `Choose date range, end date is ${formattedEndDate}`; + } + + if (!formattedEndDate) { + return `Choose date range, start date is ${formattedStartDate}`; + } + + return `Choose date range, start date is ${formattedStartDate}, end date is ${formattedEndDate}`; + }, + openTimeRangePickerDialogue: ([formattedStartTime, formattedEndTime]) => { + if (!formattedStartTime && !formattedEndTime) { + return 'Choose time range'; + } + + if (!formattedStartTime) { + return `Choose time range, end time is ${formattedEndTime}`; + } + + if (!formattedEndTime) { + return `Choose time range, start time is ${formattedStartTime}`; + } + + return `Choose time range, start time is ${formattedStartTime}, end time is ${formattedEndTime}`; + }, fieldClearLabel: 'Clear', diff --git a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts index 902aa019f149..ab9e144493b3 100644 --- a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts +++ b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts @@ -66,6 +66,8 @@ export interface PickersComponentAgnosticLocaleText { // Open picker labels openDatePickerDialogue: (formattedDate: string | null) => string; openTimePickerDialogue: (formattedTime: string | null) => string; + openDateRangePickerDialogue: (formattedRange: readonly [string | null, string | null]) => string; + openTimeRangePickerDialogue: (formattedRange: readonly [string | null, string | null]) => string; // Clear button label fieldClearLabel: string; diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index 05c0c4e0460f..964e9e75fac9 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -1,9 +1,6 @@ import * as React from 'react'; import { TextFieldProps } from '@mui/material/TextField'; -import type { - ExportedUseClearableFieldProps, - UseClearableFieldResponse, -} from '../hooks/useClearableField'; +import type { UseClearableFieldResponse } from '../hooks/useClearableField'; import { ExportedPickersSectionListProps } from '../PickersSectionList'; import type { UseFieldInternalProps, UseFieldResponse } from '../internals/hooks/useField'; import type { PickersTextFieldProps } from '../PickersTextField'; @@ -14,6 +11,7 @@ import { PickerValidValue, } from '../internals/models'; import { PickerOwnerState } from './pickers'; +import { ExportedPickerFieldUIProps } from '../internals/components/PickerFieldUI'; // Update PickersComponentAgnosticLocaleText -> viewNames when adding new entries export type FieldSectionType = @@ -150,7 +148,7 @@ export interface FieldOwnerState extends PickerOwnerState { export type PickerFieldSlotProps< TValue extends PickerValidValue, TEnableAccessibleFieldDOMStructure extends boolean, -> = ExportedUseClearableFieldProps & +> = ExportedPickerFieldUIProps & Pick< UseFieldInternalProps, 'shouldRespectLeadingZeros' | 'readOnly' From 8335ea402631bf30c18fc6144cb43a875cc70e1b Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 12:23:26 +0100 Subject: [PATCH 03/77] Work --- .../SingleInputDateRangeField.types.ts | 35 ++++++------------- .../SingleInputDateTimeRangeField.tsx | 22 +++++------- .../SingleInputDateTimeRangeField.types.ts | 33 +++++------------ .../SingleInputTimeRangeField.tsx | 22 +++++------- .../SingleInputTimeRangeField.types.ts | 33 +++++------------ .../useDesktopPicker.types.ts | 21 ++++------- .../useMobilePicker/useMobilePicker.types.ts | 21 ++++------- .../x-date-pickers/src/internals/index.ts | 1 + packages/x-date-pickers/src/models/fields.ts | 2 +- 9 files changed, 61 insertions(+), 129 deletions(-) diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts index 027ffbfbdb1d..4d2c892495a3 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts @@ -1,20 +1,17 @@ -import * as React from 'react'; -import { TextFieldProps } from '@mui/material/TextField'; -import { SlotComponentPropsFromProps } from '@mui/x-internals/types'; -import { PickerRangeValue, UseFieldInternalProps } from '@mui/x-date-pickers/internals'; -import { BuiltInFieldTextFieldProps, FieldOwnerState } from '@mui/x-date-pickers/models'; import { - ExportedUseClearableFieldProps, - UseClearableFieldSlots, - UseClearableFieldSlotProps, -} from '@mui/x-date-pickers/hooks'; -import { PickersTextFieldProps } from '@mui/x-date-pickers/PickersTextField'; + PickerRangeValue, + UseFieldInternalProps, + ExportedPickerFieldUIProps, + ExportedPickerFieldUISlots, + PickerFieldUISlotProps, +} from '@mui/x-date-pickers/internals'; +import { BuiltInFieldTextFieldProps } from '@mui/x-date-pickers/models'; import type { DateRangeValidationError, UseDateRangeFieldProps } from '../models'; export interface UseSingleInputDateRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, > extends UseDateRangeFieldProps, - ExportedUseClearableFieldProps, + ExportedPickerFieldUIProps, Pick< UseFieldInternalProps< PickerRangeValue, @@ -43,18 +40,6 @@ export type SingleInputDateRangeFieldProps< slotProps?: SingleInputDateRangeFieldSlotProps; }; -export interface SingleInputDateRangeFieldSlots extends UseClearableFieldSlots { - /** - * Form control with an input to render the value. - * @default , or from '@mui/material' if `enableAccessibleFieldDOMStructure` is `false`. - */ - textField?: React.ElementType; -} +export interface SingleInputDateRangeFieldSlots extends ExportedPickerFieldUISlots {} -export interface SingleInputDateRangeFieldSlotProps extends UseClearableFieldSlotProps { - textField?: SlotComponentPropsFromProps< - PickersTextFieldProps | TextFieldProps, - {}, - FieldOwnerState - >; -} +export interface SingleInputDateRangeFieldSlotProps extends PickerFieldUISlotProps {} diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx index f81834fd4ff7..2f8fb9e4be1c 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx @@ -2,15 +2,12 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import MuiTextField from '@mui/material/TextField'; -import { - convertFieldResponseIntoMuiTextFieldProps, - useFieldOwnerState, -} from '@mui/x-date-pickers/internals'; +import { CalendarIcon } from '@mui/x-date-pickers/icons'; +import { PickerFieldUI, useFieldOwnerState } from '@mui/x-date-pickers/internals'; import { PickersTextField } from '@mui/x-date-pickers/PickersTextField'; import { useThemeProps } from '@mui/material/styles'; import { refType } from '@mui/utils'; import useSlotProps from '@mui/utils/useSlotProps'; -import { useClearableField } from '@mui/x-date-pickers/hooks'; import { SingleInputDateTimeRangeFieldProps } from './SingleInputDateTimeRangeField.types'; import { useSingleInputDateTimeRangeField } from './useSingleInputDateTimeRangeField'; import { FieldType } from '../models'; @@ -66,15 +63,14 @@ const SingleInputDateTimeRangeField = React.forwardRef(function SingleInputDateT TEnableAccessibleFieldDOMStructure, typeof textFieldProps >(textFieldProps); - const convertedFieldResponse = convertFieldResponseIntoMuiTextFieldProps(fieldResponse); - const processedFieldProps = useClearableField({ - ...convertedFieldResponse, - slots, - slotProps, - }); - - return ; + return ( + + ); }) as DateRangeFieldComponent; SingleInputDateTimeRangeField.fieldType = 'single-input'; diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts index 9624ffa1c73e..0f66e77c346d 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts @@ -1,14 +1,11 @@ -import * as React from 'react'; -import { TextFieldProps } from '@mui/material/TextField'; -import { SlotComponentPropsFromProps } from '@mui/x-internals/types'; -import { PickersTextFieldProps } from '@mui/x-date-pickers/PickersTextField'; -import { PickerRangeValue, UseFieldInternalProps } from '@mui/x-date-pickers/internals'; -import { BuiltInFieldTextFieldProps, FieldOwnerState } from '@mui/x-date-pickers/models'; import { - ExportedUseClearableFieldProps, - UseClearableFieldSlots, - UseClearableFieldSlotProps, -} from '@mui/x-date-pickers/hooks'; + ExportedPickerFieldUISlots, + PickerFieldUISlotProps, + PickerRangeValue, + UseFieldInternalProps, +} from '@mui/x-date-pickers/internals'; +import { BuiltInFieldTextFieldProps } from '@mui/x-date-pickers/models'; +import { ExportedUseClearableFieldProps } from '@mui/x-date-pickers/hooks'; import { UseDateTimeRangeFieldProps } from '../internals/models'; import { DateTimeRangeValidationError } from '../models'; @@ -44,18 +41,6 @@ export type SingleInputDateTimeRangeFieldProps< slotProps?: SingleInputDateTimeRangeFieldSlotProps; }; -export interface SingleInputDateTimeRangeFieldSlots extends UseClearableFieldSlots { - /** - * Form control with an input to render the value. - * @default , or from '@mui/material' if `enableAccessibleFieldDOMStructure` is `false`. - */ - textField?: React.ElementType; -} +export interface SingleInputDateTimeRangeFieldSlots extends ExportedPickerFieldUISlots {} -export interface SingleInputDateTimeRangeFieldSlotProps extends UseClearableFieldSlotProps { - textField?: SlotComponentPropsFromProps< - PickersTextFieldProps | TextFieldProps, - {}, - FieldOwnerState - >; -} +export interface SingleInputDateTimeRangeFieldSlotProps extends PickerFieldUISlotProps {} diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx index b820b6a27f60..b39460cad2ec 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx @@ -2,11 +2,8 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import MuiTextField from '@mui/material/TextField'; -import { useClearableField } from '@mui/x-date-pickers/hooks'; -import { - convertFieldResponseIntoMuiTextFieldProps, - useFieldOwnerState, -} from '@mui/x-date-pickers/internals'; +import { ClockIcon } from '@mui/x-date-pickers/icons'; +import { PickerFieldUI, useFieldOwnerState } from '@mui/x-date-pickers/internals'; import { PickersTextField } from '@mui/x-date-pickers/PickersTextField'; import { useThemeProps } from '@mui/material/styles'; import useSlotProps from '@mui/utils/useSlotProps'; @@ -66,15 +63,14 @@ const SingleInputTimeRangeField = React.forwardRef(function SingleInputTimeRange TEnableAccessibleFieldDOMStructure, typeof textFieldProps >(textFieldProps); - const convertedFieldResponse = convertFieldResponseIntoMuiTextFieldProps(fieldResponse); - const processedFieldProps = useClearableField({ - ...convertedFieldResponse, - slots, - slotProps, - }); - - return ; + return ( + + ); }) as DateRangeFieldComponent; SingleInputTimeRangeField.fieldType = 'single-input'; diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts index 46b019e84e95..82e47d2dec68 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts @@ -1,14 +1,11 @@ -import * as React from 'react'; -import type { TextFieldProps } from '@mui/material/TextField'; -import { PickerRangeValue, UseFieldInternalProps } from '@mui/x-date-pickers/internals'; -import { BuiltInFieldTextFieldProps, FieldOwnerState } from '@mui/x-date-pickers/models'; -import { SlotComponentPropsFromProps } from '@mui/x-internals/types'; -import { PickersTextFieldProps } from '@mui/x-date-pickers/PickersTextField'; import { - ExportedUseClearableFieldProps, - UseClearableFieldSlots, - UseClearableFieldSlotProps, -} from '@mui/x-date-pickers/hooks'; + ExportedPickerFieldUISlots, + PickerFieldUISlotProps, + PickerRangeValue, + UseFieldInternalProps, +} from '@mui/x-date-pickers/internals'; +import { BuiltInFieldTextFieldProps } from '@mui/x-date-pickers/models'; +import { ExportedUseClearableFieldProps } from '@mui/x-date-pickers/hooks'; import { UseTimeRangeFieldProps } from '../internals/models'; import { TimeRangeValidationError } from '../models'; @@ -44,18 +41,6 @@ export type SingleInputTimeRangeFieldProps< slotProps?: SingleInputTimeRangeFieldSlotProps; }; -export interface SingleInputTimeRangeFieldSlots extends UseClearableFieldSlots { - /** - * Form control with an input to render the value. - * @default , or from '@mui/material' if `enableAccessibleFieldDOMStructure` is `false`. - */ - textField?: React.ElementType; -} +export interface SingleInputTimeRangeFieldSlots extends ExportedPickerFieldUISlots {} -export interface SingleInputTimeRangeFieldSlotProps extends UseClearableFieldSlotProps { - textField?: SlotComponentPropsFromProps< - PickersTextFieldProps | TextFieldProps, - {}, - FieldOwnerState - >; -} +export interface SingleInputTimeRangeFieldSlotProps extends PickerFieldUISlotProps {} diff --git a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.types.ts b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.types.ts index 29e462fe2d34..6c1589a12575 100644 --- a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.types.ts @@ -1,5 +1,4 @@ import * as React from 'react'; -import type { TextFieldProps } from '@mui/material/TextField'; import { MakeRequired, SlotComponentPropsFromProps } from '@mui/x-internals/types'; import { BaseNonStaticPickerProps, @@ -8,7 +7,7 @@ import { } from '../../models/props/basePickerProps'; import { PickersPopperSlots, PickersPopperSlotProps } from '../../components/PickersPopper'; import { UsePickerParams } from '../usePicker'; -import { FieldOwnerState, PickerFieldSlotProps, PickerOwnerState } from '../../../models'; +import { PickerFieldSlotProps, PickerOwnerState } from '../../../models'; import { ExportedPickersLayoutSlots, ExportedPickersLayoutSlotProps, @@ -17,7 +16,6 @@ import { import { UsePickerValueNonStaticProps } from '../usePicker/usePickerValue.types'; import { UsePickerViewsProps } from '../usePicker/usePickerViews'; import { DateOrTimeViewWithMeridiem, PickerValue } from '../../models'; -import { PickersTextFieldProps } from '../../../PickersTextField'; import { ExportedPickerFieldUISlots, PickerFieldUISlotProps } from '../../components/PickerFieldUI'; import { UsePickerProviderNonStaticProps } from '../usePicker/usePickerProvider'; @@ -39,12 +37,6 @@ export interface UseDesktopPickerSlots textField?: React.ElementType; } -export interface UseDesktopPickerSlotProps< - TView extends DateOrTimeViewWithMeridiem, - TEnableAccessibleFieldDOMStructure extends boolean, -> extends ExportedUseDesktopPickerSlotProps, - Pick, 'toolbar'> {} - export interface ExportedUseDesktopPickerSlotProps< TView extends DateOrTimeViewWithMeridiem, TEnableAccessibleFieldDOMStructure extends boolean, @@ -56,13 +48,14 @@ export interface ExportedUseDesktopPickerSlotProps< {}, PickerOwnerState >; - textField?: SlotComponentPropsFromProps< - PickersTextFieldProps | TextFieldProps, - {}, - FieldOwnerState - >; } +export interface UseDesktopPickerSlotProps< + TView extends DateOrTimeViewWithMeridiem, + TEnableAccessibleFieldDOMStructure extends boolean, +> extends ExportedUseDesktopPickerSlotProps, + Pick, 'toolbar'> {} + export interface DesktopOnlyPickerProps extends BaseNonStaticPickerProps, BaseNonRangeNonStaticPickerProps, diff --git a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.types.ts b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.types.ts index 11436beb1e84..37dea729d592 100644 --- a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.types.ts @@ -1,5 +1,4 @@ import * as React from 'react'; -import type { TextFieldProps } from '@mui/material/TextField'; import { MakeRequired, SlotComponentPropsFromProps } from '@mui/x-internals/types'; import { BaseNonStaticPickerProps, @@ -11,7 +10,7 @@ import { PickersModalDialogSlotProps, } from '../../components/PickersModalDialog'; import { UsePickerParams } from '../usePicker'; -import { FieldOwnerState, PickerFieldSlotProps, PickerOwnerState } from '../../../models'; +import { PickerFieldSlotProps, PickerOwnerState } from '../../../models'; import { ExportedPickersLayoutSlots, ExportedPickersLayoutSlotProps, @@ -20,38 +19,30 @@ import { import { UsePickerValueNonStaticProps } from '../usePicker/usePickerValue.types'; import { UsePickerViewsProps } from '../usePicker/usePickerViews'; import { DateOrTimeViewWithMeridiem, PickerValue } from '../../models'; -import { PickersTextFieldProps } from '../../../PickersTextField'; import { UsePickerProviderNonStaticProps } from '../usePicker/usePickerProvider'; +import { ExportedPickerFieldUISlots, PickerFieldUISlotProps } from '../../components/PickerFieldUI'; export interface UseMobilePickerSlots extends PickersModalDialogSlots, - ExportedPickersLayoutSlots { + ExportedPickersLayoutSlots, + ExportedPickerFieldUISlots { /** * Component used to enter the date with the keyboard. */ field: React.ElementType; - /** - * Form control with an input to render the value inside the default field. - * @default TextField from '@mui/material' or PickersTextField if `enableAccessibleFieldDOMStructure` is `true`. - */ - textField?: React.ElementType; } export interface ExportedUseMobilePickerSlotProps< TView extends DateOrTimeViewWithMeridiem, TEnableAccessibleFieldDOMStructure extends boolean, > extends PickersModalDialogSlotProps, - ExportedPickersLayoutSlotProps { + ExportedPickersLayoutSlotProps, + PickerFieldUISlotProps { field?: SlotComponentPropsFromProps< PickerFieldSlotProps, {}, PickerOwnerState >; - textField?: SlotComponentPropsFromProps< - PickersTextFieldProps | TextFieldProps, - {}, - FieldOwnerState - >; } export interface UseMobilePickerSlotProps< diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index cf4ebe8da733..d4502a766712 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -6,6 +6,7 @@ export type { } from './components/PickersArrowSwitcher'; export { PickerFieldUI, cleanFieldResponse } from './components/PickerFieldUI'; export type { + ExportedPickerFieldUIProps, ExportedPickerFieldUISlots, PickerFieldUISlotProps, } from './components/PickerFieldUI'; diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index 964e9e75fac9..43d3e22c6866 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -11,7 +11,7 @@ import { PickerValidValue, } from '../internals/models'; import { PickerOwnerState } from './pickers'; -import { ExportedPickerFieldUIProps } from '../internals/components/PickerFieldUI'; +import type { ExportedPickerFieldUIProps } from '../internals/components/PickerFieldUI'; // Update PickersComponentAgnosticLocaleText -> viewNames when adding new entries export type FieldSectionType = From 20f6337c407f8a68bbb04c5d0c0879309d504c9d Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 12:25:19 +0100 Subject: [PATCH 04/77] Regen API --- docs/pages/x/api/date-pickers/date-field.json | 8 +++++ .../x/api/date-pickers/date-time-field.json | 8 +++++ .../api/date-pickers/mobile-date-picker.json | 33 +++++++++++++++++-- .../date-pickers/mobile-date-time-picker.json | 33 +++++++++++++++++-- .../api/date-pickers/mobile-time-picker.json | 33 +++++++++++++++++-- .../single-input-date-range-field.json | 8 +++++ docs/pages/x/api/date-pickers/time-field.json | 8 +++++ .../date-pickers/date-field/date-field.json | 6 ++++ .../date-time-field/date-time-field.json | 6 ++++ .../mobile-date-picker.json | 7 +++- .../mobile-date-time-picker.json | 7 +++- .../mobile-time-picker.json | 7 +++- .../single-input-date-range-field.json | 6 ++++ .../date-pickers/time-field/time-field.json | 6 ++++ .../SingleInputDateRangeField.tsx | 12 +++++++ .../src/DateField/DateField.tsx | 12 +++++++ .../src/DateTimeField/DateTimeField.tsx | 12 +++++++ .../src/TimeField/TimeField.tsx | 12 +++++++ 18 files changed, 215 insertions(+), 9 deletions(-) diff --git a/docs/pages/x/api/date-pickers/date-field.json b/docs/pages/x/api/date-pickers/date-field.json index 6a53307f3dc3..90efc47fd660 100644 --- a/docs/pages/x/api/date-pickers/date-field.json +++ b/docs/pages/x/api/date-pickers/date-field.json @@ -2,6 +2,10 @@ "props": { "autoFocus": { "type": { "name": "bool" }, "default": "false" }, "clearable": { "type": { "name": "bool" }, "default": "false" }, + "clearButtonPosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'end'" + }, "color": { "type": { "name": "enum", @@ -61,6 +65,10 @@ "describedArgs": ["newValue"] } }, + "openPickerButtonPosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'end'" + }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { "type": { "name": "object" }, diff --git a/docs/pages/x/api/date-pickers/date-time-field.json b/docs/pages/x/api/date-pickers/date-time-field.json index 8ddb6b01c5cc..cadb7130bc60 100644 --- a/docs/pages/x/api/date-pickers/date-time-field.json +++ b/docs/pages/x/api/date-pickers/date-time-field.json @@ -3,6 +3,10 @@ "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "autoFocus": { "type": { "name": "bool" }, "default": "false" }, "clearable": { "type": { "name": "bool" }, "default": "false" }, + "clearButtonPosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'end'" + }, "color": { "type": { "name": "enum", @@ -68,6 +72,10 @@ "describedArgs": ["newValue"] } }, + "openPickerButtonPosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'end'" + }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { "type": { "name": "object" }, diff --git a/docs/pages/x/api/date-pickers/mobile-date-picker.json b/docs/pages/x/api/date-pickers/mobile-date-picker.json index 37e3b9e9be0b..1b489748bf04 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-picker.json @@ -207,6 +207,18 @@ "default": "PickersCalendarHeader", "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": "day", "description": "Custom component for day.\nCheck the [PickersDay](https://mui.com/x/api/date-pickers/pickers-day/) component.", @@ -224,6 +236,12 @@ "description": "Component used to enter the date with the keyboard.", "class": null }, + { + "name": "inputAdornment", + "description": "Component displayed on the start or end input adornment used to open the picker on desktop.", + "default": "InputAdornment", + "class": null + }, { "name": "layout", "description": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", @@ -259,6 +277,17 @@ "default": "IconButton", "class": null }, + { + "name": "openPickerButton", + "description": "Button to open the picker on desktop.", + "default": "IconButton", + "class": null + }, + { + "name": "openPickerIcon", + "description": "Icon displayed in the open picker button on desktop.", + "class": null + }, { "name": "previousIconButton", "description": "Button allowing to switch to the left view.", @@ -291,8 +320,8 @@ }, { "name": "textField", - "description": "Form control with an input to render the value inside the default field.", - "default": "TextField from '@mui/material' or PickersTextField if `enableAccessibleFieldDOMStructure` is `true`.", + "description": "Form control with an input to render the value.", + "default": ", or from '@mui/material' if `enableAccessibleFieldDOMStructure` is `false`.", "class": null }, { diff --git a/docs/pages/x/api/date-pickers/mobile-date-time-picker.json b/docs/pages/x/api/date-pickers/mobile-date-time-picker.json index 23adb960d841..8fe6f17b6f01 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-time-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-time-picker.json @@ -226,6 +226,18 @@ "default": "PickersCalendarHeader", "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": "day", "description": "Custom component for day.\nCheck the [PickersDay](https://mui.com/x/api/date-pickers/pickers-day/) component.", @@ -243,6 +255,12 @@ "description": "Component used to enter the date with the keyboard.", "class": null }, + { + "name": "inputAdornment", + "description": "Component displayed on the start or end input adornment used to open the picker on desktop.", + "default": "InputAdornment", + "class": null + }, { "name": "layout", "description": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", @@ -278,6 +296,17 @@ "default": "IconButton", "class": null }, + { + "name": "openPickerButton", + "description": "Button to open the picker on desktop.", + "default": "IconButton", + "class": null + }, + { + "name": "openPickerIcon", + "description": "Icon displayed in the open picker button on desktop.", + "class": null + }, { "name": "previousIconButton", "description": "Button allowing to switch to the left view.", @@ -316,8 +345,8 @@ }, { "name": "textField", - "description": "Form control with an input to render the value inside the default field.", - "default": "TextField from '@mui/material' or PickersTextField if `enableAccessibleFieldDOMStructure` is `true`.", + "description": "Form control with an input to render the value.", + "default": ", or from '@mui/material' if `enableAccessibleFieldDOMStructure` is `false`.", "class": null }, { diff --git a/docs/pages/x/api/date-pickers/mobile-time-picker.json b/docs/pages/x/api/date-pickers/mobile-time-picker.json index c3898c0d4a92..17c84e66f763 100644 --- a/docs/pages/x/api/date-pickers/mobile-time-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-time-picker.json @@ -143,6 +143,18 @@ "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.", @@ -154,6 +166,12 @@ "description": "Component used to enter the date with the keyboard.", "class": null }, + { + "name": "inputAdornment", + "description": "Component displayed on the start or end input adornment used to open the picker on desktop.", + "default": "InputAdornment", + "class": null + }, { "name": "layout", "description": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", @@ -183,6 +201,17 @@ "default": "IconButton", "class": null }, + { + "name": "openPickerButton", + "description": "Button to open the picker on desktop.", + "default": "IconButton", + "class": null + }, + { + "name": "openPickerIcon", + "description": "Icon displayed in the open picker button on desktop.", + "class": null + }, { "name": "previousIconButton", "description": "Button allowing to switch to the left view.", @@ -203,8 +232,8 @@ }, { "name": "textField", - "description": "Form control with an input to render the value inside the default field.", - "default": "TextField from '@mui/material' or PickersTextField if `enableAccessibleFieldDOMStructure` is `true`.", + "description": "Form control with an input to render the value.", + "default": ", or from '@mui/material' if `enableAccessibleFieldDOMStructure` is `false`.", "class": null }, { diff --git a/docs/pages/x/api/date-pickers/single-input-date-range-field.json b/docs/pages/x/api/date-pickers/single-input-date-range-field.json index 179b58765222..1f621fa213ea 100644 --- a/docs/pages/x/api/date-pickers/single-input-date-range-field.json +++ b/docs/pages/x/api/date-pickers/single-input-date-range-field.json @@ -2,6 +2,10 @@ "props": { "autoFocus": { "type": { "name": "bool" }, "default": "false" }, "clearable": { "type": { "name": "bool" }, "default": "false" }, + "clearButtonPosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'end'" + }, "color": { "type": { "name": "enum", @@ -62,6 +66,10 @@ "describedArgs": ["newValue"] } }, + "openPickerButtonPosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'end'" + }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { "type": { "name": "object" }, diff --git a/docs/pages/x/api/date-pickers/time-field.json b/docs/pages/x/api/date-pickers/time-field.json index fb99ace144ee..3bb471d4c5f0 100644 --- a/docs/pages/x/api/date-pickers/time-field.json +++ b/docs/pages/x/api/date-pickers/time-field.json @@ -3,6 +3,10 @@ "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "autoFocus": { "type": { "name": "bool" }, "default": "false" }, "clearable": { "type": { "name": "bool" }, "default": "false" }, + "clearButtonPosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'end'" + }, "color": { "type": { "name": "enum", @@ -64,6 +68,10 @@ "describedArgs": ["newValue"] } }, + "openPickerButtonPosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'end'" + }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { "type": { "name": "object" }, diff --git a/docs/translations/api-docs/date-pickers/date-field/date-field.json b/docs/translations/api-docs/date-pickers/date-field/date-field.json index 08b247cab667..494d49396573 100644 --- a/docs/translations/api-docs/date-pickers/date-field/date-field.json +++ b/docs/translations/api-docs/date-pickers/date-field/date-field.json @@ -7,6 +7,9 @@ "clearable": { "description": "If true, a clear button will be shown in the field allowing value clearing." }, + "clearButtonPosition": { + "description": "The position at which the UI to clear the value should be placed. If the field is not clearable, the button will not be rendered." + }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." }, @@ -78,6 +81,9 @@ "description": "Callback fired when the selected sections change.", "typeDescriptions": { "newValue": "The new selected sections." } }, + "openPickerButtonPosition": { + "description": "The position at which the UI to clear the value should be placed. If there is no picker to open, the button will not be rendered" + }, "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." }, diff --git a/docs/translations/api-docs/date-pickers/date-time-field/date-time-field.json b/docs/translations/api-docs/date-pickers/date-time-field/date-time-field.json index 30b020a97b08..de6c37256403 100644 --- a/docs/translations/api-docs/date-pickers/date-time-field/date-time-field.json +++ b/docs/translations/api-docs/date-pickers/date-time-field/date-time-field.json @@ -8,6 +8,9 @@ "clearable": { "description": "If true, a clear button will be shown in the field allowing value clearing." }, + "clearButtonPosition": { + "description": "The position at which the UI to clear the value should be placed. If the field is not clearable, the button will not be rendered." + }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." }, @@ -95,6 +98,9 @@ "description": "Callback fired when the selected sections change.", "typeDescriptions": { "newValue": "The new selected sections." } }, + "openPickerButtonPosition": { + "description": "The position at which the UI to clear the value should be placed. If there is no picker to open, the button will not be rendered" + }, "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." }, diff --git a/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json b/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json index de8638284e24..f3d7f4877503 100644 --- a/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json @@ -170,21 +170,26 @@ "slotDescriptions": { "actionBar": "Custom component for the action bar, it is placed below the picker views.", "calendarHeader": "Custom component for calendar header. Check the PickersCalendarHeader component.", + "clearButton": "Button to clear the value.", + "clearIcon": "Icon to display inside the clear button.", "day": "Custom component for day. Check the PickersDay component.", "dialog": "Custom component for the dialog inside which the views are rendered on mobile.", "field": "Component used to enter the date with the keyboard.", + "inputAdornment": "Component displayed on the start or end input adornment used to open the picker on desktop.", "layout": "Custom component for wrapping the layout. 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.", "monthButton": "Button displayed to render a single month in the month view.", "nextIconButton": "Button allowing to switch to the right view.", + "openPickerButton": "Button to open the picker on desktop.", + "openPickerIcon": "Icon displayed in the open picker button 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.", "switchViewButton": "Button displayed to switch between different calendar views.", "switchViewIcon": "Icon displayed in the SwitchViewButton. Rotated by 180° when the open view is year.", - "textField": "Form control with an input to render the value inside the default field.", + "textField": "Form control with an input to render the value.", "toolbar": "Custom component for the toolbar rendered above the views.", "yearButton": "Button displayed to render a single year in the year view." } diff --git a/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json b/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json index 43e3030a0a43..ade4cedfddf9 100644 --- a/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json @@ -198,22 +198,27 @@ "slotDescriptions": { "actionBar": "Custom component for the action bar, it is placed below the picker views.", "calendarHeader": "Custom component for calendar header. Check the PickersCalendarHeader component.", + "clearButton": "Button to clear the value.", + "clearIcon": "Icon to display inside the clear button.", "day": "Custom component for day. Check the PickersDay component.", "dialog": "Custom component for the dialog inside which the views are rendered on mobile.", "field": "Component used to enter the date with the keyboard.", + "inputAdornment": "Component displayed on the start or end input adornment used to open the picker on desktop.", "layout": "Custom component for wrapping the layout. 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.", "monthButton": "Button displayed to render a single month in the month view.", "nextIconButton": "Button allowing to switch to the right view.", + "openPickerButton": "Button to open the picker on desktop.", + "openPickerIcon": "Icon displayed in the open picker button 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.", "switchViewButton": "Button displayed to switch between different calendar views.", "switchViewIcon": "Icon displayed in the SwitchViewButton. Rotated by 180° when the open view is year.", "tabs": "Tabs enabling toggling between date and time pickers.", - "textField": "Form control with an input to render the value inside the default field.", + "textField": "Form control with an input to render the value.", "toolbar": "Custom component for the toolbar rendered above the views.", "yearButton": "Button displayed to render a single year in the year view." } diff --git a/docs/translations/api-docs/date-pickers/mobile-time-picker/mobile-time-picker.json b/docs/translations/api-docs/date-pickers/mobile-time-picker/mobile-time-picker.json index 2f933308ab83..1f16a1e9aa05 100644 --- a/docs/translations/api-docs/date-pickers/mobile-time-picker/mobile-time-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-time-picker/mobile-time-picker.json @@ -129,17 +129,22 @@ "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.", "field": "Component used to enter the date with the keyboard.", + "inputAdornment": "Component displayed on the start or end input adornment used to open the picker on desktop.", "layout": "Custom component for wrapping the layout. 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.", + "openPickerButton": "Button to open the picker on desktop.", + "openPickerIcon": "Icon displayed in the open picker button 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 the value inside the default field.", + "textField": "Form control with an input to render the value.", "toolbar": "Custom component for the toolbar rendered above the views." } } diff --git a/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json b/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json index 72e27d93359f..c3df4a9c2330 100644 --- a/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json +++ b/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json @@ -7,6 +7,9 @@ "clearable": { "description": "If true, a clear button will be shown in the field allowing value clearing." }, + "clearButtonPosition": { + "description": "The position at which the UI to clear the value should be placed. If the field is not clearable, the button will not be rendered." + }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." }, @@ -79,6 +82,9 @@ "description": "Callback fired when the selected sections change.", "typeDescriptions": { "newValue": "The new selected sections." } }, + "openPickerButtonPosition": { + "description": "The position at which the UI to clear the value should be placed. If there is no picker to open, the button will not be rendered" + }, "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." }, diff --git a/docs/translations/api-docs/date-pickers/time-field/time-field.json b/docs/translations/api-docs/date-pickers/time-field/time-field.json index 376ab6e3e422..baa18f7071ca 100644 --- a/docs/translations/api-docs/date-pickers/time-field/time-field.json +++ b/docs/translations/api-docs/date-pickers/time-field/time-field.json @@ -8,6 +8,9 @@ "clearable": { "description": "If true, a clear button will be shown in the field allowing value clearing." }, + "clearButtonPosition": { + "description": "The position at which the UI to clear the value should be placed. If the field is not clearable, the button will not be rendered." + }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." }, @@ -87,6 +90,9 @@ "description": "Callback fired when the selected sections change.", "typeDescriptions": { "newValue": "The new selected sections." } }, + "openPickerButtonPosition": { + "description": "The position at which the UI to clear the value should be placed. If there is no picker to open, the button will not be rendered" + }, "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." }, diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx index 02f04b9486ae..6eab053da73b 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx @@ -90,6 +90,12 @@ SingleInputDateRangeField.propTypes = { * @default false */ clearable: PropTypes.bool, + /** + * The position at which the UI to clear the value should be placed. + * If the field is not clearable, the button will not be rendered. + * @default 'end' + */ + clearButtonPosition: PropTypes.oneOf(['end', 'start']), /** * The color of the component. * It supports both default and custom theme colors, which can be added as shown in the @@ -238,6 +244,12 @@ SingleInputDateRangeField.propTypes = { * @param {FieldSelectedSections} newValue The new selected sections. */ onSelectedSectionsChange: PropTypes.func, + /** + * The position at which the UI to clear the value should be placed. + * If there is no picker to open, the button will not be rendered + * @default 'end' + */ + openPickerButtonPosition: 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. diff --git a/packages/x-date-pickers/src/DateField/DateField.tsx b/packages/x-date-pickers/src/DateField/DateField.tsx index f65eb0e676be..f5fbc345cbda 100644 --- a/packages/x-date-pickers/src/DateField/DateField.tsx +++ b/packages/x-date-pickers/src/DateField/DateField.tsx @@ -82,6 +82,12 @@ DateField.propTypes = { * @default false */ clearable: PropTypes.bool, + /** + * The position at which the UI to clear the value should be placed. + * If the field is not clearable, the button will not be rendered. + * @default 'end' + */ + clearButtonPosition: PropTypes.oneOf(['end', 'start']), /** * The color of the component. * It supports both default and custom theme colors, which can be added as shown in the @@ -225,6 +231,12 @@ DateField.propTypes = { * @param {FieldSelectedSections} newValue The new selected sections. */ onSelectedSectionsChange: PropTypes.func, + /** + * The position at which the UI to clear the value should be placed. + * If there is no picker to open, the button will not be rendered + * @default 'end' + */ + openPickerButtonPosition: 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. diff --git a/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx b/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx index d92f11d7dbac..0973f8c08647 100644 --- a/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx +++ b/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx @@ -93,6 +93,12 @@ DateTimeField.propTypes = { * @default false */ clearable: PropTypes.bool, + /** + * The position at which the UI to clear the value should be placed. + * If the field is not clearable, the button will not be rendered. + * @default 'end' + */ + clearButtonPosition: PropTypes.oneOf(['end', 'start']), /** * The color of the component. * It supports both default and custom theme colors, which can be added as shown in the @@ -264,6 +270,12 @@ DateTimeField.propTypes = { * @param {FieldSelectedSections} newValue The new selected sections. */ onSelectedSectionsChange: PropTypes.func, + /** + * The position at which the UI to clear the value should be placed. + * If there is no picker to open, the button will not be rendered + * @default 'end' + */ + openPickerButtonPosition: 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. diff --git a/packages/x-date-pickers/src/TimeField/TimeField.tsx b/packages/x-date-pickers/src/TimeField/TimeField.tsx index cd62db77e478..4eed03b33c33 100644 --- a/packages/x-date-pickers/src/TimeField/TimeField.tsx +++ b/packages/x-date-pickers/src/TimeField/TimeField.tsx @@ -87,6 +87,12 @@ TimeField.propTypes = { * @default false */ clearable: PropTypes.bool, + /** + * The position at which the UI to clear the value should be placed. + * If the field is not clearable, the button will not be rendered. + * @default 'end' + */ + clearButtonPosition: PropTypes.oneOf(['end', 'start']), /** * The color of the component. * It supports both default and custom theme colors, which can be added as shown in the @@ -240,6 +246,12 @@ TimeField.propTypes = { * @param {FieldSelectedSections} newValue The new selected sections. */ onSelectedSectionsChange: PropTypes.func, + /** + * The position at which the UI to clear the value should be placed. + * If there is no picker to open, the button will not be rendered + * @default 'end' + */ + openPickerButtonPosition: 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. From 26e641dd42683d99732a864e9189af865b6adbde Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 12:28:22 +0100 Subject: [PATCH 05/77] Work --- .../SingleInputDateRangeField.types.ts | 4 ++-- .../SingleInputDateTimeRangeField.types.ts | 6 +++--- .../SingleInputTimeRangeField.types.ts | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts index 4d2c892495a3..87e498b3dc91 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts @@ -11,7 +11,6 @@ import type { DateRangeValidationError, UseDateRangeFieldProps } from '../models export interface UseSingleInputDateRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, > extends UseDateRangeFieldProps, - ExportedPickerFieldUIProps, Pick< UseFieldInternalProps< PickerRangeValue, @@ -19,7 +18,8 @@ export interface UseSingleInputDateRangeFieldProps< DateRangeValidationError >, 'unstableFieldRef' - > {} + >, + ExportedPickerFieldUIProps {} export type SingleInputDateRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean = true, diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts index 0f66e77c346d..a35195ddc293 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts @@ -1,18 +1,17 @@ import { + ExportedPickerFieldUIProps, ExportedPickerFieldUISlots, PickerFieldUISlotProps, PickerRangeValue, UseFieldInternalProps, } from '@mui/x-date-pickers/internals'; import { BuiltInFieldTextFieldProps } from '@mui/x-date-pickers/models'; -import { ExportedUseClearableFieldProps } from '@mui/x-date-pickers/hooks'; import { UseDateTimeRangeFieldProps } from '../internals/models'; import { DateTimeRangeValidationError } from '../models'; export interface UseSingleInputDateTimeRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, > extends UseDateTimeRangeFieldProps, - ExportedUseClearableFieldProps, Pick< UseFieldInternalProps< PickerRangeValue, @@ -20,7 +19,8 @@ export interface UseSingleInputDateTimeRangeFieldProps< DateTimeRangeValidationError >, 'unstableFieldRef' - > {} + >, + ExportedPickerFieldUIProps {} export type SingleInputDateTimeRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean = true, diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts index 82e47d2dec68..dfd5783c659d 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts @@ -1,18 +1,17 @@ import { + ExportedPickerFieldUIProps, ExportedPickerFieldUISlots, PickerFieldUISlotProps, PickerRangeValue, UseFieldInternalProps, } from '@mui/x-date-pickers/internals'; import { BuiltInFieldTextFieldProps } from '@mui/x-date-pickers/models'; -import { ExportedUseClearableFieldProps } from '@mui/x-date-pickers/hooks'; import { UseTimeRangeFieldProps } from '../internals/models'; import { TimeRangeValidationError } from '../models'; export interface UseSingleInputTimeRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, > extends UseTimeRangeFieldProps, - ExportedUseClearableFieldProps, Pick< UseFieldInternalProps< PickerRangeValue, @@ -20,7 +19,8 @@ export interface UseSingleInputTimeRangeFieldProps< TimeRangeValidationError >, 'unstableFieldRef' - > {} + >, + ExportedPickerFieldUIProps {} export type SingleInputTimeRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean = true, From b84e04c3d0c1d006cd2233fb718f4c2bd409cdd6 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 12:34:22 +0100 Subject: [PATCH 06/77] Fix TS --- .../src/internals/hooks/useEnrichedRangePickerFieldProps.ts | 2 +- .../x-date-pickers/src/internals/components/PickerFieldUI.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts index a10a6e1d9827..1f91cf51afa6 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts @@ -108,7 +108,7 @@ export interface UseEnrichedRangePickerFieldPropsParams< TEnableAccessibleFieldDOMStructure, TError >; - anchorRef?: React.Ref; + anchorRef?: React.Ref; currentView?: TView | null; initialView?: TView; onViewChange?: (view: TView) => void; diff --git a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx index 3b4ce3313353..0dbecf8653e4 100644 --- a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx @@ -97,7 +97,7 @@ export function PickerFieldUI(props: PickerFieldUIProps) { } = cleanFieldResponse(fieldResponse); const ownerState = useFieldOwnerState(textFieldProps); - const handleTogglePicker = (event) => { + const handleTogglePicker = (event: React.MouseEvent) => { if (!pickerContext) { return; } From f65cf6763396540340a293c9f2e7fd63cdccf069 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 13:20:03 +0100 Subject: [PATCH 07/77] Fix --- .../date-pickers/custom-field/BrowserV7Field.tsx | 11 +++++------ packages/x-date-pickers-pro/src/models/fields.ts | 12 +++++++++--- .../src/hooks/useClearableField.tsx | 16 ++++++++++------ .../src/internals/components/PickerFieldUI.tsx | 2 +- .../internals/hooks/useField/useField.types.ts | 5 +++-- .../src/internals/models/fields.ts | 16 ++++++++-------- packages/x-date-pickers/src/models/fields.ts | 12 +++++++++--- 7 files changed, 45 insertions(+), 29 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx index a2cc66b242e7..a7814a5f66b8 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx @@ -9,7 +9,10 @@ import { DatePickerProps, } from '@mui/x-date-pickers/DatePicker'; import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateField'; -import { useClearableField } from '@mui/x-date-pickers/hooks'; +import { + useClearableField, + UseClearableFieldResponse, +} from '@mui/x-date-pickers/hooks'; import { BaseSingleInputPickersTextFieldProps } from '@mui/x-date-pickers/models'; import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList'; @@ -32,11 +35,7 @@ const BrowserFieldContent = styled('div', { name: 'BrowserField', slot: 'Content ); interface BrowserTextFieldProps - extends BaseSingleInputPickersTextFieldProps, - Omit< - React.HTMLAttributes, - keyof BaseSingleInputPickersTextFieldProps - > {} + extends UseClearableFieldResponse> {} const BrowserTextField = React.forwardRef( (props: BrowserTextFieldProps, ref: React.Ref) => { diff --git a/packages/x-date-pickers-pro/src/models/fields.ts b/packages/x-date-pickers-pro/src/models/fields.ts index 648dc4c4f277..0fe3c8c4415a 100644 --- a/packages/x-date-pickers-pro/src/models/fields.ts +++ b/packages/x-date-pickers-pro/src/models/fields.ts @@ -6,7 +6,6 @@ import { PickerRangeValue, } from '@mui/x-date-pickers/internals'; import { FieldRef, PickerFieldSlotProps } from '@mui/x-date-pickers/models'; -import { UseClearableFieldResponse } from '@mui/x-date-pickers/hooks'; export type { FieldRangeSection } from '@mui/x-date-pickers/internals'; @@ -62,6 +61,13 @@ export type PickerRangeFieldSlotProps = UseClearableFieldResponse< - UseFieldResponse +> = Omit< + UseFieldResponse, + | 'slots' + | 'slotProps' + | 'clearable' + | 'onClear' + | 'openPickerButtonPosition' + | 'clearButtonPosition' + | 'openPickerAriaLabel' >; diff --git a/packages/x-date-pickers/src/hooks/useClearableField.tsx b/packages/x-date-pickers/src/hooks/useClearableField.tsx index 11dafcc2b3a4..950c9c117655 100644 --- a/packages/x-date-pickers/src/hooks/useClearableField.tsx +++ b/packages/x-date-pickers/src/hooks/useClearableField.tsx @@ -7,6 +7,9 @@ import InputAdornment from '@mui/material/InputAdornment'; import { SxProps } from '@mui/system'; import { ClearIcon } from '../icons'; import { usePickerTranslations } from './usePickerTranslations'; +import { FieldOwnerState } from '../models/fields'; +import { useFieldOwnerState } from '../internals/hooks/useFieldOwnerState'; +import { FormProps } from '../internals/models'; export interface ExportedUseClearableFieldProps { /** @@ -34,11 +37,11 @@ export interface UseClearableFieldSlots { } export interface UseClearableFieldSlotProps { - clearIcon?: SlotComponentProps; - clearButton?: SlotComponentProps; + clearIcon?: SlotComponentProps; + clearButton?: SlotComponentProps; } -interface UseClearableFieldProps extends ExportedUseClearableFieldProps { +interface UseClearableFieldProps extends ExportedUseClearableFieldProps, FormProps { InputProps?: { endAdornment?: React.ReactNode }; sx?: SxProps; slots?: UseClearableFieldSlots; @@ -54,15 +57,16 @@ export const useClearableField = ( props: TFieldProps, ): UseClearableFieldResponse => { const translations = usePickerTranslations(); + const ownerState = useFieldOwnerState(props); const { clearable, onClear, InputProps, sx, slots, slotProps, ...other } = props; const IconButton = slots?.clearButton ?? MuiIconButton; // The spread is here to avoid this bug mui/material-ui#34056 - const { ownerState, ...iconButtonProps } = useSlotProps({ + const { ownerState: iconButtonOwnerState, ...iconButtonProps } = useSlotProps({ elementType: IconButton, externalSlotProps: slotProps?.clearButton, - ownerState: {}, + ownerState, className: 'clearButton', additionalProps: { title: translations.fieldClearLabel, @@ -73,7 +77,7 @@ export const useClearableField = ( const endClearIconProps = useSlotProps({ elementType: EndClearIcon, externalSlotProps: slotProps?.clearIcon, - ownerState: {}, + ownerState, }); return { diff --git a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx index 0dbecf8653e4..6320a8faa922 100644 --- a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx @@ -11,7 +11,7 @@ import { usePickerTranslations } from '../../hooks'; import { ClearIcon as MuiClearIcon } from '../../icons'; import { useNullablePickerContext } from '../hooks/useNullablePickerContext'; import { usePickerPrivateContext } from '../hooks/usePickerPrivateContext'; -import { UseFieldResponse } from '../hooks/useField'; +import type { UseFieldResponse } from '../hooks/useField'; import { PickersTextField, PickersTextFieldProps } from '../../PickersTextField'; export const cleanFieldResponse = < diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts index 6fc93a88d3c7..8bdc9d6b32e2 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts @@ -18,8 +18,8 @@ import type { Validator } from '../../../validation'; import type { UseFieldStateResponse } from './useFieldState'; import type { UseFieldCharacterEditingResponse } from './useFieldCharacterEditing'; import { PickersSectionElement, PickersSectionListRef } from '../../../PickersSectionList'; -import { ExportedUseClearableFieldProps } from '../../../hooks/useClearableField'; import { FormProps, InferNonNullablePickerValue, PickerValidValue } from '../../models'; +import type { ExportedPickerFieldUIProps } from '../../components/PickerFieldUI'; export interface UseFieldParams< TValue extends PickerValidValue, @@ -127,7 +127,8 @@ export interface UseFieldCommonAdditionalProps openPickerAriaLabel: string; } -export interface UseFieldCommonForwardedProps extends ExportedUseClearableFieldProps { +export interface UseFieldCommonForwardedProps + extends Pick { onKeyDown?: React.KeyboardEventHandler; error?: boolean; } diff --git a/packages/x-date-pickers/src/internals/models/fields.ts b/packages/x-date-pickers/src/internals/models/fields.ts index b7476ca12f04..d51566ab2488 100644 --- a/packages/x-date-pickers/src/internals/models/fields.ts +++ b/packages/x-date-pickers/src/internals/models/fields.ts @@ -1,20 +1,20 @@ import { SxProps } from '@mui/material/styles'; import { MakeRequired } from '@mui/x-internals/types'; -import type { - ExportedUseClearableFieldProps, - UseClearableFieldSlotProps, - UseClearableFieldSlots, -} from '../../hooks/useClearableField'; import type { FieldSection, PickerOwnerState } from '../../models'; import type { UseFieldInternalProps } from '../hooks/useField'; import { RangePosition } from './pickers'; import { PickerValidValue } from './value'; +import type { + ExportedPickerFieldUIProps, + ExportedPickerFieldUISlots, + PickerFieldUISlotProps, +} from '../components/PickerFieldUI'; export interface FieldRangeSection extends FieldSection { dateName: RangePosition; } -export interface BaseForwardedSingleInputFieldProps extends ExportedUseClearableFieldProps { +export interface BaseForwardedSingleInputFieldProps extends ExportedPickerFieldUIProps { className: string | undefined; sx: SxProps | undefined; label: React.ReactNode | undefined; @@ -33,8 +33,8 @@ export interface BaseForwardedSingleInputFieldProps extends ExportedUseClearable inputProps?: { 'aria-label'?: string; }; - slots?: UseClearableFieldSlots; - slotProps?: UseClearableFieldSlotProps & { + slots?: ExportedPickerFieldUISlots; + slotProps?: PickerFieldUISlotProps & { textField?: {}; }; ownerState: PickerOwnerState; diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index 43d3e22c6866..4c85545f0889 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -1,6 +1,5 @@ import * as React from 'react'; import { TextFieldProps } from '@mui/material/TextField'; -import type { UseClearableFieldResponse } from '../hooks/useClearableField'; import { ExportedPickersSectionListProps } from '../PickersSectionList'; import type { UseFieldInternalProps, UseFieldResponse } from '../internals/hooks/useField'; import type { PickersTextFieldProps } from '../PickersTextField'; @@ -163,8 +162,15 @@ export type PickerFieldSlotProps< */ export type BaseSingleInputPickersTextFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, -> = UseClearableFieldResponse< - UseFieldResponse +> = Omit< + UseFieldResponse, + | 'slots' + | 'slotProps' + | 'clearable' + | 'onClear' + | 'openPickerButtonPosition' + | 'clearButtonPosition' + | 'openPickerAriaLabel' >; /** From 6a46821c9fdd8eb215acfb3fe29fce1ad5dc15d5 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 13:30:38 +0100 Subject: [PATCH 08/77] Hide opening ui on range pickers --- .../hooks/useDesktopRangePicker/useDesktopRangePicker.tsx | 3 +++ .../hooks/useMobileRangePicker/useMobileRangePicker.tsx | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) 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 a540f77a569f..742b19b7ab78 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 @@ -110,6 +110,9 @@ export const useDesktopRangePicker = < }, }); + // Temporary hack to hide the opening button on the range pickers until we have migrate them to the new opening logic. + providerProps.privateContextValue.openingUIStatus = 'hidden'; + React.useEffect(() => { if (layoutProps.view) { initialView.current = layoutProps.view; diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx index 32b4ac1dab03..45ba99db994f 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx @@ -106,8 +106,10 @@ export const useMobileRangePicker = < }, }); - const Field = slots.field; + // Temporary hack to hide the opening button on the range pickers until we have migrate them to the new opening logic. + providerProps.privateContextValue.openingUIStatus = 'hidden'; + const Field = slots.field; const fieldProps: RangePickerPropsForFieldSlot< boolean, TEnableAccessibleFieldDOMStructure, From 2c9669ba4c9638b453dd4884bab51be21d067a2c Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 13:45:45 +0100 Subject: [PATCH 09/77] Fix --- .../CustomPropsOpeningButton.js | 2 +- .../CustomPropsOpeningButton.tsx | 2 +- .../CustomPropsOpeningButton.tsx.preview | 2 +- .../StartEdgeOpeningButton.js | 19 +++++++++++++++++++ .../StartEdgeOpeningButton.tsx | 19 +++++++++++++++++++ .../StartEdgeOpeningButton.tsx.preview | 5 +++++ .../custom-opening-button.md | 4 ++++ .../migration-pickers-v7.md | 13 +++++++++++++ 8 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 docs/data/date-pickers/custom-opening-button/StartEdgeOpeningButton.js create mode 100644 docs/data/date-pickers/custom-opening-button/StartEdgeOpeningButton.tsx create mode 100644 docs/data/date-pickers/custom-opening-button/StartEdgeOpeningButton.tsx.preview diff --git a/docs/data/date-pickers/custom-opening-button/CustomPropsOpeningButton.js b/docs/data/date-pickers/custom-opening-button/CustomPropsOpeningButton.js index 5ecabf3b7b20..5331d6123024 100644 --- a/docs/data/date-pickers/custom-opening-button/CustomPropsOpeningButton.js +++ b/docs/data/date-pickers/custom-opening-button/CustomPropsOpeningButton.js @@ -16,7 +16,7 @@ export default function CustomPropsOpeningButton() { }, // Targets the `InputAdornment` component. inputAdornment: { - position: 'start', + component: 'span', }, }} /> diff --git a/docs/data/date-pickers/custom-opening-button/CustomPropsOpeningButton.tsx b/docs/data/date-pickers/custom-opening-button/CustomPropsOpeningButton.tsx index 5ecabf3b7b20..5331d6123024 100644 --- a/docs/data/date-pickers/custom-opening-button/CustomPropsOpeningButton.tsx +++ b/docs/data/date-pickers/custom-opening-button/CustomPropsOpeningButton.tsx @@ -16,7 +16,7 @@ export default function CustomPropsOpeningButton() { }, // Targets the `InputAdornment` component. inputAdornment: { - position: 'start', + component: 'span', }, }} /> diff --git a/docs/data/date-pickers/custom-opening-button/CustomPropsOpeningButton.tsx.preview b/docs/data/date-pickers/custom-opening-button/CustomPropsOpeningButton.tsx.preview index 685e218097c6..1487b57d2a90 100644 --- a/docs/data/date-pickers/custom-opening-button/CustomPropsOpeningButton.tsx.preview +++ b/docs/data/date-pickers/custom-opening-button/CustomPropsOpeningButton.tsx.preview @@ -6,7 +6,7 @@ }, // Targets the `InputAdornment` component. inputAdornment: { - position: 'start', + component: 'span', }, }} /> \ No newline at end of file diff --git a/docs/data/date-pickers/custom-opening-button/StartEdgeOpeningButton.js b/docs/data/date-pickers/custom-opening-button/StartEdgeOpeningButton.js new file mode 100644 index 000000000000..04a1a2803acd --- /dev/null +++ b/docs/data/date-pickers/custom-opening-button/StartEdgeOpeningButton.js @@ -0,0 +1,19 @@ +import * as React from 'react'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { DatePicker } from '@mui/x-date-pickers/DatePicker'; + +export default function StartEdgeOpeningButton() { + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/custom-opening-button/StartEdgeOpeningButton.tsx b/docs/data/date-pickers/custom-opening-button/StartEdgeOpeningButton.tsx new file mode 100644 index 000000000000..04a1a2803acd --- /dev/null +++ b/docs/data/date-pickers/custom-opening-button/StartEdgeOpeningButton.tsx @@ -0,0 +1,19 @@ +import * as React from 'react'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { DatePicker } from '@mui/x-date-pickers/DatePicker'; + +export default function StartEdgeOpeningButton() { + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/custom-opening-button/StartEdgeOpeningButton.tsx.preview b/docs/data/date-pickers/custom-opening-button/StartEdgeOpeningButton.tsx.preview new file mode 100644 index 000000000000..0a9731df02dd --- /dev/null +++ b/docs/data/date-pickers/custom-opening-button/StartEdgeOpeningButton.tsx.preview @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/docs/data/date-pickers/custom-opening-button/custom-opening-button.md b/docs/data/date-pickers/custom-opening-button/custom-opening-button.md index c0ef70d69eb9..e066befdc404 100644 --- a/docs/data/date-pickers/custom-opening-button/custom-opening-button.md +++ b/docs/data/date-pickers/custom-opening-button/custom-opening-button.md @@ -39,6 +39,10 @@ If you want to track the opening of the picker, you should use the `onOpen` / `o ::: +## Render the opening button of the left of the input + +{{"demo": "StartEdgeOpeningButton.js"}} + ## Add an icon next to the opening button If you want to add an icon next to the opening button, you can use the `inputAdornment` slot. diff --git a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md index 764f28cfb98a..a8db03c58d36 100644 --- a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md +++ b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md @@ -259,6 +259,19 @@ const theme = createTheme({ ## Slots breaking changes +### Slot: `inputAdornment` + +- The `position` props passed to the `inputAdornment` slot props no longer sets the position of the opening button. This allow to define the position of the opening button and of the clear button independently. Instead you can use the `openPickerButtonPosition` prop: + + ```diff + + ``` + ### Slot: `layout` - The `` and `` components must now receive the `ownerState` returned by `usePickerLayout` instead of their props: From ab16f5c3d18296a29be6c1b1ea8d252403abdacd Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 13:50:28 +0100 Subject: [PATCH 10/77] Fix --- .../date-pickers/single-input-date-range-field.json | 4 ---- .../single-input-date-time-range-field.json | 8 ++++++++ .../date-pickers/single-input-time-range-field.json | 4 ++++ .../single-input-date-range-field.json | 3 --- .../single-input-date-time-range-field.json | 6 ++++++ .../single-input-time-range-field.json | 3 +++ .../SingleInputDateRangeField.tsx | 6 ------ .../SingleInputDateRangeField.types.ts | 3 ++- .../SingleInputDateTimeRangeField.tsx | 12 ++++++++++++ .../SingleInputDateTimeRangeField.types.ts | 3 ++- .../SingleInputTimeRangeField.tsx | 6 ++++++ .../SingleInputTimeRangeField.types.ts | 3 ++- 12 files changed, 45 insertions(+), 16 deletions(-) diff --git a/docs/pages/x/api/date-pickers/single-input-date-range-field.json b/docs/pages/x/api/date-pickers/single-input-date-range-field.json index 1f621fa213ea..b12c8e6071cd 100644 --- a/docs/pages/x/api/date-pickers/single-input-date-range-field.json +++ b/docs/pages/x/api/date-pickers/single-input-date-range-field.json @@ -66,10 +66,6 @@ "describedArgs": ["newValue"] } }, - "openPickerButtonPosition": { - "type": { "name": "enum", "description": "'end'
| 'start'" }, - "default": "'end'" - }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { "type": { "name": "object" }, diff --git a/docs/pages/x/api/date-pickers/single-input-date-time-range-field.json b/docs/pages/x/api/date-pickers/single-input-date-time-range-field.json index 483f9c001649..b0d9faa015ad 100644 --- a/docs/pages/x/api/date-pickers/single-input-date-time-range-field.json +++ b/docs/pages/x/api/date-pickers/single-input-date-time-range-field.json @@ -3,6 +3,10 @@ "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "autoFocus": { "type": { "name": "bool" }, "default": "false" }, "clearable": { "type": { "name": "bool" }, "default": "false" }, + "clearButtonPosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'end'" + }, "color": { "type": { "name": "enum", @@ -69,6 +73,10 @@ "describedArgs": ["newValue"] } }, + "openPickerButtonPosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'end'" + }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { "type": { "name": "object" }, diff --git a/docs/pages/x/api/date-pickers/single-input-time-range-field.json b/docs/pages/x/api/date-pickers/single-input-time-range-field.json index fbfcdcd2781e..ceeded9aa680 100644 --- a/docs/pages/x/api/date-pickers/single-input-time-range-field.json +++ b/docs/pages/x/api/date-pickers/single-input-time-range-field.json @@ -3,6 +3,10 @@ "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "autoFocus": { "type": { "name": "bool" }, "default": "false" }, "clearable": { "type": { "name": "bool" }, "default": "false" }, + "clearButtonPosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'end'" + }, "color": { "type": { "name": "enum", diff --git a/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json b/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json index c3df4a9c2330..09638efb2c1f 100644 --- a/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json +++ b/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json @@ -82,9 +82,6 @@ "description": "Callback fired when the selected sections change.", "typeDescriptions": { "newValue": "The new selected sections." } }, - "openPickerButtonPosition": { - "description": "The position at which the UI to clear the value should be placed. If there is no picker to open, the button will not be rendered" - }, "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." }, diff --git a/docs/translations/api-docs/date-pickers/single-input-date-time-range-field/single-input-date-time-range-field.json b/docs/translations/api-docs/date-pickers/single-input-date-time-range-field/single-input-date-time-range-field.json index 871afaaa2574..ca4f3ff06dea 100644 --- a/docs/translations/api-docs/date-pickers/single-input-date-time-range-field/single-input-date-time-range-field.json +++ b/docs/translations/api-docs/date-pickers/single-input-date-time-range-field/single-input-date-time-range-field.json @@ -8,6 +8,9 @@ "clearable": { "description": "If true, a clear button will be shown in the field allowing value clearing." }, + "clearButtonPosition": { + "description": "The position at which the UI to clear the value should be placed. If the field is not clearable, the button will not be rendered." + }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." }, @@ -96,6 +99,9 @@ "description": "Callback fired when the selected sections change.", "typeDescriptions": { "newValue": "The new selected sections." } }, + "openPickerButtonPosition": { + "description": "The position at which the UI to clear the value should be placed. If there is no picker to open, the button will not be rendered" + }, "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." }, diff --git a/docs/translations/api-docs/date-pickers/single-input-time-range-field/single-input-time-range-field.json b/docs/translations/api-docs/date-pickers/single-input-time-range-field/single-input-time-range-field.json index 11ab48673c0f..0fb7ec97acbf 100644 --- a/docs/translations/api-docs/date-pickers/single-input-time-range-field/single-input-time-range-field.json +++ b/docs/translations/api-docs/date-pickers/single-input-time-range-field/single-input-time-range-field.json @@ -8,6 +8,9 @@ "clearable": { "description": "If true, a clear button will be shown in the field allowing value clearing." }, + "clearButtonPosition": { + "description": "The position at which the UI to clear the value should be placed. If the field is not clearable, the button will not be rendered." + }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." }, diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx index 6eab053da73b..ef6f2e1e6b84 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx @@ -244,12 +244,6 @@ SingleInputDateRangeField.propTypes = { * @param {FieldSelectedSections} newValue The new selected sections. */ onSelectedSectionsChange: PropTypes.func, - /** - * The position at which the UI to clear the value should be placed. - * If there is no picker to open, the button will not be rendered - * @default 'end' - */ - openPickerButtonPosition: 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. diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts index 87e498b3dc91..a97713d8e076 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.types.ts @@ -19,7 +19,8 @@ export interface UseSingleInputDateRangeFieldProps< >, 'unstableFieldRef' >, - ExportedPickerFieldUIProps {} + // TODO v8: Remove once the range fields open with a button. + Omit {} export type SingleInputDateRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean = true, diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx index 2f8fb9e4be1c..2a3c1938c80e 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx @@ -96,6 +96,12 @@ SingleInputDateTimeRangeField.propTypes = { * @default false */ clearable: PropTypes.bool, + /** + * The position at which the UI to clear the value should be placed. + * If the field is not clearable, the button will not be rendered. + * @default 'end' + */ + clearButtonPosition: PropTypes.oneOf(['end', 'start']), /** * The color of the component. * It supports both default and custom theme colors, which can be added as shown in the @@ -272,6 +278,12 @@ SingleInputDateTimeRangeField.propTypes = { * @param {FieldSelectedSections} newValue The new selected sections. */ onSelectedSectionsChange: PropTypes.func, + /** + * The position at which the UI to clear the value should be placed. + * If there is no picker to open, the button will not be rendered + * @default 'end' + */ + openPickerButtonPosition: 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. diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts index a35195ddc293..db2d381a24dd 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts @@ -20,7 +20,8 @@ export interface UseSingleInputDateTimeRangeFieldProps< >, 'unstableFieldRef' >, - ExportedPickerFieldUIProps {} + // TODO v8: Remove once the range fields open with a button. + Omit {} export type SingleInputDateTimeRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean = true, diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx index b39460cad2ec..c5c87bc69962 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx @@ -96,6 +96,12 @@ SingleInputTimeRangeField.propTypes = { * @default false */ clearable: PropTypes.bool, + /** + * The position at which the UI to clear the value should be placed. + * If the field is not clearable, the button will not be rendered. + * @default 'end' + */ + clearButtonPosition: PropTypes.oneOf(['end', 'start']), /** * The color of the component. * It supports both default and custom theme colors, which can be added as shown in the diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts index dfd5783c659d..818c6ca2cb37 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts @@ -20,7 +20,8 @@ export interface UseSingleInputTimeRangeFieldProps< >, 'unstableFieldRef' >, - ExportedPickerFieldUIProps {} + // TODO v8: Remove once the range fields open with a button. + Omit {} export type SingleInputTimeRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean = true, From ec32af777aae90b60088f89e4d4ea41e2d6f9389 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 13:58:55 +0100 Subject: [PATCH 11/77] Fix doc --- docs/data/date-pickers/custom-field/BrowserV7Field.tsx | 6 +++++- .../custom-opening-button/custom-opening-button.md | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx index a7814a5f66b8..baeb15f8f6ce 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx @@ -35,7 +35,11 @@ const BrowserFieldContent = styled('div', { name: 'BrowserField', slot: 'Content ); interface BrowserTextFieldProps - extends UseClearableFieldResponse> {} + extends Omit< + React.HTMLAttributes, + keyof BaseSingleInputPickersTextFieldProps + >, + UseClearableFieldResponse> {} const BrowserTextField = React.forwardRef( (props: BrowserTextFieldProps, ref: React.Ref) => { diff --git a/docs/data/date-pickers/custom-opening-button/custom-opening-button.md b/docs/data/date-pickers/custom-opening-button/custom-opening-button.md index e066befdc404..10e97f52f8e1 100644 --- a/docs/data/date-pickers/custom-opening-button/custom-opening-button.md +++ b/docs/data/date-pickers/custom-opening-button/custom-opening-button.md @@ -39,7 +39,9 @@ If you want to track the opening of the picker, you should use the `onOpen` / `o ::: -## Render the opening button of the left of the input +## Render the opening button at the start of the input + +You can use the `openPickerButtonPosition` on the `field` slot to set the opening button at the start of the input (on the left in lef-to-right direction, on the right in left-to-right direction). {{"demo": "StartEdgeOpeningButton.js"}} From d94e3682ec14a08d1a1d10981efb2756885d83b0 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 13:58:59 +0100 Subject: [PATCH 12/77] Fix doc --- .../data/date-pickers/custom-field/BrowserV7Field.tsx | 11 ++++------- .../custom-opening-button/custom-opening-button.md | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx index baeb15f8f6ce..a2cc66b242e7 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx @@ -9,10 +9,7 @@ import { DatePickerProps, } from '@mui/x-date-pickers/DatePicker'; import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateField'; -import { - useClearableField, - UseClearableFieldResponse, -} from '@mui/x-date-pickers/hooks'; +import { useClearableField } from '@mui/x-date-pickers/hooks'; import { BaseSingleInputPickersTextFieldProps } from '@mui/x-date-pickers/models'; import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList'; @@ -35,11 +32,11 @@ const BrowserFieldContent = styled('div', { name: 'BrowserField', slot: 'Content ); interface BrowserTextFieldProps - extends Omit< + extends BaseSingleInputPickersTextFieldProps, + Omit< React.HTMLAttributes, keyof BaseSingleInputPickersTextFieldProps - >, - UseClearableFieldResponse> {} + > {} const BrowserTextField = React.forwardRef( (props: BrowserTextFieldProps, ref: React.Ref) => { diff --git a/docs/data/date-pickers/custom-opening-button/custom-opening-button.md b/docs/data/date-pickers/custom-opening-button/custom-opening-button.md index 10e97f52f8e1..bf7f520ee36b 100644 --- a/docs/data/date-pickers/custom-opening-button/custom-opening-button.md +++ b/docs/data/date-pickers/custom-opening-button/custom-opening-button.md @@ -41,7 +41,7 @@ If you want to track the opening of the picker, you should use the `onOpen` / `o ## Render the opening button at the start of the input -You can use the `openPickerButtonPosition` on the `field` slot to set the opening button at the start of the input (on the left in lef-to-right direction, on the right in left-to-right direction). +You can use the `openPickerButtonPosition` on the `field` slot to set the opening button at the start of the input (on the left in lef-to-right direction, on the right in left-to-right direction): {{"demo": "StartEdgeOpeningButton.js"}} From 37aed614609b00fdbc498c4401a48a2f722a78f4 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 14:06:15 +0100 Subject: [PATCH 13/77] Work --- .../useSingleInputDateRangeField.ts | 9 ++---- .../SingleInputDateTimeRangeField.tsx | 6 ---- .../SingleInputDateTimeRangeField.types.ts | 2 +- .../useSingleInputDateTimeRangeField.ts | 9 ++---- .../useSingleInputTimeRangeField.ts | 9 ++---- .../hooks/useGetOpenRangeDialogAriaText.ts | 20 ------------- packages/x-date-pickers/src/locales/enUS.ts | 30 ------------------- .../src/locales/utils/pickersLocaleTextApi.ts | 2 -- 8 files changed, 7 insertions(+), 80 deletions(-) delete mode 100644 packages/x-date-pickers-pro/src/internals/hooks/useGetOpenRangeDialogAriaText.ts diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts index f4b93c231fb9..13e91f743146 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts @@ -5,7 +5,6 @@ import { useSplitFieldProps } from '@mui/x-date-pickers/hooks'; import { UseSingleInputDateRangeFieldProps } from './SingleInputDateRangeField.types'; import { rangeValueManager, getRangeFieldValueManager } from '../internals/utils/valueManagers'; import { validateDateRange } from '../validation'; -import { useGetOpenRangeDialogAriaText } from '../internals/hooks/useGetOpenRangeDialogAriaText'; export const useSingleInputDateRangeField = < TEnableAccessibleFieldDOMStructure extends boolean, @@ -25,11 +24,6 @@ export const useSingleInputDateRangeField = < [internalProps.dateSeparator], ); - const getOpenDialogAriaText = useGetOpenRangeDialogAriaText({ - formatKey: 'fullDate', - translationKey: 'openDateRangePickerDialogue', - }); - return useField< PickerRangeValue, TEnableAccessibleFieldDOMStructure, @@ -42,6 +36,7 @@ export const useSingleInputDateRangeField = < fieldValueManager, validator: validateDateRange, valueType: 'date', - getOpenDialogAriaText, + // TODO v8: Add a real aria label before enabling the button. + getOpenDialogAriaText: () => '', }); }; diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx index 2a3c1938c80e..fa37c3d400df 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx @@ -278,12 +278,6 @@ SingleInputDateTimeRangeField.propTypes = { * @param {FieldSelectedSections} newValue The new selected sections. */ onSelectedSectionsChange: PropTypes.func, - /** - * The position at which the UI to clear the value should be placed. - * If there is no picker to open, the button will not be rendered - * @default 'end' - */ - openPickerButtonPosition: 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. diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts index db2d381a24dd..44441fe6f60a 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts @@ -21,7 +21,7 @@ export interface UseSingleInputDateTimeRangeFieldProps< 'unstableFieldRef' >, // TODO v8: Remove once the range fields open with a button. - Omit {} + Omit {} export type SingleInputDateTimeRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean = true, diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts index 0c9f0aeb917d..84482e65cbc2 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts @@ -9,7 +9,6 @@ import { useSplitFieldProps } from '@mui/x-date-pickers/hooks'; import { UseSingleInputDateTimeRangeFieldProps } from './SingleInputDateTimeRangeField.types'; import { rangeValueManager, getRangeFieldValueManager } from '../internals/utils/valueManagers'; import { validateDateTimeRange } from '../validation'; -import { useGetOpenRangeDialogAriaText } from '../internals/hooks/useGetOpenRangeDialogAriaText'; export const useSingleInputDateTimeRangeField = < TEnableAccessibleFieldDOMStructure extends boolean, @@ -29,11 +28,6 @@ export const useSingleInputDateTimeRangeField = < [internalProps.dateSeparator], ); - const getOpenDialogAriaText = useGetOpenRangeDialogAriaText({ - formatKey: 'fullDate', - translationKey: 'openDateRangePickerDialogue', - }); - return useField< PickerRangeValue, TEnableAccessibleFieldDOMStructure, @@ -46,6 +40,7 @@ export const useSingleInputDateTimeRangeField = < fieldValueManager, validator: validateDateTimeRange, valueType: 'date-time', - getOpenDialogAriaText, + // TODO v8: Add a real aria label before enabling the button. + getOpenDialogAriaText: () => '', }); }; diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts index a049219ee1c8..55984a316a25 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts @@ -5,7 +5,6 @@ import { useSplitFieldProps } from '@mui/x-date-pickers/hooks'; import { UseSingleInputTimeRangeFieldProps } from './SingleInputTimeRangeField.types'; import { rangeValueManager, getRangeFieldValueManager } from '../internals/utils/valueManagers'; import { validateTimeRange } from '../validation'; -import { useGetOpenRangeDialogAriaText } from '../internals/hooks/useGetOpenRangeDialogAriaText'; export const useSingleInputTimeRangeField = < TEnableAccessibleFieldDOMStructure extends boolean, @@ -25,11 +24,6 @@ export const useSingleInputTimeRangeField = < [internalProps.dateSeparator], ); - const getOpenDialogAriaText = useGetOpenRangeDialogAriaText({ - formatKey: 'fullTime', - translationKey: 'openTimeRangePickerDialogue', - }); - return useField< PickerRangeValue, TEnableAccessibleFieldDOMStructure, @@ -42,6 +36,7 @@ export const useSingleInputTimeRangeField = < fieldValueManager, validator: validateTimeRange, valueType: 'time', - getOpenDialogAriaText, + // TODO v8: Add a real aria label before enabling the button. + getOpenDialogAriaText: () => '', }); }; diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useGetOpenRangeDialogAriaText.ts b/packages/x-date-pickers-pro/src/internals/hooks/useGetOpenRangeDialogAriaText.ts deleted file mode 100644 index 08b138fa15eb..000000000000 --- a/packages/x-date-pickers-pro/src/internals/hooks/useGetOpenRangeDialogAriaText.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; -import { PickerRangeValue, useUtils } from '@mui/x-date-pickers/internals'; -import { AdapterFormats } from '@mui/x-date-pickers/models'; - -export const useGetOpenRangeDialogAriaText = (params: { - formatKey: keyof AdapterFormats; - translationKey: 'openDateRangePickerDialogue' | 'openTimeRangePickerDialogue'; -}) => { - const utils = useUtils(); - const translations = usePickerTranslations(); - const { formatKey, translationKey } = params; - - return (value: PickerRangeValue) => { - const formattedValue = [ - value[0] !== null && utils.isValid(value[0]) ? utils.format(value[0], formatKey) : null, - value[1] !== null && utils.isValid(value[1]) ? utils.format(value[1], formatKey) : null, - ] as const; - return translations[translationKey](formattedValue); - }; -}; diff --git a/packages/x-date-pickers/src/locales/enUS.ts b/packages/x-date-pickers/src/locales/enUS.ts index 4bbe5857a848..488a0681602f 100644 --- a/packages/x-date-pickers/src/locales/enUS.ts +++ b/packages/x-date-pickers/src/locales/enUS.ts @@ -57,36 +57,6 @@ const enUSPickers: PickersLocaleText = { formattedDate ? `Choose date, selected date is ${formattedDate}` : 'Choose date', openTimePickerDialogue: (formattedTime) => formattedTime ? `Choose time, selected time is ${formattedTime}` : 'Choose time', - openDateRangePickerDialogue: ([formattedStartDate, formattedEndDate]) => { - if (!formattedStartDate && !formattedEndDate) { - return 'Choose date range'; - } - - if (!formattedStartDate) { - return `Choose date range, end date is ${formattedEndDate}`; - } - - if (!formattedEndDate) { - return `Choose date range, start date is ${formattedStartDate}`; - } - - return `Choose date range, start date is ${formattedStartDate}, end date is ${formattedEndDate}`; - }, - openTimeRangePickerDialogue: ([formattedStartTime, formattedEndTime]) => { - if (!formattedStartTime && !formattedEndTime) { - return 'Choose time range'; - } - - if (!formattedStartTime) { - return `Choose time range, end time is ${formattedEndTime}`; - } - - if (!formattedEndTime) { - return `Choose time range, start time is ${formattedStartTime}`; - } - - return `Choose time range, start time is ${formattedStartTime}, end time is ${formattedEndTime}`; - }, fieldClearLabel: 'Clear', diff --git a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts index ab9e144493b3..902aa019f149 100644 --- a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts +++ b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts @@ -66,8 +66,6 @@ export interface PickersComponentAgnosticLocaleText { // Open picker labels openDatePickerDialogue: (formattedDate: string | null) => string; openTimePickerDialogue: (formattedTime: string | null) => string; - openDateRangePickerDialogue: (formattedRange: readonly [string | null, string | null]) => string; - openTimeRangePickerDialogue: (formattedRange: readonly [string | null, string | null]) => string; // Clear button label fieldClearLabel: string; From e3f8964dfefc0d3281db83f588ddc760d4dad45b Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 14:08:11 +0100 Subject: [PATCH 14/77] Work --- ...nvertFieldResponseIntoMuiTextFieldProps.ts | 27 ------------------- 1 file changed, 27 deletions(-) delete mode 100644 packages/x-date-pickers/src/internals/utils/convertFieldResponseIntoMuiTextFieldProps.ts diff --git a/packages/x-date-pickers/src/internals/utils/convertFieldResponseIntoMuiTextFieldProps.ts b/packages/x-date-pickers/src/internals/utils/convertFieldResponseIntoMuiTextFieldProps.ts deleted file mode 100644 index 7cfc387fc6a3..000000000000 --- a/packages/x-date-pickers/src/internals/utils/convertFieldResponseIntoMuiTextFieldProps.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TextFieldProps } from '@mui/material/TextField'; -import { UseFieldResponse } from '../hooks/useField'; - -export const convertFieldResponseIntoMuiTextFieldProps = < - TFieldResponse extends UseFieldResponse, ->({ - enableAccessibleFieldDOMStructure, - ...fieldResponse -}: TFieldResponse): TextFieldProps => { - if (enableAccessibleFieldDOMStructure) { - const { InputProps, readOnly, value, ...other } = fieldResponse; - - return { - ...other, - InputProps: { ...(InputProps ?? {}), readOnly }, - } as any; - } - - const { onPaste, onKeyDown, inputMode, readOnly, InputProps, inputProps, inputRef, ...other } = - fieldResponse; - - return { - ...other, - InputProps: { ...(InputProps ?? {}), readOnly }, - inputProps: { ...(inputProps ?? {}), inputMode, onPaste, onKeyDown, ref: inputRef }, - } as any; -}; From 6af3e7cb2cf9f929f69bb8eca11f4a28c41321da Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 14:10:12 +0100 Subject: [PATCH 15/77] Fix --- .../src/internals/hooks/useField/useField.types.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts index 8bdc9d6b32e2..1794dde0f353 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts @@ -124,6 +124,9 @@ export interface UseFieldInternalProps< export interface UseFieldCommonAdditionalProps extends Required, 'disabled' | 'readOnly'>> { + /** + * The aria label to set on the button that opens the picker. + */ openPickerAriaLabel: string; } From 6f499e0be9738a74377c6e0c6f401ee5be2b239b Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 14:19:31 +0100 Subject: [PATCH 16/77] Fix --- .../date-pickers/single-input-date-time-range-field.json | 4 ---- .../api-docs/date-pickers/date-field/date-field.json | 4 ++-- .../date-pickers/date-time-field/date-time-field.json | 4 ++-- .../single-input-date-range-field.json | 2 +- .../single-input-date-time-range-field.json | 5 +---- .../single-input-time-range-field.json | 2 +- .../api-docs/date-pickers/time-field/time-field.json | 4 ++-- .../SingleInputDateRangeField.tsx | 2 +- .../SingleInputDateTimeRangeField.tsx | 2 +- .../SingleInputTimeRangeField.tsx | 2 +- packages/x-date-pickers/src/DateField/DateField.tsx | 4 ++-- .../x-date-pickers/src/DateTimeField/DateTimeField.tsx | 4 ++-- packages/x-date-pickers/src/TimeField/TimeField.tsx | 4 ++-- .../src/internals/components/PickerFieldUI.tsx | 7 +++++-- 14 files changed, 23 insertions(+), 27 deletions(-) diff --git a/docs/pages/x/api/date-pickers/single-input-date-time-range-field.json b/docs/pages/x/api/date-pickers/single-input-date-time-range-field.json index b0d9faa015ad..119936cbddf1 100644 --- a/docs/pages/x/api/date-pickers/single-input-date-time-range-field.json +++ b/docs/pages/x/api/date-pickers/single-input-date-time-range-field.json @@ -73,10 +73,6 @@ "describedArgs": ["newValue"] } }, - "openPickerButtonPosition": { - "type": { "name": "enum", "description": "'end'
| 'start'" }, - "default": "'end'" - }, "readOnly": { "type": { "name": "bool" }, "default": "false" }, "referenceDate": { "type": { "name": "object" }, diff --git a/docs/translations/api-docs/date-pickers/date-field/date-field.json b/docs/translations/api-docs/date-pickers/date-field/date-field.json index 494d49396573..205a45188419 100644 --- a/docs/translations/api-docs/date-pickers/date-field/date-field.json +++ b/docs/translations/api-docs/date-pickers/date-field/date-field.json @@ -8,7 +8,7 @@ "description": "If true, a clear button will be shown in the field allowing value clearing." }, "clearButtonPosition": { - "description": "The position at which the UI to clear the value should be placed. If the field is not clearable, the button will not be rendered." + "description": "The position at which the clear button is placed. If the field is not clearable, the button will not be rendered." }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." @@ -82,7 +82,7 @@ "typeDescriptions": { "newValue": "The new selected sections." } }, "openPickerButtonPosition": { - "description": "The position at which the UI to clear the value should be placed. If there is no picker to open, the button will not be rendered" + "description": "The position at which the opening button is placed. If there is no picker to open, the button will not be rendered" }, "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." diff --git a/docs/translations/api-docs/date-pickers/date-time-field/date-time-field.json b/docs/translations/api-docs/date-pickers/date-time-field/date-time-field.json index de6c37256403..dc32d44c1554 100644 --- a/docs/translations/api-docs/date-pickers/date-time-field/date-time-field.json +++ b/docs/translations/api-docs/date-pickers/date-time-field/date-time-field.json @@ -9,7 +9,7 @@ "description": "If true, a clear button will be shown in the field allowing value clearing." }, "clearButtonPosition": { - "description": "The position at which the UI to clear the value should be placed. If the field is not clearable, the button will not be rendered." + "description": "The position at which the clear button is placed. If the field is not clearable, the button will not be rendered." }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." @@ -99,7 +99,7 @@ "typeDescriptions": { "newValue": "The new selected sections." } }, "openPickerButtonPosition": { - "description": "The position at which the UI to clear the value should be placed. If there is no picker to open, the button will not be rendered" + "description": "The position at which the opening button is placed. If there is no picker to open, the button will not be rendered" }, "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." diff --git a/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json b/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json index 09638efb2c1f..845f18a03bb0 100644 --- a/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json +++ b/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json @@ -8,7 +8,7 @@ "description": "If true, a clear button will be shown in the field allowing value clearing." }, "clearButtonPosition": { - "description": "The position at which the UI to clear the value should be placed. If the field is not clearable, the button will not be rendered." + "description": "The position at which the clear button is placed. If the field is not clearable, the button will not be rendered." }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." diff --git a/docs/translations/api-docs/date-pickers/single-input-date-time-range-field/single-input-date-time-range-field.json b/docs/translations/api-docs/date-pickers/single-input-date-time-range-field/single-input-date-time-range-field.json index ca4f3ff06dea..5b8f6ba4caf8 100644 --- a/docs/translations/api-docs/date-pickers/single-input-date-time-range-field/single-input-date-time-range-field.json +++ b/docs/translations/api-docs/date-pickers/single-input-date-time-range-field/single-input-date-time-range-field.json @@ -9,7 +9,7 @@ "description": "If true, a clear button will be shown in the field allowing value clearing." }, "clearButtonPosition": { - "description": "The position at which the UI to clear the value should be placed. If the field is not clearable, the button will not be rendered." + "description": "The position at which the clear button is placed. If the field is not clearable, the button will not be rendered." }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." @@ -99,9 +99,6 @@ "description": "Callback fired when the selected sections change.", "typeDescriptions": { "newValue": "The new selected sections." } }, - "openPickerButtonPosition": { - "description": "The position at which the UI to clear the value should be placed. If there is no picker to open, the button will not be rendered" - }, "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." }, diff --git a/docs/translations/api-docs/date-pickers/single-input-time-range-field/single-input-time-range-field.json b/docs/translations/api-docs/date-pickers/single-input-time-range-field/single-input-time-range-field.json index 0fb7ec97acbf..87896fc9172f 100644 --- a/docs/translations/api-docs/date-pickers/single-input-time-range-field/single-input-time-range-field.json +++ b/docs/translations/api-docs/date-pickers/single-input-time-range-field/single-input-time-range-field.json @@ -9,7 +9,7 @@ "description": "If true, a clear button will be shown in the field allowing value clearing." }, "clearButtonPosition": { - "description": "The position at which the UI to clear the value should be placed. If the field is not clearable, the button will not be rendered." + "description": "The position at which the clear button is placed. If the field is not clearable, the button will not be rendered." }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." diff --git a/docs/translations/api-docs/date-pickers/time-field/time-field.json b/docs/translations/api-docs/date-pickers/time-field/time-field.json index baa18f7071ca..0cc7443c8494 100644 --- a/docs/translations/api-docs/date-pickers/time-field/time-field.json +++ b/docs/translations/api-docs/date-pickers/time-field/time-field.json @@ -9,7 +9,7 @@ "description": "If true, a clear button will be shown in the field allowing value clearing." }, "clearButtonPosition": { - "description": "The position at which the UI to clear the value should be placed. If the field is not clearable, the button will not be rendered." + "description": "The position at which the clear button is placed. If the field is not clearable, the button will not be rendered." }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." @@ -91,7 +91,7 @@ "typeDescriptions": { "newValue": "The new selected sections." } }, "openPickerButtonPosition": { - "description": "The position at which the UI to clear the value should be placed. If there is no picker to open, the button will not be rendered" + "description": "The position at which the opening button is placed. If there is no picker to open, the button will not be rendered" }, "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." diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx index ef6f2e1e6b84..4974b116d016 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx @@ -91,7 +91,7 @@ SingleInputDateRangeField.propTypes = { */ clearable: PropTypes.bool, /** - * The position at which the UI to clear the value should be placed. + * The position at which the clear button is placed. * If the field is not clearable, the button will not be rendered. * @default 'end' */ diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx index fa37c3d400df..2a1c2a44d6c8 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx @@ -97,7 +97,7 @@ SingleInputDateTimeRangeField.propTypes = { */ clearable: PropTypes.bool, /** - * The position at which the UI to clear the value should be placed. + * The position at which the clear button is placed. * If the field is not clearable, the button will not be rendered. * @default 'end' */ diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx index c5c87bc69962..36b5c4310393 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx @@ -97,7 +97,7 @@ SingleInputTimeRangeField.propTypes = { */ clearable: PropTypes.bool, /** - * The position at which the UI to clear the value should be placed. + * The position at which the clear button is placed. * If the field is not clearable, the button will not be rendered. * @default 'end' */ diff --git a/packages/x-date-pickers/src/DateField/DateField.tsx b/packages/x-date-pickers/src/DateField/DateField.tsx index f5fbc345cbda..a583bb7cfc67 100644 --- a/packages/x-date-pickers/src/DateField/DateField.tsx +++ b/packages/x-date-pickers/src/DateField/DateField.tsx @@ -83,7 +83,7 @@ DateField.propTypes = { */ clearable: PropTypes.bool, /** - * The position at which the UI to clear the value should be placed. + * The position at which the clear button is placed. * If the field is not clearable, the button will not be rendered. * @default 'end' */ @@ -232,7 +232,7 @@ DateField.propTypes = { */ onSelectedSectionsChange: PropTypes.func, /** - * The position at which the UI to clear the value should be placed. + * The position at which the opening button is placed. * If there is no picker to open, the button will not be rendered * @default 'end' */ diff --git a/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx b/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx index 0973f8c08647..576e1c8855d8 100644 --- a/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx +++ b/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx @@ -94,7 +94,7 @@ DateTimeField.propTypes = { */ clearable: PropTypes.bool, /** - * The position at which the UI to clear the value should be placed. + * The position at which the clear button is placed. * If the field is not clearable, the button will not be rendered. * @default 'end' */ @@ -271,7 +271,7 @@ DateTimeField.propTypes = { */ onSelectedSectionsChange: PropTypes.func, /** - * The position at which the UI to clear the value should be placed. + * The position at which the opening button is placed. * If there is no picker to open, the button will not be rendered * @default 'end' */ diff --git a/packages/x-date-pickers/src/TimeField/TimeField.tsx b/packages/x-date-pickers/src/TimeField/TimeField.tsx index 4eed03b33c33..2981893a9ae9 100644 --- a/packages/x-date-pickers/src/TimeField/TimeField.tsx +++ b/packages/x-date-pickers/src/TimeField/TimeField.tsx @@ -88,7 +88,7 @@ TimeField.propTypes = { */ clearable: PropTypes.bool, /** - * The position at which the UI to clear the value should be placed. + * The position at which the clear button is placed. * If the field is not clearable, the button will not be rendered. * @default 'end' */ @@ -247,7 +247,7 @@ TimeField.propTypes = { */ onSelectedSectionsChange: PropTypes.func, /** - * The position at which the UI to clear the value should be placed. + * The position at which the opening button is placed. * If there is no picker to open, the button will not be rendered * @default 'end' */ diff --git a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx index 6320a8faa922..1aed40099763 100644 --- a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx @@ -250,13 +250,13 @@ export interface ExportedPickerFieldUIProps { */ onClear?: React.MouseEventHandler; /** - * The position at which the UI to clear the value should be placed. + * The position at which the clear button is placed. * If the field is not clearable, the button will not be rendered. * @default 'end' */ clearButtonPosition?: 'start' | 'end'; /** - * The position at which the UI to clear the value should be placed. + * The position at which the opening button is placed. * If there is no picker to open, the button will not be rendered * @default 'end' */ @@ -274,6 +274,9 @@ export interface PickerFieldUIProps { * @default {} */ slotProps?: PickerFieldUISlotProps; + /** + * Object returned by the `useField` hook or one of its wrapper (for example `useDateField`). + */ fieldResponse: UseFieldResponse; } From c4e803b556b56160efecb4f096b2c32a8a97f052 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 14:38:26 +0100 Subject: [PATCH 17/77] Fix --- .../custom-field/BrowserV7MultiInputRangeField.tsx | 4 ++-- .../date-pickers/custom-field/JoyV6MultiInputRangeField.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.tsx b/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.tsx index 4c60152c21d0..e27c0399efbc 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.tsx @@ -136,13 +136,13 @@ const BrowserMultiInputDateRangeField = React.forwardRef( const startTextFieldProps = useSlotProps({ elementType: 'input', externalSlotProps: slotProps?.textField, - ownerState: { ...props, position: 'start' }, + ownerState: {} as any, }) as MultiInputFieldSlotTextFieldProps; const endTextFieldProps = useSlotProps({ elementType: 'input', externalSlotProps: slotProps?.textField, - ownerState: { ...props, position: 'end' }, + ownerState: {} as any, }) as MultiInputFieldSlotTextFieldProps; const fieldResponse = useMultiInputDateRangeField< diff --git a/docs/data/date-pickers/custom-field/JoyV6MultiInputRangeField.tsx b/docs/data/date-pickers/custom-field/JoyV6MultiInputRangeField.tsx index f4c28e574437..f84c5d9623e0 100644 --- a/docs/data/date-pickers/custom-field/JoyV6MultiInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6MultiInputRangeField.tsx @@ -162,13 +162,13 @@ const JoyMultiInputDateRangeField = React.forwardRef( const startTextFieldProps = useSlotProps({ elementType: FormControl, externalSlotProps: slotProps?.textField, - ownerState: { ...props, position: 'start' }, + ownerState: {} as any, }) as MultiInputFieldSlotTextFieldProps; const endTextFieldProps = useSlotProps({ elementType: FormControl, externalSlotProps: slotProps?.textField, - ownerState: { ...props, position: 'end' }, + ownerState: {} as any, }) as MultiInputFieldSlotTextFieldProps; const fieldResponse = useMultiInputDateRangeField< From 0274ae2c11155af1e459f3f54ad3aa4f0733760b Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 14:43:08 +0100 Subject: [PATCH 18/77] Fix --- .../custom-field/BrowserV7MultiInputRangeField.js | 4 ++-- .../date-pickers/custom-field/JoyV6MultiInputRangeField.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.js b/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.js index 5f7d2d494688..325cb1a63afc 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.js +++ b/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.js @@ -100,13 +100,13 @@ const BrowserMultiInputDateRangeField = React.forwardRef((props, ref) => { const startTextFieldProps = useSlotProps({ elementType: 'input', externalSlotProps: slotProps?.textField, - ownerState: { ...props, position: 'start' }, + ownerState: {}, }); const endTextFieldProps = useSlotProps({ elementType: 'input', externalSlotProps: slotProps?.textField, - ownerState: { ...props, position: 'end' }, + ownerState: {}, }); const fieldResponse = useMultiInputDateRangeField({ diff --git a/docs/data/date-pickers/custom-field/JoyV6MultiInputRangeField.js b/docs/data/date-pickers/custom-field/JoyV6MultiInputRangeField.js index 61a8a5d231f7..0f9bbc0edfba 100644 --- a/docs/data/date-pickers/custom-field/JoyV6MultiInputRangeField.js +++ b/docs/data/date-pickers/custom-field/JoyV6MultiInputRangeField.js @@ -124,13 +124,13 @@ const JoyMultiInputDateRangeField = React.forwardRef((props, ref) => { const startTextFieldProps = useSlotProps({ elementType: FormControl, externalSlotProps: slotProps?.textField, - ownerState: { ...props, position: 'start' }, + ownerState: {}, }); const endTextFieldProps = useSlotProps({ elementType: FormControl, externalSlotProps: slotProps?.textField, - ownerState: { ...props, position: 'end' }, + ownerState: {}, }); const fieldResponse = useMultiInputDateRangeField({ From 5d6525bd5153d81d831dd9799c11a5c30d296405 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 14:56:43 +0100 Subject: [PATCH 19/77] Empty From 8a218a777540201de6bfa69f172434b067e1c3ba Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 15:28:26 +0100 Subject: [PATCH 20/77] Work --- .../MaterialDatePicker.tsx | 84 +++++++++---------- .../behavior-button/MaterialDatePicker.tsx | 14 +--- .../MaskedMaterialTextField.tsx | 27 +++++- .../MaterialDatePicker.tsx | 4 +- .../internals/components/PickerProvider.tsx | 2 +- .../src/internals/models/fields.ts | 5 -- 6 files changed, 74 insertions(+), 62 deletions(-) diff --git a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx index 7633f42d7199..868db4c35fce 100644 --- a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx +++ b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx @@ -1,8 +1,9 @@ import * as React from 'react'; import dayjs, { Dayjs } from 'dayjs'; import Autocomplete from '@mui/material/Autocomplete'; +import IconButton from '@mui/material/IconButton'; +import { CalendarIcon } from '@mui/x-date-pickers/icons'; import TextField from '@mui/material/TextField'; -import Stack from '@mui/material/Stack'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { @@ -10,7 +11,7 @@ import { DatePickerFieldProps, DatePickerProps, } from '@mui/x-date-pickers/DatePicker'; -import { useSplitFieldProps } from '@mui/x-date-pickers/hooks'; +import { usePickerContext, useSplitFieldProps } from '@mui/x-date-pickers/hooks'; import { useValidation, validateDate } from '@mui/x-date-pickers/validation'; interface AutocompleteFieldProps extends DatePickerFieldProps { @@ -24,7 +25,6 @@ function AutocompleteField(props: AutocompleteFieldProps) { const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date'); const { value, timezone, onChange } = internalProps; const { - InputProps, slotProps, slots, ownerState, @@ -36,6 +36,15 @@ function AutocompleteField(props: AutocompleteFieldProps) { ...other } = forwardedProps; + const pickerContext = usePickerContext(); + const handleTogglePicker = (event: React.MouseEvent) => { + if (pickerContext.open) { + pickerContext.onClose(event); + } else { + pickerContext.onOpen(event); + } + }; + const { hasValidationError, getValidationErrorForNewValue } = useValidation({ validator: validateDate, value, @@ -43,50 +52,41 @@ function AutocompleteField(props: AutocompleteFieldProps) { props: internalProps, }); - const mergeAdornments = (...adornments: React.ReactNode[]) => { - const nonNullAdornments = adornments.filter((el) => el != null); - if (nonNullAdornments.length === 0) { - return null; - } - - if (nonNullAdornments.length === 1) { - return nonNullAdornments[0]; - } - - return ( - - {nonNullAdornments.map((adornment, index) => ( - {adornment} - ))} - - ); - }; - return ( ( - - )} + renderInput={(params) => { + return ( + + { + (params.InputProps.endAdornment as React.ReactElement)?.props + .children + } + + + + + ), + }, + ), + }} + /> + ); + }} getOptionLabel={(option) => { if (!dayjs.isDayjs(option)) { 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 index ac64ebd3a5f0..dbf9263c52a3 100644 --- a/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx @@ -17,16 +17,8 @@ import { 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 { slotProps, slots, ownerState, label, focused, name, ...other } = + forwardedProps; const pickerContext = usePickerContext(); @@ -53,7 +45,7 @@ function ButtonDateField(props: DatePickerFieldProps) { {...other} variant="outlined" color={hasValidationError ? 'error' : 'primary'} - ref={InputProps?.ref} + ref={pickerContext.triggerRef as React.Ref} onClick={handleTogglePicker} > {label ? `${label}: ${valueStr}` : valueStr} diff --git a/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx b/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx index aa7b8023fcaf..d4d4a1ef7cbd 100644 --- a/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx +++ b/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import dayjs, { Dayjs } from 'dayjs'; import { useRifm } from 'rifm'; import TextField from '@mui/material/TextField'; +import InputAdornment from '@mui/material/InputAdornment'; +import IconButton from '@mui/material/IconButton'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { @@ -9,8 +11,13 @@ import { DatePickerProps, DatePickerFieldProps, } from '@mui/x-date-pickers/DatePicker'; -import { useSplitFieldProps, useParsedFormat } from '@mui/x-date-pickers/hooks'; +import { + useSplitFieldProps, + useParsedFormat, + usePickerContext, +} from '@mui/x-date-pickers/hooks'; import { useValidation, validateDate } from '@mui/x-date-pickers/validation'; +import { CalendarIcon } from '@mui/x-date-pickers/icons'; const MASK_USER_INPUT_SYMBOL = '_'; const ACCEPT_REGEX = /[\d]/gi; @@ -46,6 +53,14 @@ function MaskedDateField(props: DatePickerFieldProps) { }, [format, value]); const parsedFormat = useParsedFormat(internalProps); + const pickerContext = usePickerContext(); + const handleTogglePicker = (event: React.MouseEvent) => { + if (pickerContext.open) { + pickerContext.onClose(event); + } else { + pickerContext.onOpen(event); + } + }; const { hasValidationError, getValidationErrorForNewValue } = useValidation({ value, @@ -131,6 +146,16 @@ function MaskedDateField(props: DatePickerFieldProps) { error={!!hasValidationError} {...rifmProps} {...forwardedProps} + InputProps={{ + ref: pickerContext.triggerRef, + endAdornment: ( + + + + + + ), + }} /> ); } 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..fdb65b4af507 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 @@ -18,7 +18,7 @@ import { CalendarIcon } from '@mui/x-date-pickers/icons'; function ReadOnlyDateField(props: DatePickerFieldProps) { const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date'); const { value, timezone, format } = internalProps; - const { InputProps, slotProps, slots, ...other } = forwardedProps; + const { slotProps, slots, ...other } = forwardedProps; const pickerContext = usePickerContext(); @@ -44,7 +44,7 @@ function ReadOnlyDateField(props: DatePickerFieldProps) { value={value == null ? '' : value.format(format)} placeholder={parsedFormat} InputProps={{ - ...InputProps, + ref: pickerContext.triggerRef, readOnly: true, endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, diff --git a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx index 6b7ba40293a4..3af1c5eabea7 100644 --- a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx @@ -58,7 +58,7 @@ export interface PickerContextValue { /** * The ref that should be attached to the element that triggers the picker opening. */ - triggerRef: React.RefObject; + triggerRef: React.Ref; /** * `true` if the picker is open, `false` otherwise. */ diff --git a/packages/x-date-pickers/src/internals/models/fields.ts b/packages/x-date-pickers/src/internals/models/fields.ts index d51566ab2488..72eb8fa8b813 100644 --- a/packages/x-date-pickers/src/internals/models/fields.ts +++ b/packages/x-date-pickers/src/internals/models/fields.ts @@ -25,11 +25,6 @@ export interface BaseForwardedSingleInputFieldProps extends ExportedPickerFieldU onBlur?: React.FocusEventHandler; ref?: React.Ref; inputRef?: React.Ref; - InputProps?: { - ref?: React.Ref; - endAdornment?: React.ReactNode; - startAdornment?: React.ReactNode; - }; inputProps?: { 'aria-label'?: string; }; From b1e685bbc1709a6211cae876b4ebb1afd7cde9fa Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 29 Nov 2024 16:02:20 +0100 Subject: [PATCH 21/77] Work --- .../custom-field/BrowserV7Field.tsx | 42 ++++--- .../BrowserV7MultiInputRangeField.tsx | 17 ++- .../BrowserV7SingleInputRangeField.tsx | 63 +++++------ .../date-pickers/custom-field/JoyV6Field.tsx | 76 +++++++------ .../JoyV6SingleInputRangeField.tsx | 103 +++++++----------- .../MaterialDatePicker.tsx | 2 +- .../behavior-button/MaterialDatePicker.tsx | 2 +- .../MaterialDateRangePicker.tsx | 14 +-- .../MaskedMaterialTextField.tsx | 2 +- .../internals/components/PickerFieldUI.tsx | 2 +- .../internals/components/PickerProvider.tsx | 2 +- .../useDesktopPicker/useDesktopPicker.tsx | 2 +- packages/x-date-pickers/src/models/fields.ts | 3 + 13 files changed, 161 insertions(+), 169 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx index a2cc66b242e7..67294d4984bb 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx @@ -1,7 +1,9 @@ import * as React from 'react'; import useForkRef from '@mui/utils/useForkRef'; import { styled } from '@mui/material/styles'; +import IconButton from '@mui/material/IconButton'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { CalendarIcon } from '@mui/x-date-pickers/icons'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DatePicker, @@ -9,7 +11,7 @@ import { DatePickerProps, } from '@mui/x-date-pickers/DatePicker'; import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateField'; -import { useClearableField } from '@mui/x-date-pickers/hooks'; +import { usePickerContext } from '@mui/x-date-pickers/hooks'; import { BaseSingleInputPickersTextFieldProps } from '@mui/x-date-pickers/models'; import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList'; @@ -55,10 +57,17 @@ const BrowserTextField = React.forwardRef( onPaste, onKeyDown, + // Should be passed to the button that opens the picker + openPickerAriaLabel, + // Can be passed to a hidden element onChange, value, + // Can be passed to an icon to clear the value + clearable, + onClear, + // Can be used to render a custom label label, @@ -69,17 +78,23 @@ const BrowserTextField = React.forwardRef( focused, error, - InputProps: { ref: InputPropsRef, startAdornment, endAdornment } = {}, - // The rest can be passed to the root element ...other } = props; - const handleRef = useForkRef(InputPropsRef, ref); + const pickerContext = usePickerContext(); + const handleTogglePicker = (event: React.UIEvent) => { + if (pickerContext.open) { + pickerContext.onClose(event); + } else { + pickerContext.onOpen(event); + } + }; + + const handleRef = useForkRef(pickerContext.triggerRef, ref); return ( - {startAdornment} - {endAdornment} + + + ); }, @@ -105,14 +126,7 @@ const BrowserDateField = React.forwardRef( const fieldResponse = useDateField(textFieldProps); - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); - - return ; + return ; }, ); diff --git a/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.tsx b/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.tsx index e27c0399efbc..8c29e3ba1a7b 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.tsx @@ -170,6 +170,19 @@ const BrowserMultiInputDateRangeField = React.forwardRef( unstableEndFieldRef, }); + const { + onClear: onClearStartDate, + clearable: isStartDateClearable, + openPickerAriaLabel: openPickerStartDateAriaLabel, + ...startDateProps + } = fieldResponse.startDate; + const { + onClear: onClearEndDate, + clearable: isEndDateClearable, + openPickerAriaLabel: openPickerEndDateAriaLabel, + ...endDateProps + } = fieldResponse.endDate; + return ( - + — - + ); }, diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx index 2c1c935104e7..2291ae929d0d 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx @@ -3,8 +3,7 @@ import useForkRef from '@mui/utils/useForkRef'; import useSlotProps from '@mui/utils/useSlotProps'; import { styled } from '@mui/material/styles'; import IconButton from '@mui/material/IconButton'; -import InputAdornment from '@mui/material/InputAdornment'; -import { DateRangeIcon } from '@mui/x-date-pickers/icons'; +import { CalendarIcon } from '@mui/x-date-pickers/icons'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { @@ -13,7 +12,7 @@ import { DateRangePickerProps, } from '@mui/x-date-pickers-pro/DateRangePicker'; import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; -import { useClearableField, usePickerContext } from '@mui/x-date-pickers/hooks'; +import { usePickerContext } from '@mui/x-date-pickers/hooks'; import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList'; import { FieldType } from '@mui/x-date-pickers-pro/models'; import { BaseSingleInputPickersTextFieldProps } from '@mui/x-date-pickers/models'; @@ -60,10 +59,17 @@ const BrowserTextField = React.forwardRef( onPaste, onKeyDown, + // Should be passed to the button that opens the picker + openPickerAriaLabel, + // Can be passed to a hidden element onChange, value, + // Can be passed to an icon to clear the value + clearable, + onClear, + // Can be used to render a custom label label, @@ -74,17 +80,23 @@ const BrowserTextField = React.forwardRef( focused, error, - InputProps: { ref: InputPropsRef, startAdornment, endAdornment } = {}, - // The rest can be passed to the root element ...other } = props; - const handleRef = useForkRef(InputPropsRef, ref); + const pickerContext = usePickerContext(); + const handleTogglePicker = (event: React.UIEvent) => { + if (pickerContext.open) { + pickerContext.onClose(event); + } else { + pickerContext.onOpen(event); + } + }; + + const handleRef = useForkRef(pickerContext.triggerRef, ref); return ( - {startAdornment} - {endAdornment} + + + ); }, @@ -114,15 +132,6 @@ const BrowserSingleInputDateRangeField = React.forwardRef( (props: BrowserSingleInputDateRangeFieldProps, ref: React.Ref) => { 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', externalSlotProps: slotProps?.textField, @@ -130,31 +139,13 @@ const BrowserSingleInputDateRangeField = React.forwardRef( ownerState: props as any, }); - textFieldProps.InputProps = { - ...textFieldProps.InputProps, - endAdornment: ( - - - - - - ), - }; - const fieldResponse = useSingleInputDateRangeField( textFieldProps, ); - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); - return ( ; - enableAccessibleFieldDOMStructure?: boolean; - InputProps?: { - ref?: React.Ref; - endAdornment?: React.ReactNode; - startAdornment?: React.ReactNode; - }; +interface JoyFieldProps + extends Omit>, + BaseSingleInputPickersTextFieldProps { formControlSx?: InputProps['sx']; } @@ -47,44 +44,62 @@ const JoyField = React.forwardRef( // Should be ignored enableAccessibleFieldDOMStructure, - disabled, - id, + // Should be passed to the button that opens the picker + openPickerAriaLabel, + + // Can be passed to an icon to clear the value + clearable, + onClear, + + // Can be used to render a custom label label, - InputProps: { ref: containerRef, startAdornment, endAdornment } = {}, + + // Can be used to style the component + disabled, + readOnly, + focused, + error, + inputRef, + + // The rest can be passed to the root element formControlSx, endDecorator, - startDecorator, slotProps, - inputRef, + slots, ...other } = props; + const pickerContext = usePickerContext(); + const handleTogglePicker = (event: React.UIEvent) => { + if (pickerContext.open) { + pickerContext.onClose(event); + } else { + pickerContext.onOpen(event); + } + }; + return ( {label} - {startAdornment} - {startDecorator} - - } endDecorator={ - {endAdornment} + + + {endDecorator} } slotProps={{ ...slotProps, - root: { ...slotProps?.root, ref: containerRef }, input: { ...slotProps?.input, ref: inputRef }, }} {...other} @@ -103,14 +118,7 @@ const JoyDateField = React.forwardRef( enableAccessibleFieldDOMStructure: false, }); - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); - - return ; + return ; }, ); diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx index 36d33af92f98..7993ec758990 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx @@ -14,8 +14,6 @@ import { import Input, { InputProps } from '@mui/joy/Input'; import FormControl from '@mui/joy/FormControl'; import FormLabel from '@mui/joy/FormLabel'; -import IconButton from '@mui/joy/IconButton'; -import { DateRangeIcon } from '@mui/x-date-pickers/icons'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { @@ -24,20 +22,16 @@ import { DateRangePickerProps, } from '@mui/x-date-pickers-pro/DateRangePicker'; import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; -import { useClearableField, usePickerContext } from '@mui/x-date-pickers/hooks'; +import { usePickerContext } from '@mui/x-date-pickers/hooks'; import { FieldType } from '@mui/x-date-pickers-pro/models'; +import { BaseSingleInputPickersTextFieldProps } from '@mui/x-date-pickers/models'; const joyTheme = extendJoyTheme(); -interface JoyFieldProps extends InputProps { - label?: React.ReactNode; - inputRef?: React.Ref; - enableAccessibleFieldDOMStructure?: boolean; - InputProps?: { - ref?: React.Ref; - endAdornment?: React.ReactNode; - startAdornment?: React.ReactNode; - }; +interface JoyFieldProps + extends Omit>, + BaseSingleInputPickersTextFieldProps { + formControlSx?: InputProps['sx']; } type JoyFieldComponent = (( @@ -50,38 +44,43 @@ const JoyField = React.forwardRef( // Should be ignored enableAccessibleFieldDOMStructure, - disabled, - id, + // Should be passed to the button that opens the picker + openPickerAriaLabel, + + // Can be passed to an icon to clear the value + clearable, + onClear, + + // Can be used to render a custom label label, - InputProps: { ref: containerRef, startAdornment, endAdornment } = {}, - endDecorator, - startDecorator, - slotProps, + + // Can be used to style the component + disabled, + readOnly, + focused, + error, inputRef, + + // The rest can be passed to the root element + formControlSx, + slotProps, + slots, ...other } = props; + const pickerContext = usePickerContext(); + return ( - + {label} - {startAdornment} - {startDecorator} - - } - endDecorator={ - - {endAdornment} - {endDecorator} - - } slotProps={{ ...slotProps, - root: { ...slotProps?.root, ref: containerRef }, input: { ...slotProps?.input, ref: inputRef }, }} {...other} @@ -102,15 +101,6 @@ const JoySingleInputDateRangeField = React.forwardRef( (props: JoySingleInputDateRangeFieldProps, ref: React.Ref) => { 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: JoySingleInputDateRangeFieldProps = useSlotProps({ elementType: FormControl, externalSlotProps: slotProps?.textField, @@ -120,32 +110,13 @@ const JoySingleInputDateRangeField = React.forwardRef( const fieldResponse = useSingleInputDateRangeField< false, - JoySingleInputDateRangeFieldProps - >({ ...textFieldProps, enableAccessibleFieldDOMStructure: false }); - - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, + Omit + >({ + ...textFieldProps, + enableAccessibleFieldDOMStructure: false, }); - return ( - - - - } - /> - ); + return ; }, ) as JoySingleInputDateRangeFieldComponent; diff --git a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx index 868db4c35fce..9274e8a420ed 100644 --- a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx +++ b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx @@ -37,7 +37,7 @@ function AutocompleteField(props: AutocompleteFieldProps) { } = forwardedProps; const pickerContext = usePickerContext(); - const handleTogglePicker = (event: React.MouseEvent) => { + const handleTogglePicker = (event: React.UIEvent) => { if (pickerContext.open) { pickerContext.onClose(event); } else { 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 dbf9263c52a3..e42defdf2195 100644 --- a/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx @@ -45,7 +45,7 @@ function ButtonDateField(props: DatePickerFieldProps) { {...other} variant="outlined" color={hasValidationError ? 'error' : 'primary'} - ref={pickerContext.triggerRef as React.Ref} + ref={pickerContext.triggerRef} onClick={handleTogglePicker} > {label ? `${label}: ${valueStr}` : valueStr} 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..6f955b436a36 100644 --- a/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx @@ -19,16 +19,8 @@ import { 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 { slotProps, slots, ownerState, label, focused, name, ...other } = + forwardedProps; const pickerContext = usePickerContext(); @@ -57,7 +49,7 @@ function ButtonDateRangeField(props: DateRangePickerFieldProps) { {...other} variant="outlined" color={hasValidationError ? 'error' : 'primary'} - ref={InputProps?.ref} + ref={pickerContext.triggerRef} onClick={handleTogglePicker} > {label ? `${label}: ${formattedValue}` : formattedValue} diff --git a/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx b/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx index d4d4a1ef7cbd..699c4c05fbc5 100644 --- a/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx +++ b/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx @@ -54,7 +54,7 @@ function MaskedDateField(props: DatePickerFieldProps) { const parsedFormat = useParsedFormat(internalProps); const pickerContext = usePickerContext(); - const handleTogglePicker = (event: React.MouseEvent) => { + const handleTogglePicker = (event: React.UIEvent) => { if (pickerContext.open) { pickerContext.onClose(event); } else { diff --git a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx index 1aed40099763..27390c82d112 100644 --- a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx @@ -97,7 +97,7 @@ export function PickerFieldUI(props: PickerFieldUIProps) { } = cleanFieldResponse(fieldResponse); const ownerState = useFieldOwnerState(textFieldProps); - const handleTogglePicker = (event: React.MouseEvent) => { + const handleTogglePicker = (event: React.UIEvent) => { if (!pickerContext) { return; } diff --git a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx index 3af1c5eabea7..8cc97803898c 100644 --- a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx @@ -58,7 +58,7 @@ export interface PickerContextValue { /** * The ref that should be attached to the element that triggers the picker opening. */ - triggerRef: React.Ref; + triggerRef: React.RefObject; /** * `true` if the picker is open, `false` otherwise. */ diff --git a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx index fe0e539feb22..c8cdc20a92ec 100644 --- a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx +++ b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx @@ -152,7 +152,7 @@ export const useDesktopPicker = < ; +export type BaseSingleInputPickerFieldResponse = + UseFieldResponse; + /** * Props the built-in text field component can receive. */ From da6aa21dc1adb05f33616ea5e9bc21a0855220fb Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 2 Dec 2024 10:03:11 +0100 Subject: [PATCH 22/77] Work --- .../custom-field/BrowserV7Field.js | 39 +++++--- .../BrowserV7MultiInputRangeField.js | 17 +++- .../BrowserV7SingleInputRangeField.js | 60 +++++------- .../date-pickers/custom-field/JoyV6Field.js | 66 +++++++------ .../date-pickers/custom-field/JoyV6Field.tsx | 14 ++- .../JoyV6SingleInputRangeField.js | 94 +++++-------------- .../JoyV6SingleInputRangeField.tsx | 36 ++----- .../MaterialDatePicker.js | 78 +++++++-------- .../behavior-button/MaterialDatePicker.js | 14 +-- .../MaterialDateRangePicker.js | 14 +-- .../MaskedMaterialTextField.js | 27 +++++- .../MaterialDatePicker.js | 4 +- .../overview/mainDemo/PickerButton.tsx | 5 +- .../useDesktopRangePicker.tsx | 2 +- .../useMobileRangePicker.tsx | 2 +- .../internals/components/PickerFieldUI.tsx | 7 +- .../internals/components/PickerProvider.tsx | 16 ++-- .../hooks/usePicker/usePickerProvider.ts | 6 +- packages/x-date-pickers/src/models/fields.ts | 12 ++- scripts/x-date-pickers-pro.exports.json | 1 + scripts/x-date-pickers.exports.json | 1 + 21 files changed, 247 insertions(+), 268 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7Field.js b/docs/data/date-pickers/custom-field/BrowserV7Field.js index 3e6be2ea7b36..5eaa7b440e29 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7Field.js +++ b/docs/data/date-pickers/custom-field/BrowserV7Field.js @@ -1,11 +1,13 @@ import * as React from 'react'; import useForkRef from '@mui/utils/useForkRef'; import { styled } from '@mui/material/styles'; +import IconButton from '@mui/material/IconButton'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { CalendarIcon } from '@mui/x-date-pickers/icons'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateField'; -import { useClearableField } from '@mui/x-date-pickers/hooks'; +import { usePickerContext } from '@mui/x-date-pickers/hooks'; import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList'; @@ -41,9 +43,14 @@ const BrowserTextField = React.forwardRef((props, ref) => { onInput, onPaste, onKeyDown, + // Should be passed to the button that opens the picker + openPickerAriaLabel, // Can be passed to a hidden element onChange, value, + // Can be passed to an icon to clear the value + clearable, + onClear, // Can be used to render a custom label label, // Can be used to style the component @@ -52,16 +59,23 @@ const BrowserTextField = React.forwardRef((props, ref) => { readOnly, focused, error, - InputProps: { ref: InputPropsRef, startAdornment, endAdornment } = {}, // The rest can be passed to the root element ...other } = props; - const handleRef = useForkRef(InputPropsRef, ref); + const pickerContext = usePickerContext(); + const handleTogglePicker = (event) => { + if (pickerContext.open) { + pickerContext.onClose(event); + } else { + pickerContext.onOpen(event); + } + }; + + const handleRef = useForkRef(pickerContext.triggerRef, ref); return ( - {startAdornment} { onKeyDown={onKeyDown} /> - {endAdornment} + + + ); }); @@ -85,14 +105,7 @@ const BrowserDateField = React.forwardRef((props, ref) => { const fieldResponse = useDateField(textFieldProps); - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); - - return ; + return ; }); const BrowserDatePicker = React.forwardRef((props, ref) => { diff --git a/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.js b/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.js index 325cb1a63afc..2d9bef9d5a83 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.js +++ b/docs/data/date-pickers/custom-field/BrowserV7MultiInputRangeField.js @@ -131,6 +131,19 @@ const BrowserMultiInputDateRangeField = React.forwardRef((props, ref) => { unstableEndFieldRef, }); + const { + onClear: onClearStartDate, + clearable: isStartDateClearable, + openPickerAriaLabel: openPickerStartDateAriaLabel, + ...startDateProps + } = fieldResponse.startDate; + const { + onClear: onClearEndDate, + clearable: isEndDateClearable, + openPickerAriaLabel: openPickerEndDateAriaLabel, + ...endDateProps + } = fieldResponse.endDate; + return ( { overflow="auto" className={className} > - + — - + ); }); diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js index a86335cd7dd7..d548ca1ceff2 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js @@ -3,13 +3,12 @@ import useForkRef from '@mui/utils/useForkRef'; import useSlotProps from '@mui/utils/useSlotProps'; import { styled } from '@mui/material/styles'; import IconButton from '@mui/material/IconButton'; -import InputAdornment from '@mui/material/InputAdornment'; -import { DateRangeIcon } from '@mui/x-date-pickers/icons'; +import { CalendarIcon } from '@mui/x-date-pickers/icons'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker'; import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; -import { useClearableField, usePickerContext } from '@mui/x-date-pickers/hooks'; +import { usePickerContext } from '@mui/x-date-pickers/hooks'; import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList'; const BrowserFieldRoot = styled('div', { name: 'BrowserField', slot: 'Root' })({ @@ -44,9 +43,14 @@ const BrowserTextField = React.forwardRef((props, ref) => { onInput, onPaste, onKeyDown, + // Should be passed to the button that opens the picker + openPickerAriaLabel, // Can be passed to a hidden element onChange, value, + // Can be passed to an icon to clear the value + clearable, + onClear, // Can be used to render a custom label label, // Can be used to style the component @@ -55,16 +59,23 @@ const BrowserTextField = React.forwardRef((props, ref) => { readOnly, focused, error, - InputProps: { ref: InputPropsRef, startAdornment, endAdornment } = {}, // The rest can be passed to the root element ...other } = props; - const handleRef = useForkRef(InputPropsRef, ref); + const pickerContext = usePickerContext(); + const handleTogglePicker = (event) => { + if (pickerContext.open) { + pickerContext.onClose(event); + } else { + pickerContext.onOpen(event); + } + }; + + const handleRef = useForkRef(pickerContext.triggerRef, ref); return ( - {startAdornment} { onKeyDown={onKeyDown} /> - {endAdornment} + + + ); }); @@ -86,15 +103,6 @@ const BrowserTextField = React.forwardRef((props, ref) => { 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', externalSlotProps: slotProps?.textField, @@ -102,29 +110,11 @@ const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => { ownerState: props, }); - textFieldProps.InputProps = { - ...textFieldProps.InputProps, - endAdornment: ( - - - - - - ), - }; - const fieldResponse = useSingleInputDateRangeField(textFieldProps); - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); - return ( { const { // Should be ignored enableAccessibleFieldDOMStructure, - disabled, - id, + // Should be passed to the button that opens the picker + openPickerAriaLabel, + // Can be passed to an icon to clear the value + clearable, + onClear, + // Can be used to render a custom label label, - InputProps: { ref: containerRef, startAdornment, endAdornment } = {}, + // Can be used to style the component + disabled, + readOnly, + focused, + error, + inputRef, + // The rest can be passed to the root element formControlSx, endDecorator, - startDecorator, slotProps, - inputRef, + slots, ...other } = props; + const pickerContext = usePickerContext(); + const handleTogglePicker = (event) => { + if (pickerContext.open) { + pickerContext.onClose(event); + } else { + pickerContext.onOpen(event); + } + }; + return ( {label} - {startAdornment} - {startDecorator} - - } endDecorator={ - {endAdornment} + + + {endDecorator} } slotProps={{ ...slotProps, - root: { ...slotProps?.root, ref: containerRef }, - input: { ...slotProps?.input, ref: inputRef }, + input: { ref: inputRef }, }} {...other} /> @@ -72,21 +89,12 @@ const JoyField = React.forwardRef((props, ref) => { }); const JoyDateField = React.forwardRef((props, ref) => { - const { slots, slotProps, ...textFieldProps } = props; - const fieldResponse = useDateField({ - ...textFieldProps, + ...props, enableAccessibleFieldDOMStructure: false, }); - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); - - return ; + return ; }); const JoyDatePicker = React.forwardRef((props, ref) => { diff --git a/docs/data/date-pickers/custom-field/JoyV6Field.tsx b/docs/data/date-pickers/custom-field/JoyV6Field.tsx index 9748bc48a4ba..918927dfd2d9 100644 --- a/docs/data/date-pickers/custom-field/JoyV6Field.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6Field.tsx @@ -23,14 +23,14 @@ import { } from '@mui/x-date-pickers/DatePicker'; import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateField'; import { usePickerContext } from '@mui/x-date-pickers/hooks'; -import { BaseSingleInputPickersTextFieldProps } from '@mui/x-date-pickers/models'; +import { BaseSingleInputPickersFieldHooksReturnValue } from '@mui/x-date-pickers/models'; import { CalendarIcon } from '@mui/x-date-pickers/icons'; const joyTheme = extendJoyTheme(); interface JoyFieldProps - extends Omit>, - BaseSingleInputPickersTextFieldProps { + extends Omit>, + BaseSingleInputPickersFieldHooksReturnValue { formControlSx?: InputProps['sx']; } @@ -100,7 +100,7 @@ const JoyField = React.forwardRef( } slotProps={{ ...slotProps, - input: { ...slotProps?.input, ref: inputRef }, + input: { ref: inputRef }, }} {...other} /> @@ -111,10 +111,8 @@ const JoyField = React.forwardRef( const JoyDateField = React.forwardRef( (props: DatePickerFieldProps, ref: React.Ref) => { - const { slots, slotProps, ...textFieldProps } = props; - - const fieldResponse = useDateField({ - ...textFieldProps, + const fieldResponse = useDateField({ + ...props, enableAccessibleFieldDOMStructure: false, }); diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js index dd5ee96d6f52..39072847d6fb 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js @@ -4,7 +4,6 @@ import { useColorScheme as useMaterialColorScheme, Experimental_CssVarsProvider as MaterialCssVarsProvider, } from '@mui/material/styles'; -import useSlotProps from '@mui/utils/useSlotProps'; import { extendTheme as extendJoyTheme, useColorScheme, @@ -14,13 +13,11 @@ import { import Input from '@mui/joy/Input'; import FormControl from '@mui/joy/FormControl'; import FormLabel from '@mui/joy/FormLabel'; -import IconButton from '@mui/joy/IconButton'; -import { DateRangeIcon } from '@mui/x-date-pickers/icons'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker'; import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; -import { useClearableField, usePickerContext } from '@mui/x-date-pickers/hooks'; +import { usePickerContext } from '@mui/x-date-pickers/hooks'; const joyTheme = extendJoyTheme(); @@ -28,39 +25,40 @@ const JoyField = React.forwardRef((props, ref) => { const { // Should be ignored enableAccessibleFieldDOMStructure, - disabled, - id, + // Should be passed to the button that opens the picker + openPickerAriaLabel, + // Can be passed to an icon to clear the value + clearable, + onClear, + // Can be used to render a custom label label, - InputProps: { ref: containerRef, startAdornment, endAdornment } = {}, - endDecorator, - startDecorator, - slotProps, + // Can be used to style the component + disabled, + readOnly, + focused, + error, inputRef, + // The rest can be passed to the root element + formControlSx, + slotProps, + slots, ...other } = props; + const pickerContext = usePickerContext(); + return ( - + {label} - {startAdornment} - {startDecorator} - - } - endDecorator={ - - {endAdornment} - {endDecorator} - - } slotProps={{ ...slotProps, - root: { ...slotProps?.root, ref: containerRef }, - input: { ...slotProps?.input, ref: inputRef }, + input: { ref: inputRef }, }} {...other} /> @@ -69,52 +67,12 @@ const JoyField = React.forwardRef((props, ref) => { }); 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, - externalSlotProps: slotProps?.textField, - externalForwardedProps: other, - ownerState: props, - }); - const fieldResponse = useSingleInputDateRangeField({ - ...textFieldProps, + ...props, enableAccessibleFieldDOMStructure: false, }); - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); - - return ( - - - - } - /> - ); + return ; }); JoySingleInputDateRangeField.fieldType = 'single-input'; diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx index 7993ec758990..a883cab66d38 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx @@ -4,7 +4,6 @@ import { useColorScheme as useMaterialColorScheme, Experimental_CssVarsProvider as MaterialCssVarsProvider, } from '@mui/material/styles'; -import useSlotProps from '@mui/utils/useSlotProps'; import { extendTheme as extendJoyTheme, useColorScheme, @@ -24,13 +23,13 @@ import { import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; import { usePickerContext } from '@mui/x-date-pickers/hooks'; import { FieldType } from '@mui/x-date-pickers-pro/models'; -import { BaseSingleInputPickersTextFieldProps } from '@mui/x-date-pickers/models'; +import { BaseSingleInputPickersFieldHooksReturnValue } from '@mui/x-date-pickers/models'; const joyTheme = extendJoyTheme(); interface JoyFieldProps - extends Omit>, - BaseSingleInputPickersTextFieldProps { + extends Omit>, + BaseSingleInputPickersFieldHooksReturnValue { formControlSx?: InputProps['sx']; } @@ -81,7 +80,7 @@ const JoyField = React.forwardRef( disabled={disabled} slotProps={{ ...slotProps, - input: { ...slotProps?.input, ref: inputRef }, + input: { ref: inputRef }, }} {...other} /> @@ -90,33 +89,18 @@ const JoyField = React.forwardRef( }, ) as JoyFieldComponent; -interface JoySingleInputDateRangeFieldProps - extends DateRangePickerFieldProps {} - type JoySingleInputDateRangeFieldComponent = (( - props: JoySingleInputDateRangeFieldProps & React.RefAttributes, + props: DateRangePickerFieldProps & React.RefAttributes, ) => React.JSX.Element) & { fieldType?: FieldType }; const JoySingleInputDateRangeField = React.forwardRef( - (props: JoySingleInputDateRangeFieldProps, ref: React.Ref) => { - const { slots, slotProps, ...other } = props; - - const textFieldProps: JoySingleInputDateRangeFieldProps = useSlotProps({ - elementType: FormControl, - externalSlotProps: slotProps?.textField, - externalForwardedProps: other, - ownerState: props as any, - }); - - const fieldResponse = useSingleInputDateRangeField< - false, - Omit - >({ - ...textFieldProps, + (props: DateRangePickerFieldProps, ref: React.Ref) => { + const fieldResponse = useSingleInputDateRangeField({ + ...props, enableAccessibleFieldDOMStructure: false, - }); + }) as BaseSingleInputPickersFieldHooksReturnValue; - return ; + return ; }, ) as JoySingleInputDateRangeFieldComponent; diff --git a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.js b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.js index 2856b3af1a2d..483ac71a2721 100644 --- a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.js +++ b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.js @@ -1,19 +1,19 @@ import * as React from 'react'; import dayjs from 'dayjs'; import Autocomplete from '@mui/material/Autocomplete'; +import IconButton from '@mui/material/IconButton'; +import { CalendarIcon } from '@mui/x-date-pickers/icons'; import TextField from '@mui/material/TextField'; -import Stack from '@mui/material/Stack'; 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 { useSplitFieldProps } from '@mui/x-date-pickers/hooks'; +import { usePickerContext, useSplitFieldProps } from '@mui/x-date-pickers/hooks'; import { useValidation, validateDate } from '@mui/x-date-pickers/validation'; function AutocompleteField(props) { const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date'); const { value, timezone, onChange } = internalProps; const { - InputProps, slotProps, slots, ownerState, @@ -25,6 +25,15 @@ function AutocompleteField(props) { ...other } = forwardedProps; + const pickerContext = usePickerContext(); + const handleTogglePicker = (event) => { + if (pickerContext.open) { + pickerContext.onClose(event); + } else { + pickerContext.onOpen(event); + } + }; + const { hasValidationError, getValidationErrorForNewValue } = useValidation({ validator: validateDate, value, @@ -32,50 +41,35 @@ function AutocompleteField(props) { props: internalProps, }); - const mergeAdornments = (...adornments) => { - const nonNullAdornments = adornments.filter((el) => el != null); - if (nonNullAdornments.length === 0) { - return null; - } - - if (nonNullAdornments.length === 1) { - return nonNullAdornments[0]; - } - - return ( - - {nonNullAdornments.map((adornment, index) => ( - {adornment} - ))} - - ); - }; - return ( ( - - )} + renderInput={(params) => { + return ( + + {params.InputProps.endAdornment?.props.children} + + + + + ), + }), + }} + /> + ); + }} getOptionLabel={(option) => { if (!dayjs.isDayjs(option)) { return ''; diff --git a/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.js b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.js index f9306981aac0..78611a002f46 100644 --- a/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.js +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.js @@ -13,16 +13,8 @@ import { 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 { slotProps, slots, ownerState, label, focused, name, ...other } = + forwardedProps; const pickerContext = usePickerContext(); @@ -49,7 +41,7 @@ function ButtonDateField(props) { {...other} variant="outlined" color={hasValidationError ? 'error' : 'primary'} - ref={InputProps?.ref} + ref={pickerContext.triggerRef} onClick={handleTogglePicker} > {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..9ab421c2f3c4 100644 --- a/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.js +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.js @@ -15,16 +15,8 @@ import { 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 { slotProps, slots, ownerState, label, focused, name, ...other } = + forwardedProps; const pickerContext = usePickerContext(); @@ -53,7 +45,7 @@ function ButtonDateRangeField(props) { {...other} variant="outlined" color={hasValidationError ? 'error' : 'primary'} - ref={InputProps?.ref} + ref={pickerContext.triggerRef} onClick={handleTogglePicker} > {label ? `${label}: ${formattedValue}` : formattedValue} diff --git a/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.js b/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.js index 107fb273f496..7da7a87eb2f7 100644 --- a/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.js +++ b/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.js @@ -2,11 +2,18 @@ import * as React from 'react'; import dayjs from 'dayjs'; import { useRifm } from 'rifm'; import TextField from '@mui/material/TextField'; +import InputAdornment from '@mui/material/InputAdornment'; +import IconButton from '@mui/material/IconButton'; 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 { useSplitFieldProps, useParsedFormat } from '@mui/x-date-pickers/hooks'; +import { + useSplitFieldProps, + useParsedFormat, + usePickerContext, +} from '@mui/x-date-pickers/hooks'; import { useValidation, validateDate } from '@mui/x-date-pickers/validation'; +import { CalendarIcon } from '@mui/x-date-pickers/icons'; const MASK_USER_INPUT_SYMBOL = '_'; const ACCEPT_REGEX = /[\d]/gi; @@ -42,6 +49,14 @@ function MaskedDateField(props) { }, [format, value]); const parsedFormat = useParsedFormat(internalProps); + const pickerContext = usePickerContext(); + const handleTogglePicker = (event) => { + if (pickerContext.open) { + pickerContext.onClose(event); + } else { + pickerContext.onOpen(event); + } + }; const { hasValidationError, getValidationErrorForNewValue } = useValidation({ value, @@ -127,6 +142,16 @@ function MaskedDateField(props) { error={!!hasValidationError} {...rifmProps} {...forwardedProps} + InputProps={{ + ref: pickerContext.triggerRef, + endAdornment: ( + + + + + + ), + }} /> ); } 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..611ef6eaa534 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 @@ -14,7 +14,7 @@ import { CalendarIcon } from '@mui/x-date-pickers/icons'; function ReadOnlyDateField(props) { const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date'); const { value, timezone, format } = internalProps; - const { InputProps, slotProps, slots, ...other } = forwardedProps; + const { slotProps, slots, ...other } = forwardedProps; const pickerContext = usePickerContext(); @@ -40,7 +40,7 @@ function ReadOnlyDateField(props) { value={value == null ? '' : value.format(format)} placeholder={parsedFormat} InputProps={{ - ...InputProps, + ref: pickerContext.triggerRef, readOnly: true, endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, diff --git a/docs/src/modules/components/overview/mainDemo/PickerButton.tsx b/docs/src/modules/components/overview/mainDemo/PickerButton.tsx index d47d045fb1c6..ce64d3079b31 100644 --- a/docs/src/modules/components/overview/mainDemo/PickerButton.tsx +++ b/docs/src/modules/components/overview/mainDemo/PickerButton.tsx @@ -10,8 +10,7 @@ import { useValidation, validateDate } from '@mui/x-date-pickers/validation'; 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 { slotProps, slots, ownerState, label, focused, name, ...other } = forwardedProps; const pickerContext = usePickerContext(); @@ -42,7 +41,7 @@ function ButtonDateField(props: DatePickerFieldProps) { sx={{ minWidth: 'fit-content' }} fullWidth color={hasValidationError ? 'error' : 'primary'} - ref={InputProps?.ref} + ref={pickerContext.triggerRef} onClick={handleTogglePicker} > {label ? `${label}: ${valueStr}` : valueStr} 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 742b19b7ab78..132c9d97eafa 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 @@ -111,7 +111,7 @@ export const useDesktopRangePicker = < }); // Temporary hack to hide the opening button on the range pickers until we have migrate them to the new opening logic. - providerProps.privateContextValue.openingUIStatus = 'hidden'; + providerProps.privateContextValue.triggerStatus = 'hidden'; React.useEffect(() => { if (layoutProps.view) { diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx index 45ba99db994f..32cfc83ed3bf 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx @@ -107,7 +107,7 @@ export const useMobileRangePicker = < }); // Temporary hack to hide the opening button on the range pickers until we have migrate them to the new opening logic. - providerProps.privateContextValue.openingUIStatus = 'hidden'; + providerProps.privateContextValue.triggerStatus = 'hidden'; const Field = slots.field; const fieldProps: RangePickerPropsForFieldSlot< diff --git a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx index 27390c82d112..f466058fdbfe 100644 --- a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx @@ -86,7 +86,7 @@ export function PickerFieldUI(props: PickerFieldUIProps) { const translations = usePickerTranslations(); const pickerContext = useNullablePickerContext(); - const { openingUIStatus } = usePickerPrivateContext(); + const { triggerStatus } = usePickerPrivateContext(); const { textFieldProps, onClear, @@ -110,8 +110,7 @@ export function PickerFieldUI(props: PickerFieldUIProps) { }; const clearButtonPosition = clearable ? clearButtonPositionProp : null; - const openPickerButtonPosition = - openingUIStatus !== 'hidden' ? openPickerButtonPositionProp : null; + const openPickerButtonPosition = triggerStatus !== 'hidden' ? openPickerButtonPositionProp : null; const TextField = slots.textField ?? @@ -143,7 +142,7 @@ export function PickerFieldUI(props: PickerFieldUIProps) { elementType: OpenPickerButton, externalSlotProps: slotProps?.openPickerButton, additionalProps: { - disabled: openingUIStatus === 'disabled', + disabled: triggerStatus === 'disabled', onClick: handleTogglePicker, 'aria-label': openPickerAriaLabel, edge: diff --git a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx index 8cc97803898c..81e0d44521e4 100644 --- a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx @@ -15,7 +15,7 @@ export const PickerPrivateContext = React.createContext void; - /** - * The ref that should be attached to the element that triggers the picker opening. - */ - triggerRef: React.RefObject; /** * `true` if the picker is open, `false` otherwise. */ open: boolean; + /** + * The ref that should be attached to the element that triggers the picker opening. + * When using a built-in field component, this property is automatically handled. + */ + triggerRef: React.RefObject; /** * `true` if the picker is disabled, `false` otherwise. */ @@ -96,6 +97,9 @@ export interface PickerPrivateContextValue { ownerState: PickerOwnerState; /** * Informs the field if it should render the UI to open the picker. + * If it is "hidden", the field should not render the UI to open the picker. + * If it is "disabled", the field should render the UI to open the picker, but it should be disabled. + * If it is "enabled", the field should render the UI to open the picker and it should be enabled. */ - openingUIStatus: 'hidden' | 'disabled' | 'enabled'; + triggerStatus: 'hidden' | 'disabled' | 'enabled'; } 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 8b8364e1d203..3fdec5edd6cb 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts @@ -116,7 +116,7 @@ export function usePickerProvider( ], ); - const openingUIStatus = React.useMemo(() => { + const triggerStatus = React.useMemo(() => { if (props.disableOpenPicker || !hasUIView) { return 'hidden'; } @@ -129,8 +129,8 @@ export function usePickerProvider( }, [props.disableOpenPicker, hasUIView, props.disabled, props.readOnly]); const privateContextValue = React.useMemo( - () => ({ ownerState, openingUIStatus }), - [ownerState, openingUIStatus], + () => ({ ownerState, triggerStatus }), + [ownerState, triggerStatus], ); return { diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index 641df1586482..0dd2256a0ff0 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -157,13 +157,21 @@ export type PickerFieldSlotProps< }; /** - * Props the text field receives when used with a single input picker. + * Props the `useDateField()` and equivalent hooks return when used inside a single input picker. + * Only contains what the MUI components are passing to the field, not what users can pass using the `props.slotProps.field` and `props.slotProps.textField`. + */ +export type BaseSingleInputPickersFieldHooksReturnValue< + TEnableAccessibleFieldDOMStructure extends boolean, +> = UseFieldResponse; + +/** + * Props the text field receives when used inside a single input picker. * Only contains what the MUI components are passing to the text field, not what users can pass using the `props.slotProps.field` and `props.slotProps.textField`. */ export type BaseSingleInputPickersTextFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, > = Omit< - UseFieldResponse, + BaseSingleInputPickersFieldHooksReturnValue, | 'slots' | 'slotProps' | 'clearable' diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index 36b647590889..7430f1a48bf4 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -5,6 +5,7 @@ { "name": "ArrowLeftIcon", "kind": "Variable" }, { "name": "ArrowRightIcon", "kind": "Variable" }, { "name": "BaseMultiInputPickersTextFieldProps", "kind": "TypeAlias" }, + { "name": "BaseSingleInputPickerFieldResponse", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BuiltInFieldTextFieldProps", "kind": "TypeAlias" }, { "name": "CalendarIcon", "kind": "Variable" }, diff --git a/scripts/x-date-pickers.exports.json b/scripts/x-date-pickers.exports.json index 60cb4180bd3c..df16a555e53a 100644 --- a/scripts/x-date-pickers.exports.json +++ b/scripts/x-date-pickers.exports.json @@ -4,6 +4,7 @@ { "name": "ArrowDropDownIcon", "kind": "Variable" }, { "name": "ArrowLeftIcon", "kind": "Variable" }, { "name": "ArrowRightIcon", "kind": "Variable" }, + { "name": "BaseSingleInputPickerFieldResponse", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BuiltInFieldTextFieldProps", "kind": "TypeAlias" }, { "name": "CalendarIcon", "kind": "Variable" }, From 5e0edb34138a0f1ea3f63a3f318ec5c6174030bc Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 2 Dec 2024 10:27:51 +0100 Subject: [PATCH 23/77] Fix --- .../date-pickers/calendar-systems/AdapterHijri.js | 14 +++----------- .../date-pickers/calendar-systems/AdapterHijri.tsx | 14 +++----------- .../date-pickers/custom-field/BrowserV7Field.tsx | 6 +++--- .../BrowserV7SingleInputRangeField.tsx | 8 ++++---- docs/data/date-pickers/custom-field/JoyV6Field.tsx | 4 ++-- .../x-date-pickers/src/internals/models/fields.ts | 3 ++- scripts/x-date-pickers-pro.exports.json | 1 + scripts/x-date-pickers.exports.json | 1 + 8 files changed, 19 insertions(+), 32 deletions(-) diff --git a/docs/data/date-pickers/calendar-systems/AdapterHijri.js b/docs/data/date-pickers/calendar-systems/AdapterHijri.js index fa738ee1e6e3..342425c95008 100644 --- a/docs/data/date-pickers/calendar-systems/AdapterHijri.js +++ b/docs/data/date-pickers/calendar-systems/AdapterHijri.js @@ -25,16 +25,8 @@ const cacheRtl = createCache({ function ButtonDateTimeField(props) { const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date'); const { value, timezone, format } = internalProps; - const { - InputProps, - slotProps, - slots, - ownerState, - label, - focused, - name, - ...other - } = forwardedProps; + const { slotProps, slots, ownerState, label, focused, name, ...other } = + forwardedProps; const pickerContext = usePickerContext(); @@ -61,7 +53,7 @@ function ButtonDateTimeField(props) { {...other} variant="outlined" color={hasValidationError ? 'error' : 'primary'} - ref={InputProps?.ref} + ref={pickerContext.triggerRef} onClick={handleTogglePicker} > {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..deea11bbec9f 100644 --- a/docs/data/date-pickers/calendar-systems/AdapterHijri.tsx +++ b/docs/data/date-pickers/calendar-systems/AdapterHijri.tsx @@ -29,16 +29,8 @@ const cacheRtl = createCache({ function ButtonDateTimeField(props: DateTimePickerFieldProps) { const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date'); const { value, timezone, format } = internalProps; - const { - InputProps, - slotProps, - slots, - ownerState, - label, - focused, - name, - ...other - } = forwardedProps; + const { slotProps, slots, ownerState, label, focused, name, ...other } = + forwardedProps; const pickerContext = usePickerContext(); @@ -65,7 +57,7 @@ function ButtonDateTimeField(props: DateTimePickerFieldProps) { {...other} variant="outlined" color={hasValidationError ? 'error' : 'primary'} - ref={InputProps?.ref} + ref={pickerContext.triggerRef} onClick={handleTogglePicker} > {label ? `${label}: ${valueStr}` : valueStr} diff --git a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx index 67294d4984bb..1c17f617b34e 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx @@ -12,7 +12,7 @@ import { } from '@mui/x-date-pickers/DatePicker'; import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateField'; import { usePickerContext } from '@mui/x-date-pickers/hooks'; -import { BaseSingleInputPickersTextFieldProps } from '@mui/x-date-pickers/models'; +import { BaseSingleInputPickersFieldHooksReturnValue } from '@mui/x-date-pickers/models'; import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList'; const BrowserFieldRoot = styled('div', { name: 'BrowserField', slot: 'Root' })({ @@ -34,10 +34,10 @@ const BrowserFieldContent = styled('div', { name: 'BrowserField', slot: 'Content ); interface BrowserTextFieldProps - extends BaseSingleInputPickersTextFieldProps, + extends BaseSingleInputPickersFieldHooksReturnValue, Omit< React.HTMLAttributes, - keyof BaseSingleInputPickersTextFieldProps + keyof BaseSingleInputPickersFieldHooksReturnValue > {} const BrowserTextField = React.forwardRef( diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx index 2291ae929d0d..d57ca1228593 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx @@ -15,7 +15,7 @@ import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } import { usePickerContext } from '@mui/x-date-pickers/hooks'; import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList'; import { FieldType } from '@mui/x-date-pickers-pro/models'; -import { BaseSingleInputPickersTextFieldProps } from '@mui/x-date-pickers/models'; +import { BaseSingleInputPickersFieldHooksReturnValue } from '@mui/x-date-pickers/models'; const BrowserFieldRoot = styled('div', { name: 'BrowserField', slot: 'Root' })({ display: 'flex', @@ -36,10 +36,10 @@ const BrowserFieldContent = styled('div', { name: 'BrowserField', slot: 'Content ); interface BrowserTextFieldProps - extends BaseSingleInputPickersTextFieldProps, + extends BaseSingleInputPickersFieldHooksReturnValue, Omit< React.HTMLAttributes, - keyof BaseSingleInputPickersTextFieldProps + keyof BaseSingleInputPickersFieldHooksReturnValue > {} const BrowserTextField = React.forwardRef( @@ -141,7 +141,7 @@ const BrowserSingleInputDateRangeField = React.forwardRef( const fieldResponse = useSingleInputDateRangeField( textFieldProps, - ); + ) as BaseSingleInputPickersFieldHooksReturnValue; return ( >, - BaseSingleInputPickersFieldHooksReturnValue { + extends BaseSingleInputPickersFieldHooksReturnValue, + Omit> { formControlSx?: InputProps['sx']; } diff --git a/packages/x-date-pickers/src/internals/models/fields.ts b/packages/x-date-pickers/src/internals/models/fields.ts index 72eb8fa8b813..260757e063c0 100644 --- a/packages/x-date-pickers/src/internals/models/fields.ts +++ b/packages/x-date-pickers/src/internals/models/fields.ts @@ -14,7 +14,8 @@ export interface FieldRangeSection extends FieldSection { dateName: RangePosition; } -export interface BaseForwardedSingleInputFieldProps extends ExportedPickerFieldUIProps { +export interface BaseForwardedSingleInputFieldProps + extends Pick { className: string | undefined; sx: SxProps | undefined; label: React.ReactNode | undefined; diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index 7430f1a48bf4..bdb9f15f5f4c 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -6,6 +6,7 @@ { "name": "ArrowRightIcon", "kind": "Variable" }, { "name": "BaseMultiInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickerFieldResponse", "kind": "TypeAlias" }, + { "name": "BaseSingleInputPickersFieldHooksReturnValue", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BuiltInFieldTextFieldProps", "kind": "TypeAlias" }, { "name": "CalendarIcon", "kind": "Variable" }, diff --git a/scripts/x-date-pickers.exports.json b/scripts/x-date-pickers.exports.json index df16a555e53a..be5984f42690 100644 --- a/scripts/x-date-pickers.exports.json +++ b/scripts/x-date-pickers.exports.json @@ -5,6 +5,7 @@ { "name": "ArrowLeftIcon", "kind": "Variable" }, { "name": "ArrowRightIcon", "kind": "Variable" }, { "name": "BaseSingleInputPickerFieldResponse", "kind": "TypeAlias" }, + { "name": "BaseSingleInputPickersFieldHooksReturnValue", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BuiltInFieldTextFieldProps", "kind": "TypeAlias" }, { "name": "CalendarIcon", "kind": "Variable" }, From 22826755bfecf3a10ee1fb9838187eb9559635e5 Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 2 Dec 2024 14:08:40 +0100 Subject: [PATCH 24/77] Work on tests --- .../BrowserV7SingleInputRangeField.tsx | 4 +- .../MaterialDatePicker.js | 2 +- .../MaterialDatePicker.tsx | 6 +-- .../tests/DesktopDateRangePicker.test.tsx | 48 +++++++++---------- .../tests/DesktopDateTimeRangePicker.test.tsx | 4 +- ...cribes.DesktopDateTimeRangePicker.test.tsx | 1 - .../tests/MobileDateRangePicker.test.tsx | 18 +++---- .../describes.MobileDateRangePicker.test.tsx | 3 +- ...scribes.MobileDateTimeRangePicker.test.tsx | 3 +- .../StaticDateRangePicker.test.tsx | 1 - .../src/DatePicker/tests/DatePicker.test.tsx | 7 +-- .../tests/DateTimePicker.test.tsx | 7 +-- .../tests/DesktopDatePicker.test.tsx | 30 ++++++------ .../describes.DesktopDatePicker.test.tsx | 1 - .../tests/DesktopDateTimePicker.test.tsx | 4 +- .../describes.DesktopDateTimePicker.test.tsx | 1 - .../tests/DesktopTimePicker.test.tsx | 8 ++-- .../describes.DesktopTimePicker.test.tsx | 1 - .../tests/describes.DigitalClock.test.tsx | 3 +- .../tests/MobileDatePicker.test.tsx | 4 +- .../tests/describes.MobileDatePicker.test.tsx | 2 +- .../tests/MobileDateTimePicker.test.tsx | 2 +- .../describes.MobileDateTimePicker.test.tsx | 3 +- .../tests/MobileTimePicker.test.tsx | 2 +- .../tests/describes.MobileTimePicker.test.tsx | 3 +- ...escribes.MultiSectionDigitalClock.test.tsx | 3 +- .../src/TimePicker/tests/TimePicker.test.tsx | 9 ++-- .../internals/components/PickerFieldUI.tsx | 6 +-- .../describeValue/describeValue.types.ts | 1 + test/utils/pickers/misc.ts | 2 +- test/utils/pickers/openPicker.ts | 8 ---- 31 files changed, 91 insertions(+), 106 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx index d57ca1228593..59dca1e341a6 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx @@ -3,7 +3,7 @@ import useForkRef from '@mui/utils/useForkRef'; import useSlotProps from '@mui/utils/useSlotProps'; import { styled } from '@mui/material/styles'; import IconButton from '@mui/material/IconButton'; -import { CalendarIcon } from '@mui/x-date-pickers/icons'; +import { DateRangeIcon } from '@mui/x-date-pickers/icons'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { @@ -115,7 +115,7 @@ const BrowserTextField = React.forwardRef( sx={{ marginLeft: 1.5 }} aria-label={openPickerAriaLabel} > - + ); diff --git a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.js b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.js index 483ac71a2721..96568ab5a14d 100644 --- a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.js +++ b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.js @@ -59,10 +59,10 @@ function AutocompleteField(props) { endAdornment: React.cloneElement(params.InputProps.endAdornment, { children: ( - {params.InputProps.endAdornment?.props.children} + {params.InputProps.endAdornment?.props.children} ), }), diff --git a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx index 9274e8a420ed..58bf46405fc1 100644 --- a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx +++ b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx @@ -72,13 +72,13 @@ function AutocompleteField(props: AutocompleteFieldProps) { { children: ( + + + { (params.InputProps.endAdornment as React.ReactElement)?.props .children } - - - ), }, diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx index 807b5511d78a..b58a5b9ca70f 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx @@ -36,14 +36,14 @@ describe('', () => { />, ); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(screen.getByText('May 2019')).toBeVisible(); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'end' }); + openPicker({ type: 'date-range', initialFocus: 'end' }); expect(screen.getByText('October 2019')).toBeVisible(); // scroll back - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(screen.getByText('May 2019')).toBeVisible(); }); @@ -52,7 +52,7 @@ describe('', () => { , ); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(screen.getByRole('tooltip')).toBeVisible(); }); @@ -168,7 +168,7 @@ describe('', () => { render(); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(onOpen.callCount).to.equal(1); expect(screen.getByRole('tooltip')).toBeVisible(); @@ -179,7 +179,7 @@ describe('', () => { render(); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'end' }); + openPicker({ type: 'date-range', initialFocus: 'end' }); expect(onOpen.callCount).to.equal(1); expect(screen.getByRole('tooltip')).toBeVisible(); @@ -236,7 +236,7 @@ describe('', () => { ); // Open the picker - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); @@ -278,7 +278,7 @@ describe('', () => { ); // Open the picker - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'end' }); + openPicker({ type: 'date-range', initialFocus: 'end' }); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); @@ -311,7 +311,7 @@ describe('', () => { />, ); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'end' }); + openPicker({ type: 'date-range', initialFocus: 'end' }); // Change the end date fireEvent.click(getPickerDay('3')); @@ -338,7 +338,7 @@ describe('', () => { />, ); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); // Change the start date (already tested) fireEvent.click(getPickerDay('3')); @@ -365,7 +365,7 @@ describe('', () => { , ); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); // Dismiss the picker const input = document.getElementById('test-id')!; @@ -403,7 +403,7 @@ describe('', () => { , ); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); // Change the start date (already tested) fireEvent.click(getPickerDay('3')); @@ -461,7 +461,7 @@ describe('', () => { , ); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(screen.getByRole('tooltip')).toBeVisible(); document.querySelector('#test')!.focus(); @@ -493,7 +493,7 @@ describe('', () => { , ); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(screen.getByRole('tooltip')).toBeVisible(); // Change the start date (already tested) @@ -531,7 +531,7 @@ describe('', () => { />, ); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); // Clear the date fireEvent.click(screen.getByText(/clear/i)); @@ -557,7 +557,7 @@ describe('', () => { />, ); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); // Clear the date fireEvent.click(screen.getByText(/clear/i)); @@ -584,10 +584,10 @@ describe('', () => { ); // Open the picker (already tested) - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); // Switch to end date - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'end' }); + openPicker({ type: 'date-range', initialFocus: 'end' }); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); @@ -608,10 +608,10 @@ describe('', () => { ); // Open the picker (already tested) - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'end' }); + openPicker({ type: 'date-range', initialFocus: 'end' }); // Switch to start date - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); @@ -622,7 +622,7 @@ describe('', () => { it('should respect the disablePast prop', () => { render(); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(getPickerDay('8')).to.have.attribute('disabled'); expect(getPickerDay('9')).to.have.attribute('disabled'); @@ -634,7 +634,7 @@ describe('', () => { it('should respect the disableFuture prop', () => { render(); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(getPickerDay('8')).not.to.have.attribute('disabled'); expect(getPickerDay('9')).not.to.have.attribute('disabled'); @@ -646,7 +646,7 @@ describe('', () => { it('should respect the minDate prop', () => { render(); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(getPickerDay('13')).to.have.attribute('disabled'); expect(getPickerDay('14')).to.have.attribute('disabled'); @@ -658,7 +658,7 @@ describe('', () => { it('should respect the maxDate prop', () => { render(); - openPicker({ type: 'date-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(getPickerDay('13')).not.to.have.attribute('disabled'); expect(getPickerDay('14')).not.to.have.attribute('disabled'); diff --git a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/DesktopDateTimeRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/DesktopDateTimeRangePicker.test.tsx index e8537c5cfc1d..4dea6eb3e186 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/DesktopDateTimeRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/DesktopDateTimeRangePicker.test.tsx @@ -20,7 +20,7 @@ describe('', () => { it('should allow to select range within the same day', () => { render(); - openPicker({ type: 'date-time-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-time-range', initialFocus: 'start' }); // select start date range fireEvent.click(screen.getByRole('gridcell', { name: '11' })); @@ -45,7 +45,7 @@ describe('', () => { , ); - openPicker({ type: 'date-time-range', variant: 'desktop', initialFocus: 'start' }); + openPicker({ type: 'date-time-range', initialFocus: 'start' }); fireEvent.click(screen.getByRole('gridcell', { name: '11' })); diff --git a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx index dfdd329087ff..f2e86f975a81 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx @@ -28,7 +28,6 @@ describe(' - Describes', () => { clock, views: ['day', 'hours', 'minutes'], componentFamily: 'picker', - variant: 'desktop', })); describeConformance(, () => ({ diff --git a/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/MobileDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/MobileDateRangePicker.test.tsx index 83fee1c9814b..83e2457bd23b 100644 --- a/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/MobileDateRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/MobileDateRangePicker.test.tsx @@ -44,7 +44,7 @@ describe('', () => { render(); - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(onOpen.callCount).to.equal(1); expect(screen.queryByRole('dialog')).toBeVisible(); @@ -55,7 +55,7 @@ describe('', () => { render(); - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'end' }); + openPicker({ type: 'date-range', initialFocus: 'end' }); expect(onOpen.callCount).to.equal(1); expect(screen.queryByRole('dialog')).toBeVisible(); @@ -80,7 +80,7 @@ describe('', () => { ); // Open the picker - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); @@ -120,7 +120,7 @@ describe('', () => { ); // Open the picker - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'end' }); + openPicker({ type: 'date-range', initialFocus: 'end' }); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); @@ -151,7 +151,7 @@ describe('', () => { />, ); - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'end' }); + openPicker({ type: 'date-range', initialFocus: 'end' }); // Change the end date fireEvent.click(screen.getByRole('gridcell', { name: '3' })); @@ -181,7 +181,7 @@ describe('', () => { />, ); - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); // Change the start date (already tested) fireEvent.click(screen.getByRole('gridcell', { name: '3' })); @@ -213,7 +213,7 @@ describe('', () => { />, ); - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); // Change the start date (already tested) fireEvent.click(screen.getByRole('gridcell', { name: '3' })); @@ -246,7 +246,7 @@ describe('', () => { />, ); - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); // Clear the date fireEvent.click(screen.getByText(/clear/i)); @@ -272,7 +272,7 @@ describe('', () => { />, ); - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); // Clear the date fireEvent.click(screen.getByText(/clear/i)); diff --git a/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/describes.MobileDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/describes.MobileDateRangePicker.test.tsx index 830468015211..abf9a3c52398 100644 --- a/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/describes.MobileDateRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/describes.MobileDateRangePicker.test.tsx @@ -27,7 +27,6 @@ describe(' - Describes', () => { clock, componentFamily: 'picker', views: ['day'], - variant: 'mobile', })); describeConformance(, () => ({ @@ -84,7 +83,7 @@ describe(' - Describes', () => { } if (!isOpened) { - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + openPicker({ type: 'date-range', initialFocus: 'start' }); } fireEvent.click( diff --git a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/describes.MobileDateTimeRangePicker.test.tsx b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/describes.MobileDateTimeRangePicker.test.tsx index 90a5dc4057ec..dd26967bf82f 100644 --- a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/describes.MobileDateTimeRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/describes.MobileDateTimeRangePicker.test.tsx @@ -29,7 +29,6 @@ describe(' - Describes', () => { clock, views: ['day', 'hours', 'minutes'], componentFamily: 'picker', - variant: 'mobile', })); describeConformance(, () => ({ @@ -88,7 +87,7 @@ describe(' - Describes', () => { if (!isOpened) { openPicker({ type: 'date-time-range', - variant: 'mobile', + initialFocus: setEndDate ? 'end' : 'start', }); } diff --git a/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.test.tsx index b79aa2643aaa..e5b10b6c6ab0 100644 --- a/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.test.tsx @@ -33,7 +33,6 @@ describe('', () => { clock, componentFamily: 'static-picker', views: ['day'], - variant: 'mobile', })); it('allows disabling dates', () => { diff --git a/packages/x-date-pickers/src/DatePicker/tests/DatePicker.test.tsx b/packages/x-date-pickers/src/DatePicker/tests/DatePicker.test.tsx index 3ad845d85883..69f65acc3adf 100644 --- a/packages/x-date-pickers/src/DatePicker/tests/DatePicker.test.tsx +++ b/packages/x-date-pickers/src/DatePicker/tests/DatePicker.test.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import { expect } from 'chai'; +import { dialogClasses } from '@mui/material/Dialog'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; -import { screen } from '@mui/internal-test-utils/createRenderer'; +import { fireEvent, screen } from '@mui/internal-test-utils/createRenderer'; import { createPickerRenderer, stubMatchMedia } from 'test/utils/pickers'; -import { pickersInputBaseClasses } from '@mui/x-date-pickers/PickersTextField'; describe('', () => { const { render } = createPickerRenderer(); @@ -14,7 +14,8 @@ describe('', () => { render(); - expect(screen.getByLabelText(/Choose date/)).to.have.class(pickersInputBaseClasses.input); + fireEvent.click(screen.getByLabelText(/Choose date/)); + expect(screen.getByRole('dialog')).to.have.class(dialogClasses.paper); window.matchMedia = originalMatchMedia; }); diff --git a/packages/x-date-pickers/src/DateTimePicker/tests/DateTimePicker.test.tsx b/packages/x-date-pickers/src/DateTimePicker/tests/DateTimePicker.test.tsx index 933f61c48f16..51e56cc25af3 100644 --- a/packages/x-date-pickers/src/DateTimePicker/tests/DateTimePicker.test.tsx +++ b/packages/x-date-pickers/src/DateTimePicker/tests/DateTimePicker.test.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import { expect } from 'chai'; +import { dialogClasses } from '@mui/material/Dialog'; import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker'; -import { screen } from '@mui/internal-test-utils/createRenderer'; +import { fireEvent, screen } from '@mui/internal-test-utils/createRenderer'; import { createPickerRenderer, stubMatchMedia } from 'test/utils/pickers'; -import { pickersInputBaseClasses } from '@mui/x-date-pickers/PickersTextField'; describe('', () => { const { render } = createPickerRenderer(); @@ -14,7 +14,8 @@ describe('', () => { render(); - expect(screen.getByLabelText(/Choose date/)).to.have.class(pickersInputBaseClasses.input); + fireEvent.click(screen.getByLabelText(/Choose date/)); + expect(screen.getByRole('dialog')).to.have.class(dialogClasses.paper); window.matchMedia = originalMatchMedia; }); diff --git a/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx b/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx index fe9e436f6926..ab12fd1f66e3 100644 --- a/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx @@ -40,7 +40,7 @@ describe('', () => { />, ); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); fireEvent.click(screen.getByLabelText(/switch to year view/i)); expect(handleViewChange.callCount).to.equal(1); @@ -49,7 +49,7 @@ describe('', () => { // eslint-disable-next-line material-ui/disallow-active-element-as-key-event-target fireEvent.keyDown(document.activeElement!, { key: 'Escape' }); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); expect(handleViewChange.callCount).to.equal(2); expect(handleViewChange.lastCall.firstArg).to.equal('day'); }); @@ -66,7 +66,7 @@ describe('', () => { />, ); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); fireEvent.click(screen.getByLabelText(/switch to year view/i)); expect(handleViewChange.callCount).to.equal(1); @@ -75,7 +75,7 @@ describe('', () => { // eslint-disable-next-line material-ui/disallow-active-element-as-key-event-target fireEvent.keyDown(document.activeElement!, { key: 'Escape' }); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); expect(handleViewChange.callCount).to.equal(2); expect(handleViewChange.lastCall.firstArg).to.equal('month'); }); @@ -85,7 +85,7 @@ describe('', () => { , ); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); expect(screen.getByRole('radio', { checked: true, name: '2018' })).not.to.equal(null); @@ -93,7 +93,7 @@ describe('', () => { // eslint-disable-next-line material-ui/disallow-active-element-as-key-event-target fireEvent.keyDown(document.activeElement!, { key: 'Escape' }); setProps({ views: ['month', 'year'] }); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); // wait for all pending changes to be flushed clock.runToLast(); @@ -107,7 +107,7 @@ describe('', () => { } render(); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); expect(document.activeElement).to.have.text('2019'); fireEvent.click(screen.getByText('2020')); @@ -123,7 +123,7 @@ describe('', () => { />, ); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); expect(screen.getByRole('radio', { checked: true, name: 'January' })).not.to.equal(null); @@ -131,7 +131,7 @@ describe('', () => { // eslint-disable-next-line material-ui/disallow-active-element-as-key-event-target fireEvent.keyDown(document.activeElement!, { key: 'Escape' }); setProps({ view: 'year' }); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); // wait for all pending changes to be flushed clock.runToLast(); @@ -245,7 +245,7 @@ describe('', () => { />, ); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); // Select year fireEvent.click(screen.getByRole('radio', { name: '2025' })); @@ -272,7 +272,7 @@ describe('', () => { />, ); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); expect(screen.getByLabelText('Previous month')).to.have.attribute('disabled'); }); @@ -285,7 +285,7 @@ describe('', () => { />, ); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); expect(screen.getByLabelText('Previous month')).not.to.have.attribute('disabled'); }); @@ -298,7 +298,7 @@ describe('', () => { />, ); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); expect(screen.getByLabelText('Next month')).to.have.attribute('disabled'); }); @@ -311,7 +311,7 @@ describe('', () => { />, ); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); expect(screen.getByLabelText('Next month')).not.to.have.attribute('disabled'); }); @@ -356,7 +356,7 @@ describe('', () => { expect(() => { render(); - openPicker({ type: 'date', variant: 'desktop' }); + openPicker({ type: 'date' }); }).toWarnDev('MUI X: `openTo="month"` is not a valid prop.'); }); }); diff --git a/packages/x-date-pickers/src/DesktopDatePicker/tests/describes.DesktopDatePicker.test.tsx b/packages/x-date-pickers/src/DesktopDatePicker/tests/describes.DesktopDatePicker.test.tsx index 1c79140c4807..1bb38f834e57 100644 --- a/packages/x-date-pickers/src/DesktopDatePicker/tests/describes.DesktopDatePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopDatePicker/tests/describes.DesktopDatePicker.test.tsx @@ -23,7 +23,6 @@ describe(' - Describes', () => { clock, views: ['year', 'month', 'day'], componentFamily: 'picker', - variant: 'desktop', })); describeConformance(, () => ({ diff --git a/packages/x-date-pickers/src/DesktopDateTimePicker/tests/DesktopDateTimePicker.test.tsx b/packages/x-date-pickers/src/DesktopDateTimePicker/tests/DesktopDateTimePicker.test.tsx index ea815c570641..5d8534b3971e 100644 --- a/packages/x-date-pickers/src/DesktopDateTimePicker/tests/DesktopDateTimePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopDateTimePicker/tests/DesktopDateTimePicker.test.tsx @@ -35,7 +35,7 @@ describe('', () => { />, ); - openPicker({ type: 'date-time', variant: 'desktop' }); + openPicker({ type: 'date-time' }); // Select year fireEvent.click(screen.getByRole('radio', { name: '2025' })); @@ -75,7 +75,7 @@ describe('', () => { />, ); - openPicker({ type: 'date-time', variant: 'desktop' }); + openPicker({ type: 'date-time' }); // Change the date multiple times to check that picker doesn't close after cycling through all views internally fireEvent.click(screen.getByRole('gridcell', { name: '2' })); diff --git a/packages/x-date-pickers/src/DesktopDateTimePicker/tests/describes.DesktopDateTimePicker.test.tsx b/packages/x-date-pickers/src/DesktopDateTimePicker/tests/describes.DesktopDateTimePicker.test.tsx index 5d6ab646c7b9..e02ad8b1ebf3 100644 --- a/packages/x-date-pickers/src/DesktopDateTimePicker/tests/describes.DesktopDateTimePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopDateTimePicker/tests/describes.DesktopDateTimePicker.test.tsx @@ -36,7 +36,6 @@ describe(' - Describes', () => { clock, views: ['year', 'month', 'day', 'hours', 'minutes'], componentFamily: 'picker', - variant: 'desktop', })); describeConformance(, () => ({ diff --git a/packages/x-date-pickers/src/DesktopTimePicker/tests/DesktopTimePicker.test.tsx b/packages/x-date-pickers/src/DesktopTimePicker/tests/DesktopTimePicker.test.tsx index f6d1314d7694..2ddfa4243ec1 100644 --- a/packages/x-date-pickers/src/DesktopTimePicker/tests/DesktopTimePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopTimePicker/tests/DesktopTimePicker.test.tsx @@ -75,7 +75,7 @@ describe('', () => { />, ); - openPicker({ type: 'time', variant: 'desktop' }); + openPicker({ type: 'time' }); fireEvent.click(screen.getByRole('option', { name: '09:00 AM' })); expect(onChange.callCount).to.equal(1); @@ -99,7 +99,7 @@ describe('', () => { />, ); - openPicker({ type: 'time', variant: 'desktop' }); + openPicker({ type: 'time' }); fireEvent.click(screen.getByRole('option', { name: '2 hours' })); expect(onChange.callCount).to.equal(1); @@ -132,7 +132,7 @@ describe('', () => { />, ); - openPicker({ type: 'time', variant: 'desktop' }); + openPicker({ type: 'time' }); fireEvent.click(screen.getByRole('option', { name: '15 minutes' })); expect(onChange.callCount).to.equal(1); @@ -170,7 +170,7 @@ describe('', () => { />, ); - openPicker({ type: 'time', variant: 'desktop' }); + openPicker({ type: 'time' }); fireEvent.click(screen.getByRole('option', { name: 'PM' })); expect(onChange.callCount).to.equal(1); diff --git a/packages/x-date-pickers/src/DesktopTimePicker/tests/describes.DesktopTimePicker.test.tsx b/packages/x-date-pickers/src/DesktopTimePicker/tests/describes.DesktopTimePicker.test.tsx index 700a92a4156f..77caadcfb15c 100644 --- a/packages/x-date-pickers/src/DesktopTimePicker/tests/describes.DesktopTimePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopTimePicker/tests/describes.DesktopTimePicker.test.tsx @@ -28,7 +28,6 @@ describe(' - Describes', () => { clock, views: ['hours', 'minutes'], componentFamily: 'picker', - variant: 'desktop', })); describeConformance(, () => ({ diff --git a/packages/x-date-pickers/src/DigitalClock/tests/describes.DigitalClock.test.tsx b/packages/x-date-pickers/src/DigitalClock/tests/describes.DigitalClock.test.tsx index c4f5013abc99..6b521b9de35e 100644 --- a/packages/x-date-pickers/src/DigitalClock/tests/describes.DigitalClock.test.tsx +++ b/packages/x-date-pickers/src/DigitalClock/tests/describes.DigitalClock.test.tsx @@ -21,7 +21,6 @@ describe(' - Describes', () => { clock, views: ['hours'], componentFamily: 'digital-clock', - variant: 'desktop', })); describeConformance(, () => ({ @@ -37,7 +36,7 @@ describe(' - Describes', () => { render, componentFamily: 'digital-clock', type: 'time', - variant: 'desktop', + defaultProps: { views: ['hours'], }, diff --git a/packages/x-date-pickers/src/MobileDatePicker/tests/MobileDatePicker.test.tsx b/packages/x-date-pickers/src/MobileDatePicker/tests/MobileDatePicker.test.tsx index 586d963955a2..74188094c7da 100644 --- a/packages/x-date-pickers/src/MobileDatePicker/tests/MobileDatePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileDatePicker/tests/MobileDatePicker.test.tsx @@ -154,7 +154,7 @@ describe('', () => { render(); - openPicker({ type: 'date', variant: 'mobile' }); + openPicker({ type: 'date' }); fireEvent.click(screen.getByText('15', { selector: 'button' })); fireEvent.click(screen.getByText('OK', { selector: 'button' })); @@ -176,7 +176,7 @@ describe('', () => { expectFieldValueV7(view.getSectionsContainer(), 'MM/DD/YYYY'); // Open and Dismiss the picker - openPicker({ type: 'date', variant: 'mobile' }); + openPicker({ type: 'date' }); // eslint-disable-next-line material-ui/disallow-active-element-as-key-event-target fireEvent.keyDown(document.activeElement!, { key: 'Escape' }); clock.runToLast(); diff --git a/packages/x-date-pickers/src/MobileDatePicker/tests/describes.MobileDatePicker.test.tsx b/packages/x-date-pickers/src/MobileDatePicker/tests/describes.MobileDatePicker.test.tsx index 2a75c950b93d..ed5371703071 100644 --- a/packages/x-date-pickers/src/MobileDatePicker/tests/describes.MobileDatePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileDatePicker/tests/describes.MobileDatePicker.test.tsx @@ -61,7 +61,7 @@ describe(' - Describes', () => { }, setNewValue: (value, { isOpened, applySameValue }) => { if (!isOpened) { - openPicker({ type: 'date', variant: 'mobile' }); + openPicker({ type: 'date' }); } const newValue = applySameValue ? value! : adapterToUse.addDays(value!, 1); diff --git a/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx b/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx index da2eb24c177e..51a62e3da389 100644 --- a/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx @@ -114,7 +114,7 @@ describe('', () => { />, ); - openPicker({ type: 'date-time', variant: 'mobile' }); + openPicker({ type: 'date-time' }); expect(onChange.callCount).to.equal(0); expect(onAccept.callCount).to.equal(0); expect(onClose.callCount).to.equal(0); diff --git a/packages/x-date-pickers/src/MobileDateTimePicker/tests/describes.MobileDateTimePicker.test.tsx b/packages/x-date-pickers/src/MobileDateTimePicker/tests/describes.MobileDateTimePicker.test.tsx index 30ae63e192e4..88975bfea2bd 100644 --- a/packages/x-date-pickers/src/MobileDateTimePicker/tests/describes.MobileDateTimePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileDateTimePicker/tests/describes.MobileDateTimePicker.test.tsx @@ -28,7 +28,6 @@ describe(' - Describes', () => { clock, views: ['year', 'day', 'hours', 'minutes'], componentFamily: 'picker', - variant: 'mobile', })); describeConformance(, () => ({ @@ -73,7 +72,7 @@ describe(' - Describes', () => { }, setNewValue: (value, { isOpened, applySameValue }) => { if (!isOpened) { - openPicker({ type: 'date-time', variant: 'mobile' }); + openPicker({ type: 'date-time' }); } const newValue = applySameValue diff --git a/packages/x-date-pickers/src/MobileTimePicker/tests/MobileTimePicker.test.tsx b/packages/x-date-pickers/src/MobileTimePicker/tests/MobileTimePicker.test.tsx index e5442cc50276..4b052523d02e 100644 --- a/packages/x-date-pickers/src/MobileTimePicker/tests/MobileTimePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileTimePicker/tests/MobileTimePicker.test.tsx @@ -64,7 +64,7 @@ describe('', () => { />, ); - openPicker({ type: 'time', variant: 'mobile' }); + openPicker({ type: 'time' }); // Change the hours const hourClockEvent = getClockTouchEvent(11, '12hours'); diff --git a/packages/x-date-pickers/src/MobileTimePicker/tests/describes.MobileTimePicker.test.tsx b/packages/x-date-pickers/src/MobileTimePicker/tests/describes.MobileTimePicker.test.tsx index 5cff45ba0c9c..cb211de30b1d 100644 --- a/packages/x-date-pickers/src/MobileTimePicker/tests/describes.MobileTimePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileTimePicker/tests/describes.MobileTimePicker.test.tsx @@ -29,7 +29,6 @@ describe(' - Describes', () => { clock, views: ['hours', 'minutes'], componentFamily: 'picker', - variant: 'mobile', })); describeConformance(, () => ({ @@ -71,7 +70,7 @@ describe(' - Describes', () => { }, setNewValue: (value, { isOpened, applySameValue }) => { if (!isOpened) { - openPicker({ type: 'time', variant: 'mobile' }); + openPicker({ type: 'time' }); } const newValue = applySameValue diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/tests/describes.MultiSectionDigitalClock.test.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/tests/describes.MultiSectionDigitalClock.test.tsx index 3ab127d6bafa..8227003da285 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/tests/describes.MultiSectionDigitalClock.test.tsx +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/tests/describes.MultiSectionDigitalClock.test.tsx @@ -23,7 +23,6 @@ describe(' - Describes', () => { clock, views: ['hours', 'minutes'], componentFamily: 'multi-section-digital-clock', - variant: 'desktop', })); describeConformance(, () => ({ @@ -39,7 +38,7 @@ describe(' - Describes', () => { render, componentFamily: 'multi-section-digital-clock', type: 'time', - variant: 'desktop', + values: [adapterToUse.date('2018-01-01T11:30:00'), adapterToUse.date('2018-01-01T12:35:00')], emptyValue: null, clock, diff --git a/packages/x-date-pickers/src/TimePicker/tests/TimePicker.test.tsx b/packages/x-date-pickers/src/TimePicker/tests/TimePicker.test.tsx index aaa91fd391fa..dbbf6115c2ed 100644 --- a/packages/x-date-pickers/src/TimePicker/tests/TimePicker.test.tsx +++ b/packages/x-date-pickers/src/TimePicker/tests/TimePicker.test.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; -import { TimePicker } from '@mui/x-date-pickers/TimePicker'; -import { screen } from '@mui/internal-test-utils/createRenderer'; import { expect } from 'chai'; +import { dialogClasses } from '@mui/material/Dialog'; +import { TimePicker } from '@mui/x-date-pickers/TimePicker'; +import { fireEvent, screen } from '@mui/internal-test-utils/createRenderer'; import { createPickerRenderer, stubMatchMedia } from 'test/utils/pickers'; -import { pickersInputBaseClasses } from '@mui/x-date-pickers/PickersTextField'; describe('', () => { const { render } = createPickerRenderer(); @@ -14,7 +14,8 @@ describe('', () => { render(); - expect(screen.getByLabelText(/Choose time/)).to.have.class(pickersInputBaseClasses.input); + fireEvent.click(screen.getByLabelText(/Choose time/)); + expect(screen.getByRole('dialog')).to.have.class(dialogClasses.paper); window.matchMedia = originalMatchMedia; }); diff --git a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx index f466058fdbfe..4ae37af3dd71 100644 --- a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx @@ -250,13 +250,13 @@ export interface ExportedPickerFieldUIProps { onClear?: React.MouseEventHandler; /** * The position at which the clear button is placed. - * If the field is not clearable, the button will not be rendered. + * If the field is not clearable, the button is not rendered. * @default 'end' */ clearButtonPosition?: 'start' | 'end'; /** * The position at which the opening button is placed. - * If there is no picker to open, the button will not be rendered + * If there is no picker to open, the button is not rendered * @default 'end' */ openPickerButtonPosition?: 'start' | 'end'; @@ -326,7 +326,7 @@ export interface PickerFieldUISlotProps { FieldInputAdornmentOwnerState >; openPickerButton?: SlotComponentPropsFromProps; - openPickerIcon?: SlotComponentPropsFromProps, {}, FieldOwnerState>; + openPickerIcon?: SlotComponentPropsFromProps; clearIcon?: SlotComponentPropsFromProps; clearButton?: SlotComponentPropsFromProps; } diff --git a/test/utils/pickers/describeValue/describeValue.types.ts b/test/utils/pickers/describeValue/describeValue.types.ts index c1cb3b358d3f..91e42ace1a1c 100644 --- a/test/utils/pickers/describeValue/describeValue.types.ts +++ b/test/utils/pickers/describeValue/describeValue.types.ts @@ -29,6 +29,7 @@ export type DescribeValueOptions< > = DescribeValueBaseOptions & (C extends 'picker' ? OpenPickerParams & { + variant: 'desktop' | 'mobile'; setNewValue: ( value: InferNonNullablePickerValue, options: { diff --git a/test/utils/pickers/misc.ts b/test/utils/pickers/misc.ts index 76e9ba1d5068..8fe2f45957bb 100644 --- a/test/utils/pickers/misc.ts +++ b/test/utils/pickers/misc.ts @@ -24,7 +24,7 @@ const getChangeCountForComponentFamily = (componentFamily: PickerComponentFamily export const getExpectedOnChangeCount = ( componentFamily: PickerComponentFamily, - params: OpenPickerParams, + params: OpenPickerParams & { variant: 'desktop' | 'mobile' }, ) => { if (componentFamily === 'digital-clock') { return getChangeCountForComponentFamily(componentFamily); diff --git a/test/utils/pickers/openPicker.ts b/test/utils/pickers/openPicker.ts index b34715ce5f8b..1a4285de7b39 100644 --- a/test/utils/pickers/openPicker.ts +++ b/test/utils/pickers/openPicker.ts @@ -5,11 +5,9 @@ import { pickersInputBaseClasses } from '@mui/x-date-pickers/PickersTextField'; export type OpenPickerParams = | { type: 'date' | 'date-time' | 'time'; - variant: 'mobile' | 'desktop'; } | { type: 'date-range' | 'date-time-range'; - variant: 'mobile' | 'desktop'; initialFocus: 'start' | 'end'; /** * @default false @@ -36,12 +34,6 @@ export const openPicker = (params: OpenPickerParams) => { return true; } - if (params.variant === 'mobile') { - fireEvent.click(fieldSectionsContainer); - - return true; - } - const target = params.type === 'time' ? screen.getByLabelText(/choose time/i) From d93c25b69d0b6e4dc01841381d6c47d57bd468b9 Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 2 Dec 2024 14:15:31 +0100 Subject: [PATCH 25/77] Fix --- .../custom-field/BrowserV7SingleInputRangeField.js | 4 ++-- .../api-docs/date-pickers/date-field/date-field.json | 4 ++-- .../date-pickers/date-time-field/date-time-field.json | 4 ++-- .../single-input-date-range-field.json | 2 +- .../single-input-date-time-range-field.json | 2 +- .../single-input-time-range-field.json | 2 +- .../api-docs/date-pickers/time-field/time-field.json | 4 ++-- .../SingleInputDateRangeField/SingleInputDateRangeField.tsx | 2 +- .../SingleInputDateTimeRangeField.tsx | 2 +- .../SingleInputTimeRangeField/SingleInputTimeRangeField.tsx | 2 +- packages/x-date-pickers/src/DateField/DateField.tsx | 4 ++-- packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx | 4 ++-- packages/x-date-pickers/src/TimeField/TimeField.tsx | 4 ++-- 13 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js index d548ca1ceff2..512719dadfd8 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js @@ -3,7 +3,7 @@ import useForkRef from '@mui/utils/useForkRef'; import useSlotProps from '@mui/utils/useSlotProps'; import { styled } from '@mui/material/styles'; import IconButton from '@mui/material/IconButton'; -import { CalendarIcon } from '@mui/x-date-pickers/icons'; +import { DateRangeIcon } from '@mui/x-date-pickers/icons'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker'; @@ -94,7 +94,7 @@ const BrowserTextField = React.forwardRef((props, ref) => { sx={{ marginLeft: 1.5 }} aria-label={openPickerAriaLabel} > - + ); diff --git a/docs/translations/api-docs/date-pickers/date-field/date-field.json b/docs/translations/api-docs/date-pickers/date-field/date-field.json index 205a45188419..6022893a1b8c 100644 --- a/docs/translations/api-docs/date-pickers/date-field/date-field.json +++ b/docs/translations/api-docs/date-pickers/date-field/date-field.json @@ -8,7 +8,7 @@ "description": "If true, a clear button will be shown in the field allowing value clearing." }, "clearButtonPosition": { - "description": "The position at which the clear button is placed. If the field is not clearable, the button will not be rendered." + "description": "The position at which the clear button is placed. If the field is not clearable, the button is not rendered." }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." @@ -82,7 +82,7 @@ "typeDescriptions": { "newValue": "The new selected sections." } }, "openPickerButtonPosition": { - "description": "The position at which the opening button is placed. If there is no picker to open, the button will not be rendered" + "description": "The position at which the opening button is placed. If there is no picker to open, the button is not rendered" }, "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." diff --git a/docs/translations/api-docs/date-pickers/date-time-field/date-time-field.json b/docs/translations/api-docs/date-pickers/date-time-field/date-time-field.json index dc32d44c1554..3a6bc00dd54f 100644 --- a/docs/translations/api-docs/date-pickers/date-time-field/date-time-field.json +++ b/docs/translations/api-docs/date-pickers/date-time-field/date-time-field.json @@ -9,7 +9,7 @@ "description": "If true, a clear button will be shown in the field allowing value clearing." }, "clearButtonPosition": { - "description": "The position at which the clear button is placed. If the field is not clearable, the button will not be rendered." + "description": "The position at which the clear button is placed. If the field is not clearable, the button is not rendered." }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." @@ -99,7 +99,7 @@ "typeDescriptions": { "newValue": "The new selected sections." } }, "openPickerButtonPosition": { - "description": "The position at which the opening button is placed. If there is no picker to open, the button will not be rendered" + "description": "The position at which the opening button is placed. If there is no picker to open, the button is not rendered" }, "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." diff --git a/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json b/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json index 845f18a03bb0..03f4bf83d3a7 100644 --- a/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json +++ b/docs/translations/api-docs/date-pickers/single-input-date-range-field/single-input-date-range-field.json @@ -8,7 +8,7 @@ "description": "If true, a clear button will be shown in the field allowing value clearing." }, "clearButtonPosition": { - "description": "The position at which the clear button is placed. If the field is not clearable, the button will not be rendered." + "description": "The position at which the clear button is placed. If the field is not clearable, the button is not rendered." }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." diff --git a/docs/translations/api-docs/date-pickers/single-input-date-time-range-field/single-input-date-time-range-field.json b/docs/translations/api-docs/date-pickers/single-input-date-time-range-field/single-input-date-time-range-field.json index 5b8f6ba4caf8..08f57b1fb609 100644 --- a/docs/translations/api-docs/date-pickers/single-input-date-time-range-field/single-input-date-time-range-field.json +++ b/docs/translations/api-docs/date-pickers/single-input-date-time-range-field/single-input-date-time-range-field.json @@ -9,7 +9,7 @@ "description": "If true, a clear button will be shown in the field allowing value clearing." }, "clearButtonPosition": { - "description": "The position at which the clear button is placed. If the field is not clearable, the button will not be rendered." + "description": "The position at which the clear button is placed. If the field is not clearable, the button is not rendered." }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." diff --git a/docs/translations/api-docs/date-pickers/single-input-time-range-field/single-input-time-range-field.json b/docs/translations/api-docs/date-pickers/single-input-time-range-field/single-input-time-range-field.json index 87896fc9172f..32b0d8c393e7 100644 --- a/docs/translations/api-docs/date-pickers/single-input-time-range-field/single-input-time-range-field.json +++ b/docs/translations/api-docs/date-pickers/single-input-time-range-field/single-input-time-range-field.json @@ -9,7 +9,7 @@ "description": "If true, a clear button will be shown in the field allowing value clearing." }, "clearButtonPosition": { - "description": "The position at which the clear button is placed. If the field is not clearable, the button will not be rendered." + "description": "The position at which the clear button is placed. If the field is not clearable, the button is not rendered." }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." diff --git a/docs/translations/api-docs/date-pickers/time-field/time-field.json b/docs/translations/api-docs/date-pickers/time-field/time-field.json index 0cc7443c8494..9a6ba3f53aab 100644 --- a/docs/translations/api-docs/date-pickers/time-field/time-field.json +++ b/docs/translations/api-docs/date-pickers/time-field/time-field.json @@ -9,7 +9,7 @@ "description": "If true, a clear button will be shown in the field allowing value clearing." }, "clearButtonPosition": { - "description": "The position at which the clear button is placed. If the field is not clearable, the button will not be rendered." + "description": "The position at which the clear button is placed. If the field is not clearable, the button is not rendered." }, "color": { "description": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide." @@ -91,7 +91,7 @@ "typeDescriptions": { "newValue": "The new selected sections." } }, "openPickerButtonPosition": { - "description": "The position at which the opening button is placed. If there is no picker to open, the button will not be rendered" + "description": "The position at which the opening button is placed. If there is no picker to open, the button is not rendered" }, "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." diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx index 4974b116d016..1e38cadcbc0f 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/SingleInputDateRangeField.tsx @@ -92,7 +92,7 @@ SingleInputDateRangeField.propTypes = { clearable: PropTypes.bool, /** * The position at which the clear button is placed. - * If the field is not clearable, the button will not be rendered. + * If the field is not clearable, the button is not rendered. * @default 'end' */ clearButtonPosition: PropTypes.oneOf(['end', 'start']), diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx index 2a1c2a44d6c8..b1db1dd9ec3c 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.tsx @@ -98,7 +98,7 @@ SingleInputDateTimeRangeField.propTypes = { clearable: PropTypes.bool, /** * The position at which the clear button is placed. - * If the field is not clearable, the button will not be rendered. + * If the field is not clearable, the button is not rendered. * @default 'end' */ clearButtonPosition: PropTypes.oneOf(['end', 'start']), diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx index 36b5c4310393..09adefda7eaa 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.tsx @@ -98,7 +98,7 @@ SingleInputTimeRangeField.propTypes = { clearable: PropTypes.bool, /** * The position at which the clear button is placed. - * If the field is not clearable, the button will not be rendered. + * If the field is not clearable, the button is not rendered. * @default 'end' */ clearButtonPosition: PropTypes.oneOf(['end', 'start']), diff --git a/packages/x-date-pickers/src/DateField/DateField.tsx b/packages/x-date-pickers/src/DateField/DateField.tsx index a583bb7cfc67..46cd1acb8f4e 100644 --- a/packages/x-date-pickers/src/DateField/DateField.tsx +++ b/packages/x-date-pickers/src/DateField/DateField.tsx @@ -84,7 +84,7 @@ DateField.propTypes = { clearable: PropTypes.bool, /** * The position at which the clear button is placed. - * If the field is not clearable, the button will not be rendered. + * If the field is not clearable, the button is not rendered. * @default 'end' */ clearButtonPosition: PropTypes.oneOf(['end', 'start']), @@ -233,7 +233,7 @@ DateField.propTypes = { onSelectedSectionsChange: PropTypes.func, /** * The position at which the opening button is placed. - * If there is no picker to open, the button will not be rendered + * If there is no picker to open, the button is not rendered * @default 'end' */ openPickerButtonPosition: PropTypes.oneOf(['end', 'start']), diff --git a/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx b/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx index 576e1c8855d8..1d1cd36a845a 100644 --- a/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx +++ b/packages/x-date-pickers/src/DateTimeField/DateTimeField.tsx @@ -95,7 +95,7 @@ DateTimeField.propTypes = { clearable: PropTypes.bool, /** * The position at which the clear button is placed. - * If the field is not clearable, the button will not be rendered. + * If the field is not clearable, the button is not rendered. * @default 'end' */ clearButtonPosition: PropTypes.oneOf(['end', 'start']), @@ -272,7 +272,7 @@ DateTimeField.propTypes = { onSelectedSectionsChange: PropTypes.func, /** * The position at which the opening button is placed. - * If there is no picker to open, the button will not be rendered + * If there is no picker to open, the button is not rendered * @default 'end' */ openPickerButtonPosition: PropTypes.oneOf(['end', 'start']), diff --git a/packages/x-date-pickers/src/TimeField/TimeField.tsx b/packages/x-date-pickers/src/TimeField/TimeField.tsx index 2981893a9ae9..1057e4a8909c 100644 --- a/packages/x-date-pickers/src/TimeField/TimeField.tsx +++ b/packages/x-date-pickers/src/TimeField/TimeField.tsx @@ -89,7 +89,7 @@ TimeField.propTypes = { clearable: PropTypes.bool, /** * The position at which the clear button is placed. - * If the field is not clearable, the button will not be rendered. + * If the field is not clearable, the button is not rendered. * @default 'end' */ clearButtonPosition: PropTypes.oneOf(['end', 'start']), @@ -248,7 +248,7 @@ TimeField.propTypes = { onSelectedSectionsChange: PropTypes.func, /** * The position at which the opening button is placed. - * If there is no picker to open, the button will not be rendered + * If there is no picker to open, the button is not rendered * @default 'end' */ openPickerButtonPosition: PropTypes.oneOf(['end', 'start']), From df850772c45b0d73449ac9400d5428c37769a703 Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 2 Dec 2024 14:32:13 +0100 Subject: [PATCH 26/77] Fix --- .../MobileDatePicker/tests/MobileDatePicker.test.tsx | 12 ------------ .../tests/MobileDateTimePicker.test.tsx | 12 ------------ .../MobileTimePicker/tests/MobileTimePicker.test.tsx | 12 ------------ .../describeValue/testControlledUnControlled.tsx | 4 ++-- 4 files changed, 2 insertions(+), 38 deletions(-) diff --git a/packages/x-date-pickers/src/MobileDatePicker/tests/MobileDatePicker.test.tsx b/packages/x-date-pickers/src/MobileDatePicker/tests/MobileDatePicker.test.tsx index 74188094c7da..1c6255189b9e 100644 --- a/packages/x-date-pickers/src/MobileDatePicker/tests/MobileDatePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileDatePicker/tests/MobileDatePicker.test.tsx @@ -11,7 +11,6 @@ import { expectFieldValueV7, buildFieldInteractions, openPicker, - getFieldSectionsContainer, } from 'test/utils/pickers'; describe('', () => { @@ -132,17 +131,6 @@ describe('', () => { }); describe('picker state', () => { - it('should open when clicking the input', () => { - const onOpen = spy(); - - render(); - - fireEvent.click(getFieldSectionsContainer()); - - expect(onOpen.callCount).to.equal(1); - expect(screen.queryByRole('dialog')).toBeVisible(); - }); - it('should call `onAccept` even if controlled', () => { const onAccept = spy(); diff --git a/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx b/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx index 51a62e3da389..474374f61806 100644 --- a/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileDateTimePicker/tests/MobileDateTimePicker.test.tsx @@ -8,7 +8,6 @@ import { createPickerRenderer, openPicker, getClockTouchEvent, - getFieldSectionsContainer, } from 'test/utils/pickers'; describe('', () => { @@ -83,17 +82,6 @@ describe('', () => { }); describe('picker state', () => { - it('should open when clicking the input', () => { - const onOpen = spy(); - - render(); - - fireEvent.click(getFieldSectionsContainer()); - - expect(onOpen.callCount).to.equal(1); - expect(screen.queryByRole('dialog')).toBeVisible(); - }); - it('should call onChange when selecting each view', function test() { if (typeof window.Touch === 'undefined' || typeof window.TouchEvent === 'undefined') { this.skip(); diff --git a/packages/x-date-pickers/src/MobileTimePicker/tests/MobileTimePicker.test.tsx b/packages/x-date-pickers/src/MobileTimePicker/tests/MobileTimePicker.test.tsx index 4b052523d02e..6fd96148682b 100644 --- a/packages/x-date-pickers/src/MobileTimePicker/tests/MobileTimePicker.test.tsx +++ b/packages/x-date-pickers/src/MobileTimePicker/tests/MobileTimePicker.test.tsx @@ -8,24 +8,12 @@ import { adapterToUse, openPicker, getClockTouchEvent, - getFieldSectionsContainer, } from 'test/utils/pickers'; describe('', () => { const { render } = createPickerRenderer({ clock: 'fake' }); describe('picker state', () => { - it('should open when clicking the input', () => { - const onOpen = spy(); - - render(); - - fireEvent.click(getFieldSectionsContainer()); - - expect(onOpen.callCount).to.equal(1); - expect(screen.queryByRole('dialog')).toBeVisible(); - }); - it('should fire a change event when meridiem changes', () => { const handleChange = spy(); render( diff --git a/test/utils/pickers/describeValue/testControlledUnControlled.tsx b/test/utils/pickers/describeValue/testControlledUnControlled.tsx index 272360c609c0..318f1baaafab 100644 --- a/test/utils/pickers/describeValue/testControlledUnControlled.tsx +++ b/test/utils/pickers/describeValue/testControlledUnControlled.tsx @@ -157,7 +157,7 @@ export const testControlledUnControlled: DescribeValueTestSuite = ( }); }); - it('should not allow editing with keyboard in mobile pickers', () => { + it('should allow editing with keyboard in mobile pickers', () => { if (componentFamily !== 'picker' || params.variant !== 'mobile') { return; } @@ -170,7 +170,7 @@ export const testControlledUnControlled: DescribeValueTestSuite = ( }); v7Response.selectSection(undefined); fireUserEvent.keyPress(v7Response.getActiveSection(0), { key: 'ArrowUp' }); - expect(handleChange.callCount).to.equal(0); + expect(handleChange.callCount).to.equal(1); }); it('should have correct labelledby relationship when toolbar is shown', () => { From 00f7c3c12b88201b45ffbc9cb55d8a09c863c235 Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 2 Dec 2024 14:54:44 +0100 Subject: [PATCH 27/77] Fix --- .../tests/describes.DesktopDateRangePicker.test.tsx | 1 + .../tests/describes.DesktopDateTimeRangePicker.test.tsx | 1 + .../tests/describes.MobileDateRangePicker.test.tsx | 1 + .../tests/describes.MobileDateTimeRangePicker.test.tsx | 1 + 4 files changed, 4 insertions(+) diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/describes.DesktopDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/describes.DesktopDateRangePicker.test.tsx index f9255bdd65af..fb3b3c4abda5 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/describes.DesktopDateRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/describes.DesktopDateRangePicker.test.tsx @@ -28,6 +28,7 @@ describe(' - Describes', () => { clock, componentFamily: 'picker', views: ['day'], + variant: 'mobile', })); describeConformance(, () => ({ diff --git a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx index f2e86f975a81..7a43207f16e9 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx @@ -28,6 +28,7 @@ describe(' - Describes', () => { clock, views: ['day', 'hours', 'minutes'], componentFamily: 'picker', + variant: 'mobile', })); describeConformance(, () => ({ diff --git a/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/describes.MobileDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/describes.MobileDateRangePicker.test.tsx index abf9a3c52398..1b8a91aec129 100644 --- a/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/describes.MobileDateRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateRangePicker/tests/describes.MobileDateRangePicker.test.tsx @@ -27,6 +27,7 @@ describe(' - Describes', () => { clock, componentFamily: 'picker', views: ['day'], + variant: 'mobile', })); describeConformance(, () => ({ diff --git a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/describes.MobileDateTimeRangePicker.test.tsx b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/describes.MobileDateTimeRangePicker.test.tsx index dd26967bf82f..fe4f71d11525 100644 --- a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/describes.MobileDateTimeRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/describes.MobileDateTimeRangePicker.test.tsx @@ -29,6 +29,7 @@ describe(' - Describes', () => { clock, views: ['day', 'hours', 'minutes'], componentFamily: 'picker', + variant: 'mobile', })); describeConformance(, () => ({ From 6003978ed08799a821e37d84b8b58f72ce604fda Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 2 Dec 2024 15:07:33 +0100 Subject: [PATCH 28/77] Fix --- .../tests/describes.DesktopDateRangePicker.test.tsx | 2 +- .../src/StaticDateRangePicker/StaticDateRangePicker.test.tsx | 1 + .../pickers/describeValidation/describeValidation.types.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/describes.DesktopDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/describes.DesktopDateRangePicker.test.tsx index fb3b3c4abda5..0ece845e3939 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/describes.DesktopDateRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/describes.DesktopDateRangePicker.test.tsx @@ -28,7 +28,7 @@ describe(' - Describes', () => { clock, componentFamily: 'picker', views: ['day'], - variant: 'mobile', + variant: 'desktop', })); describeConformance(, () => ({ diff --git a/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.test.tsx index e5b10b6c6ab0..794abb288435 100644 --- a/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.test.tsx @@ -33,6 +33,7 @@ describe('', () => { clock, componentFamily: 'static-picker', views: ['day'], + variant: 'static', })); it('allows disabling dates', () => { diff --git a/test/utils/pickers/describeValidation/describeValidation.types.ts b/test/utils/pickers/describeValidation/describeValidation.types.ts index 66d1f7720def..07b3d5f40450 100644 --- a/test/utils/pickers/describeValidation/describeValidation.types.ts +++ b/test/utils/pickers/describeValidation/describeValidation.types.ts @@ -10,7 +10,7 @@ export interface DescribeValidationInputOptions { after?: () => void; componentFamily: PickerComponentFamily; views: DateOrTimeView[]; - variant?: 'mobile' | 'desktop'; + variant?: 'mobile' | 'desktop' | 'static'; } export interface DescribeValidationOptions extends DescribeValidationInputOptions { From 02a07b0d6f5186ce649a6d6ec0aed145481a52d5 Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 2 Dec 2024 15:09:48 +0100 Subject: [PATCH 29/77] Fix --- test/utils/pickers/describePicker/describePicker.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/utils/pickers/describePicker/describePicker.tsx b/test/utils/pickers/describePicker/describePicker.tsx index 4332a4c15710..82638cd3f052 100644 --- a/test/utils/pickers/describePicker/describePicker.tsx +++ b/test/utils/pickers/describePicker/describePicker.tsx @@ -62,9 +62,7 @@ function innerDescribePicker(ElementToTest: React.ElementType, options: Describe />, ); - const shouldRenderOpenPickerIcon = !hasNoView && variant !== 'mobile'; - - expect(queryAllByTestId('component-test')).to.have.length(shouldRenderOpenPickerIcon ? 1 : 0); + expect(queryAllByTestId('component-test')).to.have.length(hasNoView ? 0 : 1); }); }); From 6a98cdfa6825b81628b9d2d5c59b2257df27bfa9 Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 2 Dec 2024 16:04:42 +0100 Subject: [PATCH 30/77] Fix --- .../pickers/describeValue/testControlledUnControlled.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/utils/pickers/describeValue/testControlledUnControlled.tsx b/test/utils/pickers/describeValue/testControlledUnControlled.tsx index 318f1baaafab..77be94a9414a 100644 --- a/test/utils/pickers/describeValue/testControlledUnControlled.tsx +++ b/test/utils/pickers/describeValue/testControlledUnControlled.tsx @@ -157,11 +157,13 @@ export const testControlledUnControlled: DescribeValueTestSuite = ( }); }); - it('should allow editing with keyboard in mobile pickers', () => { + it('should allow editing in field on non-range mobile pickers', () => { if (componentFamily !== 'picker' || params.variant !== 'mobile') { return; } + const hasMobileFieldEditing = ['time', 'date', 'date-time'].includes(params.type); + const handleChange = spy(); const v7Response = renderWithProps({ @@ -170,7 +172,7 @@ export const testControlledUnControlled: DescribeValueTestSuite = ( }); v7Response.selectSection(undefined); fireUserEvent.keyPress(v7Response.getActiveSection(0), { key: 'ArrowUp' }); - expect(handleChange.callCount).to.equal(1); + expect(handleChange.callCount).to.equal(hasMobileFieldEditing ? 1 : 0); }); it('should have correct labelledby relationship when toolbar is shown', () => { From 8b1925486cdc6cf52a2e1ea89d787b9a175bdd89 Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 2 Dec 2024 16:35:29 +0100 Subject: [PATCH 31/77] Fix --- test/e2e/index.test.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/e2e/index.test.ts b/test/e2e/index.test.ts index f9145efca503..96cd1976cb7e 100644 --- a/test/e2e/index.test.ts +++ b/test/e2e/index.test.ts @@ -799,10 +799,7 @@ async function initializeEnvironment( it('should allow selecting a value', async () => { await renderFixture('DatePicker/BasicMobileDatePicker'); - // Old selector: await page.getByRole('textbox').click({ position: { x: 10, y: 2 } }); - await page - .locator(`.${pickersTextFieldClasses.root}`) - .click({ position: { x: 10, y: 2 } }); + await page.getByRole('button').click(); await page.getByRole('gridcell', { name: '11' }).click(); await page.getByRole('button', { name: 'OK' }).click(); @@ -824,7 +821,7 @@ async function initializeEnvironment( const input = page.getByRole('textbox'); - await input.click({ position: { x: 10, y: 2 } }); + await page.getByRole('button').click(); await page.getByRole('button', { name: 'Clear' }).click(); await input.blur(); From e22c78fe660c8703e9e9ea2af7b1604e6955a2b6 Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 2 Dec 2024 16:45:58 +0100 Subject: [PATCH 32/77] Fix --- test/e2e/index.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/index.test.ts b/test/e2e/index.test.ts index 96cd1976cb7e..0b1cd683d848 100644 --- a/test/e2e/index.test.ts +++ b/test/e2e/index.test.ts @@ -13,7 +13,7 @@ import { WebError, Locator, } from '@playwright/test'; -import { pickersTextFieldClasses } from '@mui/x-date-pickers/PickersTextField'; +import { iconButtonClasses } from '@mui/material/IconButton'; import { pickersSectionListClasses } from '@mui/x-date-pickers/PickersSectionList'; function sleep(timeoutMS: number): Promise { @@ -806,7 +806,7 @@ async function initializeEnvironment( await waitFor(async () => { // assert that the dialog has been closed and the focused element is the input expect(await page.evaluate(() => document.activeElement?.className)).to.contain( - pickersSectionListClasses.sectionContent, + iconButtonClasses.root, ); }); expect(await page.getByRole('textbox', { includeHidden: true }).inputValue()).to.equal( From aeddc0d26b154dd8cc6e774b36ef75a043d6106f Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 2 Dec 2024 17:11:59 +0100 Subject: [PATCH 33/77] [pickers] Add new method onToggleOpening to the picker public context --- .../date-pickers/calendar-systems/AdapterHijri.js | 10 +--------- .../date-pickers/calendar-systems/AdapterHijri.tsx | 10 +--------- .../custom-field/BrowserV7SingleInputRangeField.js | 9 +-------- .../custom-field/BrowserV7SingleInputRangeField.tsx | 9 +-------- .../custom-field/JoyV6SingleInputRangeField.js | 9 +-------- .../custom-field/JoyV6SingleInputRangeField.tsx | 9 +-------- .../behavior-button/MaterialDatePicker.js | 10 +--------- .../behavior-button/MaterialDatePicker.tsx | 10 +--------- .../behavior-button/MaterialDateRangePicker.js | 10 +--------- .../behavior-button/MaterialDateRangePicker.tsx | 10 +--------- .../MaterialDatePicker.js | 10 +--------- .../MaterialDatePicker.tsx | 10 +--------- .../components/overview/mainDemo/PickerButton.tsx | 10 +--------- .../src/internals/components/PickerProvider.tsx | 5 +++++ .../internals/hooks/usePicker/usePickerProvider.ts | 11 +++++++++++ 15 files changed, 29 insertions(+), 113 deletions(-) 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, From 2db9946a577bcf797fd4f03cb7ba5b079770b0a2 Mon Sep 17 00:00:00 2001 From: flavien Date: Tue, 3 Dec 2024 08:49:31 +0100 Subject: [PATCH 34/77] Fix --- .../date-pickers/custom-field/BrowserV7Field.js | 2 +- .../date-pickers/custom-field/BrowserV7Field.tsx | 2 +- .../custom-field/BrowserV7SingleInputRangeField.js | 2 +- .../BrowserV7SingleInputRangeField.tsx | 2 +- docs/data/date-pickers/custom-field/JoyV6Field.js | 2 +- docs/data/date-pickers/custom-field/JoyV6Field.tsx | 2 +- .../custom-field/JoyV6SingleInputRangeField.js | 2 +- .../custom-field/JoyV6SingleInputRangeField.tsx | 2 +- .../src/internals/hooks/useField/useField.ts | 7 ++++++- .../internals/hooks/useGetOpenPickerAriaLabel.ts | 14 +++++++++----- 10 files changed, 23 insertions(+), 14 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7Field.js b/docs/data/date-pickers/custom-field/BrowserV7Field.js index 5eaa7b440e29..70c295c6674e 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7Field.js +++ b/docs/data/date-pickers/custom-field/BrowserV7Field.js @@ -48,7 +48,7 @@ const BrowserTextField = React.forwardRef((props, ref) => { // Can be passed to a hidden element onChange, value, - // Can be passed to an icon to clear the value + // Can be passed to the button that clears the value clearable, onClear, // Can be used to render a custom label diff --git a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx index 1c17f617b34e..7cb0f2ee283c 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx @@ -64,7 +64,7 @@ const BrowserTextField = React.forwardRef( onChange, value, - // Can be passed to an icon to clear the value + // Can be passed to the button that clears the value clearable, onClear, diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js index 512719dadfd8..88923281295c 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js @@ -48,7 +48,7 @@ const BrowserTextField = React.forwardRef((props, ref) => { // Can be passed to a hidden element onChange, value, - // Can be passed to an icon to clear the value + // Can be passed to the button that clears the value clearable, onClear, // Can be used to render a custom label diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx index 59dca1e341a6..860e0496d0b1 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx @@ -66,7 +66,7 @@ const BrowserTextField = React.forwardRef( onChange, value, - // Can be passed to an icon to clear the value + // Can be passed to the button that clears the value clearable, onClear, diff --git a/docs/data/date-pickers/custom-field/JoyV6Field.js b/docs/data/date-pickers/custom-field/JoyV6Field.js index 99d1c2aa07ad..fbb6bacd8968 100644 --- a/docs/data/date-pickers/custom-field/JoyV6Field.js +++ b/docs/data/date-pickers/custom-field/JoyV6Field.js @@ -34,7 +34,7 @@ const JoyField = React.forwardRef((props, ref) => { enableAccessibleFieldDOMStructure, // Should be passed to the button that opens the picker openPickerAriaLabel, - // Can be passed to an icon to clear the value + // Can be passed to the button that clears the value clearable, onClear, // Can be used to render a custom label diff --git a/docs/data/date-pickers/custom-field/JoyV6Field.tsx b/docs/data/date-pickers/custom-field/JoyV6Field.tsx index 40c3399f11ff..05ced243f27b 100644 --- a/docs/data/date-pickers/custom-field/JoyV6Field.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6Field.tsx @@ -50,7 +50,7 @@ const JoyField = React.forwardRef( // Should be passed to the button that opens the picker openPickerAriaLabel, - // Can be passed to an icon to clear the value + // Can be passed to the button that clears the value clearable, onClear, diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js index d2ac4d45114e..106bf4638ac7 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js @@ -34,7 +34,7 @@ const JoyField = React.forwardRef((props, ref) => { enableAccessibleFieldDOMStructure, // Should be passed to the button that opens the picker openPickerAriaLabel, - // Can be passed to an icon to clear the value + // Can be passed to the button that clears the value clearable, onClear, // Can be used to render a custom label diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx index 531a4eaa4aab..a00262bb83e3 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx @@ -50,7 +50,7 @@ const JoyField = React.forwardRef( // Should be passed to the button that opens the picker openPickerAriaLabel, - // Can be passed to an icon to clear the value + // Can be passed to the button that clears the value clearable, onClear, diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.ts index d1d23402edcb..5d84b052a5ba 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.ts @@ -280,10 +280,15 @@ export const useField = < clearable: Boolean(clearable && !areAllSectionsEmpty && !readOnly && !disabled), }; + const openPickerAriaLabel = React.useMemo( + () => getOpenDialogAriaText(state.value), + [getOpenDialogAriaText, state.value], + ); + const commonAdditionalProps: UseFieldCommonAdditionalProps = { disabled, readOnly, - openPickerAriaLabel: getOpenDialogAriaText(state.value), + openPickerAriaLabel, }; return { diff --git a/packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts b/packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts index a550f3fe9bc0..1e897c65410c 100644 --- a/packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts +++ b/packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts @@ -1,3 +1,4 @@ +import * as React from 'react'; import { usePickerTranslations } from '../../hooks'; import { AdapterFormats } from '../../models'; import { PickerValue } from '../models'; @@ -11,9 +12,12 @@ export const useGetOpenDialogAriaText = (params: { const translations = usePickerTranslations(); const { formatKey, translationKey } = params; - return (value: PickerValue) => { - const formattedValue = - value !== null && utils.isValid(value) ? utils.format(value, formatKey) : null; - return translations[translationKey](formattedValue); - }; + return React.useCallback( + (value: PickerValue) => { + const formattedValue = + value !== null && utils.isValid(value) ? utils.format(value, formatKey) : null; + return translations[translationKey](formattedValue); + }, + [formatKey, translationKey, translations, utils], + ); }; From 072e0ce72262e340e10c99f4446493c31a526423 Mon Sep 17 00:00:00 2001 From: flavien Date: Tue, 3 Dec 2024 09:14:12 +0100 Subject: [PATCH 35/77] [docs] Clean Joy and Browser custom field demos --- .../custom-field/BrowserV7Field.js | 17 +-- .../custom-field/BrowserV7Field.tsx | 24 ++-- .../BrowserV7SingleInputRangeField.js | 58 +++------ .../BrowserV7SingleInputRangeField.tsx | 69 ++++------- .../date-pickers/custom-field/JoyV6Field.js | 48 ++------ .../date-pickers/custom-field/JoyV6Field.tsx | 72 +++-------- .../custom-field/JoyV6Field.tsx.preview | 6 +- .../JoyV6SingleInputRangeField.js | 84 +++---------- .../JoyV6SingleInputRangeField.tsx | 116 +++++------------- .../JoyV6SingleInputRangeField.tsx.preview | 6 +- packages/x-date-pickers/src/models/fields.ts | 20 +-- scripts/x-date-pickers-pro.exports.json | 1 + scripts/x-date-pickers.exports.json | 1 + 13 files changed, 153 insertions(+), 369 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7Field.js b/docs/data/date-pickers/custom-field/BrowserV7Field.js index 3e6be2ea7b36..c7f6b65b0029 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7Field.js +++ b/docs/data/date-pickers/custom-field/BrowserV7Field.js @@ -5,7 +5,6 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateField'; -import { useClearableField } from '@mui/x-date-pickers/hooks'; import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList'; @@ -44,6 +43,9 @@ const BrowserTextField = React.forwardRef((props, ref) => { // Can be passed to a hidden element onChange, value, + // Can be passed to the button that clears the value + clearable, + onClear, // Can be used to render a custom label label, // Can be used to style the component @@ -81,18 +83,9 @@ const BrowserTextField = React.forwardRef((props, ref) => { }); const BrowserDateField = React.forwardRef((props, ref) => { - const { slots, slotProps, ...textFieldProps } = props; + const fieldResponse = useDateField(props); - const fieldResponse = useDateField(textFieldProps); - - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); - - return ; + return ; }); const BrowserDatePicker = React.forwardRef((props, ref) => { diff --git a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx index a2cc66b242e7..0642da6a11a9 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx @@ -9,8 +9,7 @@ import { DatePickerProps, } from '@mui/x-date-pickers/DatePicker'; import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateField'; -import { useClearableField } from '@mui/x-date-pickers/hooks'; -import { BaseSingleInputPickersTextFieldProps } from '@mui/x-date-pickers/models'; +import { BaseSingleInputPickersFieldHooksReturnValue } from '@mui/x-date-pickers/models'; import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList'; const BrowserFieldRoot = styled('div', { name: 'BrowserField', slot: 'Root' })({ @@ -32,10 +31,10 @@ const BrowserFieldContent = styled('div', { name: 'BrowserField', slot: 'Content ); interface BrowserTextFieldProps - extends BaseSingleInputPickersTextFieldProps, + extends BaseSingleInputPickersFieldHooksReturnValue, Omit< React.HTMLAttributes, - keyof BaseSingleInputPickersTextFieldProps + keyof BaseSingleInputPickersFieldHooksReturnValue > {} const BrowserTextField = React.forwardRef( @@ -59,6 +58,10 @@ const BrowserTextField = React.forwardRef( onChange, value, + // Can be passed to the button that clears the value + clearable, + onClear, + // Can be used to render a custom label label, @@ -101,18 +104,9 @@ const BrowserTextField = React.forwardRef( const BrowserDateField = React.forwardRef( (props: DatePickerFieldProps, ref: React.Ref) => { - const { slots, slotProps, ...textFieldProps } = props; - - const fieldResponse = useDateField(textFieldProps); - - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); + const fieldResponse = useDateField(props); - return ; + return ; }, ); diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js index a86335cd7dd7..a0b648502dbc 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js @@ -1,6 +1,5 @@ import * as React from 'react'; import useForkRef from '@mui/utils/useForkRef'; -import useSlotProps from '@mui/utils/useSlotProps'; import { styled } from '@mui/material/styles'; import IconButton from '@mui/material/IconButton'; import InputAdornment from '@mui/material/InputAdornment'; @@ -9,7 +8,7 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker'; import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; -import { useClearableField, usePickerContext } from '@mui/x-date-pickers/hooks'; +import { usePickerContext } from '@mui/x-date-pickers/hooks'; import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList'; const BrowserFieldRoot = styled('div', { name: 'BrowserField', slot: 'Root' })({ @@ -47,6 +46,9 @@ const BrowserTextField = React.forwardRef((props, ref) => { // Can be passed to a hidden element onChange, value, + // Can be passed to the button that clears the value + clearable, + onClear, // Can be used to render a custom label label, // Can be used to style the component @@ -62,6 +64,15 @@ const BrowserTextField = React.forwardRef((props, ref) => { const handleRef = useForkRef(InputPropsRef, ref); + const pickerContext = usePickerContext(); + const handleTogglePicker = (event) => { + if (pickerContext.open) { + pickerContext.onClose(event); + } else { + pickerContext.onOpen(event); + } + }; + return ( {startAdornment} @@ -79,52 +90,21 @@ const BrowserTextField = React.forwardRef((props, ref) => { /> {endAdornment} - - ); -}); - -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', - externalSlotProps: slotProps?.textField, - externalForwardedProps: other, - ownerState: props, - }); - - textFieldProps.InputProps = { - ...textFieldProps.InputProps, - endAdornment: ( - ), - }; - - const fieldResponse = useSingleInputDateRangeField(textFieldProps); + + ); +}); - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); +const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => { + const fieldResponse = useSingleInputDateRangeField(props); return ( , + extends BaseSingleInputPickersFieldHooksReturnValue, Omit< React.HTMLAttributes, - keyof BaseSingleInputPickersTextFieldProps + keyof BaseSingleInputPickersFieldHooksReturnValue > {} const BrowserTextField = React.forwardRef( @@ -64,6 +63,10 @@ const BrowserTextField = React.forwardRef( onChange, value, + // Can be passed to the button that clears the value + clearable, + onClear, + // Can be used to render a custom label label, @@ -82,6 +85,15 @@ const BrowserTextField = React.forwardRef( const handleRef = useForkRef(InputPropsRef, ref); + const pickerContext = usePickerContext(); + const handleTogglePicker = (event: React.UIEvent) => { + if (pickerContext.open) { + pickerContext.onClose(event); + } else { + pickerContext.onOpen(event); + } + }; + return ( {startAdornment} @@ -99,6 +111,11 @@ const BrowserTextField = React.forwardRef( /> {endAdornment} + + + + + ); }, @@ -112,49 +129,11 @@ type BrowserSingleInputDateRangeFieldComponent = (( const BrowserSingleInputDateRangeField = React.forwardRef( (props: BrowserSingleInputDateRangeFieldProps, ref: React.Ref) => { - 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', - externalSlotProps: slotProps?.textField, - externalForwardedProps: other, - ownerState: props as any, - }); - - textFieldProps.InputProps = { - ...textFieldProps.InputProps, - endAdornment: ( - - - - - - ), - }; - - const fieldResponse = useSingleInputDateRangeField( - textFieldProps, - ); - - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); + const fieldResponse = useSingleInputDateRangeField(props); return ( { const { // Should be ignored enableAccessibleFieldDOMStructure, + // Can be passed to the button that clears the value + clearable, + onClear, disabled, id, label, InputProps: { ref: containerRef, startAdornment, endAdornment } = {}, - formControlSx, endDecorator, startDecorator, - slotProps, inputRef, + slots, + slotProps, ...other } = props; return ( - + {label} { } slotProps={{ - ...slotProps, - root: { ...slotProps?.root, ref: containerRef }, - input: { ...slotProps?.input, ref: inputRef }, + root: { ref: containerRef }, + input: { ref: inputRef }, }} {...other} /> @@ -72,21 +68,12 @@ const JoyField = React.forwardRef((props, ref) => { }); const JoyDateField = React.forwardRef((props, ref) => { - const { slots, slotProps, ...textFieldProps } = props; - const fieldResponse = useDateField({ - ...textFieldProps, + ...props, enableAccessibleFieldDOMStructure: false, }); - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); - - return ; + return ; }); const JoyDatePicker = React.forwardRef((props, ref) => { @@ -95,15 +82,6 @@ const JoyDatePicker = React.forwardRef((props, ref) => { ref={ref} {...props} slots={{ ...props.slots, field: JoyDateField }} - slotProps={{ - ...props.slotProps, - field: { - ...props.slotProps?.field, - formControlSx: { - flexDirection: 'row', - }, - }, - }} /> ); }); @@ -129,11 +107,7 @@ export default function JoyV6Field() { - + diff --git a/docs/data/date-pickers/custom-field/JoyV6Field.tsx b/docs/data/date-pickers/custom-field/JoyV6Field.tsx index 50b0fabe3c09..f1914a5f0a8a 100644 --- a/docs/data/date-pickers/custom-field/JoyV6Field.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6Field.tsx @@ -21,25 +21,13 @@ import { DatePickerProps, } from '@mui/x-date-pickers/DatePicker'; import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateField'; -import { useClearableField } from '@mui/x-date-pickers/hooks'; +import { BaseSingleInputPickersFieldHooksReturnValue } from '@mui/x-date-pickers/models'; const joyTheme = extendJoyTheme(); -interface JoyFieldProps extends InputProps { - label?: React.ReactNode; - inputRef?: React.Ref; - enableAccessibleFieldDOMStructure?: boolean; - InputProps?: { - ref?: React.Ref; - endAdornment?: React.ReactNode; - startAdornment?: React.ReactNode; - }; - formControlSx?: InputProps['sx']; -} - -type JoyFieldComponent = (( - props: JoyFieldProps & React.RefAttributes, -) => React.JSX.Element) & { propTypes?: any }; +interface JoyFieldProps + extends BaseSingleInputPickersFieldHooksReturnValue, + Omit> {} const JoyField = React.forwardRef( (props: JoyFieldProps, ref: React.Ref) => { @@ -47,25 +35,24 @@ const JoyField = React.forwardRef( // Should be ignored enableAccessibleFieldDOMStructure, + // Can be passed to the button that clears the value + clearable, + onClear, + disabled, id, label, InputProps: { ref: containerRef, startAdornment, endAdornment } = {}, - formControlSx, endDecorator, startDecorator, - slotProps, inputRef, + slots, + slotProps, ...other } = props; return ( - + {label} } slotProps={{ - ...slotProps, - root: { ...slotProps?.root, ref: containerRef }, - input: { ...slotProps?.input, ref: inputRef }, + root: { ref: containerRef }, + input: { ref: inputRef }, }} {...other} /> ); }, -) as JoyFieldComponent; +); const JoyDateField = React.forwardRef( (props: DatePickerFieldProps, ref: React.Ref) => { - const { slots, slotProps, ...textFieldProps } = props; - - const fieldResponse = useDateField({ - ...textFieldProps, + const fieldResponse = useDateField({ + ...props, enableAccessibleFieldDOMStructure: false, }); - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); - - return ; + return ; }, ); @@ -121,15 +98,6 @@ const JoyDatePicker = React.forwardRef( ref={ref} {...props} slots={{ ...props.slots, field: JoyDateField }} - slotProps={{ - ...props.slotProps, - field: { - ...props.slotProps?.field, - formControlSx: { - flexDirection: 'row', - }, - } as any, - }} /> ); }, @@ -156,11 +124,7 @@ export default function JoyV6Field() { - + diff --git a/docs/data/date-pickers/custom-field/JoyV6Field.tsx.preview b/docs/data/date-pickers/custom-field/JoyV6Field.tsx.preview index cff735f8a7af..d1fc44acb736 100644 --- a/docs/data/date-pickers/custom-field/JoyV6Field.tsx.preview +++ b/docs/data/date-pickers/custom-field/JoyV6Field.tsx.preview @@ -2,11 +2,7 @@ - + \ No newline at end of file diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js index dd5ee96d6f52..32459d7f5ed6 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js @@ -4,23 +4,25 @@ import { useColorScheme as useMaterialColorScheme, Experimental_CssVarsProvider as MaterialCssVarsProvider, } from '@mui/material/styles'; -import useSlotProps from '@mui/utils/useSlotProps'; import { extendTheme as extendJoyTheme, useColorScheme, CssVarsProvider, THEME_ID, } from '@mui/joy/styles'; +import { createSvgIcon } from '@mui/joy/utils'; import Input from '@mui/joy/Input'; import FormControl from '@mui/joy/FormControl'; import FormLabel from '@mui/joy/FormLabel'; -import IconButton from '@mui/joy/IconButton'; -import { DateRangeIcon } from '@mui/x-date-pickers/icons'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker'; import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; -import { useClearableField, usePickerContext } from '@mui/x-date-pickers/hooks'; + +export const DateRangeIcon = createSvgIcon( + , + 'DateRange', +); const joyTheme = extendJoyTheme(); @@ -28,39 +30,37 @@ const JoyField = React.forwardRef((props, ref) => { const { // Should be ignored enableAccessibleFieldDOMStructure, + // Can be passed to the button that clears the value + clearable, + onClear, disabled, id, label, - InputProps: { ref: containerRef, startAdornment, endAdornment } = {}, + InputProps: { ref: containerRef } = {}, endDecorator, startDecorator, - slotProps, inputRef, + slots, + slotProps, ...other } = props; return ( - + {label} - {startAdornment} - {startDecorator} - - } + startDecorator={{startDecorator}} endDecorator={ - {endAdornment} + {endDecorator} } slotProps={{ - ...slotProps, - root: { ...slotProps?.root, ref: containerRef }, - input: { ...slotProps?.input, ref: inputRef }, + root: { ref: containerRef }, + input: { ref: inputRef }, }} {...other} /> @@ -69,52 +69,12 @@ const JoyField = React.forwardRef((props, ref) => { }); 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, - externalSlotProps: slotProps?.textField, - externalForwardedProps: other, - ownerState: props, - }); - const fieldResponse = useSingleInputDateRangeField({ - ...textFieldProps, + ...props, enableAccessibleFieldDOMStructure: false, }); - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, - }); - - return ( - - - - } - /> - ); + return ; }); JoySingleInputDateRangeField.fieldType = 'single-input'; @@ -150,11 +110,7 @@ export default function JoyV6SingleInputRangeField() { - + diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx index 36d33af92f98..9c3a13eac6f2 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx @@ -4,18 +4,16 @@ import { useColorScheme as useMaterialColorScheme, Experimental_CssVarsProvider as MaterialCssVarsProvider, } from '@mui/material/styles'; -import useSlotProps from '@mui/utils/useSlotProps'; import { extendTheme as extendJoyTheme, useColorScheme, CssVarsProvider, THEME_ID, } from '@mui/joy/styles'; +import { createSvgIcon } from '@mui/joy/utils'; import Input, { InputProps } from '@mui/joy/Input'; import FormControl from '@mui/joy/FormControl'; import FormLabel from '@mui/joy/FormLabel'; -import IconButton from '@mui/joy/IconButton'; -import { DateRangeIcon } from '@mui/x-date-pickers/icons'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { @@ -24,25 +22,19 @@ import { DateRangePickerProps, } from '@mui/x-date-pickers-pro/DateRangePicker'; import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; -import { useClearableField, usePickerContext } from '@mui/x-date-pickers/hooks'; import { FieldType } from '@mui/x-date-pickers-pro/models'; +import { BaseSingleInputPickersFieldHooksReturnValue } from '@mui/x-date-pickers/models'; -const joyTheme = extendJoyTheme(); +export const DateRangeIcon = createSvgIcon( + , + 'DateRange', +); -interface JoyFieldProps extends InputProps { - label?: React.ReactNode; - inputRef?: React.Ref; - enableAccessibleFieldDOMStructure?: boolean; - InputProps?: { - ref?: React.Ref; - endAdornment?: React.ReactNode; - startAdornment?: React.ReactNode; - }; -} +const joyTheme = extendJoyTheme(); -type JoyFieldComponent = (( - props: JoyFieldProps & React.RefAttributes, -) => React.JSX.Element) & { propTypes?: any }; +interface JoyFieldProps + extends BaseSingleInputPickersFieldHooksReturnValue, + Omit> {} const JoyField = React.forwardRef( (props: JoyFieldProps, ref: React.Ref) => { @@ -50,102 +42,58 @@ const JoyField = React.forwardRef( // Should be ignored enableAccessibleFieldDOMStructure, + // Can be passed to the button that clears the value + clearable, + onClear, + disabled, id, label, - InputProps: { ref: containerRef, startAdornment, endAdornment } = {}, + InputProps: { ref: containerRef } = {}, endDecorator, startDecorator, - slotProps, inputRef, + slots, + slotProps, ...other } = props; return ( - + {label} - {startAdornment} - {startDecorator} - - } + startDecorator={{startDecorator}} endDecorator={ - {endAdornment} + {endDecorator} } slotProps={{ - ...slotProps, - root: { ...slotProps?.root, ref: containerRef }, - input: { ...slotProps?.input, ref: inputRef }, + root: { ref: containerRef }, + input: { ref: inputRef }, }} {...other} /> ); }, -) as JoyFieldComponent; - -interface JoySingleInputDateRangeFieldProps - extends DateRangePickerFieldProps {} +); type JoySingleInputDateRangeFieldComponent = (( - props: JoySingleInputDateRangeFieldProps & React.RefAttributes, + props: DateRangePickerFieldProps & React.RefAttributes, ) => React.JSX.Element) & { fieldType?: FieldType }; const JoySingleInputDateRangeField = React.forwardRef( - (props: JoySingleInputDateRangeFieldProps, ref: React.Ref) => { - 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: JoySingleInputDateRangeFieldProps = useSlotProps({ - elementType: FormControl, - externalSlotProps: slotProps?.textField, - externalForwardedProps: other, - ownerState: props as any, - }); - - const fieldResponse = useSingleInputDateRangeField< - false, - JoySingleInputDateRangeFieldProps - >({ ...textFieldProps, enableAccessibleFieldDOMStructure: false }); - - /* If you don't need a clear button, you can skip the use of this hook */ - const processedFieldProps = useClearableField({ - ...fieldResponse, - slots, - slotProps, + (props: DateRangePickerFieldProps, ref: React.Ref) => { + const fieldResponse = useSingleInputDateRangeField({ + ...props, + enableAccessibleFieldDOMStructure: false, }); - return ( - - - - } - /> - ); + return ; }, ) as JoySingleInputDateRangeFieldComponent; @@ -184,11 +132,7 @@ export default function JoyV6SingleInputRangeField() { - + diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx.preview b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx.preview index 90b0c5ff3c08..b2b8613af3c6 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx.preview +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx.preview @@ -2,11 +2,7 @@ - + \ No newline at end of file diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index 05c0c4e0460f..0b76e0ab4b28 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -1,9 +1,6 @@ import * as React from 'react'; import { TextFieldProps } from '@mui/material/TextField'; -import type { - ExportedUseClearableFieldProps, - UseClearableFieldResponse, -} from '../hooks/useClearableField'; +import type { ExportedUseClearableFieldProps } from '../hooks/useClearableField'; import { ExportedPickersSectionListProps } from '../PickersSectionList'; import type { UseFieldInternalProps, UseFieldResponse } from '../internals/hooks/useField'; import type { PickersTextFieldProps } from '../PickersTextField'; @@ -159,14 +156,23 @@ export type PickerFieldSlotProps< ref?: React.Ref; }; +/* + * Props the `useDateField()` and equivalent hooks return when used inside a single input picker. + * Only contains what the MUI components are passing to the field, not what users can pass using the `props.slotProps.field` and `props.slotProps.textField`. + */ +export type BaseSingleInputPickersFieldHooksReturnValue< + TEnableAccessibleFieldDOMStructure extends boolean, +> = UseFieldResponse; + /** - * Props the text field receives when used with a single input picker. + * Props the text field receives when used with inside single input picker. * Only contains what the MUI components are passing to the text field, not what users can pass using the `props.slotProps.field` and `props.slotProps.textField`. */ export type BaseSingleInputPickersTextFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, -> = UseClearableFieldResponse< - UseFieldResponse +> = Omit< + BaseSingleInputPickersFieldHooksReturnValue, + 'slots' | 'slotProps' | 'clearable' | 'onClear' >; /** diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index 36b647590889..701e3a5209f6 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -5,6 +5,7 @@ { "name": "ArrowLeftIcon", "kind": "Variable" }, { "name": "ArrowRightIcon", "kind": "Variable" }, { "name": "BaseMultiInputPickersTextFieldProps", "kind": "TypeAlias" }, + { "name": "BaseSingleInputPickersFieldHooksReturnValue", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BuiltInFieldTextFieldProps", "kind": "TypeAlias" }, { "name": "CalendarIcon", "kind": "Variable" }, diff --git a/scripts/x-date-pickers.exports.json b/scripts/x-date-pickers.exports.json index 60cb4180bd3c..691aea9117d3 100644 --- a/scripts/x-date-pickers.exports.json +++ b/scripts/x-date-pickers.exports.json @@ -4,6 +4,7 @@ { "name": "ArrowDropDownIcon", "kind": "Variable" }, { "name": "ArrowLeftIcon", "kind": "Variable" }, { "name": "ArrowRightIcon", "kind": "Variable" }, + { "name": "BaseSingleInputPickersFieldHooksReturnValue", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BuiltInFieldTextFieldProps", "kind": "TypeAlias" }, { "name": "CalendarIcon", "kind": "Variable" }, From 26b4206a8524e5fd7662dd716b966eb66e552bc6 Mon Sep 17 00:00:00 2001 From: flavien Date: Wed, 4 Dec 2024 08:43:36 +0100 Subject: [PATCH 36/77] Replace all the opening methods with setOpen --- .../calendar-systems/AdapterHijri.js | 2 +- .../calendar-systems/AdapterHijri.tsx | 2 +- .../BrowserV7SingleInputRangeField.js | 2 +- .../BrowserV7SingleInputRangeField.tsx | 2 +- .../JoyV6SingleInputRangeField.js | 2 +- .../JoyV6SingleInputRangeField.tsx | 2 +- .../behavior-button/MaterialDatePicker.js | 2 +- .../behavior-button/MaterialDatePicker.tsx | 2 +- .../MaterialDateRangePicker.js | 2 +- .../MaterialDateRangePicker.tsx | 2 +- .../MaterialDatePicker.js | 2 +- .../MaterialDatePicker.tsx | 2 +- .../overview/mainDemo/PickerButton.tsx | 2 +- .../internals/components/PickerProvider.tsx | 22 +---------- .../src/internals/hooks/useOpenState.ts | 19 ++++----- .../internals/hooks/usePicker/usePicker.ts | 2 +- .../hooks/usePicker/usePicker.types.ts | 2 +- .../hooks/usePicker/usePickerProvider.ts | 39 +++++-------------- .../hooks/usePicker/usePickerValue.ts | 33 +++++++++++----- .../hooks/usePicker/usePickerValue.types.ts | 18 +++++++++ 20 files changed, 78 insertions(+), 83 deletions(-) diff --git a/docs/data/date-pickers/calendar-systems/AdapterHijri.js b/docs/data/date-pickers/calendar-systems/AdapterHijri.js index f146aaa31ba3..377759e11375 100644 --- a/docs/data/date-pickers/calendar-systems/AdapterHijri.js +++ b/docs/data/date-pickers/calendar-systems/AdapterHijri.js @@ -54,7 +54,7 @@ function ButtonDateTimeField(props) { variant="outlined" color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={pickerContext.onToggleOpening} + onClick={() => pickerContext.setOpen((prev) => !prev)} > {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 319f93f591ac..704dbee32ae7 100644 --- a/docs/data/date-pickers/calendar-systems/AdapterHijri.tsx +++ b/docs/data/date-pickers/calendar-systems/AdapterHijri.tsx @@ -58,7 +58,7 @@ function ButtonDateTimeField(props: DateTimePickerFieldProps) { variant="outlined" color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={pickerContext.onToggleOpening} + onClick={() => pickerContext.setOpen((prev) => !prev)} > {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 7adc0f2e453a..edfed553188e 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js @@ -99,7 +99,7 @@ const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => { ...textFieldProps.InputProps, endAdornment: ( - + pickerContext.setOpen((prev) => !prev)}> diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx index e6e44e9656e4..c19472a59405 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx @@ -127,7 +127,7 @@ const BrowserSingleInputDateRangeField = React.forwardRef( ...textFieldProps.InputProps, endAdornment: ( - + pickerContext.setOpen((prev) => !prev)}> diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js index 95be4b633756..35cf00fa9a7e 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js @@ -98,7 +98,7 @@ const JoySingleInputDateRangeField = React.forwardRef((props, ref) => { ref={ref} endDecorator={ pickerContext.setOpen((prev) => !prev)} variant="plain" color="neutral" sx={{ marginLeft: 2.5 }} diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx index 55554a38e418..9cf3261ab611 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx @@ -129,7 +129,7 @@ const JoySingleInputDateRangeField = React.forwardRef( ref={ref} endDecorator={ pickerContext.setOpen((prev) => !prev)} variant="plain" color="neutral" sx={{ marginLeft: 2.5 }} diff --git a/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.js b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.js index 9ed91020e8ec..0e30e8d2605a 100644 --- a/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.js +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.js @@ -42,7 +42,7 @@ function ButtonDateField(props) { variant="outlined" color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={pickerContext.onToggleOpening} + onClick={() => pickerContext.setOpen((prev) => !prev)} > {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 d19c72fb95b0..1da1b675decd 100644 --- a/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDatePicker.tsx @@ -46,7 +46,7 @@ function ButtonDateField(props: DatePickerFieldProps) { variant="outlined" color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={pickerContext.onToggleOpening} + onClick={() => pickerContext.setOpen((prev) => !prev)} > {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 d2e26d720904..0884deadb8b4 100644 --- a/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.js +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.js @@ -46,7 +46,7 @@ function ButtonDateRangeField(props) { variant="outlined" color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={pickerContext.onToggleOpening} + onClick={() => pickerContext.setOpen((prev) => !prev)} > {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 b4a39597513e..9361a51c256a 100644 --- a/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx +++ b/docs/data/date-pickers/custom-field/behavior-button/MaterialDateRangePicker.tsx @@ -50,7 +50,7 @@ function ButtonDateRangeField(props: DateRangePickerFieldProps) { variant="outlined" color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={pickerContext.onToggleOpening} + onClick={() => pickerContext.setOpen((prev) => !prev)} > {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 96e29f79763a..c5637b320e0e 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 @@ -38,7 +38,7 @@ function ReadOnlyDateField(props) { sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} - onClick={pickerContext.onToggleOpening} + onClick={() => pickerContext.setOpen((prev) => !prev)} /> ); } 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 cc2b1180fdf7..a42da5e10407 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 @@ -42,7 +42,7 @@ function ReadOnlyDateField(props: DatePickerFieldProps) { sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} - onClick={pickerContext.onToggleOpening} + onClick={() => pickerContext.setOpen((prev) => !prev)} /> ); } diff --git a/docs/src/modules/components/overview/mainDemo/PickerButton.tsx b/docs/src/modules/components/overview/mainDemo/PickerButton.tsx index 59043f6ea467..fb531c0e5204 100644 --- a/docs/src/modules/components/overview/mainDemo/PickerButton.tsx +++ b/docs/src/modules/components/overview/mainDemo/PickerButton.tsx @@ -35,7 +35,7 @@ function ButtonDateField(props: DatePickerFieldProps) { fullWidth color={hasValidationError ? 'error' : 'primary'} ref={InputProps?.ref} - onClick={pickerContext.onToggleOpening} + onClick={() => pickerContext.setOpen((prev) => !prev)} > {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 4fa7eb07cbf1..ec63075b5027 100644 --- a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx @@ -3,6 +3,7 @@ import { PickerOwnerState } from '../../models'; import { PickersInputLocaleText } from '../../locales'; import { LocalizationProvider } from '../../LocalizationProvider'; import { PickerOrientation, PickerVariant } from '../models'; +import { UsePickerValueContextValue } from '../hooks/usePicker/usePickerValue.types'; export const PickerContext = React.createContext(null); @@ -43,26 +44,7 @@ export interface PickerProviderProps { children: React.ReactNode; } -export interface PickerContextValue { - /** - * Open the picker. - * @param {React.UIEvent} event The DOM event that triggered the change. - */ - onOpen: (event: React.UIEvent) => void; - /** - * Close the picker. - * @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. - */ - open: boolean; +export interface PickerContextValue extends UsePickerValueContextValue { /** * `true` if the picker is disabled, `false` otherwise. */ diff --git a/packages/x-date-pickers/src/internals/hooks/useOpenState.ts b/packages/x-date-pickers/src/internals/hooks/useOpenState.ts index 558814e5be26..93c9d7f733bc 100644 --- a/packages/x-date-pickers/src/internals/hooks/useOpenState.ts +++ b/packages/x-date-pickers/src/internals/hooks/useOpenState.ts @@ -8,7 +8,7 @@ export interface OpenStateProps { export const useOpenState = ({ open, onOpen, onClose }: OpenStateProps) => { const isControllingOpenProp = React.useRef(typeof open === 'boolean').current; - const [openState, setIsOpenState] = React.useState(false); + const [openState, setOpenState] = React.useState(false); // It is required to update inner state in useEffect in order to avoid situation when // Our component is not mounted yet, but `open` state is set to `true` (for example initially opened) @@ -18,26 +18,27 @@ export const useOpenState = ({ open, onOpen, onClose }: OpenStateProps) => { throw new Error('You must not mix controlling and uncontrolled mode for `open` prop'); } - setIsOpenState(open); + setOpenState(open); } }, [isControllingOpenProp, open]); - const setIsOpen = React.useCallback( - (newIsOpen: boolean) => { + const setOpen = React.useCallback( + (action: React.SetStateAction) => { + const newOpen = typeof action === 'function' ? action(openState) : action; if (!isControllingOpenProp) { - setIsOpenState(newIsOpen); + setOpenState(newOpen); } - if (newIsOpen && onOpen) { + if (newOpen && onOpen) { onOpen(); } - if (!newIsOpen && onClose) { + if (!newOpen && onClose) { onClose(); } }, - [isControllingOpenProp, onOpen, onClose], + [isControllingOpenProp, onOpen, onClose, openState], ); - return { isOpen: openState, setIsOpen }; + return { open: openState, setOpen }; }; diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts index 30b80061a4af..09a7ee5dc06a 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts @@ -55,11 +55,11 @@ export const usePicker = < const providerProps = usePickerProvider({ props, - pickerValueResponse, localeText, valueManager, variant, views: pickerViewsResponse.views, + paramsFromUsePickerValue: pickerValueResponse.provider, }); return { diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts index 37bbb59b667c..ae01b284b29a 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts @@ -62,7 +62,7 @@ export interface UsePickerResponse< TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem, TError, -> extends Omit, 'viewProps' | 'layoutProps'>, +> extends Pick, 'open' | 'actions' | 'fieldProps'>, Omit, 'layoutProps' | 'views'> { ownerState: PickerOwnerState; providerProps: UsePickerProviderReturnValue; 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 6c4746dbc8b7..a0508b1546ea 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts @@ -1,8 +1,7 @@ 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 { PickerValueManager, UsePickerValueProviderParams } from './usePickerValue.types'; import { PickerProviderProps, PickerContextValue, @@ -63,27 +62,19 @@ export const usePickerOrientation = ( export function usePickerProvider( parameters: UsePickerProviderParameters, ): UsePickerProviderReturnValue { - const { props, pickerValueResponse, valueManager, localeText, variant, views } = parameters; + const { props, valueManager, localeText, variant, views, paramsFromUsePickerValue } = parameters; 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( utils, - pickerValueResponse.viewProps.value, + paramsFromUsePickerValue.value, valueManager.emptyValue, ), - isPickerOpen: pickerValueResponse.open, + isPickerOpen: paramsFromUsePickerValue.contextValue.open, isPickerDisabled: props.disabled ?? false, isPickerReadOnly: props.readOnly ?? false, pickerOrientation: orientation, @@ -92,8 +83,8 @@ export function usePickerProvider( [ utils, valueManager, - pickerValueResponse.viewProps.value, - pickerValueResponse.open, + paramsFromUsePickerValue.value, + paramsFromUsePickerValue.contextValue.open, orientation, variant, props.disabled, @@ -103,25 +94,13 @@ export function usePickerProvider( const contextValue = React.useMemo( () => ({ - onOpen: pickerValueResponse.actions.onOpen, - onClose: pickerValueResponse.actions.onClose, - onToggleOpening: handleTogglePicker, - open: pickerValueResponse.open, + ...paramsFromUsePickerValue.contextValue, disabled: props.disabled ?? false, readOnly: props.readOnly ?? false, variant, orientation, }), - [ - pickerValueResponse.actions.onOpen, - pickerValueResponse.actions.onClose, - handleTogglePicker, - pickerValueResponse.open, - variant, - orientation, - props.disabled, - props.readOnly, - ], + [paramsFromUsePickerValue.contextValue, variant, orientation, props.disabled, props.readOnly], ); const privateContextValue = React.useMemo( @@ -139,10 +118,10 @@ export function usePickerProvider( export interface UsePickerProviderParameters extends Pick { props: UsePickerProps; - pickerValueResponse: UsePickerValueResponse; valueManager: PickerValueManager; variant: PickerVariant; views: readonly DateOrTimeViewWithMeridiem[]; + paramsFromUsePickerValue: UsePickerValueProviderParams; } export interface UsePickerProviderReturnValue extends Omit {} diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts index 6481132bd86f..e973b01eaba3 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts @@ -21,6 +21,8 @@ import { UsePickerValueActions, PickerSelectionState, PickerValueUpdaterParams, + UsePickerValueContextValue, + UsePickerValueProviderParams, } from './usePickerValue.types'; import { useValueWithTimezone } from '../useValueWithTimezone'; import { PickerValidValue } from '../../models'; @@ -208,7 +210,7 @@ export const usePickerValue = < const utils = useUtils(); const adapter = useLocalizationContext(); - const { isOpen, setIsOpen } = useOpenState(props); + const { open, setOpen } = useOpenState(props); const { timezone, @@ -312,7 +314,7 @@ export const usePickerValue = < } if (shouldClose) { - setIsOpen(false); + setOpen(false); } }); @@ -379,12 +381,12 @@ export const usePickerValue = < const handleOpen = useEventCallback((event: React.UIEvent) => { event.preventDefault(); - setIsOpen(true); + setOpen(true); }); const handleClose = useEventCallback((event?: React.UIEvent) => { event?.preventDefault(); - setIsOpen(false); + setOpen(false); }); const handleChange = useEventCallback( @@ -426,16 +428,16 @@ export const usePickerValue = < onChange: handleChangeFromField, }; - const viewValue = React.useMemo( + const valueWithoutError = React.useMemo( () => valueManager.cleanValue(utils, dateState.draft), [utils, valueManager, dateState.draft], ); const viewResponse: UsePickerValueViewsResponse = { - value: viewValue, + value: valueWithoutError, onChange: handleChange, onClose: handleClose, - open: isOpen, + open, }; const isValid = (testedValue: TValue) => { @@ -451,17 +453,30 @@ export const usePickerValue = < const layoutResponse: UsePickerValueLayoutResponse = { ...actions, - value: viewValue, + value: valueWithoutError, onChange: handleChange, onSelectShortcut: handleSelectShortcut, isValid, }; + const contextValue = React.useMemo(() => { + return { + open, + setOpen, + }; + }, [open, setOpen]); + + const providerParams: UsePickerValueProviderParams = { + value: valueWithoutError, + contextValue, + }; + return { - open: isOpen, + open, fieldProps: fieldResponse, viewProps: viewResponse, layoutProps: layoutResponse, actions, + provider: providerParams, }; }; diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts index 1b301efd05be..5550c7535fa6 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts @@ -17,6 +17,7 @@ import { PickersShortcutsItemContext, } from '../../../PickersShortcuts'; import { InferNonNullablePickerValue, PickerValidValue } from '../../models'; +import React from 'react'; export interface PickerValueManager { /** @@ -313,10 +314,27 @@ export interface UsePickerValueLayoutResponse isValid: (value: TValue) => boolean; } +/** + * Params passed to `usePickerProvider`. + */ +export interface UsePickerValueProviderParams { + value: TValue; + contextValue: UsePickerValueContextValue; +} + export interface UsePickerValueResponse { open: boolean; actions: UsePickerValueActions; viewProps: UsePickerValueViewsResponse; fieldProps: UsePickerValueFieldResponse; layoutProps: UsePickerValueLayoutResponse; + provider: UsePickerValueProviderParams; +} + +export interface UsePickerValueContextValue { + setOpen: React.Dispatch>; + /** + * `true` if the picker is open, `false` otherwise. + */ + open: boolean; } From c0e4cede5a5973ee54b73f018d7617ca33e4fd43 Mon Sep 17 00:00:00 2001 From: flavien Date: Wed, 4 Dec 2024 08:55:03 +0100 Subject: [PATCH 37/77] Add migration guide --- .../migration-pickers-v7.md | 40 +++++++++++++++++++ .../hooks/usePicker/usePickerValue.types.ts | 11 ++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md index 764f28cfb98a..30541674081d 100644 --- a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md +++ b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md @@ -404,6 +404,46 @@ The following variables and types have been renamed to have a coherent `Picker` +import { FieldRangeSection } from '@mui/x-date-pickers-pro'; ``` +## Hooks breaking changes + +### `usePickerContext` + +- The `onOpen` and `onClock` methods have been replaced with a single `setOpen` method. + This method no longer takes an event, which was used to prevent the browser default behavior: + + ```diff + const pickerContext = usePickerContext(); + + - + + + + - + + + + - + + + ``` + + If you want to prevent the default behavior, you now have to do it manually: + + ```diff +
{ + if (event.key === 'Escape') { + - pickerContext.onClose(); + + event.preventDefault(); + + pickerContext.setOpen(false); + } + }} + /> + ``` + ## Typing breaking changes ### Do not pass the date object as a generic diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts index 5550c7535fa6..60c022e497a9 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts @@ -1,3 +1,4 @@ +import * as React from 'react'; import { FieldChangeHandlerContext, UseFieldInternalProps } from '../useField'; import { Validator } from '../../../validation'; import { PickerVariant } from '../../models/common'; @@ -17,7 +18,6 @@ import { PickersShortcutsItemContext, } from '../../../PickersShortcuts'; import { InferNonNullablePickerValue, PickerValidValue } from '../../models'; -import React from 'react'; export interface PickerValueManager { /** @@ -332,6 +332,15 @@ export interface UsePickerValueResponse } export interface UsePickerValueContextValue { + /** + * Sets the current opening status of the picker. + * ```ts + * setOpen(true); // Opens the picker. + * setOpen(false); // Closes the picker. + * setOpen((prevOpen) => !prevOpen); // Toggles the opening status. + * ``` + * @param {React.SetStateAction} action The new opening status of the picker, it can be a function that will receive the previous opening status. + */ setOpen: React.Dispatch>; /** * `true` if the picker is open, `false` otherwise. From 496340ec7590dcff4a2ea8a2e5fefb7e82547c8d Mon Sep 17 00:00:00 2001 From: flavien Date: Wed, 4 Dec 2024 09:44:52 +0100 Subject: [PATCH 38/77] Clean useGetOpenDialogAriaLabel --- .../useSingleInputDateRangeField.ts | 2 +- .../useSingleInputDateTimeRangeField.ts | 2 +- .../useSingleInputTimeRangeField.ts | 2 +- packages/x-date-pickers/src/DateField/useDateField.ts | 6 +++--- .../x-date-pickers/src/DateTimeField/useDateTimeField.ts | 6 +++--- packages/x-date-pickers/src/TimeField/useTimeField.ts | 6 +++--- .../x-date-pickers/src/internals/hooks/useField/useField.ts | 2 +- .../src/internals/hooks/useField/useField.types.ts | 2 +- ...tOpenPickerAriaLabel.ts => useGetOpenDialogAriaLabel.ts} | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) rename packages/x-date-pickers/src/internals/hooks/{useGetOpenPickerAriaLabel.ts => useGetOpenDialogAriaLabel.ts} (93%) diff --git a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts index 13e91f743146..de4de0d86976 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateRangeField/useSingleInputDateRangeField.ts @@ -37,6 +37,6 @@ export const useSingleInputDateRangeField = < validator: validateDateRange, valueType: 'date', // TODO v8: Add a real aria label before enabling the button. - getOpenDialogAriaText: () => '', + getOpenDialogAriaLabel: () => '', }); }; diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts index 84482e65cbc2..17c7ef01605c 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/useSingleInputDateTimeRangeField.ts @@ -41,6 +41,6 @@ export const useSingleInputDateTimeRangeField = < validator: validateDateTimeRange, valueType: 'date-time', // TODO v8: Add a real aria label before enabling the button. - getOpenDialogAriaText: () => '', + getOpenDialogAriaLabel: () => '', }); }; diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts index 55984a316a25..367372d9a946 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/useSingleInputTimeRangeField.ts @@ -37,6 +37,6 @@ export const useSingleInputTimeRangeField = < validator: validateTimeRange, valueType: 'time', // TODO v8: Add a real aria label before enabling the button. - getOpenDialogAriaText: () => '', + getOpenDialogAriaLabel: () => '', }); }; diff --git a/packages/x-date-pickers/src/DateField/useDateField.ts b/packages/x-date-pickers/src/DateField/useDateField.ts index afd4b540aa94..0a479b80806b 100644 --- a/packages/x-date-pickers/src/DateField/useDateField.ts +++ b/packages/x-date-pickers/src/DateField/useDateField.ts @@ -9,7 +9,7 @@ import { validateDate } from '../validation'; import { useSplitFieldProps } from '../hooks'; import { useDefaultizedDateField } from '../internals/hooks/defaultizedFieldProps'; import { PickerValue } from '../internals/models'; -import { useGetOpenDialogAriaText } from '../internals/hooks/useGetOpenPickerAriaLabel'; +import { useGetOpenDialogAriaLabel } from '../internals/hooks/useGetOpenDialogAriaLabel'; export const useDateField = < TEnableAccessibleFieldDOMStructure extends boolean, @@ -24,7 +24,7 @@ export const useDateField = < const { forwardedProps, internalProps } = useSplitFieldProps(props, 'date'); - const getOpenDialogAriaText = useGetOpenDialogAriaText({ + const getOpenDialogAriaLabel = useGetOpenDialogAriaLabel({ formatKey: 'fullDate', translationKey: 'openDatePickerDialogue', }); @@ -41,6 +41,6 @@ export const useDateField = < fieldValueManager: singleItemFieldValueManager, validator: validateDate, valueType: 'date', - getOpenDialogAriaText, + getOpenDialogAriaLabel, }); }; diff --git a/packages/x-date-pickers/src/DateTimeField/useDateTimeField.ts b/packages/x-date-pickers/src/DateTimeField/useDateTimeField.ts index fe58b3aff6dd..a1c6f0a35870 100644 --- a/packages/x-date-pickers/src/DateTimeField/useDateTimeField.ts +++ b/packages/x-date-pickers/src/DateTimeField/useDateTimeField.ts @@ -9,7 +9,7 @@ import { validateDateTime } from '../validation'; import { useSplitFieldProps } from '../hooks'; import { useDefaultizedDateTimeField } from '../internals/hooks/defaultizedFieldProps'; import { PickerValue } from '../internals/models'; -import { useGetOpenDialogAriaText } from '../internals/hooks/useGetOpenPickerAriaLabel'; +import { useGetOpenDialogAriaLabel } from '../internals/hooks/useGetOpenDialogAriaLabel'; export const useDateTimeField = < TEnableAccessibleFieldDOMStructure extends boolean, @@ -24,7 +24,7 @@ export const useDateTimeField = < const { forwardedProps, internalProps } = useSplitFieldProps(props, 'date-time'); - const getOpenDialogAriaText = useGetOpenDialogAriaText({ + const getOpenDialogAriaLabel = useGetOpenDialogAriaLabel({ formatKey: 'fullDate', translationKey: 'openDatePickerDialogue', }); @@ -41,6 +41,6 @@ export const useDateTimeField = < fieldValueManager: singleItemFieldValueManager, validator: validateDateTime, valueType: 'date-time', - getOpenDialogAriaText, + getOpenDialogAriaLabel, }); }; diff --git a/packages/x-date-pickers/src/TimeField/useTimeField.ts b/packages/x-date-pickers/src/TimeField/useTimeField.ts index 8549b49889b2..a8f0f5a16d35 100644 --- a/packages/x-date-pickers/src/TimeField/useTimeField.ts +++ b/packages/x-date-pickers/src/TimeField/useTimeField.ts @@ -9,7 +9,7 @@ import { validateTime } from '../validation'; import { useSplitFieldProps } from '../hooks'; import { useDefaultizedTimeField } from '../internals/hooks/defaultizedFieldProps'; import { PickerValue } from '../internals/models'; -import { useGetOpenDialogAriaText } from '../internals/hooks/useGetOpenPickerAriaLabel'; +import { useGetOpenDialogAriaLabel } from '../internals/hooks/useGetOpenDialogAriaLabel'; export const useTimeField = < TEnableAccessibleFieldDOMStructure extends boolean, @@ -24,7 +24,7 @@ export const useTimeField = < const { forwardedProps, internalProps } = useSplitFieldProps(props, 'time'); - const getOpenDialogAriaText = useGetOpenDialogAriaText({ + const getOpenDialogAriaLabel = useGetOpenDialogAriaLabel({ formatKey: 'fullTime', translationKey: 'openTimePickerDialogue', }); @@ -41,6 +41,6 @@ export const useTimeField = < fieldValueManager: singleItemFieldValueManager, validator: validateTime, valueType: 'time', - getOpenDialogAriaText, + getOpenDialogAriaLabel, }); }; diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.ts index 5d84b052a5ba..636146760326 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.ts @@ -52,7 +52,7 @@ export const useField = < fieldValueManager, valueManager, validator, - getOpenDialogAriaText, + getOpenDialogAriaLabel: getOpenDialogAriaText, } = params; const isRtl = useRtl(); diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts index 1794dde0f353..cead4431240f 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts @@ -34,7 +34,7 @@ export interface UseFieldParams< fieldValueManager: FieldValueManager; validator: Validator, TInternalProps>; valueType: PickerValueType; - getOpenDialogAriaText: (value: TValue) => string; + getOpenDialogAriaLabel: (value: TValue) => string; } export interface UseFieldInternalProps< diff --git a/packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts b/packages/x-date-pickers/src/internals/hooks/useGetOpenDialogAriaLabel.ts similarity index 93% rename from packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts rename to packages/x-date-pickers/src/internals/hooks/useGetOpenDialogAriaLabel.ts index 1e897c65410c..b5accebc5589 100644 --- a/packages/x-date-pickers/src/internals/hooks/useGetOpenPickerAriaLabel.ts +++ b/packages/x-date-pickers/src/internals/hooks/useGetOpenDialogAriaLabel.ts @@ -4,7 +4,7 @@ import { AdapterFormats } from '../../models'; import { PickerValue } from '../models'; import { useUtils } from './useUtils'; -export const useGetOpenDialogAriaText = (params: { +export const useGetOpenDialogAriaLabel = (params: { formatKey: keyof AdapterFormats; translationKey: 'openDatePickerDialogue' | 'openTimePickerDialogue'; }) => { From 93e4b03807074e8a8f08053a005d7255b1de9349 Mon Sep 17 00:00:00 2001 From: flavien Date: Wed, 4 Dec 2024 10:09:21 +0100 Subject: [PATCH 39/77] Work --- .../data/date-pickers/custom-field/JoyV6SingleInputRangeField.js | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js index 106bf4638ac7..5dbc0f76ddaa 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js @@ -11,7 +11,6 @@ import { THEME_ID, } from '@mui/joy/styles'; import Input from '@mui/joy/Input'; - import FormControl from '@mui/joy/FormControl'; import FormLabel from '@mui/joy/FormLabel'; import { createSvgIcon } from '@mui/joy/utils'; From ef5387474c3eabc33926ef816e44bdf19dd256fe Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE Date: Wed, 4 Dec 2024 10:36:34 +0100 Subject: [PATCH 40/77] Update docs/data/migration/migration-pickers-v7/migration-pickers-v7.md Co-authored-by: Lukas Tyla Signed-off-by: Flavien DELANGLE --- .../data/migration/migration-pickers-v7/migration-pickers-v7.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md index 30541674081d..199fe9357457 100644 --- a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md +++ b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md @@ -408,7 +408,7 @@ The following variables and types have been renamed to have a coherent `Picker` ### `usePickerContext` -- The `onOpen` and `onClock` methods have been replaced with a single `setOpen` method. +- The `onOpen` and `onClose` methods have been replaced with a single `setOpen` method. This method no longer takes an event, which was used to prevent the browser default behavior: ```diff From c047749913c6745b15d7599d437c2c9bdd94f971 Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE Date: Wed, 4 Dec 2024 10:36:40 +0100 Subject: [PATCH 41/77] Update packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts Co-authored-by: Lukas Tyla Signed-off-by: Flavien DELANGLE --- .../src/internals/hooks/usePicker/usePickerValue.types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts index 60c022e497a9..aaff1bd843e5 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts @@ -333,7 +333,7 @@ export interface UsePickerValueResponse export interface UsePickerValueContextValue { /** - * Sets the current opening status of the picker. + * Sets the current open state of the Picker. * ```ts * setOpen(true); // Opens the picker. * setOpen(false); // Closes the picker. From e00ff3a884f5dfa412388fe3b1dd88e2989b6c4a Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE Date: Wed, 4 Dec 2024 10:36:46 +0100 Subject: [PATCH 42/77] Update packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts Co-authored-by: Lukas Tyla Signed-off-by: Flavien DELANGLE --- .../src/internals/hooks/usePicker/usePickerValue.types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts index aaff1bd843e5..05795702cd11 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts @@ -337,7 +337,7 @@ export interface UsePickerValueContextValue { * ```ts * setOpen(true); // Opens the picker. * setOpen(false); // Closes the picker. - * setOpen((prevOpen) => !prevOpen); // Toggles the opening status. + * setOpen((prevOpen) => !prevOpen); // Toggles the open state. * ``` * @param {React.SetStateAction} action The new opening status of the picker, it can be a function that will receive the previous opening status. */ From 58e722c7ab4fa139ea17f4630725c4a8ae760d7b Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE Date: Wed, 4 Dec 2024 10:36:51 +0100 Subject: [PATCH 43/77] Update packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts Co-authored-by: Lukas Tyla Signed-off-by: Flavien DELANGLE --- .../src/internals/hooks/usePicker/usePickerValue.types.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts index 05795702cd11..d58af8940c43 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts @@ -339,7 +339,8 @@ export interface UsePickerValueContextValue { * setOpen(false); // Closes the picker. * setOpen((prevOpen) => !prevOpen); // Toggles the open state. * ``` - * @param {React.SetStateAction} action The new opening status of the picker, it can be a function that will receive the previous opening status. + * @param {React.SetStateAction} action The new open state of the Picker. + * It can be a function that will receive the current open state. */ setOpen: React.Dispatch>; /** From fcbcce6f469c12d477f34a227da8b7b8be7f1695 Mon Sep 17 00:00:00 2001 From: flavien Date: Wed, 4 Dec 2024 11:13:19 +0100 Subject: [PATCH 44/77] Work --- .../src/internals/components/PickerFieldUI.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx index 46c9cea8c777..f7d6e4a75d65 100644 --- a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx @@ -80,6 +80,7 @@ export const cleanFieldResponse = < }; /** + * Adds the button to open the picker and the button to clear the value of the field. * @ignore - internal component. */ export function PickerFieldUI(props: PickerFieldUIProps) { @@ -126,6 +127,7 @@ export function PickerFieldUI(props: PickerFieldUIProps) { }); const OpenPickerButton = slots.openPickerButton ?? MuiIconButton; + // We don't want to forward the `ownerState` to the `` component, see mui/material-ui#34056 const { ownerState: openPickerButtonOwnerState, ...openPickerButtonProps @@ -152,7 +154,7 @@ export function PickerFieldUI(props: PickerFieldUIProps) { }); const ClearButton = slots.clearButton ?? MuiIconButton; - // The spread is here to avoid this bug mui/material-ui#34056 + // We don't want to forward the `ownerState` to the `` component, see mui/material-ui#34056 const { ownerState: clearButtonOwnerState, ...clearButtonProps } = useSlotProps({ elementType: ClearButton, externalSlotProps: slotProps?.clearButton, @@ -168,6 +170,7 @@ export function PickerFieldUI(props: PickerFieldUIProps) { }, ownerState, }); + const ClearIcon = slots.clearIcon ?? MuiClearIcon; const clearIconProps = useSlotProps({ elementType: ClearIcon, From 673e6159736de331263a5ab363f1d3b7e4690ad6 Mon Sep 17 00:00:00 2001 From: flavien Date: Wed, 4 Dec 2024 11:55:49 +0100 Subject: [PATCH 45/77] Simplify --- .../custom-field/BrowserV7Field.js | 13 ++--- .../custom-field/BrowserV7Field.tsx | 22 ++------ .../BrowserV7SingleInputRangeField.js | 28 ++++------- .../BrowserV7SingleInputRangeField.tsx | 50 +++++++------------ .../date-pickers/custom-field/JoyV6Field.js | 34 ++++--------- .../date-pickers/custom-field/JoyV6Field.tsx | 43 ++++------------ .../JoyV6SingleInputRangeField.js | 28 +++-------- .../JoyV6SingleInputRangeField.tsx | 45 +++++------------ packages/x-date-pickers/src/models/fields.ts | 10 +--- scripts/x-date-pickers-pro.exports.json | 1 - scripts/x-date-pickers.exports.json | 1 - 11 files changed, 77 insertions(+), 198 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7Field.js b/docs/data/date-pickers/custom-field/BrowserV7Field.js index c7f6b65b0029..0603f30646e4 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7Field.js +++ b/docs/data/date-pickers/custom-field/BrowserV7Field.js @@ -5,7 +5,6 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateField'; - import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList'; const BrowserFieldRoot = styled('div', { name: 'BrowserField', slot: 'Root' })({ @@ -26,7 +25,9 @@ const BrowserFieldContent = styled('div', { name: 'BrowserField', slot: 'Content }, ); -const BrowserTextField = React.forwardRef((props, ref) => { +const BrowserDateField = React.forwardRef((props, ref) => { + const fieldResponse = useDateField(props); + const { // Should be ignored enableAccessibleFieldDOMStructure, @@ -57,7 +58,7 @@ const BrowserTextField = React.forwardRef((props, ref) => { InputProps: { ref: InputPropsRef, startAdornment, endAdornment } = {}, // The rest can be passed to the root element ...other - } = props; + } = fieldResponse; const handleRef = useForkRef(InputPropsRef, ref); @@ -82,12 +83,6 @@ const BrowserTextField = React.forwardRef((props, ref) => { ); }); -const BrowserDateField = React.forwardRef((props, ref) => { - const fieldResponse = useDateField(props); - - return ; -}); - const BrowserDatePicker = React.forwardRef((props, ref) => { return ( , - Omit< - React.HTMLAttributes, - keyof BaseSingleInputPickersFieldHooksReturnValue - > {} +const BrowserDateField = React.forwardRef( + (props: DatePickerFieldProps, ref: React.Ref) => { + const fieldResponse = useDateField(props); -const BrowserTextField = React.forwardRef( - (props: BrowserTextFieldProps, ref: React.Ref) => { const { // Should be ignored enableAccessibleFieldDOMStructure, @@ -76,7 +70,7 @@ const BrowserTextField = React.forwardRef( // The rest can be passed to the root element ...other - } = props; + } = fieldResponse; const handleRef = useForkRef(InputPropsRef, ref); @@ -102,14 +96,6 @@ const BrowserTextField = React.forwardRef( }, ); -const BrowserDateField = React.forwardRef( - (props: DatePickerFieldProps, ref: React.Ref) => { - const fieldResponse = useDateField(props); - - return ; - }, -); - const BrowserDatePicker = React.forwardRef( (props: DatePickerProps, ref: React.Ref) => { return ( diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js index 103f7c5606de..6ebb17a38efb 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js @@ -29,7 +29,9 @@ const BrowserFieldContent = styled('div', { name: 'BrowserField', slot: 'Content }, ); -const BrowserTextField = React.forwardRef((props, ref) => { +const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => { + const fieldResponse = useSingleInputDateRangeField(props); + const { // Should be ignored enableAccessibleFieldDOMStructure, @@ -60,14 +62,20 @@ const BrowserTextField = React.forwardRef((props, ref) => { InputProps: { ref: InputPropsRef, startAdornment, endAdornment } = {}, // The rest can be passed to the root element ...other - } = props; + } = fieldResponse; const handleRef = useForkRef(InputPropsRef, ref); const pickerContext = usePickerContext(); return ( - + {startAdornment} { ); }); -const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => { - const fieldResponse = useSingleInputDateRangeField(props); - - return ( - - ); -}); - BrowserSingleInputDateRangeField.fieldType = 'single-input'; const BrowserSingleInputDateRangePicker = React.forwardRef((props, ref) => { diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx index 222fbeca48bc..1e200c85d19e 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx @@ -15,7 +15,6 @@ import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } import { usePickerContext } from '@mui/x-date-pickers/hooks'; import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList'; import { FieldType } from '@mui/x-date-pickers-pro/models'; -import { BaseSingleInputPickersFieldHooksReturnValue } from '@mui/x-date-pickers/models'; const BrowserFieldRoot = styled('div', { name: 'BrowserField', slot: 'Root' })({ display: 'flex', @@ -35,15 +34,16 @@ const BrowserFieldContent = styled('div', { name: 'BrowserField', slot: 'Content }, ); -interface BrowserTextFieldProps - extends BaseSingleInputPickersFieldHooksReturnValue, - Omit< - React.HTMLAttributes, - keyof BaseSingleInputPickersFieldHooksReturnValue - > {} +interface BrowserSingleInputDateRangeFieldProps extends DateRangePickerFieldProps {} + +type BrowserSingleInputDateRangeFieldComponent = (( + props: BrowserSingleInputDateRangeFieldProps & React.RefAttributes, +) => React.JSX.Element) & { fieldType?: FieldType }; + +const BrowserSingleInputDateRangeField = React.forwardRef( + (props: BrowserSingleInputDateRangeFieldProps, ref: React.Ref) => { + const fieldResponse = useSingleInputDateRangeField(props); -const BrowserTextField = React.forwardRef( - (props: BrowserTextFieldProps, ref: React.Ref) => { const { // Should be ignored enableAccessibleFieldDOMStructure, @@ -81,14 +81,20 @@ const BrowserTextField = React.forwardRef( // The rest can be passed to the root element ...other - } = props; + } = fieldResponse; const handleRef = useForkRef(InputPropsRef, ref); const pickerContext = usePickerContext(); return ( - + {startAdornment} ); }, -); - -interface BrowserSingleInputDateRangeFieldProps extends DateRangePickerFieldProps {} - -type BrowserSingleInputDateRangeFieldComponent = (( - props: BrowserSingleInputDateRangeFieldProps & React.RefAttributes, -) => React.JSX.Element) & { fieldType?: FieldType }; - -const BrowserSingleInputDateRangeField = React.forwardRef( - (props: BrowserSingleInputDateRangeFieldProps, ref: React.Ref) => { - const fieldResponse = useSingleInputDateRangeField(props); - - return ( - - ); - }, ) as BrowserSingleInputDateRangeFieldComponent; BrowserSingleInputDateRangeField.fieldType = 'single-input'; diff --git a/docs/data/date-pickers/custom-field/JoyV6Field.js b/docs/data/date-pickers/custom-field/JoyV6Field.js index 422e2cad0894..07149b867ee6 100644 --- a/docs/data/date-pickers/custom-field/JoyV6Field.js +++ b/docs/data/date-pickers/custom-field/JoyV6Field.js @@ -20,7 +20,12 @@ import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateF const joyTheme = extendJoyTheme(); -const JoyField = React.forwardRef((props, ref) => { +const JoyDateField = React.forwardRef((props, ref) => { + const fieldResponse = useDateField({ + ...props, + enableAccessibleFieldDOMStructure: false, + }); + const { // Should be ignored enableAccessibleFieldDOMStructure, @@ -31,13 +36,11 @@ const JoyField = React.forwardRef((props, ref) => { id, label, InputProps: { ref: containerRef, startAdornment, endAdornment } = {}, - endDecorator, - startDecorator, inputRef, slots, slotProps, ...other - } = props; + } = fieldResponse; return ( @@ -45,18 +48,8 @@ const JoyField = React.forwardRef((props, ref) => { - {startAdornment} - {startDecorator} - - } - endDecorator={ - - {endAdornment} - {endDecorator} - - } + startDecorator={startAdornment} + endDecorator={endAdornment} slotProps={{ root: { ref: containerRef }, input: { ref: inputRef }, @@ -67,15 +60,6 @@ const JoyField = React.forwardRef((props, ref) => { ); }); -const JoyDateField = React.forwardRef((props, ref) => { - const fieldResponse = useDateField({ - ...props, - enableAccessibleFieldDOMStructure: false, - }); - - return ; -}); - const JoyDatePicker = React.forwardRef((props, ref) => { return ( , - Omit> {} +const JoyDateField = React.forwardRef( + (props: DatePickerFieldProps, ref: React.Ref) => { + const fieldResponse = useDateField({ + ...props, + enableAccessibleFieldDOMStructure: false, + }); -const JoyField = React.forwardRef( - (props: JoyFieldProps, ref: React.Ref) => { const { // Should be ignored enableAccessibleFieldDOMStructure, @@ -43,13 +43,11 @@ const JoyField = React.forwardRef( id, label, InputProps: { ref: containerRef, startAdornment, endAdornment } = {}, - endDecorator, - startDecorator, inputRef, slots, slotProps, ...other - } = props; + } = fieldResponse; return ( @@ -57,18 +55,8 @@ const JoyField = React.forwardRef( - {startAdornment} - {startDecorator} - - } - endDecorator={ - - {endAdornment} - {endDecorator} - - } + startDecorator={startAdornment} + endDecorator={endAdornment} slotProps={{ root: { ref: containerRef }, input: { ref: inputRef }, @@ -80,17 +68,6 @@ const JoyField = React.forwardRef( }, ); -const JoyDateField = React.forwardRef( - (props: DatePickerFieldProps, ref: React.Ref) => { - const fieldResponse = useDateField({ - ...props, - enableAccessibleFieldDOMStructure: false, - }); - - return ; - }, -); - const JoyDatePicker = React.forwardRef( (props: DatePickerProps, ref: React.Ref) => { return ( diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js index 9067b1bbf24a..e2344e7631f5 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js @@ -26,7 +26,12 @@ export const DateRangeIcon = createSvgIcon( const joyTheme = extendJoyTheme(); -const JoyField = React.forwardRef((props, ref) => { +const JoySingleInputDateRangeField = React.forwardRef((props, ref) => { + const fieldResponse = useSingleInputDateRangeField({ + ...props, + enableAccessibleFieldDOMStructure: false, + }); + const { // Should be ignored enableAccessibleFieldDOMStructure, @@ -37,13 +42,11 @@ const JoyField = React.forwardRef((props, ref) => { id, label, InputProps: { ref: containerRef } = {}, - endDecorator, - startDecorator, inputRef, slots, slotProps, ...other - } = props; + } = fieldResponse; return ( @@ -51,13 +54,7 @@ const JoyField = React.forwardRef((props, ref) => { {startDecorator}} - endDecorator={ - - - {endDecorator} - - } + endDecorator={} slotProps={{ root: { ref: containerRef }, input: { ref: inputRef }, @@ -68,15 +65,6 @@ const JoyField = React.forwardRef((props, ref) => { ); }); -const JoySingleInputDateRangeField = React.forwardRef((props, ref) => { - const fieldResponse = useSingleInputDateRangeField({ - ...props, - enableAccessibleFieldDOMStructure: false, - }); - - return ; -}); - JoySingleInputDateRangeField.fieldType = 'single-input'; const JoySingleInputDateRangePicker = React.forwardRef((props, ref) => { diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx index 615b96a1c530..ba5a7f859235 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx @@ -11,7 +11,7 @@ import { THEME_ID, } from '@mui/joy/styles'; import { createSvgIcon } from '@mui/joy/utils'; -import Input, { InputProps } from '@mui/joy/Input'; +import Input from '@mui/joy/Input'; import FormControl from '@mui/joy/FormControl'; import FormLabel from '@mui/joy/FormLabel'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; @@ -23,7 +23,6 @@ import { } from '@mui/x-date-pickers-pro/DateRangePicker'; import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; import { FieldType } from '@mui/x-date-pickers-pro/models'; -import { BaseSingleInputPickersFieldHooksReturnValue } from '@mui/x-date-pickers/models'; export const DateRangeIcon = createSvgIcon( , @@ -32,12 +31,17 @@ export const DateRangeIcon = createSvgIcon( const joyTheme = extendJoyTheme(); -interface JoyFieldProps - extends BaseSingleInputPickersFieldHooksReturnValue, - Omit> {} +type JoySingleInputDateRangeFieldComponent = (( + props: DateRangePickerFieldProps & React.RefAttributes, +) => React.JSX.Element) & { fieldType?: FieldType }; + +const JoySingleInputDateRangeField = React.forwardRef( + (props: DateRangePickerFieldProps, ref: React.Ref) => { + const fieldResponse = useSingleInputDateRangeField({ + ...props, + enableAccessibleFieldDOMStructure: false, + }); -const JoyField = React.forwardRef( - (props: JoyFieldProps, ref: React.Ref) => { const { // Should be ignored enableAccessibleFieldDOMStructure, @@ -50,13 +54,11 @@ const JoyField = React.forwardRef( id, label, InputProps: { ref: containerRef } = {}, - endDecorator, - startDecorator, inputRef, slots, slotProps, ...other - } = props; + } = fieldResponse; return ( @@ -64,13 +66,7 @@ const JoyField = React.forwardRef( {startDecorator}} - endDecorator={ - - - {endDecorator} - - } + endDecorator={} slotProps={{ root: { ref: containerRef }, input: { ref: inputRef }, @@ -80,21 +76,6 @@ const JoyField = React.forwardRef( ); }, -); - -type JoySingleInputDateRangeFieldComponent = (( - props: DateRangePickerFieldProps & React.RefAttributes, -) => React.JSX.Element) & { fieldType?: FieldType }; - -const JoySingleInputDateRangeField = React.forwardRef( - (props: DateRangePickerFieldProps, ref: React.Ref) => { - const fieldResponse = useSingleInputDateRangeField({ - ...props, - enableAccessibleFieldDOMStructure: false, - }); - - return ; - }, ) as JoySingleInputDateRangeFieldComponent; JoySingleInputDateRangeField.fieldType = 'single-input'; diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index 0b76e0ab4b28..549e3d0e0ea9 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -156,14 +156,6 @@ export type PickerFieldSlotProps< ref?: React.Ref; }; -/* - * Props the `useDateField()` and equivalent hooks return when used inside a single input picker. - * Only contains what the MUI components are passing to the field, not what users can pass using the `props.slotProps.field` and `props.slotProps.textField`. - */ -export type BaseSingleInputPickersFieldHooksReturnValue< - TEnableAccessibleFieldDOMStructure extends boolean, -> = UseFieldResponse; - /** * Props the text field receives when used with inside single input picker. * Only contains what the MUI components are passing to the text field, not what users can pass using the `props.slotProps.field` and `props.slotProps.textField`. @@ -171,7 +163,7 @@ export type BaseSingleInputPickersFieldHooksReturnValue< export type BaseSingleInputPickersTextFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, > = Omit< - BaseSingleInputPickersFieldHooksReturnValue, + UseFieldResponse, 'slots' | 'slotProps' | 'clearable' | 'onClear' >; diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index 701e3a5209f6..36b647590889 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -5,7 +5,6 @@ { "name": "ArrowLeftIcon", "kind": "Variable" }, { "name": "ArrowRightIcon", "kind": "Variable" }, { "name": "BaseMultiInputPickersTextFieldProps", "kind": "TypeAlias" }, - { "name": "BaseSingleInputPickersFieldHooksReturnValue", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BuiltInFieldTextFieldProps", "kind": "TypeAlias" }, { "name": "CalendarIcon", "kind": "Variable" }, diff --git a/scripts/x-date-pickers.exports.json b/scripts/x-date-pickers.exports.json index 691aea9117d3..60cb4180bd3c 100644 --- a/scripts/x-date-pickers.exports.json +++ b/scripts/x-date-pickers.exports.json @@ -4,7 +4,6 @@ { "name": "ArrowDropDownIcon", "kind": "Variable" }, { "name": "ArrowLeftIcon", "kind": "Variable" }, { "name": "ArrowRightIcon", "kind": "Variable" }, - { "name": "BaseSingleInputPickersFieldHooksReturnValue", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BuiltInFieldTextFieldProps", "kind": "TypeAlias" }, { "name": "CalendarIcon", "kind": "Variable" }, From 6dbac5a7bee136f640d9df5b87810cd0693cd93c Mon Sep 17 00:00:00 2001 From: flavien Date: Wed, 4 Dec 2024 12:07:24 +0100 Subject: [PATCH 46/77] Fix --- .../custom-field/JoyV6SingleInputRangeField.js | 9 ++++++++- .../custom-field/JoyV6SingleInputRangeField.tsx | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js index e2344e7631f5..5bbafe3a814a 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js @@ -49,7 +49,14 @@ const JoySingleInputDateRangeField = React.forwardRef((props, ref) => { } = fieldResponse; return ( - + {label} + {label} Date: Wed, 4 Dec 2024 12:10:41 +0100 Subject: [PATCH 47/77] Fix --- packages/x-date-pickers/src/models/fields.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index 549e3d0e0ea9..05c0c4e0460f 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -1,6 +1,9 @@ import * as React from 'react'; import { TextFieldProps } from '@mui/material/TextField'; -import type { ExportedUseClearableFieldProps } from '../hooks/useClearableField'; +import type { + ExportedUseClearableFieldProps, + UseClearableFieldResponse, +} from '../hooks/useClearableField'; import { ExportedPickersSectionListProps } from '../PickersSectionList'; import type { UseFieldInternalProps, UseFieldResponse } from '../internals/hooks/useField'; import type { PickersTextFieldProps } from '../PickersTextField'; @@ -157,14 +160,13 @@ export type PickerFieldSlotProps< }; /** - * Props the text field receives when used with inside single input picker. + * Props the text field receives when used with a single input picker. * Only contains what the MUI components are passing to the text field, not what users can pass using the `props.slotProps.field` and `props.slotProps.textField`. */ export type BaseSingleInputPickersTextFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, -> = Omit< - UseFieldResponse, - 'slots' | 'slotProps' | 'clearable' | 'onClear' +> = UseClearableFieldResponse< + UseFieldResponse >; /** From 119a26e640c5c0ff1c588210a30d4bf93ceedf78 Mon Sep 17 00:00:00 2001 From: flavien Date: Wed, 4 Dec 2024 12:13:45 +0100 Subject: [PATCH 48/77] Work --- test/e2e/index.test.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/e2e/index.test.ts b/test/e2e/index.test.ts index 0b1cd683d848..4f964178a9c0 100644 --- a/test/e2e/index.test.ts +++ b/test/e2e/index.test.ts @@ -803,12 +803,9 @@ async function initializeEnvironment( await page.getByRole('gridcell', { name: '11' }).click(); await page.getByRole('button', { name: 'OK' }).click(); - await waitFor(async () => { - // assert that the dialog has been closed and the focused element is the input - expect(await page.evaluate(() => document.activeElement?.className)).to.contain( - iconButtonClasses.root, - ); - }); + // assert that the dialog closes after selection is complete + // could run into race condition otherwise + await page.waitForSelector('[role="dialog"]', { state: 'detached' }); expect(await page.getByRole('textbox', { includeHidden: true }).inputValue()).to.equal( '04/11/2022', ); From 4927e7f5cf6411b44d5cddde622304191aa38116 Mon Sep 17 00:00:00 2001 From: flavien Date: Wed, 4 Dec 2024 12:22:03 +0100 Subject: [PATCH 49/77] Work --- test/e2e/index.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/e2e/index.test.ts b/test/e2e/index.test.ts index 4f964178a9c0..5925c48e52d2 100644 --- a/test/e2e/index.test.ts +++ b/test/e2e/index.test.ts @@ -13,7 +13,6 @@ import { WebError, Locator, } from '@playwright/test'; -import { iconButtonClasses } from '@mui/material/IconButton'; import { pickersSectionListClasses } from '@mui/x-date-pickers/PickersSectionList'; function sleep(timeoutMS: number): Promise { From 05ce33057b6a0be6145ef660135a6400c6b9e8c5 Mon Sep 17 00:00:00 2001 From: flavien Date: Wed, 4 Dec 2024 12:59:50 +0100 Subject: [PATCH 50/77] Fix --- .../x-date-pickers/src/DatePicker/tests/DatePicker.test.tsx | 2 +- .../src/DateTimePicker/tests/DateTimePicker.test.tsx | 2 +- .../x-date-pickers/src/TimePicker/tests/TimePicker.test.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/x-date-pickers/src/DatePicker/tests/DatePicker.test.tsx b/packages/x-date-pickers/src/DatePicker/tests/DatePicker.test.tsx index 69f65acc3adf..ba65234304fa 100644 --- a/packages/x-date-pickers/src/DatePicker/tests/DatePicker.test.tsx +++ b/packages/x-date-pickers/src/DatePicker/tests/DatePicker.test.tsx @@ -6,7 +6,7 @@ import { fireEvent, screen } from '@mui/internal-test-utils/createRenderer'; import { createPickerRenderer, stubMatchMedia } from 'test/utils/pickers'; describe('', () => { - const { render } = createPickerRenderer(); + const { render } = createPickerRenderer({ clock: 'fake' }); it('should render in mobile mode when `useMediaQuery` returns `false`', () => { const originalMatchMedia = window.matchMedia; diff --git a/packages/x-date-pickers/src/DateTimePicker/tests/DateTimePicker.test.tsx b/packages/x-date-pickers/src/DateTimePicker/tests/DateTimePicker.test.tsx index 51e56cc25af3..d5c489cefc78 100644 --- a/packages/x-date-pickers/src/DateTimePicker/tests/DateTimePicker.test.tsx +++ b/packages/x-date-pickers/src/DateTimePicker/tests/DateTimePicker.test.tsx @@ -6,7 +6,7 @@ import { fireEvent, screen } from '@mui/internal-test-utils/createRenderer'; import { createPickerRenderer, stubMatchMedia } from 'test/utils/pickers'; describe('', () => { - const { render } = createPickerRenderer(); + const { render } = createPickerRenderer({ clock: 'fake' }); it('should render in mobile mode when `useMediaQuery` returns `false`', () => { const originalMatchMedia = window.matchMedia; diff --git a/packages/x-date-pickers/src/TimePicker/tests/TimePicker.test.tsx b/packages/x-date-pickers/src/TimePicker/tests/TimePicker.test.tsx index dbbf6115c2ed..36cbebcdf621 100644 --- a/packages/x-date-pickers/src/TimePicker/tests/TimePicker.test.tsx +++ b/packages/x-date-pickers/src/TimePicker/tests/TimePicker.test.tsx @@ -6,7 +6,7 @@ import { fireEvent, screen } from '@mui/internal-test-utils/createRenderer'; import { createPickerRenderer, stubMatchMedia } from 'test/utils/pickers'; describe('', () => { - const { render } = createPickerRenderer(); + const { render } = createPickerRenderer({ clock: 'fake' }); it('should render in mobile mode when `useMediaQuery` returns `false`', () => { const originalMatchMedia = window.matchMedia; From 034d7a17f86539d1786eaa4061e710b4efcc2d57 Mon Sep 17 00:00:00 2001 From: flavien Date: Thu, 5 Dec 2024 14:07:26 +0100 Subject: [PATCH 51/77] Fine tune the doc demos --- .../behavior-masked-text-field/MaskedMaterialTextField.js | 1 - .../behavior-masked-text-field/MaskedMaterialTextField.tsx | 1 - .../behavior-read-only-text-field/MaterialDatePicker.js | 2 +- .../behavior-read-only-text-field/MaterialDatePicker.tsx | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.js b/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.js index 69c77a1c8074..fdb3dc2151b5 100644 --- a/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.js +++ b/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.js @@ -141,7 +141,6 @@ function MaskedDateField(props) { pickerContext.setOpen((prev) => !prev)} - size="small" edge="end" > diff --git a/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx b/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx index 7920d6cc98c4..b9241d9caf2b 100644 --- a/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx +++ b/docs/data/date-pickers/custom-field/behavior-masked-text-field/MaskedMaterialTextField.tsx @@ -145,7 +145,6 @@ function MaskedDateField(props: DatePickerFieldProps) { pickerContext.setOpen((prev) => !prev)} - size="small" edge="end" > 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 16bd9f9bf4cb..f0d393220abf 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 @@ -34,7 +34,7 @@ function ReadOnlyDateField(props) { InputProps={{ ref: pickerContext.triggerRef, readOnly: true, - endAdornment: , + endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} 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 127876f1a2e3..3be9bd3aa55f 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 @@ -38,7 +38,7 @@ function ReadOnlyDateField(props: DatePickerFieldProps) { InputProps={{ ref: pickerContext.triggerRef, readOnly: true, - endAdornment: , + endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} From bd77821013daa3a467af97d7b423f766aca2ffcb Mon Sep 17 00:00:00 2001 From: flavien Date: Thu, 5 Dec 2024 14:16:41 +0100 Subject: [PATCH 52/77] Fine tune the doc demos --- packages/x-date-pickers/src/internals/models/fields.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/x-date-pickers/src/internals/models/fields.ts b/packages/x-date-pickers/src/internals/models/fields.ts index 260757e063c0..c1b59a019815 100644 --- a/packages/x-date-pickers/src/internals/models/fields.ts +++ b/packages/x-date-pickers/src/internals/models/fields.ts @@ -26,9 +26,6 @@ export interface BaseForwardedSingleInputFieldProps onBlur?: React.FocusEventHandler; ref?: React.Ref; inputRef?: React.Ref; - inputProps?: { - 'aria-label'?: string; - }; slots?: ExportedPickerFieldUISlots; slotProps?: PickerFieldUISlotProps & { textField?: {}; From 536588c392cadc71e3d4c35f067928891cf4b2ab Mon Sep 17 00:00:00 2001 From: flavien Date: Thu, 5 Dec 2024 14:28:46 +0100 Subject: [PATCH 53/77] Fix doc --- .../custom-field/behavior-autocomplete/MaterialDatePicker.js | 2 -- .../custom-field/behavior-autocomplete/MaterialDatePicker.tsx | 2 -- 2 files changed, 4 deletions(-) diff --git a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.js b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.js index 502d478e3e93..2eab5b1e68a3 100644 --- a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.js +++ b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.js @@ -21,7 +21,6 @@ function AutocompleteField(props) { focused, name, options = [], - inputProps, ...other } = forwardedProps; @@ -47,7 +46,6 @@ function AutocompleteField(props) { {...params} error={hasValidationError} label={label} - inputProps={{ ...params.inputProps, ...inputProps }} InputProps={{ ...params.InputProps, endAdornment: React.cloneElement(endAdornment, { diff --git a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx index 851bdb9ec570..740dece3ade3 100644 --- a/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx +++ b/docs/data/date-pickers/custom-field/behavior-autocomplete/MaterialDatePicker.tsx @@ -32,7 +32,6 @@ function AutocompleteField(props: AutocompleteFieldProps) { focused, name, options = [], - inputProps, ...other } = forwardedProps; @@ -58,7 +57,6 @@ function AutocompleteField(props: AutocompleteFieldProps) { {...params} error={hasValidationError} label={label} - inputProps={{ ...params.inputProps, ...inputProps }} InputProps={{ ...params.InputProps, endAdornment: React.cloneElement(endAdornment, { From 3a27864aadbf2478578664ee188460d2453bb855 Mon Sep 17 00:00:00 2001 From: flavien Date: Thu, 5 Dec 2024 14:37:41 +0100 Subject: [PATCH 54/77] Fix doc --- .../behavior-read-only-text-field/MaterialDatePicker.js | 2 +- .../behavior-read-only-text-field/MaterialDatePicker.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 f0d393220abf..3efd5669514f 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 @@ -34,7 +34,7 @@ function ReadOnlyDateField(props) { InputProps={{ ref: pickerContext.triggerRef, readOnly: true, - endAdornment: , + endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} 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 3be9bd3aa55f..656bebf80cba 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 @@ -38,7 +38,7 @@ function ReadOnlyDateField(props: DatePickerFieldProps) { InputProps={{ ref: pickerContext.triggerRef, readOnly: true, - endAdornment: , + endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} From 7fbdac64d8157386371479ef6c5079e8e138fe8a Mon Sep 17 00:00:00 2001 From: flavien Date: Thu, 5 Dec 2024 15:01:38 +0100 Subject: [PATCH 55/77] Add migration guide --- .../migration-pickers-v7.md | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md index eb3b7fd74814..5873903bb2d0 100644 --- a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md +++ b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md @@ -259,6 +259,83 @@ const theme = createTheme({ ## Slots breaking changes +### Slot: `field` + +- The component passed to the `field` slot no longer receives `InputProps` and `inputProps` props. You now need to manually add the UI to open the picker using the `usePickerContext` hook: + + ```diff + import { unstable_useDateField } from '@mui/x-date-pickers/DateField'; + +import { usePickerContext } from '@mui/x-date-pickers/hooks'; + + function CustomField(props) { + + const pickerContext = usePickerContext(); + + return ( + + + pickerContext.setOpen((prev) => !prev)} + + edge="end" + + > + + + + + + + + ), + + }} + /> + ); + } + ``` + + If you are extracting the `ref` from `InputProps` to pass it to another trigger component, you can replace it with `pickerContext.triggerRef`: + + ```diff + +import { usePickerContext } from '@mui/x-date-pickers/hooks'; + + function CustomField(props) { + + const pickerContext = usePickerContext(); + + return ( + + ); + } + ``` + + If you are using a custom editing behavior, instead of using the `openPickerAriaLabel` property returned by the `useXXXField` hooks, you can generate it manually: + + ```diff + +import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; + + function CustomField(props) { + + const translations = usePickerTranslations(); + + const formattedValue = props.value?.isValid() ? value.format('ll') : null; + + const ariaLabel = translations.openDatePickerDialogue(formattedValue); + + return ( + + ); + } + ``` + ### Slot: `inputAdornment` - The `position` props passed to the `inputAdornment` slot props no longer sets the position of the opening button. This allow to define the position of the opening button and of the clear button independently. Instead you can use the `openPickerButtonPosition` prop: From 97244541b9301cebfa9e5062ad84cae45f4a87ab Mon Sep 17 00:00:00 2001 From: flavien Date: Thu, 5 Dec 2024 15:02:33 +0100 Subject: [PATCH 56/77] Fix doc --- .../behavior-read-only-text-field/MaterialDatePicker.js | 2 +- .../behavior-read-only-text-field/MaterialDatePicker.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 3efd5669514f..bd6e7598d962 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 @@ -34,7 +34,7 @@ function ReadOnlyDateField(props) { InputProps={{ ref: pickerContext.triggerRef, readOnly: true, - endAdornment: , + endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} 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 656bebf80cba..70bc83500c54 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 @@ -38,7 +38,7 @@ function ReadOnlyDateField(props: DatePickerFieldProps) { InputProps={{ ref: pickerContext.triggerRef, readOnly: true, - endAdornment: , + endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} From d90412a5095d9842fb3442e508d3f8e6452854ad Mon Sep 17 00:00:00 2001 From: flavien Date: Thu, 5 Dec 2024 15:10:51 +0100 Subject: [PATCH 57/77] Fix --- .../migration/migration-pickers-v7/migration-pickers-v7.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md index 5873903bb2d0..64598d8c3052 100644 --- a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md +++ b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md @@ -313,9 +313,9 @@ const theme = createTheme({ ); } ``` - + If you are using a custom editing behavior, instead of using the `openPickerAriaLabel` property returned by the `useXXXField` hooks, you can generate it manually: - + ```diff +import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; From 307b1b823b4823104c7aa67d5bb0d5a65374bf03 Mon Sep 17 00:00:00 2001 From: flavien Date: Thu, 5 Dec 2024 15:11:27 +0100 Subject: [PATCH 58/77] Fix doc --- .../MaterialDatePicker.js | 2 +- .../MaterialDatePicker.tsx | 2 +- .../migration-pickers-v7.md | 20 +++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) 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 bd6e7598d962..0970bef8ede7 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 @@ -34,7 +34,7 @@ function ReadOnlyDateField(props) { InputProps={{ ref: pickerContext.triggerRef, readOnly: true, - endAdornment: , + endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} 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 70bc83500c54..649d36dd5744 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 @@ -38,7 +38,7 @@ function ReadOnlyDateField(props: DatePickerFieldProps) { InputProps={{ ref: pickerContext.triggerRef, readOnly: true, - endAdornment: , + endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} diff --git a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md index 64598d8c3052..d05d84c7653d 100644 --- a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md +++ b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md @@ -271,7 +271,7 @@ const theme = createTheme({ + const pickerContext = usePickerContext(); return ( - + + ), - + }} + + }} /> ); } @@ -303,13 +303,13 @@ const theme = createTheme({ + const pickerContext = usePickerContext(); return ( - + ); } ``` @@ -325,13 +325,13 @@ const theme = createTheme({ + const ariaLabel = translations.openDatePickerDialogue(formattedValue); return ( - + ); } ``` From 108539a18044167fbb3824e49061ff9d90971453 Mon Sep 17 00:00:00 2001 From: flavien Date: Thu, 5 Dec 2024 15:34:57 +0100 Subject: [PATCH 59/77] Work on migration guid --- .../MaterialDatePicker.js | 72 ++++++++++++++++++ .../MaterialDatePicker.tsx | 76 +++++++++++++++++++ .../MaterialDatePicker.tsx.preview | 1 + .../date-pickers/custom-field/custom-field.md | 23 +++--- .../migration-pickers-v7.md | 14 ++++ 5 files changed, 172 insertions(+), 14 deletions(-) create mode 100644 docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.js create mode 100644 docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.tsx create mode 100644 docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.tsx.preview diff --git a/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.js b/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.js new file mode 100644 index 000000000000..995bfb62834d --- /dev/null +++ b/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.js @@ -0,0 +1,72 @@ +import * as React from 'react'; +import TextField from '@mui/material/TextField'; +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, + usePickerContext, +} from '@mui/x-date-pickers/hooks'; +import { CalendarIcon } from '@mui/x-date-pickers/icons'; +import { DateField } from '@mui/x-date-pickers/DateField'; + +function ReadOnlyDateField(props) { + const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date'); + const { value, timezone, format } = internalProps; + const { slotProps, slots, ...other } = forwardedProps; + + const pickerContext = usePickerContext(); + + const parsedFormat = useParsedFormat(internalProps); + const { hasValidationError } = useValidation({ + validator: validateDate, + value, + timezone, + props: internalProps, + }); + + return ( + , + sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, + }} + error={hasValidationError} + onClick={() => pickerContext.setOpen((prev) => !prev)} + /> + ); +} + +function ReadOnlyOnMobileDateField(props) { + const pickerContext = usePickerContext(); + + if (pickerContext.variant === 'mobile') { + return ; + } + + return ; +} + +function ReadOnlyFieldDatePicker(props) { + return ( + + ); +} + +export default function MaterialDatePicker() { + return ( + + + + ); +} diff --git a/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.tsx b/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.tsx new file mode 100644 index 000000000000..85018d252cf6 --- /dev/null +++ b/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.tsx @@ -0,0 +1,76 @@ +import * as React from 'react'; +import TextField from '@mui/material/TextField'; +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, + usePickerContext, +} from '@mui/x-date-pickers/hooks'; +import { CalendarIcon } from '@mui/x-date-pickers/icons'; +import { DateField } from '@mui/x-date-pickers/DateField'; + +function ReadOnlyDateField(props: DatePickerFieldProps) { + const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date'); + const { value, timezone, format } = internalProps; + const { slotProps, slots, ...other } = forwardedProps; + + const pickerContext = usePickerContext(); + + const parsedFormat = useParsedFormat(internalProps); + const { hasValidationError } = useValidation({ + validator: validateDate, + value, + timezone, + props: internalProps, + }); + + return ( + , + sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, + }} + error={hasValidationError} + onClick={() => pickerContext.setOpen((prev) => !prev)} + /> + ); +} + +function ReadOnlyOnMobileDateField(props: DatePickerFieldProps) { + const pickerContext = usePickerContext(); + + if (pickerContext.variant === 'mobile') { + return ; + } + + return ; +} + +function ReadOnlyFieldDatePicker(props: DatePickerProps) { + return ( + + ); +} + +export default function MaterialDatePicker() { + return ( + + + + ); +} diff --git a/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.tsx.preview b/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.tsx.preview new file mode 100644 index 000000000000..e3842a12cb5d --- /dev/null +++ b/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.tsx.preview @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/data/date-pickers/custom-field/custom-field.md b/docs/data/date-pickers/custom-field/custom-field.md index e30850de8502..d0c12bd828bb 100644 --- a/docs/data/date-pickers/custom-field/custom-field.md +++ b/docs/data/date-pickers/custom-field/custom-field.md @@ -30,20 +30,9 @@ You can use the `fieldSeparator` slot to pass custom props to the `Typography` r ### Customize the `start` and `end` fields differently [](/x/introduction/licensing/#pro-plan 'Pro plan') -You can pass conditional props to the `textField` slot to customize the input styling based on the `position`. - -{{"demo": "MultiInputFieldTextFieldProps.js"}} - -### Use single input fields on range pickers [](/x/introduction/licensing/#pro-plan 'Pro plan') - -You can pass the single input fields to the range picker to use it for keyboard editing: - -{{"demo": "SingleInputDateRangePicker.js"}} - -If you want to create a wrapper around the field, make sure to set the `fieldType` static property to `'single-input'`. -Otherwise, the picker won't know your field is a single input one and use the multi input event listeners: - -{{"demo": "SingleInputDateRangePickerWrapped.js", "defaultCodeOpen": false}} +TO V8 +Breaking changes: Data Grid +Breaking ch You can manually add an `endAdornment` if you want your range picker to look exactly like on a simple picker: @@ -144,6 +133,12 @@ but you still want the UI to look like a Text Field, you can replace the field w {{"demo": "behavior-read-only-text-field/MaterialDatePicker.js", "defaultCodeOpen": false}} +### Using a read-only Text Field on mobile + +If you want to keep the default behavior on desktop but you want to have a read-only TextField on mobile, you can conditionally render the custom field presented in the previous doc section and the default Date Field: + +{{"demo": "behavior-read-only-mobile-text-field/MaterialDatePicker.js", "defaultCodeOpen": false}} + ### Using a Button If you want users to select a value exclusively through the views diff --git a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md index d05d84c7653d..77b815f38b97 100644 --- a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md +++ b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md @@ -257,6 +257,20 @@ const theme = createTheme({ }); ``` +## Enable field editing on mobile + +The field are now editable when used inside a mobile picker. +Before v8, when rendered inside a mobile picker, the field were read-only and clicking anywhere on them would open the piker. +The behavior is now the same as inside a desktop picker: + +- clicking on the field value allows to edit it +- clicking on the field end adornment opens the picker + +:::success +If you prefer the old behavior, you can create a custom field that renders a read-only Text Field on mobile. +See [Custom field—Using a read-only Text Field on mobile](/x/react-date-pickers/custom-field/#using-a-read-only-text-field-on-mobile) to learn more. +::: + ## Slots breaking changes ### Slot: `field` From f2691ba374ad24eb8ce7ebfaaa503c432ce1c711 Mon Sep 17 00:00:00 2001 From: flavien Date: Thu, 5 Dec 2024 15:38:58 +0100 Subject: [PATCH 60/77] Fix doc --- docs/data/date-pickers/custom-field/JoyV6Field.js | 2 +- docs/data/date-pickers/custom-field/JoyV6Field.tsx | 2 +- .../custom-field/JoyV6SingleInputRangeField.js | 8 ++++---- .../custom-field/JoyV6SingleInputRangeField.tsx | 8 ++++---- .../MaterialDatePicker.js | 2 +- .../MaterialDatePicker.tsx | 2 +- .../behavior-read-only-text-field/MaterialDatePicker.js | 2 +- .../behavior-read-only-text-field/MaterialDatePicker.tsx | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/data/date-pickers/custom-field/JoyV6Field.js b/docs/data/date-pickers/custom-field/JoyV6Field.js index 76a00d14c416..f7a97cd30e99 100644 --- a/docs/data/date-pickers/custom-field/JoyV6Field.js +++ b/docs/data/date-pickers/custom-field/JoyV6Field.js @@ -21,7 +21,7 @@ import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateField'; import { usePickerContext } from '@mui/x-date-pickers/hooks'; -export const CalendarIcon = createSvgIcon( +const CalendarIcon = createSvgIcon( , 'Calendar', ); diff --git a/docs/data/date-pickers/custom-field/JoyV6Field.tsx b/docs/data/date-pickers/custom-field/JoyV6Field.tsx index 51fdd6d13a74..145978ee55b4 100644 --- a/docs/data/date-pickers/custom-field/JoyV6Field.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6Field.tsx @@ -26,7 +26,7 @@ import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateF import { usePickerContext } from '@mui/x-date-pickers/hooks'; import { BaseSingleInputPickersFieldHooksReturnValue } from '@mui/x-date-pickers/models'; -export const CalendarIcon = createSvgIcon( +const CalendarIcon = createSvgIcon( , 'Calendar', ); diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js index 5dbc0f76ddaa..5cecd83038eb 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js @@ -20,9 +20,9 @@ import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker'; import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; import { usePickerContext } from '@mui/x-date-pickers/hooks'; -export const CalendarIcon = createSvgIcon( - , - 'Calendar', +const DateRangeIcon = createSvgIcon( + , + 'DateRange', ); const joyTheme = extendJoyTheme(); @@ -61,7 +61,7 @@ const JoyField = React.forwardRef((props, ref) => { disabled={disabled} endDecorator={ - + {endDecorator} } diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx index a00262bb83e3..118cfb6712ef 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx @@ -26,9 +26,9 @@ import { usePickerContext } from '@mui/x-date-pickers/hooks'; import { FieldType } from '@mui/x-date-pickers-pro/models'; import { BaseSingleInputPickersFieldHooksReturnValue } from '@mui/x-date-pickers/models'; -export const CalendarIcon = createSvgIcon( - , - 'Calendar', +const DateRangeIcon = createSvgIcon( + , + 'DateRange', ); const joyTheme = extendJoyTheme(); @@ -81,7 +81,7 @@ const JoyField = React.forwardRef( disabled={disabled} endDecorator={ - + {endDecorator} } diff --git a/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.js b/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.js index 995bfb62834d..5510187e9b85 100644 --- a/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.js +++ b/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.js @@ -35,7 +35,7 @@ function ReadOnlyDateField(props) { InputProps={{ ref: pickerContext.triggerRef, readOnly: true, - endAdornment: , + endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} diff --git a/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.tsx b/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.tsx index 85018d252cf6..071ff1af803d 100644 --- a/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.tsx +++ b/docs/data/date-pickers/custom-field/behavior-read-only-mobile-text-field/MaterialDatePicker.tsx @@ -39,7 +39,7 @@ function ReadOnlyDateField(props: DatePickerFieldProps) { InputProps={{ ref: pickerContext.triggerRef, readOnly: true, - endAdornment: , + endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} 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 0970bef8ede7..16bd9f9bf4cb 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 @@ -34,7 +34,7 @@ function ReadOnlyDateField(props) { InputProps={{ ref: pickerContext.triggerRef, readOnly: true, - endAdornment: , + endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} 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 649d36dd5744..127876f1a2e3 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 @@ -38,7 +38,7 @@ function ReadOnlyDateField(props: DatePickerFieldProps) { InputProps={{ ref: pickerContext.triggerRef, readOnly: true, - endAdornment: , + endAdornment: , sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } }, }} error={hasValidationError} From 14b2252a2eb634374b0f82aaba530a65c2a7725f Mon Sep 17 00:00:00 2001 From: flavien Date: Thu, 5 Dec 2024 15:50:18 +0100 Subject: [PATCH 61/77] Fix --- .../date-pickers/custom-field/custom-field.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/data/date-pickers/custom-field/custom-field.md b/docs/data/date-pickers/custom-field/custom-field.md index d0c12bd828bb..aed45e606143 100644 --- a/docs/data/date-pickers/custom-field/custom-field.md +++ b/docs/data/date-pickers/custom-field/custom-field.md @@ -30,9 +30,20 @@ You can use the `fieldSeparator` slot to pass custom props to the `Typography` r ### Customize the `start` and `end` fields differently [](/x/introduction/licensing/#pro-plan 'Pro plan') -TO V8 -Breaking changes: Data Grid -Breaking ch +You can pass conditional props to the `textField` slot to customize the input styling based on the `position`. + +{{"demo": "MultiInputFieldTextFieldProps.js"}} + +### Use single input fields on range pickers [](/x/introduction/licensing/#pro-plan 'Pro plan') + +You can pass the single input fields to the range picker to use it for keyboard editing: + +{{"demo": "SingleInputDateRangePicker.js"}} + +If you want to create a wrapper around the field, make sure to set the `fieldType` static property to `'single-input'`. +Otherwise, the picker won't know your field is a single input one and use the multi input event listeners: + +{{"demo": "SingleInputDateRangePickerWrapped.js", "defaultCodeOpen": false}} You can manually add an `endAdornment` if you want your range picker to look exactly like on a simple picker: From 3c337adcf57feac257a53978157f6f307bc432f0 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 6 Dec 2024 08:24:26 +0100 Subject: [PATCH 62/77] Fix test --- .../tests/describes.DesktopDateTimeRangePicker.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx index 7a43207f16e9..dfdd329087ff 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/describes.DesktopDateTimeRangePicker.test.tsx @@ -28,7 +28,7 @@ describe(' - Describes', () => { clock, views: ['day', 'hours', 'minutes'], componentFamily: 'picker', - variant: 'mobile', + variant: 'desktop', })); describeConformance(, () => ({ From 6502e1c03c02521f33e57521b0993b2b22de4f65 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 6 Dec 2024 08:30:27 +0100 Subject: [PATCH 63/77] Fix test --- .../src/DigitalClock/tests/describes.DigitalClock.test.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/x-date-pickers/src/DigitalClock/tests/describes.DigitalClock.test.tsx b/packages/x-date-pickers/src/DigitalClock/tests/describes.DigitalClock.test.tsx index 6b521b9de35e..4ec445f96f69 100644 --- a/packages/x-date-pickers/src/DigitalClock/tests/describes.DigitalClock.test.tsx +++ b/packages/x-date-pickers/src/DigitalClock/tests/describes.DigitalClock.test.tsx @@ -36,7 +36,6 @@ describe(' - Describes', () => { render, componentFamily: 'digital-clock', type: 'time', - defaultProps: { views: ['hours'], }, From 40c8d0d2531126dba5787bb20ff8f3bd83752c61 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 6 Dec 2024 08:42:47 +0100 Subject: [PATCH 64/77] Fix test --- .../tests/describes.MultiSectionDigitalClock.test.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/tests/describes.MultiSectionDigitalClock.test.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/tests/describes.MultiSectionDigitalClock.test.tsx index 8227003da285..992c33dc6dec 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/tests/describes.MultiSectionDigitalClock.test.tsx +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/tests/describes.MultiSectionDigitalClock.test.tsx @@ -38,7 +38,6 @@ describe(' - Describes', () => { render, componentFamily: 'multi-section-digital-clock', type: 'time', - values: [adapterToUse.date('2018-01-01T11:30:00'), adapterToUse.date('2018-01-01T12:35:00')], emptyValue: null, clock, From e37bf2da5652cbde35abaf876be2c2ada8656b1d Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 6 Dec 2024 08:54:30 +0100 Subject: [PATCH 65/77] Work --- docs/data/date-pickers/custom-field/JoyV6Field.tsx | 3 +-- .../date-pickers/custom-field/JoyV6SingleInputRangeField.tsx | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/data/date-pickers/custom-field/JoyV6Field.tsx b/docs/data/date-pickers/custom-field/JoyV6Field.tsx index 06aad1adb293..a6c977cadc85 100644 --- a/docs/data/date-pickers/custom-field/JoyV6Field.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6Field.tsx @@ -53,12 +53,11 @@ const JoyDateField = React.forwardRef( {label} {label} } slotProps={{ - root: { ref: containerRef }, input: { ref: inputRef }, }} {...other} From 301af071cc70452f57f60b7f053b42d2a9e04a60 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 6 Dec 2024 08:54:30 +0100 Subject: [PATCH 66/77] Work --- docs/data/date-pickers/custom-field/JoyV6Field.js | 3 +-- docs/data/date-pickers/custom-field/JoyV6Field.tsx | 3 +-- .../date-pickers/custom-field/JoyV6SingleInputRangeField.js | 3 +-- .../date-pickers/custom-field/JoyV6SingleInputRangeField.tsx | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/data/date-pickers/custom-field/JoyV6Field.js b/docs/data/date-pickers/custom-field/JoyV6Field.js index 07149b867ee6..b5178a1b5c5a 100644 --- a/docs/data/date-pickers/custom-field/JoyV6Field.js +++ b/docs/data/date-pickers/custom-field/JoyV6Field.js @@ -46,12 +46,11 @@ const JoyDateField = React.forwardRef((props, ref) => { {label} {label} { > {label} } slotProps={{ - root: { ref: containerRef }, input: { ref: inputRef }, }} {...other} diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx index 13fd6b592968..261c0cac04d8 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx @@ -71,11 +71,10 @@ const JoySingleInputDateRangeField = React.forwardRef( > {label} } slotProps={{ - root: { ref: containerRef }, input: { ref: inputRef }, }} {...other} From 1a34f50b1f11f7f1304e1fac021ab5ea59d89375 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 6 Dec 2024 08:58:44 +0100 Subject: [PATCH 67/77] Work --- .../custom-field/BrowserV7SingleInputRangeField.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx index 774aea91e9ee..9b18c994847d 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx @@ -81,8 +81,8 @@ const BrowserSingleInputDateRangeField = React.forwardRef( ...other } = fieldResponse; - const pickerContext = usePickerContext(); const handleRef = useForkRef(pickerContext.triggerRef, ref); + const pickerContext = usePickerContext(); return ( Date: Fri, 6 Dec 2024 08:59:22 +0100 Subject: [PATCH 68/77] Work --- .../date-pickers/custom-field/BrowserV7SingleInputRangeField.js | 1 - .../date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js index 6ebb17a38efb..f25990ef0cf6 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js @@ -65,7 +65,6 @@ const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => { } = fieldResponse; const handleRef = useForkRef(InputPropsRef, ref); - const pickerContext = usePickerContext(); return ( diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx index 1e200c85d19e..5edc6854e4a7 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx @@ -84,7 +84,6 @@ const BrowserSingleInputDateRangeField = React.forwardRef( } = fieldResponse; const handleRef = useForkRef(InputPropsRef, ref); - const pickerContext = usePickerContext(); return ( From a791ea87917dd038661748dcf022a6c7da5a6bc1 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 6 Dec 2024 09:00:06 +0100 Subject: [PATCH 69/77] Work --- .../date-pickers/custom-field/BrowserV7SingleInputRangeField.js | 2 +- .../custom-field/BrowserV7SingleInputRangeField.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js index f25990ef0cf6..164dffde3605 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js @@ -64,8 +64,8 @@ const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => { ...other } = fieldResponse; - const handleRef = useForkRef(InputPropsRef, ref); const pickerContext = usePickerContext(); + const handleRef = useForkRef(InputPropsRef, ref); return ( Date: Fri, 6 Dec 2024 09:05:25 +0100 Subject: [PATCH 70/77] Work --- packages/x-date-pickers/src/models/fields.ts | 10 +--------- scripts/x-date-pickers-pro.exports.json | 1 - scripts/x-date-pickers.exports.json | 1 - 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index 0dd2256a0ff0..927a2e220389 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -156,14 +156,6 @@ export type PickerFieldSlotProps< ref?: React.Ref; }; -/** - * Props the `useDateField()` and equivalent hooks return when used inside a single input picker. - * Only contains what the MUI components are passing to the field, not what users can pass using the `props.slotProps.field` and `props.slotProps.textField`. - */ -export type BaseSingleInputPickersFieldHooksReturnValue< - TEnableAccessibleFieldDOMStructure extends boolean, -> = UseFieldResponse; - /** * Props the text field receives when used inside a single input picker. * Only contains what the MUI components are passing to the text field, not what users can pass using the `props.slotProps.field` and `props.slotProps.textField`. @@ -171,7 +163,7 @@ export type BaseSingleInputPickersFieldHooksReturnValue< export type BaseSingleInputPickersTextFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, > = Omit< - BaseSingleInputPickersFieldHooksReturnValue, + UseFieldResponse, | 'slots' | 'slotProps' | 'clearable' diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index bdb9f15f5f4c..7430f1a48bf4 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -6,7 +6,6 @@ { "name": "ArrowRightIcon", "kind": "Variable" }, { "name": "BaseMultiInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickerFieldResponse", "kind": "TypeAlias" }, - { "name": "BaseSingleInputPickersFieldHooksReturnValue", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BuiltInFieldTextFieldProps", "kind": "TypeAlias" }, { "name": "CalendarIcon", "kind": "Variable" }, diff --git a/scripts/x-date-pickers.exports.json b/scripts/x-date-pickers.exports.json index be5984f42690..df16a555e53a 100644 --- a/scripts/x-date-pickers.exports.json +++ b/scripts/x-date-pickers.exports.json @@ -5,7 +5,6 @@ { "name": "ArrowLeftIcon", "kind": "Variable" }, { "name": "ArrowRightIcon", "kind": "Variable" }, { "name": "BaseSingleInputPickerFieldResponse", "kind": "TypeAlias" }, - { "name": "BaseSingleInputPickersFieldHooksReturnValue", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BuiltInFieldTextFieldProps", "kind": "TypeAlias" }, { "name": "CalendarIcon", "kind": "Variable" }, From 07b08142badc1da0ae6e4962def84dad46aefc85 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 6 Dec 2024 09:07:25 +0100 Subject: [PATCH 71/77] Work --- packages/x-date-pickers/src/models/fields.ts | 3 --- scripts/x-date-pickers-pro.exports.json | 1 - scripts/x-date-pickers.exports.json | 1 - 3 files changed, 5 deletions(-) diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index 927a2e220389..9a2bf3fd3ca1 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -173,9 +173,6 @@ export type BaseSingleInputPickersTextFieldProps< | 'openPickerAriaLabel' >; -export type BaseSingleInputPickerFieldResponse = - UseFieldResponse; - /** * Props the built-in text field component can receive. */ diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index 7430f1a48bf4..36b647590889 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -5,7 +5,6 @@ { "name": "ArrowLeftIcon", "kind": "Variable" }, { "name": "ArrowRightIcon", "kind": "Variable" }, { "name": "BaseMultiInputPickersTextFieldProps", "kind": "TypeAlias" }, - { "name": "BaseSingleInputPickerFieldResponse", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BuiltInFieldTextFieldProps", "kind": "TypeAlias" }, { "name": "CalendarIcon", "kind": "Variable" }, diff --git a/scripts/x-date-pickers.exports.json b/scripts/x-date-pickers.exports.json index df16a555e53a..60cb4180bd3c 100644 --- a/scripts/x-date-pickers.exports.json +++ b/scripts/x-date-pickers.exports.json @@ -4,7 +4,6 @@ { "name": "ArrowDropDownIcon", "kind": "Variable" }, { "name": "ArrowLeftIcon", "kind": "Variable" }, { "name": "ArrowRightIcon", "kind": "Variable" }, - { "name": "BaseSingleInputPickerFieldResponse", "kind": "TypeAlias" }, { "name": "BaseSingleInputPickersTextFieldProps", "kind": "TypeAlias" }, { "name": "BuiltInFieldTextFieldProps", "kind": "TypeAlias" }, { "name": "CalendarIcon", "kind": "Variable" }, From e77bbf339ec8eb005a1e0b8deed1196e12dda959 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 6 Dec 2024 16:17:30 +0100 Subject: [PATCH 72/77] Fix --- docs/data/date-pickers/custom-field/BrowserV7Field.js | 2 +- docs/data/date-pickers/custom-field/BrowserV7Field.tsx | 2 +- .../date-pickers/custom-field/BrowserV7SingleInputRangeField.js | 2 +- .../custom-field/BrowserV7SingleInputRangeField.tsx | 2 +- docs/data/date-pickers/custom-field/JoyV6Field.js | 2 +- docs/data/date-pickers/custom-field/JoyV6Field.tsx | 2 +- .../date-pickers/custom-field/JoyV6SingleInputRangeField.js | 2 +- .../date-pickers/custom-field/JoyV6SingleInputRangeField.tsx | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/data/date-pickers/custom-field/BrowserV7Field.js b/docs/data/date-pickers/custom-field/BrowserV7Field.js index 0603f30646e4..11f5b168ae3f 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7Field.js +++ b/docs/data/date-pickers/custom-field/BrowserV7Field.js @@ -45,8 +45,8 @@ const BrowserDateField = React.forwardRef((props, ref) => { onChange, value, // Can be passed to the button that clears the value - clearable, onClear, + clearable, // Can be used to render a custom label label, // Can be used to style the component diff --git a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx index b995c3e815b0..a218b603030f 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7Field.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7Field.tsx @@ -53,8 +53,8 @@ const BrowserDateField = React.forwardRef( value, // Can be passed to the button that clears the value - clearable, onClear, + clearable, // Can be used to render a custom label label, diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js index 164dffde3605..ae55770f6078 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.js @@ -49,8 +49,8 @@ const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => { onChange, value, // Can be passed to the button that clears the value - clearable, onClear, + clearable, // Can be used to render a custom label label, // Can be used to style the component diff --git a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx index e55bb923ec74..68f5f4c21737 100644 --- a/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/BrowserV7SingleInputRangeField.tsx @@ -64,8 +64,8 @@ const BrowserSingleInputDateRangeField = React.forwardRef( value, // Can be passed to the button that clears the value - clearable, onClear, + clearable, // Can be used to render a custom label label, diff --git a/docs/data/date-pickers/custom-field/JoyV6Field.js b/docs/data/date-pickers/custom-field/JoyV6Field.js index b5178a1b5c5a..156d8200c2f5 100644 --- a/docs/data/date-pickers/custom-field/JoyV6Field.js +++ b/docs/data/date-pickers/custom-field/JoyV6Field.js @@ -30,8 +30,8 @@ const JoyDateField = React.forwardRef((props, ref) => { // Should be ignored enableAccessibleFieldDOMStructure, // Can be passed to the button that clears the value - clearable, onClear, + clearable, disabled, id, label, diff --git a/docs/data/date-pickers/custom-field/JoyV6Field.tsx b/docs/data/date-pickers/custom-field/JoyV6Field.tsx index a6c977cadc85..9e30ca9e0b71 100644 --- a/docs/data/date-pickers/custom-field/JoyV6Field.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6Field.tsx @@ -36,8 +36,8 @@ const JoyDateField = React.forwardRef( enableAccessibleFieldDOMStructure, // Can be passed to the button that clears the value - clearable, onClear, + clearable, disabled, id, diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js index 874075b523a7..69123038f850 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js @@ -36,8 +36,8 @@ const JoySingleInputDateRangeField = React.forwardRef((props, ref) => { // Should be ignored enableAccessibleFieldDOMStructure, // Can be passed to the button that clears the value - clearable, onClear, + clearable, disabled, id, label, diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx index 261c0cac04d8..822610feac08 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx @@ -47,8 +47,8 @@ const JoySingleInputDateRangeField = React.forwardRef( enableAccessibleFieldDOMStructure, // Can be passed to the button that clears the value - clearable, onClear, + clearable, disabled, id, From 34188f5b1e87e49820ea6306cb41c73a386514ee Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 6 Dec 2024 17:02:48 +0100 Subject: [PATCH 73/77] Fix --- .../src/internals/hooks/usePicker/usePicker.types.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts index d77e131106eb..40a8ce569347 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts @@ -68,6 +68,4 @@ export interface UsePickerResponse< providerProps: UsePickerProviderReturnValue; layoutProps: UsePickerValueResponse['layoutProps'] & UsePickerViewsResponse['layoutProps']; - // TODO v8: Remove in https://github.com/mui/mui-x/pull/15671 - hasUIView: boolean; } From 175582877c34693b0cb7a545b65a7e286a8411a0 Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 9 Dec 2024 10:16:37 +0100 Subject: [PATCH 74/77] Work --- .../custom-field/JoyV6SingleInputRangeField.js | 2 +- .../custom-field/JoyV6SingleInputRangeField.tsx | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js index 8605a0315316..c332292bca70 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.js @@ -21,7 +21,7 @@ import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } import { usePickerContext } from '@mui/x-date-pickers/hooks'; -export const DateRangeIcon = createSvgIcon( +const DateRangeIcon = createSvgIcon( , 'DateRange', ); diff --git a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx index c01314f01810..b973d37c1be5 100644 --- a/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx +++ b/docs/data/date-pickers/custom-field/JoyV6SingleInputRangeField.tsx @@ -25,12 +25,7 @@ import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } import { FieldType } from '@mui/x-date-pickers-pro/models'; import { usePickerContext } from '@mui/x-date-pickers/hooks'; -export const DateRangeIcon = createSvgIcon( - , - 'DateRange', -); - -export const DateRangeIcon = createSvgIcon( +const DateRangeIcon = createSvgIcon( , 'DateRange', ); From f4d1bc90289171b0be69af7323a13ad8d3d6394b Mon Sep 17 00:00:00 2001 From: flavien Date: Mon, 9 Dec 2024 10:36:40 +0100 Subject: [PATCH 75/77] Fix --- .../StaticDateRangePicker.test.tsx | 2 +- .../useDesktopRangePicker.tsx | 2 +- .../useMobileRangePicker.tsx | 2 +- .../internals/components/PickerFieldUI.tsx | 3 +- .../internals/components/PickerProvider.tsx | 25 +++++++------ .../hooks/usePicker/usePickerProvider.ts | 36 +++++++++++-------- .../describeValidation.types.ts | 2 +- 7 files changed, 39 insertions(+), 33 deletions(-) diff --git a/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.test.tsx index 794abb288435..b79aa2643aaa 100644 --- a/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.test.tsx +++ b/packages/x-date-pickers-pro/src/StaticDateRangePicker/StaticDateRangePicker.test.tsx @@ -33,7 +33,7 @@ describe('', () => { clock, componentFamily: 'static-picker', views: ['day'], - variant: 'static', + variant: 'mobile', })); it('allows disabling dates', () => { 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 132c9d97eafa..aeea33b20121 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 @@ -111,7 +111,7 @@ export const useDesktopRangePicker = < }); // Temporary hack to hide the opening button on the range pickers until we have migrate them to the new opening logic. - providerProps.privateContextValue.triggerStatus = 'hidden'; + providerProps.contextValue.triggerStatus = 'hidden'; React.useEffect(() => { if (layoutProps.view) { diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx index 32cfc83ed3bf..6f4df1737d99 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx @@ -107,7 +107,7 @@ export const useMobileRangePicker = < }); // Temporary hack to hide the opening button on the range pickers until we have migrate them to the new opening logic. - providerProps.privateContextValue.triggerStatus = 'hidden'; + providerProps.contextValue.triggerStatus = 'hidden'; const Field = slots.field; const fieldProps: RangePickerPropsForFieldSlot< diff --git a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx index f7d6e4a75d65..b6a2477f9853 100644 --- a/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerFieldUI.tsx @@ -11,7 +11,6 @@ import { useFieldOwnerState } from '../hooks/useFieldOwnerState'; import { usePickerTranslations } from '../../hooks'; import { ClearIcon as MuiClearIcon } from '../../icons'; import { useNullablePickerContext } from '../hooks/useNullablePickerContext'; -import { usePickerPrivateContext } from '../hooks/usePickerPrivateContext'; import type { UseFieldResponse } from '../hooks/useField'; import { PickersTextField, PickersTextFieldProps } from '../../PickersTextField'; @@ -88,7 +87,6 @@ export function PickerFieldUI(props: PickerFieldUIProps) { const translations = usePickerTranslations(); const pickerContext = useNullablePickerContext(); - const { triggerStatus } = usePickerPrivateContext(); const { textFieldProps, onClear, @@ -101,6 +99,7 @@ export function PickerFieldUI(props: PickerFieldUIProps) { const handleTogglePicker = useEventCallback(() => pickerContext?.setOpen((prev) => !prev)); + const triggerStatus = pickerContext ? pickerContext.triggerStatus : 'hidden'; const clearButtonPosition = clearable ? clearButtonPositionProp : null; const openPickerButtonPosition = triggerStatus !== 'hidden' ? openPickerButtonPositionProp : null; diff --git a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx index 6ce63ae62911..6c8f23c9393a 100644 --- a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx @@ -16,7 +16,6 @@ export const PickerPrivateContext = React.createContext; /** * `true` if the picker is disabled, `false` otherwise. */ @@ -76,17 +70,22 @@ export interface PickerContextValue extends UsePickerValueContextValue { * Is always equal to "portrait" if the component you are accessing the ownerState from is not wrapped by a picker. */ orientation: PickerOrientation; -} -export interface PickerPrivateContextValue { /** - * The ownerState of the picker. + * The ref that should be attached to the element that triggers the picker opening. + * When using a built-in field component, this property is automatically handled. */ - ownerState: PickerOwnerState; + triggerRef: React.RefObject; /** - * Informs the field if it should render the UI to open the picker. + * The status of the element that triggers the picker opening. * If it is "hidden", the field should not render the UI to open the picker. - * If it is "disabled", the field should render the UI to open the picker, but it should be disabled. - * If it is "enabled", the field should render the UI to open the picker and it should be enabled. + * If it is "disabled", the field should render the UI to open the picker, but it should not have any behavior attached to it. + * If it is "enabled", the field should render the UI to open the picker and interacting with it should open the picker. */ triggerStatus: 'hidden' | 'disabled' | 'enabled'; } +export interface PickerPrivateContextValue { + /** + * The ownerState of the picker. + */ + ownerState: PickerOwnerState; +} 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 b21cb72a867c..5790da77fb18 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts @@ -102,18 +102,6 @@ export function usePickerProvider< ], ); - const contextValue = React.useMemo( - () => ({ - ...paramsFromUsePickerValue.contextValue, - disabled: props.disabled ?? false, - readOnly: props.readOnly ?? false, - variant, - orientation, - triggerRef, - }), - [paramsFromUsePickerValue.contextValue, variant, orientation, props.disabled, props.readOnly], - ); - const triggerStatus = React.useMemo(() => { if (props.disableOpenPicker || !paramsFromUsePickerViews.hasUIView) { return 'hidden'; @@ -126,9 +114,29 @@ export function usePickerProvider< return 'enabled'; }, [props.disableOpenPicker, paramsFromUsePickerViews.hasUIView, props.disabled, props.readOnly]); + const contextValue = React.useMemo( + () => ({ + ...paramsFromUsePickerValue.contextValue, + disabled: props.disabled ?? false, + readOnly: props.readOnly ?? false, + variant, + orientation, + triggerRef, + triggerStatus, + }), + [ + paramsFromUsePickerValue.contextValue, + variant, + orientation, + props.disabled, + props.readOnly, + triggerStatus, + ], + ); + const privateContextValue = React.useMemo( - () => ({ ownerState, triggerStatus }), - [ownerState, triggerStatus], + () => ({ ownerState }), + [ownerState], ); return { diff --git a/test/utils/pickers/describeValidation/describeValidation.types.ts b/test/utils/pickers/describeValidation/describeValidation.types.ts index 07b3d5f40450..66d1f7720def 100644 --- a/test/utils/pickers/describeValidation/describeValidation.types.ts +++ b/test/utils/pickers/describeValidation/describeValidation.types.ts @@ -10,7 +10,7 @@ export interface DescribeValidationInputOptions { after?: () => void; componentFamily: PickerComponentFamily; views: DateOrTimeView[]; - variant?: 'mobile' | 'desktop' | 'static'; + variant?: 'mobile' | 'desktop'; } export interface DescribeValidationOptions extends DescribeValidationInputOptions { From bc20321a6b032bac7af69137c7331471dff44583 Mon Sep 17 00:00:00 2001 From: flavien Date: Wed, 11 Dec 2024 14:55:01 +0100 Subject: [PATCH 76/77] Fix doc --- docs/data/date-pickers/base-concepts/base-concepts.md | 4 ++-- docs/data/date-pickers/date-picker/date-picker.md | 4 ++-- docs/data/date-pickers/date-range-picker/date-range-picker.md | 4 ++-- docs/data/date-pickers/date-time-picker/date-time-picker.md | 4 ++-- .../date-time-range-picker/date-time-range-picker.md | 4 ++-- docs/data/date-pickers/time-picker/time-picker.md | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/data/date-pickers/base-concepts/base-concepts.md b/docs/data/date-pickers/base-concepts/base-concepts.md index ca61ae0cbe0f..37ee4a4c2c58 100644 --- a/docs/data/date-pickers/base-concepts/base-concepts.md +++ b/docs/data/date-pickers/base-concepts/base-concepts.md @@ -113,10 +113,10 @@ Each _Picker_ is available in a responsive, desktop and mobile variant: - The responsive component (for example `DatePicker`) which renders the desktop component or the mobile one depending on the device it runs on. - The desktop component (for example `DesktopDatePicker`) which works best for mouse devices and large screens. - It renders the views inside a popover and allows editing values directly inside the field. + It renders the views inside a popover and a field for keyboard editing. - The mobile component (for example `MobileDatePicker`) 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. + It renders the view inside a modal and a field for keyboard editing. {{"demo": "ResponsivePickers.js"}} diff --git a/docs/data/date-pickers/date-picker/date-picker.md b/docs/data/date-pickers/date-picker/date-picker.md index 846716836361..b88b4c6801f6 100644 --- a/docs/data/date-pickers/date-picker/date-picker.md +++ b/docs/data/date-pickers/date-picker/date-picker.md @@ -46,10 +46,10 @@ Learn more about the _Controlled and uncontrolled_ pattern in the [React documen The component is available in four variants: - The `DesktopDatePicker` 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. + It renders the views inside a popover and a field for keyboard editing. - The `MobileDatePicker` 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. + It renders the view inside a modal and a field for keyboard editing. - The `DatePicker` component which renders `DesktopDatePicker` or `MobileDatePicker` depending on the device it runs on. diff --git a/docs/data/date-pickers/date-range-picker/date-range-picker.md b/docs/data/date-pickers/date-range-picker/date-range-picker.md index 43e680df8d33..aae228d483b8 100644 --- a/docs/data/date-pickers/date-range-picker/date-range-picker.md +++ b/docs/data/date-pickers/date-range-picker/date-range-picker.md @@ -46,10 +46,10 @@ Learn more about the _Controlled and uncontrolled_ pattern in the [React documen The component is available in four variants: - The `DesktopDateRangePicker` 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. + It renders the views inside a popover and a field for keyboard editing. - The `MobileDateRangePicker` 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. + It renders the view inside a modal and a field for keyboard editing. - The `DateRangePicker` component which renders `DesktopDateRangePicker` or `MobileDateRangePicker` depending on the device it runs on. diff --git a/docs/data/date-pickers/date-time-picker/date-time-picker.md b/docs/data/date-pickers/date-time-picker/date-time-picker.md index 075ec25dd156..dcead399e2fc 100644 --- a/docs/data/date-pickers/date-time-picker/date-time-picker.md +++ b/docs/data/date-pickers/date-time-picker/date-time-picker.md @@ -48,10 +48,10 @@ Learn more about the _Controlled and uncontrolled_ pattern in the [React documen The component is available in four variants: - The `DesktopDateTimePicker` 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. + It renders the views inside a popover and a field for keyboard editing. - The `MobileDateTimePicker` 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. + It renders the view inside a modal and a field for keyboard editing. - The `DateTimePicker` component which renders `DesktopDateTimePicker` or `MobileDateTimePicker` depending on the device it runs on. diff --git a/docs/data/date-pickers/date-time-range-picker/date-time-range-picker.md b/docs/data/date-pickers/date-time-range-picker/date-time-range-picker.md index 92137b72ba81..9bd2cb3da4a4 100644 --- a/docs/data/date-pickers/date-time-range-picker/date-time-range-picker.md +++ b/docs/data/date-pickers/date-time-range-picker/date-time-range-picker.md @@ -47,10 +47,10 @@ Learn more about the _Controlled and uncontrolled_ pattern in the [React documen The component is available in three variants: - The `DesktopDateTimeRangePicker` 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. + It renders the views inside a popover and a field for keyboard editing. - The `MobileDateTimeRangePicker` 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. + It renders the view inside a modal and a field for keyboard editing. - The `DateTimeRangePicker` component which renders `DesktopDateTimeRangePicker` or `MobileDateTimeRangePicker` depending on the device it runs on. diff --git a/docs/data/date-pickers/time-picker/time-picker.md b/docs/data/date-pickers/time-picker/time-picker.md index d6db6b9d53c9..333237139368 100644 --- a/docs/data/date-pickers/time-picker/time-picker.md +++ b/docs/data/date-pickers/time-picker/time-picker.md @@ -47,10 +47,10 @@ Learn more about the _Controlled and uncontrolled_ pattern in the [React documen The component is available in four variants: - The `DesktopTimePicker` 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. + It renders the views inside a popover and a field for keyboard editing. - The `MobileTimePicker` 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. + It renders the view inside a modal and a field for keyboard editing. - The `TimePicker` component which renders `DesktopTimePicker` or `MobileTimePicker` depending on the device it runs on. From 61fc6d56cfb9665c7454fdec1e952a186e5c9b82 Mon Sep 17 00:00:00 2001 From: flavien Date: Wed, 11 Dec 2024 15:00:58 +0100 Subject: [PATCH 77/77] Fix doc --- docs/data/date-pickers/date-picker/date-picker.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/data/date-pickers/date-picker/date-picker.md b/docs/data/date-pickers/date-picker/date-picker.md index b88b4c6801f6..f702279ebb37 100644 --- a/docs/data/date-pickers/date-picker/date-picker.md +++ b/docs/data/date-pickers/date-picker/date-picker.md @@ -125,12 +125,6 @@ You can enable the clearable behavior: See [Field components—Clearable behavior](/x/react-date-pickers/fields/#clearable-behavior) for more details. ::: -:::warning -The clearable prop is not supported yet by the mobile Picker variants. - -See discussion [in this GitHub issue](https://github.com/mui/mui-x/issues/10842#issuecomment-1951887408) for more information. -::: - ## Localization See the [Date format and localization](/x/react-date-pickers/adapters-locale/) and [Translated components](/x/react-date-pickers/localization/) documentation pages for more details.