Skip to content

Commit

Permalink
[pickers] Strictly type the props a picker passes to its field, and m…
Browse files Browse the repository at this point in the history
…igrate all the custom field demos accordingly (#15197)
  • Loading branch information
flaviendelangle authored Nov 14, 2024
1 parent f2e954d commit 16c8962
Show file tree
Hide file tree
Showing 37 changed files with 654 additions and 738 deletions.
29 changes: 7 additions & 22 deletions docs/data/date-pickers/custom-field/BrowserV7Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,14 @@ import useForkRef from '@mui/utils/useForkRef';
import { styled } from '@mui/material/styles';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DatePicker, DatePickerProps } from '@mui/x-date-pickers/DatePicker';
import {
unstable_useDateField as useDateField,
UseDateFieldProps,
} from '@mui/x-date-pickers/DateField';
DatePicker,
DatePickerFieldProps,
DatePickerProps,
} from '@mui/x-date-pickers/DatePicker';
import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateField';
import { useClearableField } from '@mui/x-date-pickers/hooks';
import {
BaseSingleInputPickersTextFieldProps,
BaseSingleInputFieldProps,
DateValidationError,
FieldSection,
PickerValidDate,
} from '@mui/x-date-pickers/models';
import { BaseSingleInputPickersTextFieldProps } from '@mui/x-date-pickers/models';
import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList';

