Skip to content

Commit

Permalink
New components: MultiInputDateTimeRangePicker and `MultiInputTimeRa…
Browse files Browse the repository at this point in the history
…ngePicker` (mui#6392)
  • Loading branch information
alexfauquette authored Oct 12, 2022
1 parent 40b0fc9 commit 277ab07
Show file tree
Hide file tree
Showing 47 changed files with 1,284 additions and 216 deletions.
11 changes: 9 additions & 2 deletions docs/data/date-pickers/date-range-field/BasicDateRangeField.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@ import { Unstable_MultiInputDateRangeField as MultiInputDateRangeField } from '@
import { Unstable_SingleInputDateRangeField as SingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField';

export default function BasicDateRangeField() {
const [value, setValue] = React.useState([null, null]);
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Stack spacing={4}>
<MultiInputDateRangeField />
<SingleInputDateRangeField />
<MultiInputDateRangeField
value={value}
onChange={(newValue) => setValue(newValue)}
/>
<SingleInputDateRangeField
value={value}
onChange={(newValue) => setValue(newValue)}
/>
</Stack>
</LocalizationProvider>
);
Expand Down
11 changes: 9 additions & 2 deletions docs/data/date-pickers/date-range-field/BasicDateRangeField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@ import { Unstable_MultiInputDateRangeField as MultiInputDateRangeField } from '@
import { Unstable_SingleInputDateRangeField as SingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField';

export default function BasicDateRangeField() {
const [value, setValue] = React.useState<any>([null, null]);
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Stack spacing={4}>
<MultiInputDateRangeField />
<SingleInputDateRangeField />
<MultiInputDateRangeField
value={value}
onChange={(newValue) => setValue(newValue)}
/>
<SingleInputDateRangeField
value={value}
onChange={(newValue) => setValue(newValue)}
/>
</Stack>
</LocalizationProvider>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Stack spacing={4}>
<MultiInputDateRangeField />
<SingleInputDateRangeField />
<MultiInputDateRangeField
value={value}
onChange={(newValue) => setValue(newValue)}
/>
<SingleInputDateRangeField
value={value}
onChange={(newValue) => setValue(newValue)}
/>
</Stack>
</LocalizationProvider>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
onSpaceOrEnter,
useLocaleText,
} from '@mui/x-date-pickers/internals';
import { CurrentlySelectingRangeEndProps, DateRange } from '../internal/models/dateRange';
import { CurrentlySelectingRangeEndProps, DateRange } from '../internal/models/range';
import { DateRangeValidationError } from '../internal/hooks/validation/useDateRangeValidation';
import {
DateRangePickerInputClasses,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,8 @@ import {
BaseDateValidationProps,
DayValidationProps,
} from '@mui/x-date-pickers/internals';
import {
DateRange,
CurrentlySelectingRangeEndProps,
DayRangeValidationProps,
} from '../internal/models/dateRange';
import { DateRange, CurrentlySelectingRangeEndProps } from '../internal/models/range';
import { DayRangeValidationProps } from '../internal/models/dateRange';
import { isRangeValid } from '../internal/utils/date-utils';
import { calculateRangeChange } from './date-range-manager';
import { DateRangePickerToolbar } from './DateRangePickerToolbar';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
DayCalendarSlotsComponentsProps,
} from '@mui/x-date-pickers/internals';
import { calculateRangePreview } from './date-range-manager';
import { DateRange } from '../internal/models';
import { DateRange } from '../internal/models/range';
import { DateRangePickerDay, DateRangePickerDayProps } from '../DateRangePickerDay';
import { isWithinRange, isStartOfRange, isEndOfRange } from '../internal/utils/date-utils';
import { doNothing } from '../internal/utils/utils';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import {
DayCalendarSlotsComponentsProps,
} from '@mui/x-date-pickers/internals';
import { doNothing } from '../internal/utils/utils';
import { DateRange } from '../internal/models/dateRange';
import { DateRange } from '../internal/models/range';
import { DateRangePickerDay, DateRangePickerDayProps } from '../DateRangePickerDay';

import { isWithinRange, isStartOfRange, isEndOfRange } from '../internal/utils/date-utils';

export interface DateRangePickerViewMobileSlotsComponent<TDate>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect } from 'chai';
import { adapterToUse } from 'test/utils/pickers-utils';
import { calculateRangeChange, calculateRangePreview } from './date-range-manager';
import { DateRange } from '../internal/models/dateRange';
import { DateRange } from '../internal/models/range';

const start2018 = adapterToUse.date(new Date(2018, 0, 1));
const mid2018 = adapterToUse.date(new Date(2018, 6, 1));
Expand Down
1 change: 1 addition & 0 deletions packages/x-date-pickers-pro/src/DateRangePicker/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export function useDateRangePickerDefaultizedProps<
};
}

