Skip to content

Commit

Permalink
[pickers] Use new ownerState for slots.field, slots.actionBar, slots.…
Browse files Browse the repository at this point in the history
…shortcuts and slots.toolbar
  • Loading branch information
flaviendelangle committed Oct 16, 2024
1 parent a005076 commit 625d829
Show file tree
Hide file tree
Showing 16 changed files with 118 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ import {
ExportedBaseTabsProps,
PickersProvider,
} from '@mui/x-date-pickers/internals';
import { PickerValidDate, FieldRef, InferError } from '@mui/x-date-pickers/models';
import {
PickerValidDate,
FieldRef,
InferError,
PickerOwnerState,
} from '@mui/x-date-pickers/models';
import {
DesktopRangePickerAdditionalViewProps,
UseDesktopRangePickerParams,
Expand Down Expand Up @@ -94,6 +99,7 @@ export const useDesktopRangePicker = <
shouldRestoreFocus,
fieldProps: pickerFieldProps,
contextValue,
ownerState,
} = usePicker<
DateRange<TDate>,
TDate,
Expand Down Expand Up @@ -143,7 +149,7 @@ export const useDesktopRangePicker = <
TEnableAccessibleFieldDOMStructure,
InferError<TExternalProps>
>,
TExternalProps
PickerOwnerState<DateRange<TDate>>
>({
elementType: Field,
externalSlotProps: slotProps?.field,
Expand All @@ -163,7 +169,7 @@ export const useDesktopRangePicker = <
ref: fieldContainerRef,
...(fieldType === 'single-input' ? { inputRef, name } : {}),
},
ownerState: props,
ownerState,
});

const enrichedFieldProps = useEnrichedRangePickerFieldProps<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
FieldSelectedSections,
FieldRef,
PickerValidDate,
PickerOwnerState,
} from '@mui/x-date-pickers/models';
import {
UseClearableFieldSlots,
Expand All @@ -22,7 +23,6 @@ import {
onSpaceOrEnter,
UsePickerResponse,
WrapperVariant,
UsePickerProps,
SlotComponentPropsFromProps,
DateOrTimeViewWithMeridiem,
} from '@mui/x-date-pickers/internals';
Expand Down Expand Up @@ -71,7 +71,7 @@ export interface RangePickerFieldSlotProps<
unknown
>,
{},
UsePickerProps<DateRange<TDate>, TDate, any, any, any, any>
PickerOwnerState<DateRange<TDate>>
>;
fieldRoot?: SlotComponentProps<typeof Stack, {}, Record<string, any>>;
fieldSeparator?: SlotComponentProps<typeof Typography, {}, Record<string, any>>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ import {
PickersProvider,
} from '@mui/x-date-pickers/internals';
import { usePickersTranslations } from '@mui/x-date-pickers/hooks';
import { PickerValidDate, FieldRef, InferError } from '@mui/x-date-pickers/models';
import {
PickerValidDate,
FieldRef,
InferError,
PickerOwnerState,
} from '@mui/x-date-pickers/models';
import useId from '@mui/utils/useId';
import {
MobileRangePickerAdditionalViewProps,
Expand Down Expand Up @@ -89,6 +94,7 @@ export const useMobileRangePicker = <
renderCurrentView,
fieldProps: pickerFieldProps,
contextValue,
ownerState,
} = usePicker<
DateRange<TDate>,
TDate,
Expand Down Expand Up @@ -119,7 +125,7 @@ export const useMobileRangePicker = <
TEnableAccessibleFieldDOMStructure,
InferError<TExternalProps>
>,
TExternalProps
PickerOwnerState<DateRange<TDate>>
>({
elementType: Field,
externalSlotProps: innerSlotProps?.field,
Expand All @@ -137,7 +143,7 @@ export const useMobileRangePicker = <
timezone,
...(fieldType === 'single-input' ? { inputRef, name } : {}),
},
ownerState: props,
ownerState,
});

const isToolbarHidden = innerSlotProps?.toolbar?.hidden ?? false;
Expand Down
21 changes: 5 additions & 16 deletions packages/x-date-pickers/src/PickersLayout/PickersLayout.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
ExportedPickersShortcutProps,
PickersShortcuts,
} from '../PickersShortcuts/PickersShortcuts';
import { PickerValidDate } from '../models';
import { PickerOwnerState, PickerValidDate } from '../models';

export interface ExportedPickersLayoutSlots<
TValue,
Expand All @@ -38,16 +38,9 @@ export interface ExportedPickersLayoutSlots<
>;
}

interface PickersLayoutActionBarOwnerState<
TValue,
TDate extends PickerValidDate,
TView extends DateOrTimeViewWithMeridiem,
> extends PickersLayoutProps<TValue, TDate, TView> {
wrapperVariant: WrapperVariant;
}

