Skip to content

Commit

Permalink
[pickers] Create a new context to pass the range position props to th…
Browse files Browse the repository at this point in the history
…e layout components and to the views (#15846)
  • Loading branch information
flaviendelangle authored Dec 30, 2024
1 parent 9bce04c commit 43411bf
Show file tree
Hide file tree
Showing 50 changed files with 358 additions and 468 deletions.
37 changes: 37 additions & 0 deletions docs/data/migration/migration-pickers-v7/migration-pickers-v7.md
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,19 @@ This change causes a few breaking changes:
The only difference is that `usePickerActionsContext` only contains variables with stable references that won't cause a re-render of your component.
:::

- The component passed to the `layout` slot no longer receives the `rangePosition` and `onRangePositionChange` on range pickers.
You can use the `usePickerRangePositionContext` hook instead:

```diff
+import { usePickerRangePositionContext } from '@mui/x-date-pickers-pro/hooks';

-const { rangePosition } = props;
+const { rangePosition } = usePickerRangePositionContext();

-const { onRangePositionChange } = props;
+const { onRangePositionChange } = usePickerRangePositionContext();
```

### Slot: `toolbar`

- The component passed to the `toolbar` slot no longer receives the `value` prop.
Expand Down Expand Up @@ -576,6 +589,18 @@ This change causes a few breaking changes:
The only difference is that `usePickerActionsContext` only contains variables with stable references that won't cause a re-render of your component.
:::

- The component passed to the `toolbar` slot no longer receives the `rangePosition` and `onRangePositionChange` on range pickers, instead you can use the `usePickerRangePositionContext` hook:

```diff
+import { usePickerRangePositionContext } from '@mui/x-date-pickers-pro/hooks';

-const { rangePosition } = props;
+const { rangePosition } = usePickerRangePositionContext();

-const { onRangePositionChange } = props;
+const { onRangePositionChange } = usePickerRangePositionContext();
```

### Slot: `tabs`

- The component passed to the `tabs` slot no longer receives the `view`, `views` and `onViewChange` props.
Expand All @@ -594,6 +619,18 @@ This change causes a few breaking changes:
+const { onViewChange } = usePickerContext();
```

- The component passed to the `tabs` slot no longer receives the `rangePosition` and `onRangePositionChange` on range pickers, instead you can use the `usePickerRangePositionContext` hook:

```diff
+import { usePickerRangePositionContext } from '@mui/x-date-pickers-pro/hooks';

-const { rangePosition } = props;
+const { rangePosition } = usePickerRangePositionContext();

-const { onRangePositionChange } = props;
+const { onRangePositionChange } = usePickerRangePositionContext();
```

### Slot: `actionBar`

- The component passed to the `actionBar` slot no longer receives the `onClear`, `onSetToday`, `onAccept` and `onCancel` props.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import {
PickersRangeCalendarHeader,
PickersRangeCalendarHeaderProps,
} from '../PickersRangeCalendarHeader';
import { useNullablePickerRangePositionContext } from '../internals/hooks/useNullablePickerRangePositionContext';

const releaseInfo = getReleaseInfo();

Expand Down Expand Up @@ -187,8 +188,8 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar(
reduceAnimations,
onMonthChange,
rangePosition: rangePositionProp,
defaultRangePosition: inDefaultRangePosition,
onRangePositionChange: inOnRangePositionChange,
defaultRangePosition: defaultRangePositionProp,
onRangePositionChange: onRangePositionChangeProp,
calendars,
currentMonthCalendarPosition = 1,
slots,
Expand All @@ -214,6 +215,8 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar(
...other
} = props;

const rangePositionContext = useNullablePickerRangePositionContext();

const { value, handleValueChange, timezone } = useControlledValueWithTimezone<
PickerRangeValue,
NonNullable<typeof onChange>
Expand Down Expand Up @@ -241,9 +244,9 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar(
const id = useId();

const { rangePosition, onRangePositionChange } = useRangePosition({
rangePosition: rangePositionProp,
defaultRangePosition: inDefaultRangePosition,
onRangePositionChange: inOnRangePositionChange,
rangePosition: rangePositionProp ?? rangePositionContext?.rangePosition,
defaultRangePosition: defaultRangePositionProp,
onRangePositionChange: onRangePositionChangeProp ?? rangePositionContext?.onRangePositionChange,
});

const handleDatePositionChange = useEventCallback((position: RangePosition) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ import {
} from '@mui/x-date-pickers/internals';
import { usePickerContext, usePickerTranslations } from '@mui/x-date-pickers/hooks';
import { PickerValidDate } from '@mui/x-date-pickers/models';
import { UseRangePositionResponse } from '../internals/hooks/useRangePosition';
import {
DateRangePickerToolbarClasses,
getDateRangePickerToolbarUtilityClass,
} from './dateRangePickerToolbarClasses';
import { usePickerRangePositionContext } from '../hooks';

const useUtilityClasses = (classes: Partial<DateRangePickerToolbarClasses> | undefined) => {
const slots = {
Expand All @@ -34,8 +34,7 @@ const useUtilityClasses = (classes: Partial<DateRangePickerToolbarClasses> | und

export interface DateRangePickerToolbarProps
extends ExportedDateRangePickerToolbarProps,
Omit<BaseToolbarProps, 'onChange' | 'isLandscape'>,
Pick<UseRangePositionResponse, 'rangePosition' | 'onRangePositionChange'> {}
Omit<BaseToolbarProps, 'onChange' | 'isLandscape'> {}

export interface ExportedDateRangePickerToolbarProps extends ExportedBaseToolbarProps {
/**
Expand Down Expand Up @@ -81,18 +80,12 @@ const DateRangePickerToolbar = React.forwardRef(function DateRangePickerToolbar(
const utils = useUtils();
const props = useThemeProps({ props: inProps, name: 'MuiDateRangePickerToolbar' });

const {
rangePosition,
onRangePositionChange,
toolbarFormat: toolbarFormatProp,
className,
classes: classesProp,
...other
} = props;
const { toolbarFormat: toolbarFormatProp, className, classes: classesProp, ...other } = props;

const { value } = usePickerContext<PickerRangeValue>();
const translations = usePickerTranslations();
const ownerState = useToolbarOwnerState();
const { rangePosition, onRangePositionChange } = usePickerRangePositionContext();
const classes = useUtilityClasses(classesProp);

// This can't be a default value when spreading because it breaks the API generation.
Expand Down Expand Up @@ -148,8 +141,6 @@ DateRangePickerToolbar.propTypes = {
* @default `true` for Desktop, `false` for Mobile.
*/
hidden: PropTypes.bool,
onRangePositionChange: PropTypes.func.isRequired,
rangePosition: PropTypes.oneOf(['end', 'start']).isRequired,
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/x-date-pickers-pro/src/DateRangePicker/shared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export interface BaseDateRangePickerProps
* If `undefined`, internally defined view will be used.
*/
viewRenderers?: Partial<
PickerViewRendererLookup<PickerRangeValue, 'day', DateRangeViewRendererProps<'day'>, {}>
PickerViewRendererLookup<PickerRangeValue, 'day', DateRangeViewRendererProps<'day'>>
>;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import {
DateTimeRangePickerTabsClasses,
getDateTimeRangePickerTabsUtilityClass,
} from './dateTimeRangePickerTabsClasses';
import { UseRangePositionResponse } from '../internals/hooks/useRangePosition';
import { RangePosition } from '../models';
import { usePickerRangePositionContext } from '../hooks';

type TabValue = 'start-date' | 'start-time' | 'end-date' | 'end-time';

Expand Down Expand Up @@ -63,9 +63,7 @@ export interface ExportedDateTimeRangePickerTabsProps extends ExportedBaseTabsPr
classes?: Partial<DateTimeRangePickerTabsClasses>;
}

export interface DateTimeRangePickerTabsProps
extends ExportedDateTimeRangePickerTabsProps,
Pick<UseRangePositionResponse, 'rangePosition' | 'onRangePositionChange'> {}
export interface DateTimeRangePickerTabsProps extends ExportedDateTimeRangePickerTabsProps {}

const useUtilityClasses = (classes: Partial<DateTimeRangePickerTabsClasses> | undefined) => {
const slots = {
Expand Down Expand Up @@ -114,8 +112,6 @@ const DateTimeRangePickerTabs = function DateTimeRangePickerTabs(
dateIcon = <DateRangeIcon />,
timeIcon = <TimeIcon />,
hidden = typeof window === 'undefined' || window.innerHeight < 667,
rangePosition,
onRangePositionChange,
className,
classes: classesProp,
sx,
Expand All @@ -125,6 +121,8 @@ const DateTimeRangePickerTabs = function DateTimeRangePickerTabs(
const { ownerState } = usePickerPrivateContext();
const { view, onViewChange } = usePickerContext();
const classes = useUtilityClasses(classesProp);
const { rangePosition, onRangePositionChange } = usePickerRangePositionContext();

const value = React.useMemo(
() => (view == null ? null : viewToTab(view, rangePosition)),
[view, rangePosition],
Expand Down Expand Up @@ -241,8 +239,6 @@ DateTimeRangePickerTabs.propTypes = {
* @default `window.innerHeight < 667` for `DesktopDateTimeRangePicker` and `MobileDateTimeRangePicker`
*/
hidden: PropTypes.bool,
onRangePositionChange: PropTypes.func.isRequired,
rangePosition: PropTypes.oneOf(['end', 'start']).isRequired,
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,61 +7,51 @@ import {
TimeViewWithMeridiem,
BaseClockProps,
PickerRangeValue,
PickerViewsRendererProps,
} from '@mui/x-date-pickers/internals';
import { PickerValidDate } from '@mui/x-date-pickers/models';
import { UseRangePositionResponse } from '../internals/hooks/useRangePosition';
import { isRangeValid } from '../internals/utils/date-utils';
import { calculateRangeChange } from '../internals/utils/date-range-manager';
import { usePickerRangePositionContext } from '../hooks';

export type DateTimeRangePickerTimeWrapperProps<
TView extends TimeViewWithMeridiem,
TComponentProps extends DefaultizedProps<
Omit<BaseClockProps<TView>, 'value' | 'defaultValue' | 'onChange'>,
Omit<BaseClockProps<TimeViewWithMeridiem>, 'value' | 'defaultValue' | 'onChange'>,
'views'
>,
> = Pick<UseRangePositionResponse, 'rangePosition' | 'onRangePositionChange'> &
Omit<
TComponentProps,
'views' | 'view' | 'onViewChange' | 'value' | 'defaultValue' | 'onChange'
> & {
view: TView;
onViewChange?: (view: TView) => void;
views: readonly TView[];
value?: PickerRangeValue;
defaultValue?: PickerRangeValue;
onChange?: (
value: PickerRangeValue,
selectionState: PickerSelectionState,
selectedView: TView,
) => void;
viewRenderer?: PickerViewRenderer<PickerRangeValue, TView, TComponentProps, any> | null;
openTo?: TView;
};
> = Omit<
TComponentProps,
'views' | 'view' | 'onViewChange' | 'value' | 'defaultValue' | 'onChange'
> & {
view: TimeViewWithMeridiem;
onViewChange?: (view: TimeViewWithMeridiem) => void;
views: readonly TimeViewWithMeridiem[];
value?: PickerRangeValue;
defaultValue?: PickerRangeValue;
onChange?: (
value: PickerRangeValue,
selectionState: PickerSelectionState,
selectedView: TimeViewWithMeridiem,
) => void;
viewRenderer?: PickerViewRenderer<PickerRangeValue, TComponentProps> | null;
openTo?: TimeViewWithMeridiem;
};

/**
* @ignore - internal component.
*/
function DateTimeRangePickerTimeWrapper<
TView extends TimeViewWithMeridiem,
TComponentProps extends DefaultizedProps<
Omit<BaseClockProps<TView>, 'value' | 'defaultValue' | 'onChange'>,
Omit<BaseClockProps<TimeViewWithMeridiem>, 'value' | 'defaultValue' | 'onChange'>,
'views'
>,
>(props: DateTimeRangePickerTimeWrapperProps<TView, TComponentProps>) {
>(props: DateTimeRangePickerTimeWrapperProps<TComponentProps>) {
const utils = useUtils();

const {
rangePosition,
onRangePositionChange,
viewRenderer,
value,
onChange,
defaultValue,
onViewChange,
views,
className,
...other
} = props;
const { viewRenderer, value, onChange, defaultValue, onViewChange, views, className, ...other } =
props;

const { rangePosition, onRangePositionChange } = usePickerRangePositionContext();

if (!viewRenderer) {
return null;
Expand All @@ -73,7 +63,7 @@ function DateTimeRangePickerTimeWrapper<
const handleOnChange = (
newDate: PickerValidDate | null,
selectionState: PickerSelectionState,
selectedView: TView,
selectedView: TimeViewWithMeridiem,
) => {
if (!onChange || !value) {
return;
Expand Down Expand Up @@ -101,7 +91,7 @@ function DateTimeRangePickerTimeWrapper<
value: currentValue,
onChange: handleOnChange,
defaultValue: currentDefaultValue,
});
} as any as PickerViewsRendererProps<PickerRangeValue, TimeViewWithMeridiem, TComponentProps>);
}

export { DateTimeRangePickerTimeWrapper };
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ import {
import { usePickerContext, usePickerTranslations } from '@mui/x-date-pickers/hooks';
import { PickerValidDate } from '@mui/x-date-pickers/models';
import { DateTimePickerToolbar } from '@mui/x-date-pickers/DateTimePicker';
import { UseRangePositionResponse } from '../internals/hooks/useRangePosition';
import {
DateTimeRangePickerToolbarClasses,
getDateTimeRangePickerToolbarUtilityClass,
} from './dateTimeRangePickerToolbarClasses';
import { calculateRangeChange } from '../internals/utils/date-range-manager';
import { usePickerRangePositionContext } from '../hooks';

const useUtilityClasses = (classes: Partial<DateTimeRangePickerToolbarClasses> | undefined) => {
const slots = {
Expand All @@ -38,7 +38,6 @@ type DateTimeRangeViews = Exclude<DateOrTimeViewWithMeridiem, 'year' | 'month'>;

export interface DateTimeRangePickerToolbarProps
extends BaseToolbarProps,
Pick<UseRangePositionResponse, 'rangePosition' | 'onRangePositionChange'>,
ExportedDateTimeRangePickerToolbarProps {
ampm?: boolean;
}
Expand Down Expand Up @@ -88,8 +87,6 @@ const DateTimeRangePickerToolbar = React.forwardRef(function DateTimeRangePicker
const utils = useUtils();

const {
rangePosition,
onRangePositionChange,
className,
classes: classesProp,
classes: inClasses,
Expand All @@ -108,6 +105,7 @@ const DateTimeRangePickerToolbar = React.forwardRef(function DateTimeRangePicker
>();
const translations = usePickerTranslations();
const ownerState = useToolbarOwnerState();
const { rangePosition, onRangePositionChange } = usePickerRangePositionContext();
const classes = useUtilityClasses(classesProp);

const commonToolbarProps = {
Expand Down Expand Up @@ -225,8 +223,6 @@ DateTimeRangePickerToolbar.propTypes = {
* @default `true` for Desktop, `false` for Mobile.
*/
hidden: PropTypes.bool,
onRangePositionChange: PropTypes.func.isRequired,
rangePosition: PropTypes.oneOf(['end', 'start']).isRequired,
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
Expand Down
23 changes: 10 additions & 13 deletions packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,16 @@ export interface BaseDateTimeRangePickerSlotProps
toolbar?: ExportedDateTimeRangePickerToolbarProps;
}

export type DateTimeRangePickerRenderers<
TView extends DateOrTimeViewWithMeridiem,
TAdditionalProps extends {} = {},
> = PickerViewRendererLookup<
PickerRangeValue,
TView,
Omit<DateRangeViewRendererProps<'day'>, 'view' | 'slots' | 'slotProps'> &
Omit<
TimeViewRendererProps<TimeViewWithMeridiem, BaseClockProps<TimeViewWithMeridiem>>,
'view' | 'slots' | 'slotProps'
> & { view: TView },
TAdditionalProps
>;
export type DateTimeRangePickerRenderers<TView extends DateOrTimeViewWithMeridiem> =
PickerViewRendererLookup<
PickerRangeValue,
TView,
Omit<DateRangeViewRendererProps<'day'>, 'view' | 'slots' | 'slotProps'> &
Omit<
TimeViewRendererProps<TimeViewWithMeridiem, BaseClockProps<TimeViewWithMeridiem>>,
'view' | 'slots' | 'slotProps'
> & { view: TView }
>;

export interface BaseDateTimeRangePickerProps
extends Omit<
Expand Down
Loading

0 comments on commit 43411bf

Please sign in to comment.