const BrowserFieldRoot = styled('div', { name: 'BrowserField', slot: 'Root' })({
Expand Down Expand Up @@ -104,18 +99,8 @@ const BrowserTextField = React.forwardRef(
},
);

interface BrowserDateFieldProps
extends UseDateFieldProps<true>,
BaseSingleInputFieldProps<
// This usage of PickerValidDate will go away with TIsRange
PickerValidDate | null,
FieldSection,
true,
DateValidationError
> {}

const BrowserDateField = React.forwardRef(
(props: BrowserDateFieldProps, ref: React.Ref<HTMLDivElement>) => {
(props: DatePickerFieldProps, ref: React.Ref<HTMLDivElement>) => {
const { slots, slotProps, ...textFieldProps } = props;

const fieldResponse = useDateField<true, typeof textFieldProps>(textFieldProps);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { styled } from '@mui/material/styles';
import Stack from '@mui/material/Stack';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';

import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker';
import { unstable_useMultiInputDateRangeField as useMultiInputDateRangeField } from '@mui/x-date-pickers-pro/MultiInputDateRangeField';
import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList';
Expand All @@ -25,8 +24,6 @@ const BrowserFieldContent = styled('div', { name: 'BrowserField', slot: 'Content
},
);

// This demo uses `BasePickersTextFieldProps` instead of `BaseMultiInputPickersTextFieldProps`,
// That way you can reuse the same `BrowserTextField` for all your pickers, range or not.
const BrowserTextField = React.forwardRef((props, ref) => {
const {
// Should be ignored
Expand Down Expand Up @@ -84,12 +81,10 @@ const BrowserMultiInputDateRangeField = React.forwardRef((props, ref) => {
const {
slotProps,
value,
defaultValue,
format,
onChange,
readOnly,
disabled,
onError,
shouldDisableDate,
minDate,
maxDate,
Expand Down Expand Up @@ -117,12 +112,10 @@ const BrowserMultiInputDateRangeField = React.forwardRef((props, ref) => {
const fieldResponse = useMultiInputDateRangeField({
sharedProps: {
value,
defaultValue,
format,
onChange,
readOnly,
disabled,
onError,
shouldDisableDate,
minDate,
maxDate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,17 @@ import { styled } from '@mui/material/styles';
import Stack from '@mui/material/Stack';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { PickerValidDate } from '@mui/x-date-pickers/models';
import {
DateRangePicker,
DateRangePickerFieldProps,
DateRangePickerProps,
} from '@mui/x-date-pickers-pro/DateRangePicker';
import { unstable_useMultiInputDateRangeField as useMultiInputDateRangeField } from '@mui/x-date-pickers-pro/MultiInputDateRangeField';
import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList';
import {
RangeFieldSection,
BaseMultiInputFieldProps,
BasePickersTextFieldProps,
MultiInputFieldSlotTextFieldProps,
DateRangeValidationError,
DateRange,
UseDateRangeFieldProps,
MultiInputFieldRefs,
BaseMultiInputPickersTextFieldProps,
} from '@mui/x-date-pickers-pro/models';

const BrowserFieldRoot = styled('div', { name: 'BrowserField', slot: 'Root' })({
Expand All @@ -38,14 +34,12 @@ const BrowserFieldContent = styled('div', { name: 'BrowserField', slot: 'Content
);

interface BrowserTextFieldProps
extends BasePickersTextFieldProps<true>,
extends BaseMultiInputPickersTextFieldProps<true>,
Omit<
React.HTMLAttributes<HTMLDivElement>,
keyof BasePickersTextFieldProps<true>
keyof BaseMultiInputPickersTextFieldProps<true>
> {}

// This demo uses `BasePickersTextFieldProps` instead of `BaseMultiInputPickersTextFieldProps`,
// That way you can reuse the same `BrowserTextField` for all your pickers, range or not.
const BrowserTextField = React.forwardRef(
(props: BrowserTextFieldProps, ref: React.Ref<unknown>) => {
const {
Expand Down Expand Up @@ -108,14 +102,11 @@ const BrowserTextField = React.forwardRef(
);

interface BrowserMultiInputDateRangeFieldProps
extends UseDateRangeFieldProps<true>,
BaseMultiInputFieldProps<
// This usage of PickerValidDate will go away with TIsRange
DateRange<PickerValidDate>,
RangeFieldSection,
true,
DateRangeValidationError
> {}
extends Omit<
DateRangePickerFieldProps,
'unstableFieldRef' | 'clearable' | 'onClear'
>,
MultiInputFieldRefs {}

type BrowserMultiInputDateRangeFieldComponent = ((
props: BrowserMultiInputDateRangeFieldProps & React.RefAttributes<HTMLDivElement>,
Expand All @@ -126,12 +117,10 @@ const BrowserMultiInputDateRangeField = React.forwardRef(
const {
slotProps,
value,
defaultValue,
format,
onChange,
readOnly,
disabled,
onError,
shouldDisableDate,
minDate,
maxDate,
Expand Down Expand Up @@ -162,12 +151,10 @@ const BrowserMultiInputDateRangeField = React.forwardRef(
>({
sharedProps: {
value,
defaultValue,
format,
onChange,
readOnly,
disabled,
onError,
shouldDisableDate,
minDate,
maxDate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker';
import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField';
import { useClearableField } from '@mui/x-date-pickers/hooks';
import { useClearableField, usePickerContext } from '@mui/x-date-pickers/hooks';
import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList';

const BrowserFieldRoot = styled('div', { name: 'BrowserField', slot: 'Root' })({
Expand Down Expand Up @@ -84,7 +84,16 @@ const BrowserTextField = React.forwardRef((props, ref) => {
});

const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => {
const { slots, slotProps, onAdornmentClick, ...other } = props;
const { slots, slotProps, ...other } = props;

const pickerContext = usePickerContext();
const handleTogglePicker = (event) => {
if (pickerContext.open) {
pickerContext.onClose(event);
} else {
pickerContext.onOpen(event);
}
};

const textFieldProps = useSlotProps({
elementType: 'input',
Expand All @@ -97,7 +106,7 @@ const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => {
...textFieldProps.InputProps,
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={onAdornmentClick}>
<IconButton onClick={handleTogglePicker}>
<DateRangeIcon />
</IconButton>
</InputAdornment>
Expand Down Expand Up @@ -127,29 +136,11 @@ const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => {
BrowserSingleInputDateRangeField.fieldType = 'single-input';

const BrowserSingleInputDateRangePicker = React.forwardRef((props, ref) => {
const [isOpen, setIsOpen] = React.useState(false);

const toggleOpen = () => setIsOpen((currentOpen) => !currentOpen);

const handleOpen = () => setIsOpen(true);

const handleClose = () => setIsOpen(false);

return (
<DateRangePicker
ref={ref}
{...props}
open={isOpen}
onClose={handleClose}
onOpen={handleOpen}
slots={{ ...props.slots, field: BrowserSingleInputDateRangeField }}
slotProps={{
...props.slotProps,
field: {
onAdornmentClick: toggleOpen,
...props.slotProps?.field,
},
}}
/>
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,14 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import {
DateRangePicker,
DateRangePickerFieldProps,
DateRangePickerProps,
} from '@mui/x-date-pickers-pro/DateRangePicker';
import {
unstable_useSingleInputDateRangeField as useSingleInputDateRangeField,
UseSingleInputDateRangeFieldProps,
} from '@mui/x-date-pickers-pro/SingleInputDateRangeField';
import { useClearableField } from '@mui/x-date-pickers/hooks';
import { unstable_useSingleInputDateRangeField as useSingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField';
import { useClearableField, usePickerContext } from '@mui/x-date-pickers/hooks';
import { Unstable_PickersSectionList as PickersSectionList } from '@mui/x-date-pickers/PickersSectionList';
import {
BasePickersTextFieldProps,
DateRangeValidationError,
RangeFieldSection,
DateRange,
FieldType,
} from '@mui/x-date-pickers-pro/models';
import {
BaseSingleInputFieldProps,
PickerValidDate,
} from '@mui/x-date-pickers/models';
import { FieldType } from '@mui/x-date-pickers-pro/models';
import { BaseSingleInputPickersTextFieldProps } from '@mui/x-date-pickers/models';

const BrowserFieldRoot = styled('div', { name: 'BrowserField', slot: 'Root' })({
display: 'flex',
Expand All @@ -48,10 +37,10 @@ const BrowserFieldContent = styled('div', { name: 'BrowserField', slot: 'Content
);

interface BrowserTextFieldProps
extends BasePickersTextFieldProps<true>,
extends BaseSingleInputPickersTextFieldProps<true>,
Omit<
React.HTMLAttributes<HTMLDivElement>,
keyof BasePickersTextFieldProps<true>
keyof BaseSingleInputPickersTextFieldProps<true>
> {}

const BrowserTextField = React.forwardRef(
Expand Down Expand Up @@ -115,25 +104,24 @@ const BrowserTextField = React.forwardRef(
},
);

interface BrowserSingleInputDateRangeFieldProps
extends UseSingleInputDateRangeFieldProps<true>,
BaseSingleInputFieldProps<
// This usage of PickerValidDate will go away with TIsRange
DateRange<PickerValidDate>,
RangeFieldSection,
true,
DateRangeValidationError
> {
onAdornmentClick?: () => void;
}
interface BrowserSingleInputDateRangeFieldProps extends DateRangePickerFieldProps {}

type BrowserSingleInputDateRangeFieldComponent = ((
props: BrowserSingleInputDateRangeFieldProps & React.RefAttributes<HTMLDivElement>,
) => React.JSX.Element) & { fieldType?: FieldType };

const BrowserSingleInputDateRangeField = React.forwardRef(
(props: BrowserSingleInputDateRangeFieldProps, ref: React.Ref<HTMLDivElement>) => {
const { slots, slotProps, onAdornmentClick, ...other } = props;
const { slots, slotProps, ...other } = props;

const pickerContext = usePickerContext();
const handleTogglePicker = (event: React.UIEvent) => {
if (pickerContext.open) {
pickerContext.onClose(event);
} else {
pickerContext.onOpen(event);
}
};

const textFieldProps: typeof props = useSlotProps({
elementType: 'input',
Expand All @@ -146,7 +134,7 @@ const BrowserSingleInputDateRangeField = React.forwardRef(
...textFieldProps.InputProps,
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={onAdornmentClick}>
<IconButton onClick={handleTogglePicker}>
<DateRangeIcon />
</IconButton>
</InputAdornment>
Expand Down Expand Up @@ -180,29 +168,11 @@ BrowserSingleInputDateRangeField.fieldType = 'single-input';

const BrowserSingleInputDateRangePicker = React.forwardRef(
(props: DateRangePickerProps, ref: React.Ref<HTMLDivElement>) => {
const [isOpen, setIsOpen] = React.useState(false);

const toggleOpen = () => setIsOpen((currentOpen) => !currentOpen);

const handleOpen = () => setIsOpen(true);

const handleClose = () => setIsOpen(false);

return (
<DateRangePicker
ref={ref}
{...props}
open={isOpen}
onClose={handleClose}
onOpen={handleOpen}
slots={{ ...props.slots, field: BrowserSingleInputDateRangeField }}
slotProps={{
...props.slotProps,
field: {
onAdornmentClick: toggleOpen,
...props.slotProps?.field,
} as any,
}}
/>
);
},
Expand Down
Loading

0 comments on commit 16c8962

Please sign in to comment.