From 86dde6ee0eff259b1f8fd60fe7b232e5410fc009 Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE Date: Tue, 19 Nov 2024 14:52:23 +0100 Subject: [PATCH] [pickers] Add new properties to `PickerOwnerState` and `PickerContextValue` (#15415) --- .../DateTimeRangePickerToolbar.tsx | 4 +- .../useDesktopRangePicker.tsx | 4 +- .../hooks/useEnrichedRangePickerFieldProps.ts | 14 +-- .../useMobileRangePicker.tsx | 4 +- .../useStaticRangePicker.tsx | 2 +- .../DateTimePicker/DateTimePickerToolbar.tsx | 4 +- .../src/PickersLayout/PickersLayout.types.ts | 4 +- .../internals/components/PickerProvider.tsx | 28 +++++ .../useDesktopPicker/useDesktopPicker.tsx | 2 +- .../hooks/useMobilePicker/useMobilePicker.tsx | 2 +- .../internals/hooks/usePicker/usePicker.ts | 16 +-- .../hooks/usePicker/usePicker.types.ts | 16 ++- .../hooks/usePicker/usePickerLayoutProps.ts | 13 +- .../hooks/usePicker/usePickerOwnerState.ts | 40 ------ .../hooks/usePicker/usePickerProvider.ts | 115 ++++++++++++++++-- .../hooks/usePicker/usePickerValue.ts | 4 +- .../hooks/usePicker/usePickerValue.types.ts | 4 +- .../hooks/usePicker/usePickerViews.ts | 2 + .../hooks/useStaticPicker/useStaticPicker.tsx | 2 +- .../x-date-pickers/src/internals/index.ts | 2 +- .../src/internals/models/common.ts | 4 +- packages/x-date-pickers/src/models/pickers.ts | 18 +++ 22 files changed, 209 insertions(+), 95 deletions(-) delete mode 100644 packages/x-date-pickers/src/internals/hooks/usePicker/usePickerOwnerState.ts diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx index 00e362c8e0674..f9c517d1c2264 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx @@ -9,7 +9,7 @@ import { ExportedBaseToolbarProps, useUtils, DateOrTimeViewWithMeridiem, - WrapperVariant, + PickerVariant, PickerRangeValue, } from '@mui/x-date-pickers/internals'; import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; @@ -43,7 +43,7 @@ export interface DateTimeRangePickerToolbarProps Pick, ExportedDateTimeRangePickerToolbarProps { ampm?: boolean; - toolbarVariant?: WrapperVariant; + toolbarVariant?: PickerVariant; } export interface ExportedDateTimeRangePickerToolbarProps extends ExportedBaseToolbarProps { 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 c34caa11572cb..34d4e46d8008a 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 @@ -97,7 +97,7 @@ export const useDesktopRangePicker = < >({ ...pickerParams, props, - wrapperVariant: 'desktop', + variant: 'desktop', autoFocusView: false, fieldRef: rangePosition === 'start' ? startFieldRef : endFieldRef, localeText, @@ -164,7 +164,7 @@ export const useDesktopRangePicker = < TEnableAccessibleFieldDOMStructure, InferError >({ - wrapperVariant: 'desktop', + variant: 'desktop', fieldType, open, actions, 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 2811bf6cda000..311e018ce3c0f 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts @@ -16,7 +16,7 @@ import { PickersInputLocaleText } from '@mui/x-date-pickers/locales'; import { onSpaceOrEnter, UsePickerResponse, - WrapperVariant, + PickerVariant, DateOrTimeViewWithMeridiem, BaseSingleInputFieldProps, PickerRangeValue, @@ -106,7 +106,7 @@ export interface UseEnrichedRangePickerFieldPropsParams< 'open' | 'actions' >, UseRangePositionResponse { - wrapperVariant: WrapperVariant; + variant: PickerVariant; fieldType: FieldType; readOnly?: boolean; labelId?: string; @@ -134,7 +134,7 @@ const useMultiInputFieldSlotProps = < TEnableAccessibleFieldDOMStructure extends boolean, TError, >({ - wrapperVariant, + variant, open, actions, readOnly, @@ -251,7 +251,7 @@ const useMultiInputFieldSlotProps = < // registering `onClick` listener on the root element as well to correctly handle cases where user is clicking on `label` // which has `pointer-events: none` and due to DOM structure the `input` does not catch the click event ...(!readOnly && !fieldProps.disabled && { onClick: openRangeStartSelection }), - ...(wrapperVariant === 'mobile' && { readOnly: true }), + ...(variant === 'mobile' && { readOnly: true }), }; if (anchorRef) { InputProps = { @@ -268,7 +268,7 @@ const useMultiInputFieldSlotProps = < // registering `onClick` listener on the root element as well to correctly handle cases where user is clicking on `label` // which has `pointer-events: none` and due to DOM structure the `input` does not catch the click event ...(!readOnly && !fieldProps.disabled && { onClick: openRangeEndSelection }), - ...(wrapperVariant === 'mobile' && { readOnly: true }), + ...(variant === 'mobile' && { readOnly: true }), }; InputProps = resolvedComponentProps?.InputProps; } @@ -312,7 +312,7 @@ const useSingleInputFieldSlotProps = < TEnableAccessibleFieldDOMStructure extends boolean, TError, >({ - wrapperVariant, + variant, open, actions, readOnly, @@ -423,7 +423,7 @@ const useSingleInputFieldSlotProps = < }, focused: open ? true : undefined, ...(labelId != null && { id: labelId }), - ...(wrapperVariant === 'mobile' && { readOnly: true }), + ...(variant === 'mobile' && { readOnly: true }), // registering `onClick` listener on the root element as well to correctly handle cases where user is clicking on `label` // which has `pointer-events: none` and due to DOM structure the `input` does not catch the click event ...(!readOnly && !fieldProps.disabled && { onClick: openPicker }), 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 4dba5c2eea8b4..fecc321ac037a 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 @@ -92,7 +92,7 @@ export const useMobileRangePicker = < >({ ...pickerParams, props, - wrapperVariant: 'mobile', + variant: 'mobile', autoFocusView: true, fieldRef: rangePosition === 'start' ? startFieldRef : endFieldRef, localeText, @@ -139,7 +139,7 @@ export const useMobileRangePicker = < TEnableAccessibleFieldDOMStructure, InferError >({ - wrapperVariant: 'mobile', + variant: 'mobile', fieldType, open, actions, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.tsx index a2597d5bb2d1f..43b7b168f4931 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.tsx @@ -55,7 +55,7 @@ export const useStaticRangePicker = < rangePosition, onRangePositionChange, }, - wrapperVariant: displayStaticWrapperAs, + variant: displayStaticWrapperAs, }); const Layout = slots?.layout ?? PickerStaticLayout; diff --git a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx index 594e72c2397fb..8de373712febc 100644 --- a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx +++ b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx @@ -17,7 +17,7 @@ import { DateTimePickerToolbarClasses, getDateTimePickerToolbarUtilityClass, } from './dateTimePickerToolbarClasses'; -import { DateOrTimeViewWithMeridiem, WrapperVariant } from '../internals/models'; +import { DateOrTimeViewWithMeridiem, PickerVariant } from '../internals/models'; import { useMeridiemMode } from '../internals/hooks/date-helpers-hooks'; import { MULTI_SECTION_CLOCK_SECTION_WIDTH } from '../internals/constants/dimensions'; import { formatMeridiem } from '../internals/utils/date-utils'; @@ -35,7 +35,7 @@ export interface ExportedDateTimePickerToolbarProps extends ExportedBaseToolbarP export interface DateTimePickerToolbarProps extends ExportedDateTimePickerToolbarProps, MakeOptional, 'view'> { - toolbarVariant?: WrapperVariant; + toolbarVariant?: PickerVariant; /** * If provided, it will be used instead of `dateTimePickerToolbarTitle` from localization. */ diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.types.ts b/packages/x-date-pickers/src/PickersLayout/PickersLayout.types.ts index fc3f594a45652..f35f7ff6755d3 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.types.ts +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.types.ts @@ -6,7 +6,7 @@ import { BaseToolbarProps, ExportedBaseToolbarProps } from '../internals/models/ import { BaseTabsProps, ExportedBaseTabsProps } from '../internals/models/props/tabs'; import { UsePickerLayoutPropsResponseLayoutProps } from '../internals/hooks/usePicker/usePickerLayoutProps'; import { PickersLayoutClasses } from './pickersLayoutClasses'; -import { DateOrTimeViewWithMeridiem, WrapperVariant } from '../internals/models/common'; +import { DateOrTimeViewWithMeridiem, PickerVariant } from '../internals/models/common'; import { PickersShortcutsProps } from '../PickersShortcuts'; import { ExportedPickersShortcutProps, @@ -35,7 +35,7 @@ export interface ExportedPickersLayoutSlots(null); @@ -11,6 +12,8 @@ export const PickerPrivateContext = React.createContext). + * Is equal to "mobile" when using a mobile picker (like ). + * Is equal to "mobile" or "desktop" when using a responsive picker (like ) depending on the `desktopModeMediaQuery` prop. + * Is equal to "mobile" or "desktop" when using a static picker (like ) depending on the `displayStaticWrapperAs` prop. + * Is always equal to "desktop" if the component you are accessing the ownerState from is not wrapped by a picker. + */ + variant: PickerVariant; + /** + * The orientation of the picker. + * Is equal to "landscape" when the picker is in landscape orientation. + * Is equal to "portrait" when the picker is in portrait orientation. + * You can use the "orientation" on any picker component to force the orientation. + * 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 { /** 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 0650af229e2a2..4d0ae7f7051c5 100644 --- a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx +++ b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx @@ -76,7 +76,7 @@ export const useDesktopPicker = < localeText, autoFocusView: true, additionalViewProps: {}, - wrapperVariant: 'desktop', + variant: 'desktop', }); const InputAdornment = slots.inputAdornment ?? MuiInputAdornment; 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 4b6e52ff244a4..4809144aa6ea4 100644 --- a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx +++ b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx @@ -70,7 +70,7 @@ export const useMobilePicker = < localeText, autoFocusView: true, additionalViewProps: {}, - wrapperVariant: 'mobile', + variant: 'mobile', }); const Field = slots.field; 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 d9693d260b45f..828d8b9df9c76 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts @@ -5,7 +5,6 @@ import { usePickerViews } from './usePickerViews'; import { usePickerLayoutProps } from './usePickerLayoutProps'; import { FieldSection, InferError } from '../../../models'; import { DateOrTimeViewWithMeridiem } from '../../models'; -import { usePickerOwnerState } from './usePickerOwnerState'; import { usePickerProvider } from './usePickerProvider'; export const usePicker = < @@ -18,7 +17,7 @@ export const usePicker = < props, valueManager, valueType, - wrapperVariant, + variant, additionalViewProps, validator, autoFocusView, @@ -44,7 +43,7 @@ export const usePicker = < props, valueManager, valueType, - wrapperVariant, + variant, validator, }); @@ -65,17 +64,18 @@ export const usePicker = < const pickerLayoutResponse = usePickerLayoutProps({ props, - wrapperVariant, + variant, propsFromPickerValue: pickerValueResponse.layoutProps, propsFromPickerViews: pickerViewsResponse.layoutProps, }); - const pickerOwnerState = usePickerOwnerState({ props, pickerValueResponse, valueManager }); - const providerProps = usePickerProvider({ + props, pickerValueResponse, - ownerState: pickerOwnerState, localeText, + valueManager, + variant, + views: pickerViewsResponse.views, }); return { @@ -96,6 +96,6 @@ export const usePicker = < providerProps, // Picker owner state - ownerState: pickerOwnerState, + ownerState: providerProps.privateContextValue.ownerState, }; }; 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 7d10cee30cffd..a2c252d807d4c 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 @@ -10,10 +10,14 @@ import { UsePickerViewsResponse, UsePickerViewsBaseProps, } from './usePickerViews'; -import { UsePickerLayoutProps, UsePickerLayoutPropsResponse } from './usePickerLayoutProps'; +import { UsePickerLayoutPropsResponse } from './usePickerLayoutProps'; import { FieldSection, PickerOwnerState } from '../../../models'; import { DateOrTimeViewWithMeridiem } from '../../models'; -import { UsePickerProviderParameters, UsePickerProviderReturnValue } from './usePickerProvider'; +import { + UsePickerProviderParameters, + UsePickerProviderProps, + UsePickerProviderReturnValue, +} from './usePickerProvider'; /** * Props common to all picker headless implementations. @@ -26,7 +30,7 @@ export interface UsePickerBaseProps< TAdditionalProps extends {}, > extends UsePickerValueBaseProps, UsePickerViewsBaseProps, - UsePickerLayoutProps {} + UsePickerProviderProps {} export interface UsePickerProps< TValue, @@ -36,7 +40,7 @@ export interface UsePickerProps< TAdditionalProps extends {}, > extends UsePickerValueProps, UsePickerViewsProps, - UsePickerLayoutProps {} + UsePickerProviderProps {} export interface UsePickerParams< TValue, @@ -46,7 +50,7 @@ export interface UsePickerParams< TAdditionalProps extends {}, > extends Pick< UsePickerValueParams, - 'valueManager' | 'valueType' | 'wrapperVariant' | 'validator' + 'valueManager' | 'valueType' | 'variant' | 'validator' >, Pick< UsePickerViewParams, @@ -62,7 +66,7 @@ export interface UsePickerResponse< TSection extends FieldSection, TError, > extends Omit, 'viewProps' | 'layoutProps'>, - Omit, 'layoutProps'>, + Omit, 'layoutProps' | 'views'>, UsePickerLayoutPropsResponse { ownerState: PickerOwnerState; providerProps: UsePickerProviderReturnValue; diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerLayoutProps.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerLayoutProps.ts index f4719f207179a..d49fd082adf3c 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerLayoutProps.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerLayoutProps.ts @@ -2,14 +2,13 @@ import { useRtl } from '@mui/system/RtlProvider'; import { useIsLandscape } from '../useIsLandscape'; import { UsePickerValueLayoutResponse } from './usePickerValue.types'; import { UsePickerViewsLayoutResponse } from './usePickerViews'; -import { DateOrTimeViewWithMeridiem, WrapperVariant } from '../../models/common'; +import { DateOrTimeViewWithMeridiem, PickerVariant } from '../../models/common'; import { FormProps } from '../../models'; /** * Props used to create the layout of the views. - * Those props are exposed on all the pickers. */ -export interface UsePickerLayoutProps extends FormProps { +interface UsePickerLayoutProps extends FormProps { /** * Force rendering in particular orientation. */ @@ -24,7 +23,7 @@ export interface UsePickerLayoutPropsResponseLayoutProps< UsePickerLayoutProps { isLandscape: boolean; isRtl: boolean; - wrapperVariant: WrapperVariant; + wrapperVariant: PickerVariant; isValid: (value: TValue) => boolean; } @@ -36,7 +35,7 @@ export interface UsePickerLayoutPropsParams; propsFromPickerViews: UsePickerViewsLayoutResponse; - wrapperVariant: WrapperVariant; + variant: PickerVariant; } /** @@ -46,7 +45,7 @@ export const usePickerLayoutProps = ): UsePickerLayoutPropsResponse => { const { orientation } = props; const isLandscape = useIsLandscape(propsFromPickerViews.views, orientation); @@ -57,7 +56,7 @@ export const usePickerLayoutProps = { - props: UsePickerProps; - pickerValueResponse: UsePickerValueResponse; - valueManager: PickerValueManager; -} - -export function usePickerOwnerState( - parameters: UsePickerOwnerStateParameters, -): PickerOwnerState { - const { props, pickerValueResponse, valueManager } = parameters; - - const utils = useUtils(); - - return React.useMemo( - () => ({ - isPickerValueEmpty: valueManager.areValuesEqual( - utils, - pickerValueResponse.viewProps.value, - valueManager.emptyValue, - ), - isPickerOpen: pickerValueResponse.open, - isPickerDisabled: props.disabled ?? false, - isPickerReadOnly: props.readOnly ?? false, - }), - [ - utils, - valueManager, - pickerValueResponse.viewProps.value, - pickerValueResponse.open, - props.disabled, - props.readOnly, - ], - ); -} 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 67e8d1eab3514..9933c91bb14d7 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts @@ -1,35 +1,114 @@ import * as React from 'react'; +import useEnhancedEffect from '@mui/utils/useEnhancedEffect'; import { FieldSection, PickerOwnerState } from '../../../models'; -import { UsePickerValueResponse } from './usePickerValue.types'; +import { PickerValueManager, UsePickerValueResponse } from './usePickerValue.types'; import { PickerProviderProps, PickerContextValue, PickerPrivateContextValue, } from '../../components/PickerProvider'; +import type { UsePickerProps } from './usePicker.types'; +import { + DateOrTimeViewWithMeridiem, + FormProps, + PickerOrientation, + PickerVariant, +} from '../../models'; +import { useUtils } from '../useUtils'; +import { arrayIncludes } from '../../utils/utils'; -export interface UsePickerProviderParameters - extends Pick { - pickerValueResponse: UsePickerValueResponse; - ownerState: PickerOwnerState; +function getOrientation(): PickerOrientation { + if (typeof window === 'undefined') { + return 'portrait'; + } + + if (window.screen && window.screen.orientation && window.screen.orientation.angle) { + return Math.abs(window.screen.orientation.angle) === 90 ? 'landscape' : 'portrait'; + } + + // Support IOS safari + if (window.orientation) { + return Math.abs(Number(window.orientation)) === 90 ? 'landscape' : 'portrait'; + } + + return 'portrait'; } -export interface UsePickerProviderReturnValue extends Omit {} +export const usePickerOrientation = ( + views: readonly DateOrTimeViewWithMeridiem[], + customOrientation: PickerOrientation | undefined, +): PickerOrientation => { + const [orientation, setOrientation] = React.useState(getOrientation); + + useEnhancedEffect(() => { + const eventHandler = () => { + setOrientation(getOrientation()); + }; + window.addEventListener('orientationchange', eventHandler); + return () => { + window.removeEventListener('orientationchange', eventHandler); + }; + }, []); + + if (arrayIncludes(views, ['hours', 'minutes', 'seconds'])) { + // could not display 13:34:44 in landscape mode + return 'portrait'; + } + + return customOrientation ?? orientation; +}; export function usePickerProvider( parameters: UsePickerProviderParameters, ): UsePickerProviderReturnValue { - const { pickerValueResponse, ownerState, localeText } = parameters; + const { props, pickerValueResponse, valueManager, localeText, variant, views } = parameters; + + const utils = useUtils(); + const orientation = usePickerOrientation(views, props.orientation); + + const ownerState = React.useMemo( + () => ({ + isPickerValueEmpty: valueManager.areValuesEqual( + utils, + pickerValueResponse.viewProps.value, + valueManager.emptyValue, + ), + isPickerOpen: pickerValueResponse.open, + isPickerDisabled: props.disabled ?? false, + isPickerReadOnly: props.readOnly ?? false, + pickerOrientation: orientation, + pickerVariant: variant, + }), + [ + utils, + valueManager, + pickerValueResponse.viewProps.value, + pickerValueResponse.open, + orientation, + variant, + props.disabled, + props.readOnly, + ], + ); const contextValue = React.useMemo( () => ({ onOpen: pickerValueResponse.actions.onOpen, onClose: pickerValueResponse.actions.onClose, open: pickerValueResponse.open, + disabled: props.disabled ?? false, + readOnly: props.readOnly ?? false, + variant, + orientation, }), [ pickerValueResponse.actions.onOpen, pickerValueResponse.actions.onClose, pickerValueResponse.open, + variant, + orientation, + props.disabled, + props.readOnly, ], ); @@ -44,3 +123,25 @@ export function usePickerProvider( privateContextValue, }; } + +export interface UsePickerProviderParameters + extends Pick { + props: UsePickerProps; + pickerValueResponse: UsePickerValueResponse; + valueManager: PickerValueManager; + variant: PickerVariant; + views: readonly DateOrTimeViewWithMeridiem[]; +} + +export interface UsePickerProviderReturnValue extends Omit {} + +/** + * Props used to create the private context. + * Those props are exposed on all the pickers. + */ +export interface UsePickerProviderProps extends FormProps { + /** + * Force rendering in particular orientation. + */ + orientation?: PickerOrientation; +} 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 b24fbad5f0e8d..7b76c62ae2d74 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts @@ -152,7 +152,7 @@ export const usePickerValue = < props, valueManager, valueType, - wrapperVariant, + variant, validator, }: UsePickerValueParams): UsePickerValueResponse< TValue, @@ -166,7 +166,7 @@ export const usePickerValue = < onChange, value: inValueWithoutRenderTimezone, defaultValue: inDefaultValue, - closeOnSelect = wrapperVariant === 'desktop' && !valueType.includes('time'), + closeOnSelect = variant === 'desktop' && !valueType.includes('time'), timezone: timezoneProp, } = props; 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 f88a9b6b8962e..5a6b85ef37457 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,6 +1,6 @@ import { FieldChangeHandlerContext, UseFieldInternalProps } from '../useField'; import { Validator } from '../../../validation'; -import { WrapperVariant } from '../../models/common'; +import { PickerVariant } from '../../models/common'; import { FieldSection, TimezoneProps, @@ -266,7 +266,7 @@ export interface UsePickerValueParams< props: TExternalProps; valueManager: PickerValueManager>; valueType: PickerValueType; - wrapperVariant: WrapperVariant; + variant: PickerVariant; validator: Validator, TExternalProps>; } 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 6c26364f8bd46..2e5c4abab94ec 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts @@ -129,6 +129,7 @@ export interface UsePickerViewsResponse React.ReactNode; shouldRestoreFocus: () => boolean; layoutProps: UsePickerViewsLayoutResponse; @@ -272,6 +273,7 @@ export const usePickerViews = < return { hasUIView, + views, shouldRestoreFocus, layoutProps, renderCurrentView: () => { diff --git a/packages/x-date-pickers/src/internals/hooks/useStaticPicker/useStaticPicker.tsx b/packages/x-date-pickers/src/internals/hooks/useStaticPicker/useStaticPicker.tsx index 15ffa93d984e2..1464a724d965d 100644 --- a/packages/x-date-pickers/src/internals/hooks/useStaticPicker/useStaticPicker.tsx +++ b/packages/x-date-pickers/src/internals/hooks/useStaticPicker/useStaticPicker.tsx @@ -44,7 +44,7 @@ export const useStaticPicker = < fieldRef: undefined, localeText, additionalViewProps: {}, - wrapperVariant: displayStaticWrapperAs, + variant: displayStaticWrapperAs, }); const Layout = slots?.layout ?? PickerStaticLayout; diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index 56be2c11a7ac5..58791c5d2476e 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -107,7 +107,7 @@ export type { BaseTabsProps, ExportedBaseTabsProps } from './models/props/tabs'; export type { BaseToolbarProps, ExportedBaseToolbarProps } from './models/props/toolbar'; export type { FormProps } from './models/formProps'; export type { - WrapperVariant, + PickerVariant, TimeViewWithMeridiem, DateOrTimeViewWithMeridiem, } from './models/common'; diff --git a/packages/x-date-pickers/src/internals/models/common.ts b/packages/x-date-pickers/src/internals/models/common.ts index 702ab2e87a08e..6c4a62e47d9ee 100644 --- a/packages/x-date-pickers/src/internals/models/common.ts +++ b/packages/x-date-pickers/src/internals/models/common.ts @@ -1,6 +1,8 @@ import { DateView, TimeView } from '../../models/views'; -export type WrapperVariant = 'mobile' | 'desktop' | null; +export type PickerOrientation = 'portrait' | 'landscape'; + +export type PickerVariant = 'mobile' | 'desktop' | null; export type TimeViewWithMeridiem = TimeView | 'meridiem'; diff --git a/packages/x-date-pickers/src/models/pickers.ts b/packages/x-date-pickers/src/models/pickers.ts index 69a2750e20f15..65f0bbc213acc 100644 --- a/packages/x-date-pickers/src/models/pickers.ts +++ b/packages/x-date-pickers/src/models/pickers.ts @@ -1,3 +1,4 @@ +import { PickerOrientation, PickerVariant } from '../internals/models/common'; import type { PickersShortcutsItemContext } from '../PickersShortcuts'; export interface PickerChangeHandlerContext { @@ -36,4 +37,21 @@ export interface PickerOwnerState { * Is always `false` if the component you are accessing the ownerState from is not wrapped by a picker. */ isPickerReadOnly: boolean; + /** + * The responsive variant of the picker. + * Is equal to "desktop" when using a desktop picker (like ). + * Is equal to "mobile" when using a mobile picker (like ). + * Is equal to "mobile" or "desktop" when using a responsive picker (like ) depending on the `desktopModeMediaQuery` prop. + * Is equal to "mobile" or "desktop" when using a static picker (like ) depending on the `displayStaticWrapperAs` prop. + * Is always equal to "desktop" if the component you are accessing the ownerState from is not wrapped by a picker. + */ + pickerVariant: PickerVariant; + /** + * The orientation of the picker. + * Is equal to "landscape" when the picker is in landscape orientation. + * Is equal to "portrait" when the picker is in portrait orientation. + * You can use the "orientation" on any picker component to force the orientation. + * Is always equal to "portrait" if the component you are accessing the ownerState from is not wrapped by a picker. + */ + pickerOrientation: PickerOrientation; }