Skip to content

Commit

Permalink
[docs] Add DateRangePicker example with a Button trigger (#10485)
Browse files Browse the repository at this point in the history
Signed-off-by: Lukas <[email protected]>
Co-authored-by: Nora <[email protected]>
  • Loading branch information
LukasTy and noraleonte authored Oct 3, 2023
1 parent e9f90e2 commit 0ead122
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import * as React from 'react';

import Button from '@mui/material/Button';
import useForkRef from '@mui/utils/useForkRef';

import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker';

const DateRangeButtonField = React.forwardRef((props, ref) => {
const {
setOpen,
label,
id,
disabled,
InputProps: { ref: containerRef } = {},
inputProps: { 'aria-label': ariaLabel } = {},
} = props;

const handleRef = useForkRef(ref, containerRef);

return (
<Button
variant="outlined"
id={id}
disabled={disabled}
ref={handleRef}
aria-label={ariaLabel}
onClick={() => setOpen?.((prev) => !prev)}
>
{label ? `Current date range: ${label}` : 'Pick a date range'}
</Button>
);
});

DateRangeButtonField.fieldType = 'single-input';

const ButtonDateRangePicker = React.forwardRef((props, ref) => {
const [open, setOpen] = React.useState(false);

return (
<DateRangePicker
slots={{ field: DateRangeButtonField, ...props.slots }}
slotProps={{ field: { setOpen } }}
ref={ref}
{...props}
open={open}
onClose={() => setOpen(false)}
onOpen={() => setOpen(true)}
/>
);
});

export default function DateRangePickerWithButtonField() {
const [value, setValue] = React.useState([null, null]);

return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<ButtonDateRangePicker
label={
value[0] === null && value[1] === null
? null
: value
.map((date) => (date ? date.format('MM/DD/YYYY') : 'null'))
.join(' - ')
}
value={value}
onChange={(newValue) => setValue(newValue)}
/>
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import * as React from 'react';
import { Dayjs } from 'dayjs';
import Button from '@mui/material/Button';
import useForkRef from '@mui/utils/useForkRef';
import { DateRange } from '@mui/x-date-pickers-pro';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import {
DateRangePicker,
DateRangePickerProps,
} from '@mui/x-date-pickers-pro/DateRangePicker';
import { SingleInputDateRangeFieldProps } from '@mui/x-date-pickers-pro/SingleInputDateRangeField';

interface DateRangeButtonFieldProps extends SingleInputDateRangeFieldProps<Dayjs> {
setOpen?: React.Dispatch<React.SetStateAction<boolean>>;
}

type DateRangeButtonFieldComponent = ((
props: DateRangeButtonFieldProps & React.RefAttributes<HTMLDivElement>,
) => React.JSX.Element) & { fieldType?: string };

const DateRangeButtonField = React.forwardRef(
(props: DateRangeButtonFieldProps, ref: React.Ref<HTMLDivElement>) => {
const {
setOpen,
label,
id,
disabled,
InputProps: { ref: containerRef } = {},
inputProps: { 'aria-label': ariaLabel } = {},
} = props;

const handleRef = useForkRef(ref, containerRef);

return (
<Button
variant="outlined"
id={id}
disabled={disabled}
ref={handleRef}
aria-label={ariaLabel}
onClick={() => setOpen?.((prev) => !prev)}
>
{label ? `Current date range: ${label}` : 'Pick a date range'}
</Button>
);
},
) as DateRangeButtonFieldComponent;

DateRangeButtonField.fieldType = 'single-input';

const ButtonDateRangePicker = React.forwardRef(
(
props: Omit<DateRangePickerProps<Dayjs>, 'open' | 'onOpen' | 'onClose'>,
ref: React.Ref<HTMLDivElement>,
) => {
const [open, setOpen] = React.useState(false);

return (
<DateRangePicker
slots={{ field: DateRangeButtonField, ...props.slots }}
slotProps={{ field: { setOpen } as any }}
ref={ref}
{...props}
open={open}
onClose={() => setOpen(false)}
onOpen={() => setOpen(true)}
/>
);
},
);

export default function DateRangePickerWithButtonField() {
const [value, setValue] = React.useState<DateRange<Dayjs>>([null, null]);

return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<ButtonDateRangePicker
label={
value[0] === null && value[1] === null
? null
: value
.map((date) => (date ? date.format('MM/DD/YYYY') : 'null'))
.join(' - ')
}
value={value}
onChange={(newValue) => setValue(newValue)}
/>
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<ButtonDateRangePicker
label={
value[0] === null && value[1] === null
? null
: value
.map((date) => (date ? date.format('MM/DD/YYYY') : 'null'))
.join(' - ')
}
value={value}
onChange={(newValue) => setValue(newValue)}
/>
17 changes: 6 additions & 11 deletions docs/data/date-pickers/custom-field/PickerWithButtonField.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from 'react';

import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
Expand All @@ -25,7 +24,7 @@ function ButtonField(props) {
aria-label={ariaLabel}
onClick={() => setOpen?.((prev) => !prev)}
>
{label ?? 'Pick a date'}
{label ? `Current date: ${label}` : 'Pick a date'}
</Button>
);
}
Expand All @@ -50,15 +49,11 @@ export default function PickerWithButtonField() {

return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Stack spacing={1}>
<ButtonDatePicker
label={`Current date: ${
value == null ? 'null' : value.format('MM/DD/YYYY')
}`}
value={value}
onChange={(newValue) => setValue(newValue)}
/>
</Stack>
<ButtonDatePicker
label={value == null ? null : value.format('MM/DD/YYYY')}
value={value}
onChange={(newValue) => setValue(newValue)}
/>
</LocalizationProvider>
);
}
17 changes: 6 additions & 11 deletions docs/data/date-pickers/custom-field/PickerWithButtonField.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from 'react';
import { Dayjs } from 'dayjs';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DatePicker, DatePickerProps } from '@mui/x-date-pickers/DatePicker';
Expand Down Expand Up @@ -42,7 +41,7 @@ function ButtonField(props: ButtonFieldProps) {
aria-label={ariaLabel}
onClick={() => setOpen?.((prev) => !prev)}
>
{label ?? 'Pick a date'}
{label ? `Current date: ${label}` : 'Pick a date'}
</Button>
);
}
Expand All @@ -69,15 +68,11 @@ export default function PickerWithButtonField() {

return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Stack spacing={1}>
<ButtonDatePicker
label={`Current date: ${
value == null ? 'null' : value.format('MM/DD/YYYY')
}`}
value={value}
onChange={(newValue) => setValue(newValue)}
/>
</Stack>
<ButtonDatePicker
label={value == null ? null : value.format('MM/DD/YYYY')}
value={value}
onChange={(newValue) => setValue(newValue)}
/>
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<ButtonDatePicker
label={`Current date: ${
value == null ? 'null' : value.format('MM/DD/YYYY')
}`}
label={value == null ? null : value.format('MM/DD/YYYY')}
value={value}
onChange={(newValue) => setValue(newValue)}
/>
4 changes: 4 additions & 0 deletions docs/data/date-pickers/custom-field/custom-field.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ you can replace the field with a `Button`:

{{"demo": "PickerWithButtonField.js", "defaultCodeOpen": false}}

The same can be applied to the `DateRangePicker`:

{{"demo": "DateRangePickerWithButtonField.js", "defaultCodeOpen": false}}

## How to build a custom field

The main challenge when building a custom field, is to make sure that all the relevant props passed by the pickers are correctly handled.
Expand Down

0 comments on commit 0ead122

Please sign in to comment.