@superdispatch/dates 0.21.13 → 0.21.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +13 -39
  3. package/.babelrc.js +0 -5
  4. package/.turbo/turbo-version.log +0 -26
  5. package/pkg/README.md +0 -10
  6. package/pkg/package.json +0 -32
  7. package/playroom.ts +0 -10
  8. package/src/__tests__/index.spec.ts +0 -48
  9. package/src/base-date-picker/BaseDatePicker.tsx +0 -145
  10. package/src/calendar/Calendar.playroom.tsx +0 -28
  11. package/src/calendar/Calendar.spec.tsx +0 -531
  12. package/src/calendar/Calendar.stories.tsx +0 -50
  13. package/src/calendar/Calendar.tsx +0 -534
  14. package/src/calendar/CalendarQuickSelection.tsx +0 -34
  15. package/src/calendar/InternalCalendarComponents.tsx +0 -79
  16. package/src/date-config/DateConfig.spec.tsx +0 -23
  17. package/src/date-config/DateConfig.tsx +0 -60
  18. package/src/date-field/DateField.playroom.tsx +0 -21
  19. package/src/date-field/DateField.spec.tsx +0 -350
  20. package/src/date-field/DateField.stories.tsx +0 -47
  21. package/src/date-field/DateField.tsx +0 -155
  22. package/src/date-range-field/DateRangeField.playroom.tsx +0 -24
  23. package/src/date-range-field/DateRangeField.spec.tsx +0 -318
  24. package/src/date-range-field/DateRangeField.stories.tsx +0 -51
  25. package/src/date-range-field/DateRangeField.tsx +0 -277
  26. package/src/date-time-utils/DateTimeUtils.spec.ts +0 -652
  27. package/src/date-time-utils/DateTimeUtils.ts +0 -339
  28. package/src/date-utils/DateUtils.spec.ts +0 -234
  29. package/src/date-utils/DateUtils.ts +0 -333
  30. package/src/formatted-date/FormattedDate.spec.tsx +0 -103
  31. package/src/formatted-date/FormattedDate.ts +0 -42
  32. package/src/formatted-relative-time/FormattedRelativeTime.spec.tsx +0 -93
  33. package/src/formatted-relative-time/FormattedRelativeTime.ts +0 -60
  34. package/src/index.ts +0 -12
  35. package/src/time-field/TimeField.playroom.tsx +0 -21
  36. package/src/time-field/TimeField.stories.tsx +0 -35
  37. package/src/time-field/TimeField.tsx +0 -221
  38. package/src/use-date-time/useDateTime.spec.ts +0 -45
  39. package/src/use-date-time/useDateTime.ts +0 -31
  40. package/src/use-date-time-range/useDateTimeRange.spec.ts +0 -53
  41. package/src/use-date-time-range/useDateTimeRange.ts +0 -24
  42. package/tsconfig.json +0 -19
  43. /package/{pkg/dist-node → dist-node}/index.js +0 -0
  44. /package/{pkg/dist-node → dist-node}/index.js.map +0 -0
  45. /package/{pkg/dist-src → dist-src}/base-date-picker/BaseDatePicker.js +0 -0
  46. /package/{pkg/dist-src → dist-src}/calendar/Calendar.js +0 -0
  47. /package/{pkg/dist-src → dist-src}/calendar/CalendarQuickSelection.js +0 -0
  48. /package/{pkg/dist-src → dist-src}/calendar/InternalCalendarComponents.js +0 -0
  49. /package/{pkg/dist-src → dist-src}/date-config/DateConfig.js +0 -0
  50. /package/{pkg/dist-src → dist-src}/date-field/DateField.js +0 -0
  51. /package/{pkg/dist-src → dist-src}/date-range-field/DateRangeField.js +0 -0
  52. /package/{pkg/dist-src → dist-src}/date-time-utils/DateTimeUtils.js +0 -0
  53. /package/{pkg/dist-src → dist-src}/date-utils/DateUtils.js +0 -0
  54. /package/{pkg/dist-src → dist-src}/formatted-date/FormattedDate.js +0 -0
  55. /package/{pkg/dist-src → dist-src}/formatted-relative-time/FormattedRelativeTime.js +0 -0
  56. /package/{pkg/dist-src → dist-src}/index.js +0 -0
  57. /package/{pkg/dist-src → dist-src}/time-field/TimeField.js +0 -0
  58. /package/{pkg/dist-src → dist-src}/use-date-time/useDateTime.js +0 -0
  59. /package/{pkg/dist-src → dist-src}/use-date-time-range/useDateTimeRange.js +0 -0
  60. /package/{pkg/dist-types → dist-types}/index.d.ts +0 -0
  61. /package/{pkg/dist-web → dist-web}/index.js +0 -0
  62. /package/{pkg/dist-web → dist-web}/index.js.map +0 -0