interface PickersShortcutsOwnerState<TValue> extends PickersShortcutsProps<TValue> {
export interface PickersLayoutOwnerState<TValue> extends PickerOwnerState<TValue> {
wrapperVariant: WrapperVariant;
isLandscape: boolean;
}

export interface ExportedPickersLayoutSlotProps<
Expand All @@ -58,15 +51,11 @@ export interface ExportedPickersLayoutSlotProps<
/**
* Props passed down to the action bar component.
*/
actionBar?: SlotComponentProps<
typeof PickersActionBar,
{},
PickersLayoutActionBarOwnerState<TValue, TDate, TView>
>;
actionBar?: SlotComponentProps<typeof PickersActionBar, {}, PickersLayoutOwnerState<TValue>>;
/**
* Props passed down to the shortcuts component.
*/
shortcuts?: SlotComponentProps<typeof PickersShortcuts, {}, PickersShortcutsOwnerState<TValue>>;
shortcuts?: SlotComponentProps<typeof PickersShortcuts, {}, PickersLayoutOwnerState<TValue>>;
/**
* Props passed down to the layoutRoot component.
*/
Expand Down
33 changes: 20 additions & 13 deletions packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@ import * as React from 'react';
import useSlotProps from '@mui/utils/useSlotProps';
import composeClasses from '@mui/utils/composeClasses';
import { PickersActionBar, PickersActionBarAction } from '../PickersActionBar';
import { PickersLayoutProps, SubComponents } from './PickersLayout.types';
import { getPickersLayoutUtilityClass } from './pickersLayoutClasses';
import { PickersLayoutOwnerState, PickersLayoutProps, SubComponents } from './PickersLayout.types';
import { getPickersLayoutUtilityClass, PickersLayoutClasses } from './pickersLayoutClasses';
import { PickersShortcuts } from '../PickersShortcuts';
import { BaseToolbarProps } from '../internals/models/props/toolbar';
import { DateOrTimeViewWithMeridiem } from '../internals/models';
import { PickerValidDate } from '../models';
import { usePickersContext } from '../hooks';

function toolbarHasView<TValue, TView extends DateOrTimeViewWithMeridiem>(
toolbarProps: BaseToolbarProps<TValue, TView> | any,
): toolbarProps is BaseToolbarProps<TValue, TView> {
return toolbarProps.view !== null;
}

const useUtilityClasses = (ownerState: PickersLayoutProps<any, any, any>) => {
const { classes, isLandscape } = ownerState;
const useUtilityClasses = (
classes: Partial<PickersLayoutClasses> | undefined,
ownerState: PickersLayoutOwnerState<any>,
) => {
const { isLandscape } = ownerState;
const slots = {
root: ['root', isLandscape && 'landscape'],
contentWrapper: ['contentWrapper'],
Expand Down Expand Up @@ -47,6 +51,8 @@ const usePickerLayout = <
>(
props: PickersLayoutProps<TValue, TDate, TView>,
): UsePickerLayoutResponse<TValue> => {
const { ownerState: pickerOwnerState } = usePickersContext<TValue>();

const {
wrapperVariant,
onAccept,
Expand All @@ -66,13 +72,19 @@ const usePickerLayout = <
children,
slots,
slotProps,
classes: classesProp,
// TODO: Remove this "as" hack. It get introduced to mark `value` prop in PickersLayoutProps as not required.
// The true type should be
// - For pickers value: TDate | null
// - For range pickers value: [TDate | null, TDate | null]
} = props as PickersLayoutPropsWithValueRequired<TValue, TDate, TView>;

const classes = useUtilityClasses(props);
const ownerState: PickersLayoutOwnerState<TValue> = {
...pickerOwnerState,
wrapperVariant,
isLandscape,
};
const classes = useUtilityClasses(classesProp, ownerState);

// Action bar
const ActionBar = slots?.actionBar ?? PickersActionBar;
Expand All @@ -88,7 +100,7 @@ const usePickerLayout = <
wrapperVariant === 'desktop' ? [] : (['cancel', 'accept'] as PickersActionBarAction[]),
},
className: classes.actionBar,
ownerState: { ...props, wrapperVariant },
ownerState,
});
const actionBar = <ActionBar {...actionBarProps} />;

Expand All @@ -108,7 +120,7 @@ const usePickerLayout = <
readOnly,
},
className: classes.toolbar,
ownerState: { ...props, wrapperVariant },
ownerState,
});
const toolbar = toolbarHasView(toolbarProps) && !!Toolbar ? <Toolbar {...toolbarProps} /> : null;

Expand All @@ -133,12 +145,7 @@ const usePickerLayout = <
onChange: onSelectShortcut,
},
className: classes.shortcuts,
ownerState: {
isValid,
isLandscape,
onChange: onSelectShortcut,
wrapperVariant,
},
ownerState,
});
const shortcuts = view && !!Shortcuts ? <Shortcuts {...shortcutsProps} /> : null;

Expand Down
9 changes: 6 additions & 3 deletions packages/x-date-pickers/src/hooks/usePickersContext.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
'use client';
import * as React from 'react';
import { PickersContext } from '../internals/components/PickersProvider';
import { PickersContext, PickersContextValue } from '../internals/components/PickersProvider';

