Skip to content

Commit

Permalink
[pickers] Implement clearable field behavior (#9095)
Browse files Browse the repository at this point in the history
Signed-off-by: noraleonte <[email protected]>
Signed-off-by: Nora <[email protected]>
Co-authored-by: Lukas <[email protected]>
  • Loading branch information
noraleonte and LukasTy authored Sep 28, 2023
1 parent aad46c8 commit 0453af4
Show file tree
Hide file tree
Showing 116 changed files with 1,560 additions and 209 deletions.
100 changes: 78 additions & 22 deletions docs/data/date-pickers/custom-field/PickerWithBrowserField.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useSlotProps } from '@mui/base/utils';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import IconButton from '@mui/material/IconButton';
import InputAdornment from '@mui/material/InputAdornment';
import { DemoContainer } from '@mui/x-date-pickers/internals/demo';
import { DateRangeIcon } from '@mui/x-date-pickers/icons';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
Expand All @@ -15,6 +16,8 @@ import { unstable_useMultiInputDateRangeField as useMultiInputDateRangeField } f
import { DatePicker } 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';

const BrowserField = React.forwardRef((props, ref) => {
const {
disabled,
Expand All @@ -26,14 +29,15 @@ const BrowserField = React.forwardRef((props, ref) => {
error,
focused,
ownerState,
sx,
...other
} = props;

const handleRef = useForkRef(containerRef, ref);

return (
<Box
sx={{ display: 'flex', alignItems: 'center', flexGrow: 1 }}
sx={{ ...(sx || {}), display: 'flex', alignItems: 'center', flexGrow: 1 }}
id={id}
ref={handleRef}
>
Expand All @@ -48,33 +52,51 @@ const BrowserSingleInputDateRangeField = React.forwardRef((props, ref) => {
const { slots, slotProps, onAdornmentClick, ...other } = props;

const { inputRef: externalInputRef, ...textFieldProps } = useSlotProps({
elementType: null,
elementType: 'input',
externalSlotProps: slotProps?.textField,
externalForwardedProps: other,
ownerState: props,
});

const { ref: inputRef, ...response } = useSingleInputDateRangeField({
const {
ref: inputRef,
onClear,
clearable,
...fieldProps
} = useSingleInputDateRangeField({
props: textFieldProps,
inputRef: externalInputRef,
});

/* If you don't need a clear button, you can skip the use of this hook */
const { InputProps: ProcessedInputProps, fieldProps: processedFieldProps } =
useClearableField({
onClear,
clearable,
fieldProps,
InputProps: {
...fieldProps.InputProps,
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={onAdornmentClick}>
<DateRangeIcon />
</IconButton>
</InputAdornment>
),
},
slots,
slotProps,
});

return (
<BrowserField
{...response}
{...processedFieldProps}
ref={ref}
style={{
minWidth: 300,
}}
inputRef={inputRef}
InputProps={{
...response.InputProps,
endAdornment: (
<IconButton onClick={onAdornmentClick}>
<DateRangeIcon />
</IconButton>
),
}}
InputProps={{ ...ProcessedInputProps }}
/>
);
});
Expand All @@ -93,14 +115,18 @@ const BrowserSingleInputDateRangePicker = React.forwardRef((props, ref) => {
return (
<DateRangePicker
ref={ref}
{...props}
open={isOpen}
onClose={handleClose}
onOpen={handleOpen}
slots={{ field: BrowserSingleInputDateRangeField }}
slotProps={{
field: { onAdornmentClick: toggleOpen },
...props?.slotProps,
field: {
onAdornmentClick: toggleOpen,
...props?.slotProps?.field,
},
}}
{...props}
/>
);
});
Expand All @@ -126,13 +152,13 @@ const BrowserMultiInputDateRangeField = React.forwardRef((props, ref) => {
} = props;

const { inputRef: startInputRef, ...startTextFieldProps } = useSlotProps({
elementType: null,
elementType: 'input',
externalSlotProps: slotProps?.textField,
ownerState: { ...props, position: 'start' },
});

const { inputRef: endInputRef, ...endTextFieldProps } = useSlotProps({
elementType: null,
elementType: 'input',
externalSlotProps: slotProps?.textField,
ownerState: { ...props, position: 'end' },
});
Expand Down Expand Up @@ -176,29 +202,51 @@ const BrowserDateRangePicker = React.forwardRef((props, ref) => {
return (
<DateRangePicker
ref={ref}
slots={{ field: BrowserMultiInputDateRangeField }}
{...props}
slots={{ ...props?.slots, field: BrowserMultiInputDateRangeField }}
/>
);
});

const BrowserDateField = React.forwardRef((props, ref) => {
const { inputRef: externalInputRef, slots, slotProps, ...textFieldProps } = props;

const { ref: inputRef, ...other } = useDateField({
const {
onClear,
clearable,
ref: inputRef,
...fieldProps
} = useDateField({
props: textFieldProps,
inputRef: externalInputRef,
});

return <BrowserField ref={ref} inputRef={inputRef} {...other} />;
/* If you don't need a clear button, you can skip the use of this hook */
const { InputProps: ProcessedInputProps, fieldProps: processedFieldProps } =
useClearableField({
onClear,
clearable,
fieldProps,
InputProps: fieldProps.InputProps,
slots,
slotProps,
});
return (
<BrowserField
ref={ref}
inputRef={inputRef}
{...processedFieldProps}
InputProps={ProcessedInputProps}
/>
);
});

const BrowserDatePicker = React.forwardRef((props, ref) => {
return (
<DatePicker
ref={ref}
slots={{ field: BrowserDateField, ...props.slots }}
{...props}
slots={{ field: BrowserDateField, ...props.slots }}
/>
);
});
Expand All @@ -209,8 +257,16 @@ export default function PickerWithBrowserField() {
<DemoContainer
components={['DatePicker', 'SingleInputDateRangeField', 'DateRangePicker']}
>
<BrowserDatePicker />
<BrowserSingleInputDateRangePicker />
<BrowserDatePicker
slotProps={{
field: { clearable: true },
}}
/>
<BrowserSingleInputDateRangePicker
slotProps={{
field: { clearable: true },
}}
/>
<BrowserDateRangePicker />
</DemoContainer>
</LocalizationProvider>
Expand Down
Loading

0 comments on commit 0453af4

Please sign in to comment.