// What about renaming it `rangePickerValueManager` such that it's clear this manager is common to date, time and dateTime?
export const dateRangePickerValueManager: PickerStateValueManager<[any, any], any> = {
emptyValue: [null, null],
getTodayValue: (utils) => [utils.date()!, utils.date()!],
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Typography, { TypographyProps } from '@mui/material/Typography';
import { styled, useThemeProps } from '@mui/material/styles';
import { useSlotProps } from '@mui/base/utils';
import { MultiInputDateRangeFieldProps } from './MultiInputDateRangeField.types';
import { useMultiInputDateRangeField } from './useMultiInputDateRangeField';
import { useMultiInputDateRangeField } from '../internal/hooks/useMultiInputRangeField/useMultiInputDateRangeField';

const MultiInputDateRangeFieldRoot = styled(
React.forwardRef((props: StackProps, ref: React.Ref<HTMLDivElement>) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ import { SlotComponentProps } from '@mui/base/utils';
import Typography from '@mui/material/Typography';
import Stack from '@mui/material/Stack';
import TextField from '@mui/material/TextField';
import { UseSingleInputDateRangeFieldProps } from '../SingleInputDateRangeField';
import { UseDateRangeFieldProps } from '../internal/models/dateRange';

export interface UseMultiInputDateRangeFieldParams<TDate, TChildProps extends {}> {
sharedProps: UseMultiInputDateRangeFieldComponentProps<TDate, {}>;
sharedProps: Omit<TChildProps, keyof UseMultiInputDateRangeFieldProps<TDate>> &
UseMultiInputDateRangeFieldProps<TDate>;
startInputProps: TChildProps;
endInputProps: TChildProps;
startInputRef?: React.Ref<HTMLInputElement>;
endInputRef?: React.Ref<HTMLInputElement>;
}

export interface UseMultiInputDateRangeFieldProps<TDate>
extends UseSingleInputDateRangeFieldProps<TDate> {}
export interface UseMultiInputDateRangeFieldProps<TDate> extends UseDateRangeFieldProps<TDate> {}

export type UseMultiInputDateRangeFieldComponentProps<TDate, TChildProps extends {}> = Omit<
TChildProps,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import * as React from 'react';
import Stack, { StackProps } from '@mui/material/Stack';
import TextField, { TextFieldProps } from '@mui/material/TextField';
import Typography, { TypographyProps } from '@mui/material/Typography';
import { styled, useThemeProps } from '@mui/material/styles';
import { useSlotProps } from '@mui/base/utils';
import { MultiInputDateTimeRangeFieldProps } from './MultiInputDateTimeRangeField.types';
import { useMultiInputDateTimeRangeField } from '../internal/hooks/useMultiInputRangeField/useMultiInputDateTimeRangeField';

const MultiInputDateTimeRangeFieldRoot = styled(
React.forwardRef((props: StackProps, ref: React.Ref<HTMLDivElement>) => (
<Stack ref={ref} {...props} spacing={2} direction="row" alignItems="center" />
)),
{
name: 'MuiMultiInputDateTimeRangeField',
slot: 'Root',
overridesResolver: (props, styles) => styles.root,
},
)({});

const MultiInputDateTimeRangeFieldSeparator = styled(
(props: TypographyProps) => <Typography {...props}>{props.children ?? ' — '}</Typography>,
{
name: 'MuiMultiInputDateTimeRangeField',
slot: 'Separator',
overridesResolver: (props, styles) => styles.separator,
},
)({});

type MultiInputDateTimeRangeFieldComponent = (<TDate>(
props: MultiInputDateTimeRangeFieldProps<TDate> & React.RefAttributes<HTMLInputElement>,
) => JSX.Element) & { propTypes?: any };

export const MultiInputDateTimeRangeField = React.forwardRef(function MultiInputDateTimeRangeField<
TDate,
>(inProps: MultiInputDateTimeRangeFieldProps<TDate>, ref: React.Ref<HTMLInputElement>) {
const themeProps = useThemeProps({
props: inProps,
name: 'MuiMultiInputDateTimeRangeField',
});

const {
components,
componentsProps,
value,
defaultValue,
format,
onChange,
readOnly,
onError,
shouldDisableDate,
minDate,
maxDate,
minTime,
maxTime,
minDateTime,
maxDateTime,
minutesStep,
shouldDisableTime,
disableFuture,
disablePast,
...other
} = themeProps;

const ownerState = themeProps;

const Root = components?.Root ?? MultiInputDateTimeRangeFieldRoot;
const rootProps = useSlotProps({
elementType: Root,
externalSlotProps: componentsProps?.root,
externalForwardedProps: other,
additionalProps: {
ref,
},
ownerState,
});

const Input = components?.Input ?? TextField;
const startInputProps: TextFieldProps = useSlotProps({
elementType: Input,
externalSlotProps: componentsProps?.input,
ownerState: { ...ownerState, position: 'start' },
});
const endInputProps: TextFieldProps = useSlotProps({
elementType: Input,
externalSlotProps: componentsProps?.input,
ownerState: { ...ownerState, position: 'end' },
});

const Separator = components?.Separator ?? MultiInputDateTimeRangeFieldSeparator;
const separatorProps = useSlotProps({
elementType: Separator,
externalSlotProps: componentsProps?.separator,
ownerState,
});

const {
startDate: { onKeyDown: onStartInputKeyDown, ref: startInputRef, ...startDateProps },
endDate: { onKeyDown: onEndInputKeyDown, ref: endInputRef, ...endDateProps },
} = useMultiInputDateTimeRangeField<TDate, TextFieldProps>({
sharedProps: {
value,
defaultValue,
format,
onChange,
readOnly,
onError,
shouldDisableDate,
minDate,
maxDate,
minTime,
maxTime,
minDateTime,
maxDateTime,
minutesStep,
shouldDisableTime,
disableFuture,
disablePast,
},
startInputProps,
endInputProps,
startInputRef: startInputProps.inputRef,
endInputRef: endInputProps.inputRef,
});

return (
<Root {...rootProps}>
<Input
{...startDateProps}
inputProps={{
...startDateProps.inputProps,
ref: startInputRef,
onKeyDown: onStartInputKeyDown,
}}
/>
<Separator {...separatorProps} />
<Input
{...endDateProps}
inputProps={{
...endDateProps.inputProps,
ref: endInputRef,
onKeyDown: onEndInputKeyDown,
}}
/>
</Root>
);
}) as MultiInputDateTimeRangeFieldComponent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import * as React from 'react';
import { SlotComponentProps } from '@mui/base/utils';
import Typography from '@mui/material/Typography';
import Stack from '@mui/material/Stack';
import TextField, { TextFieldProps } from '@mui/material/TextField';
import {
UseDateTimeRangeFieldDefaultizedProps,
UseDateTimeRangeFieldProps,
} from '../internal/models/dateTimeRange';

export interface UseMultiInputDateTimeRangeFieldParams<TDate, TChildProps extends {}> {
sharedProps: Omit<TChildProps, keyof UseMultiInputDateTimeRangeFieldProps<TDate>> &
UseMultiInputDateTimeRangeFieldProps<TDate>;
startInputProps: TChildProps;
endInputProps: TChildProps;
startInputRef?: React.Ref<HTMLInputElement>;
endInputRef?: React.Ref<HTMLInputElement>;
}

export interface UseMultiInputDateTimeRangeFieldProps<TDate>
extends UseDateTimeRangeFieldProps<TDate> {}

export type UseMultiInputDateTimeRangeFieldComponentProps<TDate, TChildProps extends {}> = Omit<
TChildProps,
keyof UseMultiInputDateTimeRangeFieldProps<TDate>
> &
UseMultiInputDateTimeRangeFieldProps<TDate>;

export interface MultiInputDateTimeRangeFieldProps<TDate>
extends UseMultiInputDateTimeRangeFieldComponentProps<TDate, TextFieldProps> {
/**
* Overrideable components.
* @default {}
*/
components?: MultiInputDateTimeRangeFieldSlotsComponent;
/**
* The props used for each component slot.
* @default {}
*/
componentsProps?: MultiInputDateTimeRangeFieldSlotsComponentsProps<TDate>;
}

export type MultiInputDateTimeRangeFieldOwnerState<TDate> =
MultiInputDateTimeRangeFieldProps<TDate>;

export interface MultiInputDateTimeRangeFieldSlotsComponent {
/**
* Element rendered at the root.
* @default MultiInputDateTimeRangeFieldRoot
*/
Root?: React.ElementType;
/**
* Input rendered for the start or end date.
* @default TextField
*/
Input?: React.ElementType;
/**
* Element rendered between the two inputs.
* @default MultiInputDateTimeRangeFieldSeparator
*/
Separator?: React.ElementType;
}

export interface MultiInputDateTimeRangeFieldSlotsComponentsProps<TDate> {
root?: SlotComponentProps<typeof Stack, {}, MultiInputDateTimeRangeFieldOwnerState<TDate>>;
input?: SlotComponentProps<
typeof TextField,
{},
MultiInputDateTimeRangeFieldOwnerState<TDate> & { position: 'start' | 'end' }
>;
separator?: SlotComponentProps<
typeof Typography,
{},
MultiInputDateTimeRangeFieldOwnerState<TDate>
>;
}

export type UseMultiInputDateTimeRangeFieldDefaultizedProps<TDate> =
UseDateTimeRangeFieldDefaultizedProps<TDate>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { MultiInputDateTimeRangeField as Unstable_MultiInputDateTimeRangeField } from './MultiInputDateTimeRangeField';
export type { UseMultiInputDateTimeRangeFieldProps } from './MultiInputDateTimeRangeField.types';
Loading

0 comments on commit 277ab07

Please sign in to comment.