/**
* Returns the context passed by the picker that wraps the current component.
*/
export const usePickersContext = () => {
const value = React.useContext(PickersContext);
export const usePickersContext = <
// TODO v8: Replace with TIsRange when available
TValue = any,
>() => {
const value = React.useContext(PickersContext) as PickersContextValue<TValue> | null;
if (value == null) {
throw new Error(
[
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as React from 'react';
import { PickerValidDate } from '../../models';
import { PickerOwnerState, PickerValidDate } from '../../models';
import { PickersInputLocaleText } from '../../locales';
import { LocalizationProvider } from '../../LocalizationProvider';

export const PickersContext = React.createContext<PickersContextValue | null>(null);
export const PickersContext = React.createContext<PickersContextValue<any> | null>(null);

/**
* Provides the context for the various parts of a picker component:
Expand All @@ -12,8 +12,8 @@ export const PickersContext = React.createContext<PickersContextValue | null>(nu
*
* @ignore - do not document.
*/
export function PickersProvider<TDate extends PickerValidDate>(
props: PickersFieldProviderProps<TDate>,
export function PickersProvider<TValue, TDate extends PickerValidDate>(
props: PickersProviderProps<TValue, TDate>,
) {
const { contextValue, localeText, children } = props;

Expand All @@ -24,13 +24,13 @@ export function PickersProvider<TDate extends PickerValidDate>(
);
}

interface PickersFieldProviderProps<TDate extends PickerValidDate> {
contextValue: PickersContextValue;
interface PickersProviderProps<TValue, TDate extends PickerValidDate> {
contextValue: PickersContextValue<TValue>;
localeText: PickersInputLocaleText<TDate> | undefined;
children: React.ReactNode;
}

export interface PickersContextValue {
export interface PickersContextValue<TValue> {
/**
* Open the picker.
* @param {React.UIEvent} event The DOM event that triggered the change.
Expand All @@ -45,4 +45,8 @@ export interface PickersContextValue {
* `true` if the picker is open, `false` otherwise.
*/
open: boolean;
/**
* The ownerState of the picker.
*/
ownerState: PickerOwnerState<TValue>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
FieldRef,
BaseSingleInputFieldProps,
InferError,
PickerOwnerState,
} from '../../../models';
import { DateOrTimeViewWithMeridiem } from '../../models';
import { PickersProvider } from '../../components/PickersProvider';
Expand Down Expand Up @@ -133,7 +134,7 @@ export const useDesktopPicker = <
InferError<TExternalProps>
>
>,
TExternalProps
PickerOwnerState<TDate | null>
>({
elementType: Field,
externalSlotProps: innerSlotProps?.field,
Expand All @@ -156,7 +157,7 @@ export const useDesktopPicker = <
focused: open ? true : undefined,
...(inputRef ? { inputRef } : {}),
},
ownerState: props,
ownerState,
});

// TODO: Move to `useSlotProps` when /~https://github.com/mui/material-ui/pull/35088 will be merged
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
BaseNonRangeNonStaticPickerProps,
} from '../../models/props/basePickerProps';
import { PickersPopperSlots, PickersPopperSlotProps } from '../../components/PickersPopper';
import { UsePickerParams, UsePickerProps } from '../usePicker';
import { UsePickerParams } from '../usePicker';
import {
BaseSingleInputFieldProps,
FieldSection,
Expand Down Expand Up @@ -87,7 +87,7 @@ export interface ExportedUseDesktopPickerSlotProps<
unknown
>,
{},
UsePickerProps<TDate | null, TDate, any, any, any, any>
PickerOwnerState<TDate | null>
>;
textField?: SlotComponentProps<typeof TextField, {}, Record<string, any>>;
inputAdornment?: Partial<InputAdornmentProps>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
PickerValidDate,
FieldRef,
InferError,
PickerOwnerState,
} from '../../../models';
import { DateOrTimeViewWithMeridiem } from '../../models';
import { PickersProvider } from '../../components/PickersProvider';
Expand Down Expand Up @@ -74,6 +75,7 @@ export const useMobilePicker = <
renderCurrentView,
fieldProps: pickerFieldProps,
contextValue,
ownerState,
} = usePicker<TDate | null, TDate, TView, FieldSection, TExternalProps, {}>({
...pickerParams,
props,
Expand All @@ -96,7 +98,7 @@ export const useMobilePicker = <
InferError<TExternalProps>
>
>,
TExternalProps
PickerOwnerState<TDate | null>
>({
elementType: Field,
externalSlotProps: innerSlotProps?.field,
Expand All @@ -121,7 +123,7 @@ export const useMobilePicker = <
name,
...(inputRef ? { inputRef } : {}),
},
ownerState: props,
ownerState,
});

// TODO: Move to `useSlotProps` when /~https://github.com/mui/material-ui/pull/35088 will be merged
Expand Down
Loading

0 comments on commit 625d829

Please sign in to comment.