@@ -1,318 +0,0 @@
1
- import {
2
- mockDate,
3
- renderComponent,
4
- renderCSS,
5
- } from '@superdispatch/ui-testutils';
6
- import { fireEvent, Matcher, screen } from '@testing-library/react';
7
- import userEvent from '@testing-library/user-event';
8
- import { DateTime } from 'luxon';
9
- import { useState } from 'react';
10
- import { defaultDateConfig } from '../date-config/DateConfig';
11
- import {
12
- DateStringRange,
13
- DateTimeRange,
14
- } from '../date-time-utils/DateTimeUtils';
15
- import { DateRangeField, DateRangeFieldProps } from './DateRangeField';
16
-
17
- function queryByClassName(classNames: string): Element[] {
18
- return Array.from(document.getElementsByClassName(classNames));
19
- }
20
-
21
- function UncontrolledDateRangeField(props: DateRangeFieldProps) {
22
- const [value, setValue] = useState<DateTimeRange>();
23
-
24
- return (
25
- <DateRangeField
26
- {...props}
27
- value={value}
28
- onChange={({ dateValue }) => {
29
- setValue(dateValue);
30
- }}
31
- />
32
- );
33
- }
34
-
35
- beforeEach(() => {
36
- mockDate();
37
- });
38
-
39
- test('basic', () => {
40
- const onChange = jest.fn();
41
- renderComponent(<DateRangeField label="Range" onChange={onChange} />);
42
-
43
- expect(screen.queryByRole('grid')).toBeNull();
44
- expect(screen.getByLabelText('Range')).toHaveValue('');
45
-
46
- userEvent.click(screen.getByLabelText('Range'));
47
-
48
- expect(onChange).not.toHaveBeenCalled();
49
-
50
- expect(screen.queryAllByRole('grid')).toHaveLength(2);
51
-
52
- userEvent.click(screen.getByRole('gridcell', { name: /May 24/ }));
53
-
54
- expect(onChange).toHaveBeenCalledTimes(1);
55
- expect(onChange).toHaveBeenLastCalledWith({
56
- config: defaultDateConfig,
57
- dateValue: [expect.any(DateTime), null],
58
- stringValue: ['2019-05-24T00:00:00.000-05:00', null],
59
- });
60
-
61
- expect(screen.queryAllByRole('grid')).toHaveLength(2);
62
- expect(screen.getByLabelText('Range')).toHaveValue('');
63
- });
64
-
65
- test('uncontrolled', () => {
66
- renderComponent(<UncontrolledDateRangeField label="Range" />);
67
-
68
- expect(screen.getByLabelText('Range')).toHaveValue('');
69
-
70
- userEvent.click(screen.getByLabelText('Range'));
71
-
72
- userEvent.click(screen.getByRole('gridcell', { name: /May 24/ }));
73
-
74
- expect(screen.getByLabelText('Range')).toHaveValue('May 24, 2019 - …');
75
-
76
- userEvent.click(screen.getByRole('gridcell', { name: /May 30/ }));
77
-
78
- expect(screen.queryByRole('grid')).toBeNull();
79
- expect(screen.getByLabelText('Range')).toHaveValue('May 24 - May 30, 2019');
80
- });
81
-
82
- test('close on select', () => {
83
- renderComponent(<DateRangeField value={[Date.now()]} />);
84
-
85
- expect(screen.queryByRole('grid')).toBeNull();
86
-
87
- userEvent.click(screen.getByRole('textbox'));
88
- userEvent.click(screen.getByRole('gridcell', { name: /May 25/ }));
89
-
90
- expect(screen.queryByRole('grid')).toBeNull();
91
- });
92
-
93
- test('selected days', () => {
94
- renderComponent(<DateRangeField value={['2019-05-24T00:00:00.000-05:00']} />);
95
-
96
- function assertSelection(startDay: number, finishDay?: number): void {
97
- const selected = queryByClassName('SD-DateRangeField-selected').filter(
98
- (element) => !element.classList.contains('SD-DateRangeField-outside'),
99
- );
100
-
101
- const startDays = selected.filter((element) =>
102
- element.classList.contains('SD-DateRangeField-rangeStart'),
103
- );
104
- const finishDays = selected.filter((element) =>
105
- element.classList.contains('SD-DateRangeField-rangeFinish'),
106
- );
107
-
108
- const [startDate] = selected;
109
- const finishDate = selected[selected.length - 1];
110
-
111
- expect(startDays).toHaveLength(1);
112
- expect(startDays[0]).toHaveTextContent(String(startDay));
113
-
114
- if (finishDay == null) {
115
- // eslint-disable-next-line jest/no-conditional-expect
116
- expect(selected).toHaveLength(1);
117
- // eslint-disable-next-line jest/no-conditional-expect
118
- expect(startDate).toBe(finishDate);
119
- // eslint-disable-next-line jest/no-conditional-expect
120
- expect(finishDays).toHaveLength(0);
121
- } else {
122
- // eslint-disable-next-line jest/no-conditional-expect
123
- expect(selected).toHaveLength(finishDay - startDay + 1);
124
-
125
- // eslint-disable-next-line jest/no-conditional-expect
126
- expect(finishDays).toHaveLength(1);
127
- // eslint-disable-next-line jest/no-conditional-expect
128
- expect(finishDays[0]).toHaveTextContent(String(finishDay));
129
-
130
- for (let i = 0; i < selected.length; i++) {
131
- // eslint-disable-next-line jest/no-conditional-expect
132
- expect(selected[i]).toHaveTextContent(String(startDay + i));
133
- }
134
- }
135
- }
136
-
137
- userEvent.click(screen.getByRole('textbox'));
138
-
139
- assertSelection(24);
140
-
141
- fireEvent.mouseEnter(screen.getByRole('gridcell', { name: /May 24/ }));
142
-
143
- assertSelection(24, 24);
144
-
145
- fireEvent.mouseEnter(screen.getByRole('gridcell', { name: /May 26/ }));
146
-
147
- assertSelection(24, 26);
148
-
149
- fireEvent.mouseEnter(screen.getByRole('gridcell', { name: /May 20/ }));
150
-
151
- assertSelection(20, 24);
152
- });
153
-
154
- test('disabledDays', () => {
155
- const onChange = jest.fn();
156
- const onDayClick = jest.fn();
157
-
158
- renderComponent(
159
- <DateRangeField
160
- onChange={onChange}
161
- CalendarProps={{
162
- onDayClick,
163
- disabledDays: ({ dateValue }) => dateValue.day >= 24,
164
- }}
165
- />,
166
- );
167
-
168
- userEvent.click(screen.getByRole('textbox'));
169
-
170
- expect(onChange).not.toHaveBeenCalled();
171
- expect(onDayClick).not.toHaveBeenCalled();
172
-
173
- expect(screen.getByRole('gridcell', { name: /May 24/ })).toHaveClass(
174
- 'SD-Calendar-disabled',
175
- );
176
-
177
- userEvent.click(screen.getByRole('gridcell', { name: /May 24/ }));
178
-
179
- expect(onChange).not.toHaveBeenCalled();
180
- expect(onDayClick).toHaveBeenCalledTimes(1);
181
- });
182
-
183
- test('enableClearable', () => {
184
- const onChange = jest.fn();
185
- const view = renderComponent(
186
- <DateRangeField onChange={onChange} enableClearable={true} />,
187
- );
188
-
189
- expect(screen.queryByRole('button', { name: 'clear' })).toBeNull();
190
-
191
- view.rerender(
192
- <DateRangeField
193
- onChange={onChange}
194
- enableClearable={true}
195
- value={[Date.now(), undefined]}
196
- />,
197
- );
198
- expect(screen.queryByRole('button', { name: 'clear' })).toBeNull();
199
-
200
- view.rerender(
201
- <DateRangeField
202
- onChange={onChange}
203
- enableClearable={true}
204
- value={[Date.now(), Date.now()]}
205
- />,
206
- );
207
-
208
- expect(screen.getByRole('button', { name: 'clear' })).toBeInTheDocument();
209
-
210
- expect(onChange).not.toHaveBeenCalled();
211
-
212
- userEvent.click(screen.getByRole('button', { name: 'clear' }));
213
-
214
- expect(onChange).toHaveBeenCalledTimes(1);
215
- expect(onChange).toHaveBeenLastCalledWith({
216
- config: defaultDateConfig,
217
- dateValue: [null, null],
218
- stringValue: [null, null],
219
- });
220
-
221
- view.rerender(
222
- <DateRangeField
223
- label="Custom Label"
224
- onChange={onChange}
225
- enableClearable={true}
226
- value={[Date.now(), Date.now()]}
227
- />,
228
- );
229
-
230
- expect(screen.queryByRole('button', { name: 'clear' })).toBeNull();
231
-
232
- userEvent.click(screen.getByRole('button', { name: 'clear Custom Label' }));
233
-
234
- expect(onChange).toHaveBeenCalledTimes(2);
235
- expect(onChange).toHaveBeenLastCalledWith({
236
- config: defaultDateConfig,
237
- dateValue: [null, null],
238
- stringValue: [null, null],
239
- });
240
- });
241
-
242
- test('time normalization', () => {
243
- const view = renderComponent(<DateRangeField />);
244
-
245
- const variants: Array<
246
- [
247
- input: undefined | DateStringRange,
248
- matcher: Matcher,
249
- result: DateStringRange,
250
- ]
251
- > = [
252
- [undefined, /May 24/, ['2019-05-24T00:00:00.000-05:00', null]],
253
-
254
- [
255
- ['2019-05-29T00:00:00.000-05:00', null],
256
- /May 24/,
257
- ['2019-05-24T00:00:00.000-05:00', '2019-05-29T23:59:59.999-05:00'],
258
- ],
259
-
260
- [
261
- ['2019-05-29T10:11:12.134-05:00', null],
262
- /May 24/,
263
- ['2019-05-24T10:11:12.134-05:00', '2019-05-29T23:59:59.999-05:00'],
264
- ],
265
- ];
266
-
267
- for (const [input, labelMatcher, stringValue] of variants) {
268
- const onChange = jest.fn();
269
-
270
- view.rerender(
271
- <DateRangeField
272
- id="range"
273
- label="Range"
274
- value={input}
275
- onChange={onChange}
276
- />,
277
- );
278
-
279
- userEvent.click(screen.getByLabelText('Range'));
280
- userEvent.click(screen.getByLabelText(labelMatcher));
281
-
282
- expect(onChange).toHaveBeenCalledTimes(1);
283
- expect(onChange).toHaveBeenLastCalledWith({
284
- stringValue,
285
- config: defaultDateConfig,
286
- dateValue: stringValue.map((x) => x && expect.any(DateTime)),
287
- });
288
- }
289
- });
290
-
291
- test('css', () => {
292
- expect(renderCSS(<DateRangeField />, ['SD-DateRangeField']))
293
- .toMatchInlineSnapshot(`
294
- .SD-DateRangeField-day.SD-DateRangeField-selected:not(.SD-DateRangeField-outside).SD-DateRangeField-rangeStart:before {
295
- left: 4px;
296
- }
297
-
298
- .SD-DateRangeField-day.SD-DateRangeField-selected:not(.SD-DateRangeField-outside).SD-DateRangeField-rangeFinish:before {
299
- right: 4px;
300
- }
301
-
302
- .SD-DateRangeField-day.SD-DateRangeField-selected:not(.SD-DateRangeField-outside):not(.SD-DateRangeField-rangeStart):not(.SD-DateRangeField-rangeFinish):after {
303
- background-color: Color.Transparent;
304
- }
305
-
306
- .SD-DateRangeField-day.SD-DateRangeField-selected:not(.SD-DateRangeField-outside):not(.SD-DateRangeField-rangeStart):not(.SD-DateRangeField-rangeFinish):not(.SD-DateRangeField-disabled) {
307
- color: Color.Blue500;
308
- }
309
-
310
- .SD-DateRangeField-day.SD-DateRangeField-selected:not(.SD-DateRangeField-outside):not(.SD-DateRangeField-rangeStart):not(.SD-DateRangeField-rangeFinish):not(.SD-DateRangeField-disabled):before {
311
- background-color: Color.Blue50;
312
- }
313
-
314
- .SD-DateRangeField-day.SD-DateRangeField-selected:not(.SD-DateRangeField-outside):not(.SD-DateRangeField-rangeStart):not(.SD-DateRangeField-rangeFinish).SD-DateRangeField-disabled:before {
315
- background-color: Color.Silver100;
316
- }
317
- `);
318
- });
@@ -1,51 +0,0 @@
1
- import { InputAdornment } from '@material-ui/core';
2
- import { Meta } from '@storybook/react';
3
- import { DateRangeField } from './DateRangeField.playroom';
4
-
5
- export default {
6
- title: 'Dates/DateRangeField',
7
- component: DateRangeField,
8
- } as Meta;
9
-
10
- export const basic = () => <DateRangeField />;
11
-
12
- export const advanced = () => (
13
- <DateRangeField
14
- label="Label"
15
- placeholder="Placeholder"
16
- helperText="Helper Text"
17
- />
18
- );
19
-
20
- export const errorState = () => (
21
- <DateRangeField
22
- label="Label"
23
- error={true}
24
- placeholder="Placeholder"
25
- helperText="Error Text"
26
- />
27
- );
28
-
29
- export const adornment = () => (
30
- <DateRangeField
31
- InputProps={{
32
- startAdornment: (
33
- <InputAdornment position="start">Start Adornment:</InputAdornment>
34
- ),
35
- }}
36
- />
37
- );
38
-
39
- export const fullWidth = () => <DateRangeField fullWidth={true} />;
40
-
41
- export const disabled = () => <DateRangeField disabled={true} />;
42
-
43
- export const enableClearable = () => <DateRangeField enableClearable={true} />;
44
-
45
- export const disableCloseOnSelect = () => (
46
- <DateRangeField disableCloseOnSelect={true} />
47
- );
48
-
49
- export const customEmptyText = () => (
50
- <DateRangeField fallback="Never" enableClearable={true} />
51
- );
@@ -1,277 +0,0 @@
1
- import { BaseTextFieldProps, InputBaseProps } from '@material-ui/core';
2
- import { makeStyles } from '@material-ui/styles';
3
- import { Color, SuperDispatchTheme } from '@superdispatch/ui';
4
- import { forwardRef, ReactNode, useMemo, useRef, useState } from 'react';
5
- import {
6
- BaseDatePicker,
7
- InternalBaseDateFieldAPI,
8
- } from '../base-date-picker/BaseDatePicker';
9
- import {
10
- Calendar,
11
- CalendarClassNames,
12
- CalendarProps,
13
- } from '../calendar/Calendar';
14
- import { DateFormat, useDateConfig } from '../date-config/DateConfig';
15
- import {
16
- DateRangePayload,
17
- formatDateRange,
18
- NullableDateRangeInput,
19
- parseDateRange,
20
- stringifyDateRange,
21
- toDateRangePayload,
22
- } from '../date-time-utils/DateTimeUtils';
23
- import { useDateTimeRange } from '../use-date-time-range/useDateTimeRange';
24
-
25
- const useStyles = makeStyles<
26
- SuperDispatchTheme,
27
- CalendarProps,
28
- | 'rangeStart'
29
- | 'rangeFinish'
30
- | Extract<CalendarClassNames, 'outside' | 'disabled' | 'selected' | 'day'>
31
- >(
32
- (theme) => ({
33
- rangeStart: {},
34
- rangeFinish: {},
35
-
36
- outside: {},
37
- disabled: {},
38
- selected: {},
39
-
40
- day: {
41
- '&$selected:not($outside)': {
42
- '&$rangeStart:before': {
43
- left: theme.spacing(0.5),
44
- },
45
-
46
- '&$rangeFinish:before': {
47
- right: theme.spacing(0.5),
48
- },
49
-
50
- '&:not($rangeStart):not($rangeFinish)': {
51
- '&:after': {
52
- backgroundColor: Color.Transparent,
53
- },
54
-
55
- '&$disabled': {
56
- '&:before': {
57
- backgroundColor: Color.Silver100,
58
- },
59
- },
60
-
61
- '&:not($disabled)': {
62
- color: Color.Blue500,
63
-
64
- '&:before': {
65
- backgroundColor: Color.Blue50,
66
- },
67
- },
68
- },
69
- },
70
- },
71
- }),
72
- { name: 'SD-DateRangeField' },
73
- );
74
-
75
- interface DateRangeFieldAPI extends DateRangePayload {
76
- close: () => void;
77
- change: (value: NullableDateRangeInput) => void;
78
- }
79
-
80
- export interface DateRangeFieldProps
81
- extends Pick<
82
- BaseTextFieldProps,
83
- | 'disabled'
84
- | 'error'
85
- | 'fullWidth'
86
- | 'helperText'
87
- | 'id'
88
- | 'label'
89
- | 'name'
90
- | 'required'
91
- | 'placeholder'
92
- > {
93
- fallback?: string;
94
- enableClearable?: boolean;
95
- disableCloseOnSelect?: boolean;
96
-
97
- format?: DateFormat;
98
- value?: NullableDateRangeInput;
99
-
100
- onBlur?: () => void;
101
- onFocus?: () => void;
102
- onChange?: (value: DateRangePayload) => void;
103
-
104
- renderFooter?: (api: DateRangeFieldAPI) => ReactNode;
105
- renderQuickSelection?: (api: DateRangeFieldAPI) => ReactNode;
106
-
107
- InputProps?: Pick<
108
- InputBaseProps,
109
- 'aria-label' | 'aria-labelledby' | 'startAdornment'
110
- >;
111
- CalendarProps?: Omit<
112
- CalendarProps,
113
- 'footer' | 'classes' | 'selectedDays' | 'quickSelection' | 'numberOfMonths'
114
- >;
115
- }
116
-
117
- export const DateRangeField = forwardRef<HTMLDivElement, DateRangeFieldProps>(
118
- (
119
- {
120
- onBlur,
121
- onFocus,
122
- onChange,
123
- renderFooter,
124
- renderQuickSelection,
125
-
126
- value: valueProp,
127
- format: formatProp,
128
-
129
- fallback = '',
130
-
131
- enableClearable,
132
- disableCloseOnSelect,
133
-
134
- CalendarProps: {
135
- modifiers,
136
- onDayClick,
137
- onDayMouseEnter,
138
- ...calendarProps
139
- } = {} as const,
140
-
141
- ...textFieldProps
142
- },
143
- ref,
144
- ) => {
145
- const apiRef = useRef<InternalBaseDateFieldAPI>(null);
146
- const { rangeStart, rangeFinish, ...styles } = useStyles({});
147
-
148
- const config = useDateConfig({ format: formatProp });
149
- const [startDate, finishDate] = useDateTimeRange(valueProp, config);
150
- const [startDateString, finishDateString] = useMemo(
151
- () => stringifyDateRange([startDate, finishDate], config),
152
- [config, startDate, finishDate],
153
- );
154
- const displayValue = useMemo(
155
- () => formatDateRange([startDate, finishDate], { fallback }, config),
156
- [config, fallback, startDate, finishDate],
157
- );
158
-
159
- const [hoveredDate, setHoveredDate] = useState<number>();
160
- const [calendarStartDate, calendarFinishDate] = useMemo(() => {
161
- const [nextCalendarStartDate, nextCalendarFinishDate] = parseDateRange(
162
- [startDate, finishDate || hoveredDate],
163
- config,
164
- );
165
-
166
- return [
167
- nextCalendarStartDate?.startOf('day'),
168
- nextCalendarFinishDate?.endOf('day'),
169
- ];
170
- }, [config, startDate, finishDate, hoveredDate]);
171
-
172
- function handleClose(): void {
173
- apiRef.current?.close();
174
- }
175
-
176
- function handleChange(nextValue: NullableDateRangeInput): void {
177
- let [nextStartDate, nextFinishDate] = parseDateRange(nextValue, config);
178
-
179
- if (onChange) {
180
- if (nextStartDate) {
181
- if (startDate) {
182
- nextStartDate = nextStartDate.set({
183
- hour: startDate.hour,
184
- minute: startDate.minute,
185
- second: startDate.second,
186
- millisecond: startDate.millisecond,
187
- });
188
- } else {
189
- nextStartDate = nextStartDate.startOf('day');
190
- }
191
- }
192
-
193
- if (nextFinishDate) {
194
- nextFinishDate = nextFinishDate.endOf('day');
195
- }
196
-
197
- onChange(toDateRangePayload([nextStartDate, nextFinishDate], config));
198
- }
199
-
200
- if (!disableCloseOnSelect && nextFinishDate?.isValid) {
201
- handleClose();
202
- }
203
- }
204
-
205
- const api: DateRangeFieldAPI = {
206
- config,
207
- close: handleClose,
208
- change: handleChange,
209
- dateValue: [startDate, finishDate],
210
- stringValue: [startDateString, finishDateString],
211
- };
212
-
213
- return (
214
- <BaseDatePicker
215
- {...textFieldProps}
216
- ref={ref}
217
- api={apiRef}
218
- value={displayValue || fallback}
219
- enableClearable={enableClearable && !!startDate && !!finishDate}
220
- onClear={() => {
221
- handleChange([undefined, undefined]);
222
- }}
223
- onClose={() => {
224
- onBlur?.();
225
- setHoveredDate(undefined);
226
- }}
227
- >
228
- <Calendar
229
- numberOfMonths={2}
230
- {...calendarProps}
231
- classes={styles}
232
- initialMonth={startDateString}
233
- modifiers={{
234
- ...modifiers,
235
- [rangeStart]: ({ dateValue }) =>
236
- !!calendarStartDate?.hasSame(dateValue, 'day'),
237
- [rangeFinish]: ({ dateValue }) =>
238
- !!calendarFinishDate?.hasSame(dateValue, 'day'),
239
- }}
240
- selectedDays={({ dateValue }) => {
241
- if (calendarStartDate) {
242
- if (!calendarFinishDate) {
243
- return calendarStartDate.hasSame(dateValue, 'day');
244
- }
245
-
246
- return (
247
- calendarStartDate <= dateValue &&
248
- dateValue <= calendarFinishDate
249
- );
250
- }
251
-
252
- return false;
253
- }}
254
- footer={renderFooter?.(api)}
255
- quickSelection={renderQuickSelection?.(api)}
256
- onDayMouseEnter={(event) => {
257
- onDayMouseEnter?.(event);
258
- setHoveredDate(
259
- !event.disabled ? event.dateValue.valueOf() : undefined,
260
- );
261
- }}
262
- onDayClick={(event) => {
263
- onDayClick?.(event);
264
-
265
- if (!event.disabled) {
266
- if (startDate && !finishDate) {
267
- handleChange([startDateString, event.stringValue]);
268
- } else {
269
- handleChange([event.stringValue, undefined]);
270
- }
271
- }
272
- }}
273
- />
274
- </BaseDatePicker>
275
- );
276
- },
277
- );