From 9a8aa052c124538f491f830f235197ffde26ef9c Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE Date: Thu, 19 Dec 2024 16:55:31 +0100 Subject: [PATCH] [pickers] Use `usePickerContext()` and `usePickerActionsContext()` to get the actions in the `actionBar` slot and in internal components (#15843) Signed-off-by: Flavien DELANGLE Co-authored-by: Michel Engelen <32863416+michelengelen@users.noreply.github.com> --- .../custom-components/ActionBarComponent.js | 17 ++- .../custom-components/ActionBarComponent.tsx | 17 ++- .../custom-layout/AddComponent.js | 18 ++- .../custom-layout/AddComponent.tsx | 19 ++- .../custom-layout/MovingActions.js | 15 +- .../custom-layout/MovingActions.tsx | 15 +- .../migration-pickers-v7.md | 72 ++++++++- .../useDesktopRangePicker.tsx | 12 +- .../hooks/useEnrichedRangePickerFieldProps.ts | 17 ++- .../useMobileRangePicker.tsx | 9 +- .../DesktopDateTimePickerLayout.tsx | 7 - .../PickersActionBar.test.tsx | 111 ++++---------- .../src/PickersActionBar/PickersActionBar.tsx | 21 +-- .../src/PickersLayout/PickersLayout.tsx | 7 - .../src/PickersLayout/usePickerLayout.tsx | 8 - packages/x-date-pickers/src/hooks/index.tsx | 4 +- .../src/hooks/usePickerActionsContext.ts | 20 +++ .../internals/components/PickerProvider.tsx | 25 +++- .../components/PickersModalDialog.tsx | 13 +- .../internals/components/PickersPopper.tsx | 18 +-- .../useDesktopPicker/useDesktopPicker.tsx | 12 +- .../hooks/useMobilePicker/useMobilePicker.tsx | 12 +- .../internals/hooks/usePicker/usePicker.ts | 2 - .../hooks/usePicker/usePicker.types.ts | 2 +- .../hooks/usePicker/usePickerProvider.ts | 5 +- .../hooks/usePicker/usePickerValue.ts | 137 +++++++++--------- .../hooks/usePicker/usePickerValue.types.ts | 59 +++++--- .../hooks/usePicker/usePickerViews.ts | 8 +- .../x-date-pickers/src/internals/index.ts | 2 +- .../themeAugmentation.spec.ts | 2 +- scripts/x-date-pickers-pro.exports.json | 1 + scripts/x-date-pickers.exports.json | 1 + 32 files changed, 377 insertions(+), 311 deletions(-) create mode 100644 packages/x-date-pickers/src/hooks/usePickerActionsContext.ts diff --git a/docs/data/date-pickers/custom-components/ActionBarComponent.js b/docs/data/date-pickers/custom-components/ActionBarComponent.js index 94e402db3cb9d..f4eb08d5a5b79 100644 --- a/docs/data/date-pickers/custom-components/ActionBarComponent.js +++ b/docs/data/date-pickers/custom-components/ActionBarComponent.js @@ -9,11 +9,16 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { StaticDatePicker } from '@mui/x-date-pickers/StaticDatePicker'; -import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; +import { + usePickerActionsContext, + usePickerTranslations, +} from '@mui/x-date-pickers/hooks'; function CustomActionBar(props) { - const { onAccept, onClear, onCancel, onSetToday, actions, className } = props; + const { actions, className } = props; const translations = usePickerTranslations(); + const { clearValue, setValueToToday, acceptValueChanges, cancelValueChanges } = + usePickerActionsContext(); const [anchorEl, setAnchorEl] = React.useState(null); const open = Boolean(anchorEl); const id = useId(); @@ -28,7 +33,7 @@ function CustomActionBar(props) { return ( { - onClear(); + clearValue(); setAnchorEl(null); }} key={actionType} @@ -42,7 +47,7 @@ function CustomActionBar(props) { { setAnchorEl(null); - onCancel(); + cancelValueChanges(); }} key={actionType} > @@ -55,7 +60,7 @@ function CustomActionBar(props) { { setAnchorEl(null); - onAccept(); + acceptValueChanges(); }} key={actionType} > @@ -68,7 +73,7 @@ function CustomActionBar(props) { { setAnchorEl(null); - onSetToday(); + setValueToToday(); }} key={actionType} > diff --git a/docs/data/date-pickers/custom-components/ActionBarComponent.tsx b/docs/data/date-pickers/custom-components/ActionBarComponent.tsx index e28c354c962a4..e69413bb2645f 100644 --- a/docs/data/date-pickers/custom-components/ActionBarComponent.tsx +++ b/docs/data/date-pickers/custom-components/ActionBarComponent.tsx @@ -9,11 +9,16 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { StaticDatePicker } from '@mui/x-date-pickers/StaticDatePicker'; import { PickersActionBarProps } from '@mui/x-date-pickers/PickersActionBar'; -import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; +import { + usePickerActionsContext, + usePickerTranslations, +} from '@mui/x-date-pickers/hooks'; function CustomActionBar(props: PickersActionBarProps) { - const { onAccept, onClear, onCancel, onSetToday, actions, className } = props; + const { actions, className } = props; const translations = usePickerTranslations(); + const { clearValue, setValueToToday, acceptValueChanges, cancelValueChanges } = + usePickerActionsContext(); const [anchorEl, setAnchorEl] = React.useState(null); const open = Boolean(anchorEl); const id = useId(); @@ -28,7 +33,7 @@ function CustomActionBar(props: PickersActionBarProps) { return ( { - onClear(); + clearValue(); setAnchorEl(null); }} key={actionType} @@ -41,7 +46,7 @@ function CustomActionBar(props: PickersActionBarProps) { { setAnchorEl(null); - onCancel(); + cancelValueChanges(); }} key={actionType} > @@ -53,7 +58,7 @@ function CustomActionBar(props: PickersActionBarProps) { { setAnchorEl(null); - onAccept(); + acceptValueChanges(); }} key={actionType} > @@ -65,7 +70,7 @@ function CustomActionBar(props: PickersActionBarProps) { { setAnchorEl(null); - onSetToday(); + setValueToToday(); }} key={actionType} > diff --git a/docs/data/date-pickers/custom-layout/AddComponent.js b/docs/data/date-pickers/custom-layout/AddComponent.js index 0e904ef3d2889..c17022f0ec918 100644 --- a/docs/data/date-pickers/custom-layout/AddComponent.js +++ b/docs/data/date-pickers/custom-layout/AddComponent.js @@ -8,7 +8,6 @@ import ListItemText from '@mui/material/ListItemText'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { StaticDatePicker } from '@mui/x-date-pickers/StaticDatePicker'; - import RestaurantIcon from '@mui/icons-material/Restaurant'; import { usePickerLayout, @@ -17,17 +16,22 @@ import { PickersLayoutContentWrapper, } from '@mui/x-date-pickers/PickersLayout'; +import { usePickerActionsContext } from '@mui/x-date-pickers/hooks'; + function ActionList(props) { - const { onAccept, onClear, onCancel, onSetToday } = props; + const { className } = props; + const { clearValue, setValueToToday, acceptValueChanges, cancelValueChanges } = + usePickerActionsContext(); + const actions = [ - { text: 'Accept', method: onAccept }, - { text: 'Clear', method: onClear }, - { text: 'Cancel', method: onCancel }, - { text: 'Today', method: onSetToday }, + { text: 'Accept', method: acceptValueChanges }, + { text: 'Clear', method: clearValue }, + { text: 'Cancel', method: cancelValueChanges }, + { text: 'Today', method: setValueToToday }, ]; return ( - + {actions.map(({ text, method }) => ( diff --git a/docs/data/date-pickers/custom-layout/AddComponent.tsx b/docs/data/date-pickers/custom-layout/AddComponent.tsx index 9fc41c2b0666b..837f63dd89fe8 100644 --- a/docs/data/date-pickers/custom-layout/AddComponent.tsx +++ b/docs/data/date-pickers/custom-layout/AddComponent.tsx @@ -8,7 +8,6 @@ import ListItemText from '@mui/material/ListItemText'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { StaticDatePicker } from '@mui/x-date-pickers/StaticDatePicker'; -import { PickersActionBarProps } from '@mui/x-date-pickers/PickersActionBar'; import RestaurantIcon from '@mui/icons-material/Restaurant'; import { PickersLayoutProps, @@ -18,17 +17,23 @@ import { PickersLayoutContentWrapper, } from '@mui/x-date-pickers/PickersLayout'; import { DateView } from '@mui/x-date-pickers/models'; +import { PickersActionBarProps } from '@mui/x-date-pickers/PickersActionBar'; +import { usePickerActionsContext } from '@mui/x-date-pickers/hooks'; function ActionList(props: PickersActionBarProps) { - const { onAccept, onClear, onCancel, onSetToday } = props; + const { className } = props; + const { clearValue, setValueToToday, acceptValueChanges, cancelValueChanges } = + usePickerActionsContext(); + const actions = [ - { text: 'Accept', method: onAccept }, - { text: 'Clear', method: onClear }, - { text: 'Cancel', method: onCancel }, - { text: 'Today', method: onSetToday }, + { text: 'Accept', method: acceptValueChanges }, + { text: 'Clear', method: clearValue }, + { text: 'Cancel', method: cancelValueChanges }, + { text: 'Today', method: setValueToToday }, ]; + return ( - + {actions.map(({ text, method }) => ( diff --git a/docs/data/date-pickers/custom-layout/MovingActions.js b/docs/data/date-pickers/custom-layout/MovingActions.js index 09ade4dcee744..be4da62f76096 100644 --- a/docs/data/date-pickers/custom-layout/MovingActions.js +++ b/docs/data/date-pickers/custom-layout/MovingActions.js @@ -8,13 +8,18 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { pickersLayoutClasses } from '@mui/x-date-pickers/PickersLayout'; import { StaticDatePicker } from '@mui/x-date-pickers/StaticDatePicker'; +import { usePickerActionsContext } from '@mui/x-date-pickers/hooks'; + function ActionList(props) { - const { onAccept, onClear, onCancel, onSetToday, className } = props; + const { className } = props; + const { clearValue, setValueToToday, acceptValueChanges, cancelValueChanges } = + usePickerActionsContext(); + const actions = [ - { text: 'Accept', method: onAccept }, - { text: 'Clear', method: onClear }, - { text: 'Cancel', method: onCancel }, - { text: 'Today', method: onSetToday }, + { text: 'Accept', method: acceptValueChanges }, + { text: 'Clear', method: clearValue }, + { text: 'Cancel', method: cancelValueChanges }, + { text: 'Today', method: setValueToToday }, ]; return ( diff --git a/docs/data/date-pickers/custom-layout/MovingActions.tsx b/docs/data/date-pickers/custom-layout/MovingActions.tsx index cc2af78da992c..e8a42e3a195d3 100644 --- a/docs/data/date-pickers/custom-layout/MovingActions.tsx +++ b/docs/data/date-pickers/custom-layout/MovingActions.tsx @@ -8,15 +8,20 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { pickersLayoutClasses } from '@mui/x-date-pickers/PickersLayout'; import { StaticDatePicker } from '@mui/x-date-pickers/StaticDatePicker'; import { PickersActionBarProps } from '@mui/x-date-pickers/PickersActionBar'; +import { usePickerActionsContext } from '@mui/x-date-pickers/hooks'; function ActionList(props: PickersActionBarProps) { - const { onAccept, onClear, onCancel, onSetToday, className } = props; + const { className } = props; + const { clearValue, setValueToToday, acceptValueChanges, cancelValueChanges } = + usePickerActionsContext(); + const actions = [ - { text: 'Accept', method: onAccept }, - { text: 'Clear', method: onClear }, - { text: 'Cancel', method: onCancel }, - { text: 'Today', method: onSetToday }, + { text: 'Accept', method: acceptValueChanges }, + { text: 'Clear', method: clearValue }, + { text: 'Cancel', method: cancelValueChanges }, + { text: 'Today', method: setValueToToday }, ]; + return ( // Propagate the className such that CSS selectors can be applied 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 6bc805040ba90..62df8c1afa4c8 100644 --- a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md +++ b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md @@ -393,7 +393,7 @@ This change causes a few breaking changes: } ``` -- The component passed to the `layout` slot no longer receives an `orientation` and the `isLandscape` props, instead you can use the `usePickerContext` hook: +- The component passed to the `layout` slot no longer receives the `orientation` and `isLandscape` props, instead you can use the `usePickerContext` hook: ```diff -console.log(props.orientation); @@ -415,6 +415,51 @@ This change causes a few breaking changes: +console.log(variant); ``` +- The component passed to the `layout` slot no longer receives the `onClear`, `onSetToday`, `onAccept`, `onCancel`, `onOpen`, `onClose` and `onDismiss` props, instead you can use the `usePickerActionsContext` or the `usePickerContext` hooks: + + ```diff + +import { usePickerActionsContext } from '@mui/x-date-pickers/hooks'; + + -const { onClear } = props; + +const { clearValue } = usePickerActionsContext(); + + -const { onSetToday } = props; + +const { setValueToToday } = usePickerActionsContext(); + + -const { onAccept } = props; + +const { acceptValueChanges } = usePickerActionsContext(); + + -const { onCancel } = props; + +const { cancelValueChanges } = usePickerActionsContext(); + + -const { onOpen } = props; + +const { setOpen } = usePickerActionsContext(); + +const onOpen = event => { + + event.preventDefault(); + + setOpen(true); + +} + + -props.onClose(); + +const { setOpen } = usePickerActionsContext(); + +const onClose = event => { + + event.preventDefault(); + + setOpen(false); + +} + + // This contains a small behavior change. + // If the picker is not controlled and has a default value, + // opening it and calling `acceptValueChanges` without any change will call `onAccept` with the default value. + // Whereas before, opening it and calling `onDimiss` without any change would not have called `onAccept`. + -const { onDismiss } = props; + +const { acceptValueChanges } = usePickerActionsContext(); + +const onDismiss = acceptValueChanges + ``` + + :::success + The `usePickerContext` also contain all the actions returned by `usePickerActionsContext`. + The only difference is that `usePickerActionsContext` only contains variables with stable references that won't cause a re-render of your component. + ::: + ### Slot: `toolbar` - The component passed to the `toolbar` slot no longer receives a `disabled` prop, instead you can use the `usePickerContext` hook: @@ -435,6 +480,31 @@ This change causes a few breaking changes: +console.log(readOnly); ``` +### Slot: `actionBar` + +- The component passed to the `actionBar` slot no longer receives the `onClear`, `onSetToday`, `onAccept` and `onCancel` props. You can use the `usePickerActionsContext` or the `usePickerContext` hooks instead: + + ```diff + +import { usePickerActionsContext } from '@mui/x-date-pickers/hooks'; + + -const { onClear } = props; + +const { clearValue } = usePickerActionsContext(); + + -const { onSetToday } = props; + +const { setValueToToday } = usePickerActionsContext(); + + -const { onAccept } = props; + +const { acceptValueChanges } = usePickerActionsContext(); + + -const { onCancel } = props; + +const { cancelValueChanges } = usePickerActionsContext(); + ``` + + :::success + The `usePickerContext` also contain all the actions returned by `usePickerActionsContext`. + The only difference is that `usePickerActionsContext` only contains variables with stable references that won't cause a re-render of your component. + ::: + ## Renamed variables and types The following variables and types have been renamed to have a coherent `Picker` / `Pickers` prefix: 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 4dabe621a1e73..e4910f76bb6a4 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 @@ -90,8 +90,6 @@ export const useDesktopRangePicker = < } const { - open, - actions, layoutProps, providerProps, renderCurrentView, @@ -127,7 +125,8 @@ export const useDesktopRangePicker = < return; } - actions.onDismiss(); + // This direct access to `providerProps` will go away once the range fields stop having their views in a tooltip. + providerProps.privateContextValue.dismissViews(); }); }; @@ -170,8 +169,9 @@ export const useDesktopRangePicker = < >({ variant: 'desktop', fieldType, - open, - actions, + // These direct access to `providerProps` will go away once the range fields handle the picker opening + open: providerProps.contextValue.open, + setOpen: providerProps.contextValue.setOpen, readOnly, disableOpenPicker, label, @@ -215,8 +215,6 @@ export const useDesktopRangePicker = < containerRef={popperRef} anchorEl={anchorRef.current} onBlur={handleBlur} - {...actions} - open={open} slots={slots} slotProps={slotProps} shouldRestoreFocus={shouldRestoreFocus} 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 a858ae3df40b3..99bd3516edfba 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts @@ -20,7 +20,7 @@ import { import { PickersInputLocaleText } from '@mui/x-date-pickers/locales'; import { onSpaceOrEnter, - UsePickerResponse, + UsePickerValueContextValue, PickerVariant, DateOrTimeViewWithMeridiem, BaseSingleInputFieldProps, @@ -91,7 +91,7 @@ export interface UseEnrichedRangePickerFieldPropsParams< TView extends DateOrTimeViewWithMeridiem, TEnableAccessibleFieldDOMStructure extends boolean, TError, -> extends Pick, 'open' | 'actions'>, +> extends Pick, UseRangePositionResponse { variant: PickerVariant; fieldType: FieldType; @@ -124,7 +124,7 @@ const useMultiInputFieldSlotProps = < >({ variant, open, - actions, + setOpen, readOnly, labelId, disableOpenPicker, @@ -180,7 +180,8 @@ const useMultiInputFieldSlotProps = < event.stopPropagation(); onRangePositionChange('start'); if (!readOnly && !disableOpenPicker) { - actions.onOpen(event); + event.preventDefault(); + setOpen(true); } }; @@ -188,7 +189,8 @@ const useMultiInputFieldSlotProps = < event.stopPropagation(); onRangePositionChange('end'); if (!readOnly && !disableOpenPicker) { - actions.onOpen(event); + event.preventDefault(); + setOpen(true); } }; @@ -297,7 +299,7 @@ const useSingleInputFieldSlotProps = < >({ variant, open, - actions, + setOpen, readOnly, labelId, disableOpenPicker, @@ -371,7 +373,8 @@ const useSingleInputFieldSlotProps = < event.stopPropagation(); if (!readOnly && !disableOpenPicker) { - actions.onOpen(event); + event.preventDefault(); + setOpen(true); } }; 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 32b4ac1dab036..8164a5da2fea9 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 @@ -86,8 +86,6 @@ export const useMobileRangePicker = < } const { - open, - actions, layoutProps, providerProps, renderCurrentView, @@ -145,8 +143,9 @@ export const useMobileRangePicker = < >({ variant: 'mobile', fieldType, - open, - actions, + // These direct access to `providerProps` will go away once the range fields handle the picker opening + open: providerProps.contextValue.open, + setOpen: providerProps.contextValue.setOpen, readOnly, labelId, disableOpenPicker, @@ -213,7 +212,7 @@ export const useMobileRangePicker = < const renderPicker = () => ( - + ', () => { const { render } = createPickerRenderer({ clock: 'fake' }); + const renderWithContext = (element: React.ReactElement) => { + const spys = { + setOpen: spy(), + clearValue: spy(), + setValueToToday: spy(), + acceptValueChanges: spy(), + cancelValueChanges: spy(), + }; + + render({element}); + + return spys; + }; + it('should not render buttons if actions array is empty', () => { - const onAccept = () => {}; - const onClear = () => {}; - const onCancel = () => {}; - const onSetToday = () => {}; - render( - , - ); + renderWithContext(); expect(screen.queryByRole('button')).to.equal(null); }); it('should render button for "clear" action calling the associated callback', () => { - const onAccept = spy(); - const onClear = spy(); - const onCancel = spy(); - const onSetToday = spy(); - - render( - , - ); + const { clearValue } = renderWithContext(); fireEvent.click(screen.getByText(/clear/i)); - expect(onClear.callCount).to.equal(1); + expect(clearValue.callCount).to.equal(1); }); it('should render button for "cancel" action calling the associated callback', () => { - const onAccept = spy(); - const onClear = spy(); - const onCancel = spy(); - const onSetToday = spy(); - - render( - , - ); + const { cancelValueChanges } = renderWithContext(); fireEvent.click(screen.getByText(/cancel/i)); - expect(onCancel.callCount).to.equal(1); + expect(cancelValueChanges.callCount).to.equal(1); }); it('should render button for "accept" action calling the associated callback', () => { - const onAccept = spy(); - const onClear = spy(); - const onCancel = spy(); - const onSetToday = spy(); - - render( - , - ); + const { acceptValueChanges } = renderWithContext(); fireEvent.click(screen.getByText(/ok/i)); - expect(onAccept.callCount).to.equal(1); + expect(acceptValueChanges.callCount).to.equal(1); }); it('should render button for "today" action calling the associated callback', () => { - const onAccept = spy(); - const onClear = spy(); - const onCancel = spy(); - const onSetToday = spy(); - - render( - , - ); + const { setValueToToday } = renderWithContext(); fireEvent.click(screen.getByText(/today/i)); - expect(onSetToday.callCount).to.equal(1); + expect(setValueToToday.callCount).to.equal(1); }); it('should respect actions order', () => { - const onAccept = () => {}; - const onClear = () => {}; - const onCancel = () => {}; - const onSetToday = () => {}; - render( - , - ); + renderWithContext(); const buttons = screen.getAllByRole('button'); diff --git a/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.tsx b/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.tsx index 54bd78c6dea02..8551bbf6d7fa5 100644 --- a/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.tsx +++ b/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.tsx @@ -5,6 +5,7 @@ import { styled } from '@mui/material/styles'; import Button from '@mui/material/Button'; import DialogActions, { DialogActionsProps } from '@mui/material/DialogActions'; import { usePickerTranslations } from '../hooks/usePickerTranslations'; +import { usePickerActionsContext } from '../hooks'; export type PickersActionBarAction = 'clear' | 'cancel' | 'accept' | 'today'; @@ -15,10 +16,6 @@ export interface PickersActionBarProps extends DialogActionsProps { * @default `['cancel', 'accept']` for mobile and `[]` for desktop */ actions?: PickersActionBarAction[]; - onAccept: () => void; - onClear: () => void; - onCancel: () => void; - onSetToday: () => void; } const PickersActionBarRoot = styled(DialogActions, { @@ -38,9 +35,11 @@ const PickersActionBarRoot = styled(DialogActions, { * - [PickersActionBar API](https://mui.com/x/api/date-pickers/pickers-action-bar/) */ function PickersActionBar(props: PickersActionBarProps) { - const { onAccept, onClear, onCancel, onSetToday, actions, ...other } = props; + const { actions, ...other } = props; const translations = usePickerTranslations(); + const { clearValue, setValueToToday, acceptValueChanges, cancelValueChanges } = + usePickerActionsContext(); if (actions == null || actions.length === 0) { return null; @@ -50,28 +49,28 @@ function PickersActionBar(props: PickersActionBarProps) { switch (actionType) { case 'clear': return ( - ); case 'cancel': return ( - ); case 'accept': return ( - ); case 'today': return ( - ); @@ -100,10 +99,6 @@ PickersActionBar.propTypes = { * @default false */ disableSpacing: PropTypes.bool, - onAccept: PropTypes.func.isRequired, - onCancel: PropTypes.func.isRequired, - onClear: PropTypes.func.isRequired, - onSetToday: PropTypes.func.isRequired, /** * The system prop that allows defining system overrides as well as additional CSS styles. */ diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx index db7d88b6f2a71..7a7908fc3d900 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx @@ -154,15 +154,8 @@ PickersLayout.propTypes = { classes: PropTypes.object, className: PropTypes.string, isValid: PropTypes.func.isRequired, - onAccept: PropTypes.func.isRequired, - onCancel: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired, - onClear: PropTypes.func.isRequired, - onClose: PropTypes.func.isRequired, - onDismiss: PropTypes.func.isRequired, - onOpen: PropTypes.func.isRequired, onSelectShortcut: PropTypes.func.isRequired, - onSetToday: PropTypes.func.isRequired, onViewChange: PropTypes.func.isRequired, /** * The props used for each component slot. diff --git a/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx b/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx index be4f6e3b5e95d..200e0f7e6895e 100644 --- a/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx @@ -48,10 +48,6 @@ const usePickerLayout = { + const value = React.useContext(PickerActionsContext); + if (value == null) { + throw new Error( + [ + 'MUI X: The `usePickerActionsContext` can only be called in fields that are used as a slot of a picker component', + ].join('\n'), + ); + } + + return value; +}; diff --git a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx index 0f558077d4fc3..191e45601a0fc 100644 --- a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx @@ -3,10 +3,16 @@ import { PickerOwnerState } from '../../models'; import { PickersInputLocaleText } from '../../locales'; import { LocalizationProvider } from '../../LocalizationProvider'; import { PickerOrientation, PickerVariant } from '../models'; -import type { UsePickerValueContextValue } from '../hooks/usePicker/usePickerValue.types'; +import type { + UsePickerValueActionsContextValue, + UsePickerValueContextValue, + UsePickerValuePrivateContextValue, +} from '../hooks/usePicker/usePickerValue.types'; export const PickerContext = React.createContext(null); +export const PickerActionsContext = React.createContext(null); + export const PickerPrivateContext = React.createContext({ ownerState: { isPickerDisabled: false, @@ -16,6 +22,7 @@ export const PickerPrivateContext = React.createContext {}, }); /** @@ -26,19 +33,22 @@ export const PickerPrivateContext = React.createContext - - {children} - + + + {children} + + ); } export interface PickerProviderProps { contextValue: PickerContextValue; + actionsContextValue: PickerActionsContextValue; privateContextValue: PickerPrivateContextValue; localeText: PickersInputLocaleText | undefined; children: React.ReactNode; @@ -71,7 +81,10 @@ export interface PickerContextValue extends UsePickerValueContextValue { */ orientation: PickerOrientation; } -export interface PickerPrivateContextValue { + +export interface PickerActionsContextValue extends UsePickerValueActionsContextValue {} + +export interface PickerPrivateContextValue extends UsePickerValuePrivateContextValue { /** * The ownerState of the picker. */ diff --git a/packages/x-date-pickers/src/internals/components/PickersModalDialog.tsx b/packages/x-date-pickers/src/internals/components/PickersModalDialog.tsx index 5b89bb61cf1be..6c9e7a99e8948 100644 --- a/packages/x-date-pickers/src/internals/components/PickersModalDialog.tsx +++ b/packages/x-date-pickers/src/internals/components/PickersModalDialog.tsx @@ -6,7 +6,8 @@ import { PaperProps as MuiPaperProps } from '@mui/material/Paper'; import { TransitionProps as MuiTransitionProps } from '@mui/material/transitions'; import { styled } from '@mui/material/styles'; import { DIALOG_WIDTH } from '../constants/dimensions'; -import { UsePickerValueActions } from '../hooks/usePicker/usePickerValue.types'; +import { usePickerContext } from '../../hooks'; +import { usePickerPrivateContext } from '../hooks/usePickerPrivateContext'; export interface PickersModalDialogSlots { /** @@ -41,7 +42,7 @@ export interface PickersModalDialogSlotProps { mobileTransition?: Partial; } -export interface PickersModalDialogProps extends UsePickerValueActions { +export interface PickersModalDialogProps { /** * Overridable component slots. * @default {} @@ -52,7 +53,6 @@ export interface PickersModalDialogProps extends UsePickerValueActions { * @default {} */ slotProps?: PickersModalDialogSlotProps; - open: boolean; } const PickersModalDialogRoot = styled(MuiDialog)({ @@ -72,7 +72,10 @@ const PickersModalDialogContent = styled(DialogContent)({ }); export function PickersModalDialog(props: React.PropsWithChildren) { - const { children, onDismiss, open, slots, slotProps } = props; + const { children, slots, slotProps } = props; + + const { open } = usePickerContext(); + const { dismissViews } = usePickerPrivateContext(); const Dialog = slots?.dialog ?? PickersModalDialogRoot; const Transition = slots?.mobileTransition ?? Fade; @@ -80,7 +83,7 @@ export function PickersModalDialog(props: React.PropsWithChildren; } -export interface PickerPopperProps extends UsePickerValueActions { +export interface PickerPopperProps { role: 'tooltip' | 'dialog'; anchorEl: MuiPopperProps['anchorEl']; - open: MuiPopperProps['open']; /** * @default "bottom" */ @@ -339,8 +338,6 @@ export function PickersPopper(inProps: PickerPopperProps) { containerRef = null, shouldRestoreFocus, onBlur, - onDismiss, - open, role, placement = 'bottom', slots, @@ -349,10 +346,13 @@ export function PickersPopper(inProps: PickerPopperProps) { classes: classesProp, } = props; + const { open } = usePickerContext(); + const { dismissViews } = usePickerPrivateContext(); + React.useEffect(() => { function handleKeyDown(nativeEvent: KeyboardEvent) { if (open && nativeEvent.key === 'Escape') { - onDismiss(); + dismissViews(); } } @@ -361,7 +361,7 @@ export function PickersPopper(inProps: PickerPopperProps) { return () => { document.removeEventListener('keydown', handleKeyDown); }; - }, [onDismiss, open]); + }, [dismissViews, open]); const lastFocusedElementRef = React.useRef(null); React.useEffect(() => { @@ -387,7 +387,7 @@ export function PickersPopper(inProps: PickerPopperProps) { const [clickAwayRef, onPaperClick, onPaperTouchStart] = useClickAwayListener( open, - onBlur ?? onDismiss, + onBlur ?? dismissViews, ); const paperRef = React.useRef(null); const handleRef = useForkRef(paperRef, containerRef); @@ -403,7 +403,7 @@ export function PickersPopper(inProps: PickerPopperProps) { if (event.key === 'Escape') { // stop the propagation to avoid closing parent modal event.stopPropagation(); - onDismiss(); + dismissViews(); } }; 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 3ac24e4b6227e..f206939d69f87 100644 --- a/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx +++ b/packages/x-date-pickers/src/internals/hooks/useDesktopPicker/useDesktopPicker.tsx @@ -60,8 +60,6 @@ export const useDesktopPicker = < const isToolbarHidden = innerSlotProps?.toolbar?.hidden ?? false; const { - open, - actions, hasUIView, layoutProps, providerProps, @@ -95,7 +93,11 @@ export const useDesktopPicker = < externalSlotProps: innerSlotProps?.openPickerButton, additionalProps: { disabled: disabled || readOnly, - onClick: open ? actions.onClose : actions.onOpen, + // This direct access to `providerProps` will go away in https://github.com/mui/mui-x/pull/15671 + onClick: (event: React.UIEvent) => { + event.preventDefault(); + providerProps.contextValue.setOpen((prevOpen) => !prevOpen); + }, 'aria-label': getOpenDialogAriaText(pickerFieldProps.value), edge: inputAdornmentProps.position, }, @@ -135,7 +137,7 @@ export const useDesktopPicker = < sx, label, name, - focused: open ? true : undefined, + focused: providerProps.contextValue.open ? true : undefined, ...(isToolbarHidden && { id: labelId }), ...(!!inputRef && { inputRef }), }, @@ -202,8 +204,6 @@ export const useDesktopPicker = < role="dialog" placement="bottom-start" anchorEl={containerRef.current} - {...actions} - open={open} slots={slots} slotProps={slotProps} shouldRestoreFocus={shouldRestoreFocus} 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 fc1ef14d56bef..101e2013d2cce 100644 --- a/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx +++ b/packages/x-date-pickers/src/internals/hooks/useMobilePicker/useMobilePicker.tsx @@ -56,8 +56,6 @@ export const useMobilePicker = < const isToolbarHidden = innerSlotProps?.toolbar?.hidden ?? false; const { - open, - actions, layoutProps, providerProps, renderCurrentView, @@ -100,8 +98,12 @@ export const useMobilePicker = < name, ...(isToolbarHidden && { id: labelId }), ...(!(disabled || readOnly) && { - onClick: actions.onOpen, - onKeyDown: onSpaceOrEnter(actions.onOpen), + // These direct access to `providerProps` will go away in https://github.com/mui/mui-x/pull/15671 + onClick: (event: React.UIEvent) => { + event.preventDefault(); + providerProps.contextValue.setOpen(true); + }, + onKeyDown: onSpaceOrEnter(() => providerProps.contextValue.setOpen(true)), }), ...(!!inputRef && { inputRef }), }, @@ -151,7 +153,7 @@ export const useMobilePicker = < slotProps={slotProps} unstableFieldRef={handleFieldRef} /> - + {renderCurrentView()} 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 8fff61acb1c9e..444ed5c24a8be 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts @@ -64,8 +64,6 @@ export const usePicker = < return { // Picker value - open: pickerValueResponse.open, - actions: pickerValueResponse.actions, fieldProps: pickerValueResponse.fieldProps, // Picker views 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 d77e131106eb4..a7717e8860d2e 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 Pick, 'open' | 'actions' | 'fieldProps'>, +> extends Pick, 'fieldProps'>, Pick, 'shouldRestoreFocus' | 'renderCurrentView'> { 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 10a3f4f0a50af..1ced411b7ae6e 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts @@ -113,13 +113,14 @@ export function usePickerProvider< ); const privateContextValue = React.useMemo( - () => ({ ownerState }), - [ownerState], + () => ({ ...paramsFromUsePickerValue.privateContextValue, ownerState }), + [paramsFromUsePickerValue, ownerState], ); return { localeText, contextValue, + actionsContextValue: paramsFromUsePickerValue.actionsContextValue, privateContextValue, }; } 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 e973b01eaba34..a3adeb812499f 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts @@ -18,11 +18,12 @@ import { UsePickerValueFieldResponse, UsePickerValueLayoutResponse, UsePickerValueViewsResponse, - UsePickerValueActions, PickerSelectionState, PickerValueUpdaterParams, UsePickerValueContextValue, UsePickerValueProviderParams, + UsePickerValueActionsContextValue, + UsePickerValuePrivateContextValue, } from './usePickerValue.types'; import { useValueWithTimezone } from '../useValueWithTimezone'; import { PickerValidValue } from '../../models'; @@ -339,56 +340,6 @@ export const usePickerValue = < })); } - const handleClear = useEventCallback(() => { - updateDate({ - value: valueManager.emptyValue, - name: 'setValueFromAction', - pickerAction: 'clear', - }); - }); - - const handleAccept = useEventCallback(() => { - updateDate({ - value: dateState.lastPublishedValue, - name: 'setValueFromAction', - pickerAction: 'accept', - }); - }); - - const handleDismiss = useEventCallback(() => { - updateDate({ - value: dateState.lastPublishedValue, - name: 'setValueFromAction', - pickerAction: 'dismiss', - }); - }); - - const handleCancel = useEventCallback(() => { - updateDate({ - value: dateState.lastCommittedValue, - name: 'setValueFromAction', - pickerAction: 'cancel', - }); - }); - - const handleSetToday = useEventCallback(() => { - updateDate({ - value: valueManager.getTodayValue(utils, timezone, valueType), - name: 'setValueFromAction', - pickerAction: 'today', - }); - }); - - const handleOpen = useEventCallback((event: React.UIEvent) => { - event.preventDefault(); - setOpen(true); - }); - - const handleClose = useEventCallback((event?: React.UIEvent) => { - event?.preventDefault(); - setOpen(false); - }); - const handleChange = useEventCallback( (newValue: TValue, selectionState: PickerSelectionState = 'partial') => updateDate({ name: 'setValueFromView', value: newValue, selectionState }), @@ -413,16 +364,6 @@ export const usePickerValue = < updateDate({ name: 'setValueFromField', value: newValue, context }), ); - const actions: UsePickerValueActions = { - onClear: handleClear, - onAccept: handleAccept, - onDismiss: handleDismiss, - onCancel: handleCancel, - onSetToday: handleSetToday, - onOpen: handleOpen, - onClose: handleClose, - }; - const fieldResponse: UsePickerValueFieldResponse = { value: dateState.draft, onChange: handleChangeFromField, @@ -436,8 +377,8 @@ export const usePickerValue = < const viewResponse: UsePickerValueViewsResponse = { value: valueWithoutError, onChange: handleChange, - onClose: handleClose, open, + setOpen, }; const isValid = (testedValue: TValue) => { @@ -452,31 +393,87 @@ export const usePickerValue = < }; const layoutResponse: UsePickerValueLayoutResponse = { - ...actions, value: valueWithoutError, onChange: handleChange, onSelectShortcut: handleSelectShortcut, isValid, }; - const contextValue = React.useMemo(() => { - return { - open, + const clearValue = useEventCallback(() => + updateDate({ + value: valueManager.emptyValue, + name: 'setValueFromAction', + pickerAction: 'clear', + }), + ); + + const setValueToToday = useEventCallback(() => + updateDate({ + value: valueManager.getTodayValue(utils, timezone, valueType), + name: 'setValueFromAction', + pickerAction: 'today', + }), + ); + + const acceptValueChanges = useEventCallback(() => + updateDate({ + value: dateState.lastPublishedValue, + name: 'setValueFromAction', + pickerAction: 'accept', + }), + ); + + const cancelValueChanges = useEventCallback(() => + updateDate({ + value: dateState.lastCommittedValue, + name: 'setValueFromAction', + pickerAction: 'cancel', + }), + ); + + const dismissViews = useEventCallback(() => { + updateDate({ + value: dateState.lastPublishedValue, + name: 'setValueFromAction', + pickerAction: 'dismiss', + }); + }); + + const actionsContextValue = React.useMemo( + () => ({ setOpen, - }; - }, [open, setOpen]); + clearValue, + setValueToToday, + acceptValueChanges, + cancelValueChanges, + }), + [setOpen, clearValue, setValueToToday, acceptValueChanges, cancelValueChanges], + ); + + const contextValue = React.useMemo( + () => ({ + ...actionsContextValue, + open, + }), + [actionsContextValue, open], + ); + + const privateContextValue = React.useMemo( + () => ({ dismissViews }), + [dismissViews], + ); const providerParams: UsePickerValueProviderParams = { value: valueWithoutError, contextValue, + actionsContextValue, + privateContextValue, }; return { - 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 d58af8940c43a..9644f63baa90b 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 @@ -275,16 +275,6 @@ export interface UsePickerValueParams< validator: Validator, TExternalProps>; } -export interface UsePickerValueActions { - onAccept: () => void; - onClear: () => void; - onDismiss: () => void; - onCancel: () => void; - onSetToday: () => void; - onOpen: (event: React.UIEvent) => void; - onClose: (event?: React.UIEvent) => void; -} - export type UsePickerValueFieldResponse = Required< Pick, 'value' | 'onChange'> >; @@ -296,14 +286,13 @@ export interface UsePickerValueViewsResponse { value: TValue; onChange: (value: TValue, selectionState?: PickerSelectionState) => void; open: boolean; - onClose: (event?: React.MouseEvent) => void; + setOpen: React.Dispatch>; } /** * Props passed to `usePickerLayoutProps`. */ -export interface UsePickerValueLayoutResponse - extends UsePickerValueActions { +export interface UsePickerValueLayoutResponse { value: TValue; onChange: (newValue: TValue) => void; onSelectShortcut: ( @@ -320,20 +309,27 @@ export interface UsePickerValueLayoutResponse export interface UsePickerValueProviderParams { value: TValue; contextValue: UsePickerValueContextValue; + actionsContextValue: UsePickerValueActionsContextValue; + privateContextValue: UsePickerValuePrivateContextValue; } export interface UsePickerValueResponse { - open: boolean; - actions: UsePickerValueActions; viewProps: UsePickerValueViewsResponse; fieldProps: UsePickerValueFieldResponse; layoutProps: UsePickerValueLayoutResponse; provider: UsePickerValueProviderParams; } -export interface UsePickerValueContextValue { +export interface UsePickerValueContextValue extends UsePickerValueActionsContextValue { /** - * Sets the current open state of the Picker. + * `true` if the picker is open, `false` otherwise. + */ + open: boolean; +} + +export interface UsePickerValueActionsContextValue { + /** + * Set the current open state of the Picker. * ```ts * setOpen(true); // Opens the picker. * setOpen(false); // Closes the picker. @@ -344,7 +340,32 @@ export interface UsePickerValueContextValue { */ setOpen: React.Dispatch>; /** - * `true` if the picker is open, `false` otherwise. + * Set the current value of the picker to be empty. + * The value will be `null` on single pickers and `[null, null]` on range pickers. */ - open: boolean; + clearValue: () => void; + /** + * Set the current value of the picker to be the current date. + * The value will be `today` on single pickers and `[today, today]` on range pickers. + * With `today` being the current date, with its time set to `00:00:00` on Date Pickers and its time set to the current time on Time and Date Pickers. + */ + setValueToToday: () => void; + /** + * Accept the current value of the picker. + * Will call `onAccept` if defined. + * If the picker is re-opened, this value will be the one used to initialize the views. + */ + acceptValueChanges: () => void; + /** + * Cancel the changes made to the current value of the picker. + * The value will be reset to the last accepted value. + */ + cancelValueChanges: () => void; +} + +export interface UsePickerValuePrivateContextValue { + /** + * Closes the picker and accepts the current value if it is not equal to the last accepted value. + */ + dismissViews: () => void; } 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 cf782eadbb9c8..d6199b9725c59 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.ts @@ -24,7 +24,7 @@ export type PickerViewsRendererProps< TAdditionalProps extends {}, > = Omit & TAdditionalProps & - UsePickerValueViewsResponse & { + Pick, 'value' | 'onChange'> & { view: TView; views: readonly TView[]; focusedView: TView | null; @@ -159,7 +159,7 @@ export const usePickerViews = < TExternalProps, TAdditionalProps >): UsePickerViewsResponse => { - const { onChange, open, onClose } = propsFromPickerValue; + const { onChange, value, open, setOpen } = propsFromPickerValue; const { view: inView, views, openTo, onViewChange, viewRenderers, timezone } = props; const { className, sx, ...propsToForwardToView } = props; @@ -220,7 +220,7 @@ export const usePickerViews = < useEnhancedEffect(() => { // Handle case of `DateTimePicker` without time renderers if (currentViewMode === 'field' && open) { - onClose(); + setOpen(false); setTimeout(() => { fieldRef?.current?.setSelectedSections(view); // focusing the input before the range selection is done @@ -290,9 +290,9 @@ export const usePickerViews = < > = { ...propsToForwardToView, ...additionalViewProps, - ...propsFromPickerValue, views, timezone, + value, onChange: setValueAndGoToNextView, view: popperView, onViewChange: setView, diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index d96774401a835..71f1671a2c784 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -68,13 +68,13 @@ export { useFieldOwnerState } from './hooks/useFieldOwnerState'; export type { MobileOnlyPickerProps } from './hooks/useMobilePicker'; export { usePicker } from './hooks/usePicker'; export type { - UsePickerResponse, UsePickerParams, UsePickerProps, UsePickerValueFieldResponse, PickerViewsRendererProps, } from './hooks/usePicker'; export type { + UsePickerValueContextValue, UsePickerValueNonStaticProps, PickerValueManager, PickerSelectionState, diff --git a/packages/x-date-pickers/src/themeAugmentation/themeAugmentation.spec.ts b/packages/x-date-pickers/src/themeAugmentation/themeAugmentation.spec.ts index 8bd7cdc5e7d7f..a622d4fda8e29 100644 --- a/packages/x-date-pickers/src/themeAugmentation/themeAugmentation.spec.ts +++ b/packages/x-date-pickers/src/themeAugmentation/themeAugmentation.spec.ts @@ -356,7 +356,7 @@ createTheme({ }, MuiPickersPopper: { defaultProps: { - open: true, + placement: 'bottom', // @ts-expect-error invalid MuiPickersPopper prop someRandomProp: true, }, diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index 9ec0515027031..4598d445e78f6 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -415,6 +415,7 @@ { "name": "UseMultiInputTimeRangeFieldComponentProps", "kind": "TypeAlias" }, { "name": "UseMultiInputTimeRangeFieldProps", "kind": "Interface" }, { "name": "useParsedFormat", "kind": "Variable" }, + { "name": "usePickerActionsContext", "kind": "Variable" }, { "name": "usePickerContext", "kind": "Variable" }, { "name": "usePickerLayout", "kind": "ExportAssignment" }, { "name": "usePickerTranslations", "kind": "Variable" }, diff --git a/scripts/x-date-pickers.exports.json b/scripts/x-date-pickers.exports.json index ff4ae2da325fb..b402815637025 100644 --- a/scripts/x-date-pickers.exports.json +++ b/scripts/x-date-pickers.exports.json @@ -300,6 +300,7 @@ { "name": "UseDateFieldProps", "kind": "Interface" }, { "name": "UseDateTimeFieldProps", "kind": "Interface" }, { "name": "useParsedFormat", "kind": "Variable" }, + { "name": "usePickerActionsContext", "kind": "Variable" }, { "name": "usePickerContext", "kind": "Variable" }, { "name": "usePickerLayout", "kind": "ExportAssignment" }, { "name": "usePickerTranslations", "kind": "Variable" },