Skip to content

Commit

Permalink
[@mantine/core] Add range type to DateTimePicker
Browse files Browse the repository at this point in the history
  • Loading branch information
wuifdesign committed Dec 11, 2023
1 parent 8098173 commit 40d2292
Show file tree
Hide file tree
Showing 9 changed files with 420 additions and 199 deletions.
6 changes: 6 additions & 0 deletions docs/src/pages/dates/date-time-picker.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ read through [DatePicker](/dates/date-picker/) documentation to learn about all

<Demo data={DateTimePickerDemos.withSeconds} />

## Dates range

Set `type="range"` to allow user to pick dates range:

<Demo data={DateTimePickerDemos.range} />

## Value format

Use `valueFormat` prop to change [dayjs format](https://day.js.org/docs/en/display/format) of value label:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { DateTimePicker } from '@mantine/dates';
import { MantineDemo } from '@mantinex/demo';

const code = `
import { DateTimePicker } from '@mantine/dates';
function Demo() {
return <DateTimePicker
label="Pick date and time"
placeholder="Pick date and time"
type="range"
/>;
}
`;

function Demo() {
return (
<DateTimePicker label="Pick date and time" placeholder="Pick date and time" type="range" />
);
}

export const range: MantineDemo = {
type: 'code',
centered: true,
maxWidth: 400,
component: Demo,
code,
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ export const DemoModal = {
render: renderDemo(demos.modal),
};

export const DemoRange = {
name: '⭐ Demo: range',
render: renderDemo(demos.range),
};

export const DemoConfigurator = {
name: '⭐ Demo: configurator',
render: renderDemo(demos.configurator),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { usage } from './DateTimePicker.demo.usage';
export { withSeconds } from './DateTimePicker.demo.withSeconds';
export { modal } from './DateTimePicker.demo.modal';
export { range } from './DateTimePicker.demo.range';
export { configurator } from './DateTimePicker.demo.configurator';
export { clearable } from './DateTimePicker.demo.clearable';
export { format } from './DateTimePicker.demo.format';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ export interface DatePickerBaseProps<Type extends DatePickerType = 'default'>
/** Current level displayed to the user (decade, year, month), used for controlled component */
level?: CalendarLevel;

/** Allow same day for range selects */
allowSameDay?: boolean;

/** Called when level changes */
onLevelChange?: (level: CalendarLevel) => void;
}
Expand Down Expand Up @@ -67,6 +70,7 @@ export const DatePicker: DatePickerComponent = factory<DatePickerFactory>((_prop
const {
classNames,
styles,
allowSameDay,
vars,
type,
defaultValue,
Expand All @@ -88,6 +92,7 @@ export const DatePicker: DatePickerComponent = factory<DatePickerFactory>((_prop
const { onDateChange, onRootMouseLeave, onHoveredDateChange, getControlProps } = useDatesState({
type: type as any,
level: 'day',
allowSameDay,
allowDeselect,
allowSingleDateInRange,
value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ export function WithSeconds() {
);
}

export function Range() {
return (
<div style={{ padding: 40, maxWidth: 400 }}>
<DateTimePicker placeholder="Date time picker" withSeconds type="range" />
</div>
);
}

export function MinDate() {
return (
<div style={{ padding: 40, maxWidth: 400 }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
import { DatesProvider } from '../DatesProvider';
import { DateTimePicker, DateTimePickerProps } from './DateTimePicker';

const defaultProps: DateTimePickerProps = {
const defaultProps = {
popoverProps: { withinPortal: false, transitionProps: { duration: 0 } },
modalProps: { withinPortal: false, transitionProps: { duration: 0 } },
timeInputProps: { 'aria-label': 'test-time-input' },
Expand All @@ -44,6 +44,7 @@ const defaultPropsWithInputProps: DateTimePickerProps = {
};

const getTimeInput = () => screen.getByLabelText('test-time-input');
const getTimeInputs = () => screen.getAllByLabelText('test-time-input');
const getSubmitButton = () => screen.getByLabelText('test-submit');
const getClearButton = () => screen.queryAllByLabelText('test-clear')[0];

Expand Down Expand Up @@ -182,6 +183,32 @@ describe('@mantine/dates/DateTimePicker', () => {
expectValue(container, '03/04/2022 14:45');
});

it('supports uncontrolled state with range', async () => {
const { container } = render(
<DateTimePicker
{...defaultProps}
defaultValue={[new Date(2022, 3, 11), new Date(2022, 3, 12)]}
type="range"
/>
);
expectValue(container, '11/04/2022 00:00 – 12/04/2022 00:00');

await clickInput(container);
await userEvent.click(container.querySelectorAll('table button')[6]);
expectValue(container, '03/04/2022 00:00 – ');

await userEvent.click(container.querySelectorAll('table button')[7]);
expectValue(container, '03/04/2022 00:00 – 04/04/2022 00:00');

await userEvent.clear(getTimeInputs()[0]);
await userEvent.type(getTimeInputs()[0], '14:45');
expectValue(container, '03/04/2022 14:45 – 04/04/2022 00:00');

await userEvent.clear(getTimeInputs()[1]);
await userEvent.type(getTimeInputs()[1], '12:35');
expectValue(container, '03/04/2022 14:45 – 04/04/2022 12:35');
});

it('supports uncontrolled state with timezone', async () => {
const { container } = render(
<DatesProvider settings={{ timezone: 'UTC' }}>
Expand Down Expand Up @@ -212,6 +239,24 @@ describe('@mantine/dates/DateTimePicker', () => {
expect(spy).toHaveBeenLastCalledWith(new Date(2022, 3, 3));
});

it('supports controlled state with range', async () => {
const spy = jest.fn();
const { container } = render(
<DateTimePicker
{...defaultProps}
value={[new Date(2022, 3, 11), new Date(2022, 3, 12)]}
onChange={spy}
type="range"
/>
);
expectValue(container, '11/04/2022 00:00 – 12/04/2022 00:00');

await clickInput(container);
await userEvent.click(container.querySelectorAll('table button')[6]);
expectValue(container, '11/04/2022 00:00 – 12/04/2022 00:00');
expect(spy).toHaveBeenLastCalledWith([new Date(2022, 3, 3), null]);
});

it('supports controlled state with timezone', async () => {
const spy = jest.fn();

Expand Down

0 comments on commit 40d2292

Please sign in to comment.