@react-stately/datepicker 3.7.0 → 3.9.0
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.
- package/dist/import.mjs +602 -99
- package/dist/main.js +601 -97
- package/dist/main.js.map +1 -1
- package/dist/module.js +602 -99
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +10 -9
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -6
- package/src/useDateFieldState.ts +23 -5
- package/src/useDatePickerState.ts +38 -18
- package/src/useDateRangePickerState.ts +40 -17
- package/src/useTimeFieldState.ts +5 -3
- package/src/utils.ts +103 -5
package/src/useDateFieldState.ts
CHANGED
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import {Calendar, DateFormatter, getMinimumDayInMonth, getMinimumMonthInYear, GregorianCalendar, toCalendar} from '@internationalized/date';
|
|
14
|
-
import {convertValue, createPlaceholderDate, FieldOptions, getFormatOptions,
|
|
14
|
+
import {convertValue, createPlaceholderDate, FieldOptions, getFormatOptions, getValidationResult, useDefaultProps} from './utils';
|
|
15
15
|
import {DatePickerProps, DateValue, Granularity} from '@react-types/datepicker';
|
|
16
|
+
import {FormValidationState, useFormValidationState} from '@react-stately/form';
|
|
16
17
|
import {getPlaceholder} from './placeholders';
|
|
17
18
|
import {useControlledState} from '@react-stately/utils';
|
|
18
19
|
import {useEffect, useMemo, useRef, useState} from 'react';
|
|
@@ -38,7 +39,7 @@ export interface DateSegment {
|
|
|
38
39
|
isEditable: boolean
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
export interface DateFieldState {
|
|
42
|
+
export interface DateFieldState extends FormValidationState {
|
|
42
43
|
/** The current field value. */
|
|
43
44
|
value: DateValue,
|
|
44
45
|
/** The current value, converted to a native JavaScript `Date` object. */
|
|
@@ -149,7 +150,10 @@ export function useDateFieldState<T extends DateValue = DateValue>(props: DateFi
|
|
|
149
150
|
hideTimeZone,
|
|
150
151
|
isDisabled,
|
|
151
152
|
isReadOnly,
|
|
152
|
-
isRequired
|
|
153
|
+
isRequired,
|
|
154
|
+
minValue,
|
|
155
|
+
maxValue,
|
|
156
|
+
isDateUnavailable
|
|
153
157
|
} = props;
|
|
154
158
|
|
|
155
159
|
let v: DateValue = (props.value || props.defaultValue || props.placeholderValue);
|
|
@@ -314,11 +318,25 @@ export function useDateFieldState<T extends DateValue = DateValue>(props: DateFi
|
|
|
314
318
|
}
|
|
315
319
|
};
|
|
316
320
|
|
|
317
|
-
let
|
|
318
|
-
|
|
321
|
+
let builtinValidation = useMemo(() => getValidationResult(
|
|
322
|
+
value,
|
|
323
|
+
minValue,
|
|
324
|
+
maxValue,
|
|
325
|
+
isDateUnavailable,
|
|
326
|
+
formatOpts
|
|
327
|
+
), [value, minValue, maxValue, isDateUnavailable, formatOpts]);
|
|
328
|
+
|
|
329
|
+
let validation = useFormValidationState({
|
|
330
|
+
...props,
|
|
331
|
+
value,
|
|
332
|
+
builtinValidation
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
let isValueInvalid = validation.displayValidation.isInvalid;
|
|
319
336
|
let validationState: ValidationState = props.validationState || (isValueInvalid ? 'invalid' : null);
|
|
320
337
|
|
|
321
338
|
return {
|
|
339
|
+
...validation,
|
|
322
340
|
value: calendarValue,
|
|
323
341
|
dateValue,
|
|
324
342
|
calendar,
|
|
@@ -12,10 +12,11 @@
|
|
|
12
12
|
|
|
13
13
|
import {CalendarDate, DateFormatter, toCalendarDate, toCalendarDateTime} from '@internationalized/date';
|
|
14
14
|
import {DatePickerProps, DateValue, Granularity, TimeValue} from '@react-types/datepicker';
|
|
15
|
-
import {FieldOptions, getFormatOptions, getPlaceholderTime,
|
|
15
|
+
import {FieldOptions, getFormatOptions, getPlaceholderTime, getValidationResult, useDefaultProps} from './utils';
|
|
16
|
+
import {FormValidationState, useFormValidationState} from '@react-stately/form';
|
|
16
17
|
import {OverlayTriggerState, useOverlayTriggerState} from '@react-stately/overlays';
|
|
17
18
|
import {useControlledState} from '@react-stately/utils';
|
|
18
|
-
import {useState} from 'react';
|
|
19
|
+
import {useMemo, useState} from 'react';
|
|
19
20
|
import {ValidationState} from '@react-types/shared';
|
|
20
21
|
|
|
21
22
|
export interface DatePickerStateOptions<T extends DateValue> extends DatePickerProps<T> {
|
|
@@ -26,11 +27,11 @@ export interface DatePickerStateOptions<T extends DateValue> extends DatePickerP
|
|
|
26
27
|
shouldCloseOnSelect?: boolean | (() => boolean)
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
export interface DatePickerState extends OverlayTriggerState {
|
|
30
|
+
export interface DatePickerState extends OverlayTriggerState, FormValidationState {
|
|
30
31
|
/** The currently selected date. */
|
|
31
|
-
value: DateValue,
|
|
32
|
+
value: DateValue | null,
|
|
32
33
|
/** Sets the selected date. */
|
|
33
|
-
setValue(value: DateValue): void,
|
|
34
|
+
setValue(value: DateValue | null): void,
|
|
34
35
|
/**
|
|
35
36
|
* The date portion of the value. This may be set prior to `value` if the user has
|
|
36
37
|
* selected a date but has not yet selected a time.
|
|
@@ -93,10 +94,39 @@ export function useDatePickerState<T extends DateValue = DateValue>(props: DateP
|
|
|
93
94
|
throw new Error('Invalid granularity ' + granularity + ' for value ' + v.toString());
|
|
94
95
|
}
|
|
95
96
|
|
|
97
|
+
let showEra = value?.calendar.identifier === 'gregory' && value.era === 'BC';
|
|
98
|
+
let formatOpts = useMemo(() => ({
|
|
99
|
+
granularity,
|
|
100
|
+
timeZone: defaultTimeZone,
|
|
101
|
+
hideTimeZone: props.hideTimeZone,
|
|
102
|
+
hourCycle: props.hourCycle,
|
|
103
|
+
shouldForceLeadingZeros: props.shouldForceLeadingZeros,
|
|
104
|
+
showEra
|
|
105
|
+
}), [granularity, props.hourCycle, props.shouldForceLeadingZeros, defaultTimeZone, props.hideTimeZone, showEra]);
|
|
106
|
+
|
|
107
|
+
let {minValue, maxValue, isDateUnavailable} = props;
|
|
108
|
+
let builtinValidation = useMemo(() => getValidationResult(
|
|
109
|
+
value,
|
|
110
|
+
minValue,
|
|
111
|
+
maxValue,
|
|
112
|
+
isDateUnavailable,
|
|
113
|
+
formatOpts
|
|
114
|
+
), [value, minValue, maxValue, isDateUnavailable, formatOpts]);
|
|
115
|
+
|
|
116
|
+
let validation = useFormValidationState({
|
|
117
|
+
...props,
|
|
118
|
+
value,
|
|
119
|
+
builtinValidation
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
let isValueInvalid = validation.displayValidation.isInvalid;
|
|
123
|
+
let validationState: ValidationState = props.validationState || (isValueInvalid ? 'invalid' : null);
|
|
124
|
+
|
|
96
125
|
let commitValue = (date: DateValue, time: TimeValue) => {
|
|
97
126
|
setValue('timeZone' in time ? time.set(toCalendarDate(date)) : toCalendarDateTime(date, time));
|
|
98
127
|
setSelectedDate(null);
|
|
99
128
|
setSelectedTime(null);
|
|
129
|
+
validation.commitValidation();
|
|
100
130
|
};
|
|
101
131
|
|
|
102
132
|
// Intercept setValue to make sure the Time section is not changed by date selection in Calendar
|
|
@@ -110,6 +140,7 @@ export function useDatePickerState<T extends DateValue = DateValue>(props: DateP
|
|
|
110
140
|
}
|
|
111
141
|
} else {
|
|
112
142
|
setValue(newValue);
|
|
143
|
+
validation.commitValidation();
|
|
113
144
|
}
|
|
114
145
|
|
|
115
146
|
if (shouldClose) {
|
|
@@ -125,12 +156,8 @@ export function useDatePickerState<T extends DateValue = DateValue>(props: DateP
|
|
|
125
156
|
}
|
|
126
157
|
};
|
|
127
158
|
|
|
128
|
-
let isValueInvalid = props.isInvalid || props.validationState === 'invalid' ||
|
|
129
|
-
isInvalid(value, props.minValue, props.maxValue) ||
|
|
130
|
-
value && props.isDateUnavailable?.(value);
|
|
131
|
-
let validationState: ValidationState = props.validationState || (isValueInvalid ? 'invalid' : null);
|
|
132
|
-
|
|
133
159
|
return {
|
|
160
|
+
...validation,
|
|
134
161
|
value,
|
|
135
162
|
setValue,
|
|
136
163
|
dateValue: selectedDate,
|
|
@@ -157,14 +184,7 @@ export function useDatePickerState<T extends DateValue = DateValue>(props: DateP
|
|
|
157
184
|
return '';
|
|
158
185
|
}
|
|
159
186
|
|
|
160
|
-
let formatOptions = getFormatOptions(fieldOptions,
|
|
161
|
-
granularity,
|
|
162
|
-
timeZone: defaultTimeZone,
|
|
163
|
-
hideTimeZone: props.hideTimeZone,
|
|
164
|
-
hourCycle: props.hourCycle,
|
|
165
|
-
showEra: value.calendar.identifier === 'gregory' && value.era === 'BC'
|
|
166
|
-
});
|
|
167
|
-
|
|
187
|
+
let formatOptions = getFormatOptions(fieldOptions, formatOpts);
|
|
168
188
|
let formatter = new DateFormatter(locale, formatOptions);
|
|
169
189
|
return formatter.format(dateValue);
|
|
170
190
|
}
|
|
@@ -12,11 +12,12 @@
|
|
|
12
12
|
|
|
13
13
|
import {DateFormatter, toCalendarDate, toCalendarDateTime} from '@internationalized/date';
|
|
14
14
|
import {DateRange, DateRangePickerProps, DateValue, Granularity, TimeValue} from '@react-types/datepicker';
|
|
15
|
-
import {FieldOptions, getFormatOptions, getPlaceholderTime,
|
|
15
|
+
import {FieldOptions, getFormatOptions, getPlaceholderTime, getRangeValidationResult, useDefaultProps} from './utils';
|
|
16
|
+
import {FormValidationState, useFormValidationState} from '@react-stately/form';
|
|
16
17
|
import {OverlayTriggerState, useOverlayTriggerState} from '@react-stately/overlays';
|
|
17
18
|
import {RangeValue, ValidationState} from '@react-types/shared';
|
|
18
19
|
import {useControlledState} from '@react-stately/utils';
|
|
19
|
-
import {useState} from 'react';
|
|
20
|
+
import {useMemo, useState} from 'react';
|
|
20
21
|
|
|
21
22
|
export interface DateRangePickerStateOptions<T extends DateValue = DateValue> extends DateRangePickerProps<T> {
|
|
22
23
|
/**
|
|
@@ -27,23 +28,23 @@ export interface DateRangePickerStateOptions<T extends DateValue = DateValue> ex
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
type TimeRange = RangeValue<TimeValue>;
|
|
30
|
-
export interface DateRangePickerState extends OverlayTriggerState {
|
|
31
|
+
export interface DateRangePickerState extends OverlayTriggerState, FormValidationState {
|
|
31
32
|
/** The currently selected date range. */
|
|
32
|
-
value: DateRange,
|
|
33
|
+
value: DateRange | null,
|
|
33
34
|
/** Sets the selected date range. */
|
|
34
|
-
setValue(value: DateRange): void,
|
|
35
|
+
setValue(value: DateRange | null): void,
|
|
35
36
|
/**
|
|
36
37
|
* The date portion of the selected range. This may be set prior to `value` if the user has
|
|
37
38
|
* selected a date range but has not yet selected a time range.
|
|
38
39
|
*/
|
|
39
|
-
dateRange: DateRange,
|
|
40
|
+
dateRange: DateRange | null,
|
|
40
41
|
/** Sets the date portion of the selected range. */
|
|
41
42
|
setDateRange(value: DateRange): void,
|
|
42
43
|
/**
|
|
43
44
|
* The time portion of the selected range. This may be set prior to `value` if the user has
|
|
44
45
|
* selected a time range but has not yet selected a date range.
|
|
45
46
|
*/
|
|
46
|
-
timeRange: TimeRange,
|
|
47
|
+
timeRange: TimeRange | null,
|
|
47
48
|
/** Sets the time portion of the selected range. */
|
|
48
49
|
setTimeRange(value: TimeRange): void,
|
|
49
50
|
/** Sets the date portion of either the start or end of the selected range. */
|
|
@@ -90,7 +91,7 @@ export function useDateRangePickerState<T extends DateValue = DateValue>(props:
|
|
|
90
91
|
let value = controlledValue || placeholderValue;
|
|
91
92
|
|
|
92
93
|
let setValue = (value: DateRange) => {
|
|
93
|
-
setPlaceholderValue(value);
|
|
94
|
+
setPlaceholderValue(value || {start: null, end: null});
|
|
94
95
|
if (value?.start && value.end) {
|
|
95
96
|
setControlledValue(value);
|
|
96
97
|
} else {
|
|
@@ -99,7 +100,7 @@ export function useDateRangePickerState<T extends DateValue = DateValue>(props:
|
|
|
99
100
|
};
|
|
100
101
|
|
|
101
102
|
let v = (value?.start || value?.end || props.placeholderValue);
|
|
102
|
-
let [granularity] = useDefaultProps(v, props.granularity);
|
|
103
|
+
let [granularity, defaultTimeZone] = useDefaultProps(v, props.granularity);
|
|
103
104
|
let hasTime = granularity === 'hour' || granularity === 'minute' || granularity === 'second';
|
|
104
105
|
let shouldCloseOnSelect = props.shouldCloseOnSelect ?? true;
|
|
105
106
|
|
|
@@ -120,6 +121,7 @@ export function useDateRangePickerState<T extends DateValue = DateValue>(props:
|
|
|
120
121
|
});
|
|
121
122
|
setSelectedDateRange(null);
|
|
122
123
|
setSelectedTimeRange(null);
|
|
124
|
+
validation.commitValidation();
|
|
123
125
|
};
|
|
124
126
|
|
|
125
127
|
// Intercept setValue to make sure the Time section is not changed by date selection in Calendar
|
|
@@ -136,6 +138,7 @@ export function useDateRangePickerState<T extends DateValue = DateValue>(props:
|
|
|
136
138
|
}
|
|
137
139
|
} else if (range.start && range.end) {
|
|
138
140
|
setValue(range);
|
|
141
|
+
validation.commitValidation();
|
|
139
142
|
} else {
|
|
140
143
|
setSelectedDateRange(range);
|
|
141
144
|
}
|
|
@@ -153,17 +156,37 @@ export function useDateRangePickerState<T extends DateValue = DateValue>(props:
|
|
|
153
156
|
}
|
|
154
157
|
};
|
|
155
158
|
|
|
156
|
-
let
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
159
|
+
let showEra = (value?.start?.calendar.identifier === 'gregory' && value.start.era === 'BC') || (value?.end?.calendar.identifier === 'gregory' && value.end.era === 'BC');
|
|
160
|
+
let formatOpts = useMemo(() => ({
|
|
161
|
+
granularity,
|
|
162
|
+
timeZone: defaultTimeZone,
|
|
163
|
+
hideTimeZone: props.hideTimeZone,
|
|
164
|
+
hourCycle: props.hourCycle,
|
|
165
|
+
shouldForceLeadingZeros: props.shouldForceLeadingZeros,
|
|
166
|
+
showEra
|
|
167
|
+
}), [granularity, props.hourCycle, props.shouldForceLeadingZeros, defaultTimeZone, props.hideTimeZone, showEra]);
|
|
168
|
+
|
|
169
|
+
let {minValue, maxValue, isDateUnavailable} = props;
|
|
170
|
+
let builtinValidation = useMemo(() => getRangeValidationResult(
|
|
171
|
+
value,
|
|
172
|
+
minValue,
|
|
173
|
+
maxValue,
|
|
174
|
+
isDateUnavailable,
|
|
175
|
+
formatOpts
|
|
176
|
+
), [value, minValue, maxValue, isDateUnavailable, formatOpts]);
|
|
177
|
+
|
|
178
|
+
let validation = useFormValidationState({
|
|
179
|
+
...props,
|
|
180
|
+
value: controlledValue,
|
|
181
|
+
name: useMemo(() => [props.startName, props.endName], [props.startName, props.endName]),
|
|
182
|
+
builtinValidation
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
let isValueInvalid = validation.displayValidation.isInvalid;
|
|
164
186
|
let validationState: ValidationState = props.validationState || (isValueInvalid ? 'invalid' : null);
|
|
165
187
|
|
|
166
188
|
return {
|
|
189
|
+
...validation,
|
|
167
190
|
value,
|
|
168
191
|
setValue,
|
|
169
192
|
dateRange,
|
package/src/useTimeFieldState.ts
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
import {DateFieldState, useDateFieldState} from '.';
|
|
14
14
|
import {DateValue, TimePickerProps, TimeValue} from '@react-types/datepicker';
|
|
15
15
|
import {getLocalTimeZone, GregorianCalendar, Time, toCalendarDateTime, today, toTime, toZoned} from '@internationalized/date';
|
|
16
|
+
import {useCallback, useMemo} from 'react';
|
|
16
17
|
import {useControlledState} from '@react-stately/utils';
|
|
17
|
-
import {useMemo} from 'react';
|
|
18
18
|
|
|
19
19
|
export interface TimeFieldStateOptions<T extends TimeValue = TimeValue> extends TimePickerProps<T> {
|
|
20
20
|
/** The locale to display and edit the value according to. */
|
|
@@ -36,7 +36,8 @@ export function useTimeFieldState<T extends TimeValue = TimeValue>(props: TimeFi
|
|
|
36
36
|
placeholderValue = new Time(),
|
|
37
37
|
minValue,
|
|
38
38
|
maxValue,
|
|
39
|
-
granularity
|
|
39
|
+
granularity,
|
|
40
|
+
validate
|
|
40
41
|
} = props;
|
|
41
42
|
|
|
42
43
|
let [value, setValue] = useControlledState<TimeValue>(
|
|
@@ -73,7 +74,8 @@ export function useTimeFieldState<T extends TimeValue = TimeValue>(props: TimeFi
|
|
|
73
74
|
maxGranularity: 'hour',
|
|
74
75
|
placeholderValue: placeholderDate,
|
|
75
76
|
// Calendar should not matter for time fields.
|
|
76
|
-
createCalendar: () => new GregorianCalendar()
|
|
77
|
+
createCalendar: () => new GregorianCalendar(),
|
|
78
|
+
validate: useCallback(() => validate?.(value as any), [validate, value])
|
|
77
79
|
});
|
|
78
80
|
|
|
79
81
|
return {
|
package/src/utils.ts
CHANGED
|
@@ -10,15 +10,113 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {Calendar, now, Time, toCalendar, toCalendarDate, toCalendarDateTime} from '@internationalized/date';
|
|
13
|
+
import {Calendar, DateFormatter, now, Time, toCalendar, toCalendarDate, toCalendarDateTime} from '@internationalized/date';
|
|
14
14
|
import {DatePickerProps, DateValue, Granularity, TimeValue} from '@react-types/datepicker';
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
import i18nMessages from '../intl/*.json';
|
|
17
|
+
import {LocalizedStringDictionary, LocalizedStringFormatter} from '@internationalized/string';
|
|
18
|
+
import {mergeValidation, VALID_VALIDITY_STATE} from '@react-stately/form';
|
|
19
|
+
import {RangeValue, ValidationResult} from '@react-types/shared';
|
|
15
20
|
import {useState} from 'react';
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
const dictionary = new LocalizedStringDictionary(i18nMessages);
|
|
23
|
+
|
|
24
|
+
function getLocale() {
|
|
25
|
+
// Match browser language setting here, NOT react-aria's I18nProvider, so that we match other browser-provided
|
|
26
|
+
// validation messages, which to not respect our provider's language.
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
return (typeof navigator !== 'undefined' && (navigator.language || navigator.userLanguage)) || 'en-US';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getValidationResult(
|
|
32
|
+
value: DateValue,
|
|
33
|
+
minValue: DateValue,
|
|
34
|
+
maxValue: DateValue,
|
|
35
|
+
isDateUnavailable: (v: DateValue) => boolean,
|
|
36
|
+
options: FormatterOptions
|
|
37
|
+
): ValidationResult {
|
|
38
|
+
let rangeOverflow = value != null && maxValue != null && value.compare(maxValue) > 0;
|
|
39
|
+
let rangeUnderflow = value != null && minValue != null && value.compare(minValue) < 0;
|
|
40
|
+
let isUnavailable = (value != null && isDateUnavailable?.(value)) || false;
|
|
41
|
+
let isInvalid = rangeOverflow || rangeUnderflow || isUnavailable;
|
|
42
|
+
let errors = [];
|
|
43
|
+
|
|
44
|
+
if (isInvalid) {
|
|
45
|
+
let locale = getLocale();
|
|
46
|
+
let formatter = new LocalizedStringFormatter(locale, dictionary);
|
|
47
|
+
let dateFormatter = new DateFormatter(locale, getFormatOptions({}, options));
|
|
48
|
+
let timeZone = dateFormatter.resolvedOptions().timeZone;
|
|
49
|
+
|
|
50
|
+
if (rangeUnderflow) {
|
|
51
|
+
errors.push(formatter.format('rangeUnderflow', {minValue: dateFormatter.format(minValue.toDate(timeZone))}));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (rangeOverflow) {
|
|
55
|
+
errors.push(formatter.format('rangeOverflow', {maxValue: dateFormatter.format(maxValue.toDate(timeZone))}));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (isUnavailable) {
|
|
59
|
+
errors.push(formatter.format('unavailableDate'));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
isInvalid,
|
|
65
|
+
validationErrors: errors,
|
|
66
|
+
validationDetails: {
|
|
67
|
+
badInput: isUnavailable,
|
|
68
|
+
customError: false,
|
|
69
|
+
patternMismatch: false,
|
|
70
|
+
rangeOverflow,
|
|
71
|
+
rangeUnderflow,
|
|
72
|
+
stepMismatch: false,
|
|
73
|
+
tooLong: false,
|
|
74
|
+
tooShort: false,
|
|
75
|
+
typeMismatch: false,
|
|
76
|
+
valueMissing: false,
|
|
77
|
+
valid: !isInvalid
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function getRangeValidationResult(
|
|
83
|
+
value: RangeValue<DateValue>,
|
|
84
|
+
minValue: DateValue,
|
|
85
|
+
maxValue: DateValue,
|
|
86
|
+
isDateUnavailable: (v: DateValue) => boolean,
|
|
87
|
+
options: FormatterOptions
|
|
88
|
+
) {
|
|
89
|
+
let startValidation = getValidationResult(
|
|
90
|
+
value?.start,
|
|
91
|
+
minValue,
|
|
92
|
+
maxValue,
|
|
93
|
+
isDateUnavailable,
|
|
94
|
+
options
|
|
21
95
|
);
|
|
96
|
+
|
|
97
|
+
let endValidation = getValidationResult(
|
|
98
|
+
value?.end,
|
|
99
|
+
minValue,
|
|
100
|
+
maxValue,
|
|
101
|
+
isDateUnavailable,
|
|
102
|
+
options
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
let result = mergeValidation(startValidation, endValidation);
|
|
106
|
+
if (value.end != null && value.start != null && value.end.compare(value.start) < 0) {
|
|
107
|
+
result = mergeValidation(result, {
|
|
108
|
+
isInvalid: true,
|
|
109
|
+
validationErrors: [dictionary.getStringForLocale('rangeReversed', getLocale())],
|
|
110
|
+
validationDetails: {
|
|
111
|
+
...VALID_VALIDITY_STATE,
|
|
112
|
+
rangeUnderflow: true,
|
|
113
|
+
rangeOverflow: true,
|
|
114
|
+
valid: false
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return result;
|
|
22
120
|
}
|
|
23
121
|
|
|
24
122
|
export type FieldOptions = Pick<Intl.DateTimeFormatOptions, 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second'>;
|