Skip to content

Commit

Permalink
[@mantine/dates] DateInput: Separate clearable and allowDeselect logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Gibbs committed Jul 11, 2023
1 parent 3791991 commit 72e45b9
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 14 deletions.
6 changes: 3 additions & 3 deletions docs/src/docs/dates/DateInput.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ and must return `Date` object:

<Demo data={DateInputDemos.parser} />

## Allow deselect
## Allow clear

Set `allowDeselect` prop to allow removing value from the input. Input will be cleared if
Set `clearable` prop to allow removing value from the input. Input will be cleared if
user selects the same date in dropdown or clears input value:

<Demo data={DateInputDemos.deselect} />
<Demo data={DateInputDemos.clearable} />

## Min and max date

Expand Down
73 changes: 67 additions & 6 deletions src/mantine-dates/src/components/DateInput/DateInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,9 @@ describe('@mantine/dates/DateInput', () => {
expect(spy).toHaveBeenLastCalledWith(null);
});

it('allows to clear input value when allowDeselect is set (uncontrolled)', async () => {
it('allows to clear input value when clearable is set (uncontrolled)', async () => {
const { container } = render(
<DateInput {...defaultProps} allowDeselect defaultValue={new Date(2022, 3, 11)} />
<DateInput {...defaultProps} clearable defaultValue={new Date(2022, 3, 11)} />
);

expectValue(container, 'April 11, 2022');
Expand All @@ -223,30 +223,91 @@ describe('@mantine/dates/DateInput', () => {
expectValue(container, '');
});

it('does not allow to clear input value when allowDeselect is not set (uncontrolled)', async () => {
it('allows to clear input value when clearable is set (controlled)', async () => {
const spy = jest.fn();
const { container } = render(
<DateInput {...defaultProps} allowDeselect={false} defaultValue={new Date(2022, 3, 11)} />
<DateInput {...defaultProps} clearable value={new Date(2022, 3, 11)} onChange={spy} />
);

expectValue(container, 'April 11, 2022');
await userEvent.clear(getInput(container));
await userEvent.tab();
expectValue(container, 'April 11, 2022');
expect(spy).toHaveBeenLastCalledWith(null);
});

it('allows to clear input value when allowDeselect is set (controlled)', async () => {
it('does not allow to clear input value when clearable is not set (uncontrolled)', async () => {
const { container } = render(
<DateInput {...defaultProps} clearable={false} defaultValue={new Date(2022, 3, 11)} />
);

expectValue(container, 'April 11, 2022');
await userEvent.clear(getInput(container));
await userEvent.tab();
expectValue(container, 'April 11, 2022');
});

it('does not allow to clear input value when clearable is not set (controlled)', async () => {
const spy = jest.fn();
const { container } = render(
<DateInput {...defaultProps} allowDeselect value={new Date(2022, 3, 11)} onChange={spy} />
<DateInput {...defaultProps} clearable={false} value={new Date(2022, 3, 11)} onChange={spy} />
);

expectValue(container, 'April 11, 2022');
await userEvent.clear(getInput(container));
await userEvent.tab();
expectValue(container, 'April 11, 2022');
expect(spy).not.toHaveBeenCalled();
});

it('allows to clear input value by clicking the selected date when clearable and allowDeselect are set (uncontrolled)', async () => {
const { container } = render(
<DateInput {...defaultProps} clearable allowDeselect defaultValue={new Date(2022, 3, 1)} />
);

expectValue(container, 'April 1, 2022');
await userEvent.tab();
await clickControl(container, 4);
expectValue(container, '');
});

it('allows to clear input value by clicking the selected date when clearable and allowDeselect are set (controlled)', async () => {
const spy = jest.fn();
const { container } = render(
<DateInput {...defaultProps} clearable allowDeselect value={new Date(2022, 3, 1)} onChange={spy} />
);

expectValue(container, 'April 1, 2022');
await userEvent.tab();
await clickControl(container, 4);
expectValue(container, 'April 1, 2022');
expect(spy).toHaveBeenLastCalledWith(null);
});

it('does not allow to clear input value by clicking the selected date when allowDeselect is not set (uncontrolled)', async () => {
const { container } = render(
<DateInput {...defaultProps} clearable allowDeselect={false} defaultValue={new Date(2022, 3, 1)} />
);

expectValue(container, 'April 1, 2022');
await userEvent.tab();
await clickControl(container, 4);
expectValue(container, 'April 1, 2022');
});

it('does not allow to clear input value by clicking the selected date when allowDeselect is not set (controlled)', async () => {
const spy = jest.fn();
const { container } = render(
<DateInput {...defaultProps} clearable allowDeselect={false} value={new Date(2022, 3, 1)} onChange={spy} />
);

expectValue(container, 'April 1, 2022');
await userEvent.tab();
await clickControl(container, 4);
expectValue(container, 'April 1, 2022');
expect(spy).toHaveBeenLastCalledWith(new Date(2022, 3, 1));
});

it('calls onClick when input is clicked', async () => {
const spy = jest.fn();
const { container } = render(<DateInput {...defaultProps} onClick={spy} />);
Expand Down
8 changes: 4 additions & 4 deletions src/mantine-dates/src/components/DateInput/DateInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export interface DateInputProps
/** Determines whether input value should be reverted to last known valid value on blur, true by default */
fixOnBlur?: boolean;

/** Determines whether value can be deselected when the user clicks on the selected date in the calendar or erases content of the input, true if clearable prop is set, false by default */
/** Determines whether value can be deselected when the user clicks on the selected date in the calendar (only when clearable prop is set), defaults to true if clearable prop is set, false otherwise */
allowDeselect?: boolean;

/** Determines whether time (hours, minutes, seconds and milliseconds) should be preserved when new date is picked, true by default */
Expand Down Expand Up @@ -130,7 +130,7 @@ export const DateInput = forwardRef<HTMLInputElement, DateInputProps>((props, re
};

const _dateParser = dateParser || defaultDateParser;
const _allowDeselect = clearable || allowDeselect;
const _allowDeselect = allowDeselect !== undefined ? allowDeselect : clearable;

const formatValue = (val: Date) =>
val ? dayjs(val).locale(ctx.getLocale(locale)).format(valueFormat) : '';
Expand Down Expand Up @@ -167,7 +167,7 @@ export const DateInput = forwardRef<HTMLInputElement, DateInputProps>((props, re
const val = event.currentTarget.value;
setInputValue(val);

if (val.trim() === '' && _allowDeselect) {
if (val.trim() === '' && clearable) {
setValue(null);
} else {
const dateValue = _dateParser(val);
Expand Down Expand Up @@ -199,7 +199,7 @@ export const DateInput = forwardRef<HTMLInputElement, DateInputProps>((props, re
selected: dayjs(_value).isSame(day, 'day'),
onClick: () => {
const valueWithTime = preserveTime ? assignTime(_value, day) : day;
const val = _allowDeselect
const val = clearable && _allowDeselect
? dayjs(_value).isSame(day, 'day')
? null
: valueWithTime
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const code = `
import { DateInput } from '@mantine/dates';
function Demo() {
return <DateInput label="Date input" placeholder="Date input" maw={400} mx="auto" />;
return <DateInput clearable label="Date input" placeholder="Date input" maw={400} mx="auto" />;
}
`;

Expand Down

0 comments on commit 72e45b9

Please sign in to comment.