@gravity-ui/date-components 1.0.0 → 1.1.1
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/cjs/components/Calendar/Calendar.css +9 -1
- package/dist/cjs/components/Calendar/CalendarBase.js +9 -9
- package/dist/cjs/components/Calendar/hooks/types.d.ts +5 -2
- package/dist/cjs/components/Calendar/hooks/useCalendarCellProps.js +21 -16
- package/dist/cjs/components/Calendar/hooks/useCalendarGridProps.js +2 -7
- package/dist/cjs/components/Calendar/hooks/useCalendarProps.js +6 -3
- package/dist/cjs/components/Calendar/hooks/useCalendarState.js +69 -26
- package/dist/cjs/components/Calendar/hooks/useRangeCalendarState.js +16 -11
- package/dist/cjs/components/Calendar/utils.d.ts +3 -1
- package/dist/cjs/components/Calendar/utils.js +7 -1
- package/dist/cjs/components/DateField/hooks/useDateFieldProps.js +23 -16
- package/dist/cjs/components/DateField/hooks/useDateFieldState.d.ts +2 -0
- package/dist/cjs/components/DateField/hooks/useDateFieldState.js +49 -166
- package/dist/cjs/components/DateField/types.d.ts +1 -1
- package/dist/cjs/components/DateField/utils.d.ts +12 -9
- package/dist/cjs/components/DateField/utils.js +168 -25
- package/dist/cjs/components/DatePicker/DatePicker.css +6 -0
- package/dist/cjs/components/DatePicker/DatePicker.d.ts +4 -1
- package/dist/cjs/components/DatePicker/DatePicker.js +6 -33
- package/dist/cjs/components/DatePicker/MobileCalendar.js +4 -4
- package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
- package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.js +134 -0
- package/dist/cjs/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
- package/dist/cjs/components/DatePicker/hooks/useDatePickerState.js +18 -8
- package/dist/cjs/components/DatePicker/index.d.ts +1 -0
- package/dist/cjs/components/DatePicker/index.js +1 -0
- package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.css +1 -0
- package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.d.ts +3 -0
- package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.js +1 -1
- package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +35 -27
- package/dist/cjs/components/utils/dates.d.ts +9 -0
- package/dist/cjs/components/utils/dates.js +28 -0
- package/dist/esm/components/Calendar/Calendar.css +9 -1
- package/dist/esm/components/Calendar/CalendarBase.js +10 -10
- package/dist/esm/components/Calendar/hooks/types.d.ts +5 -2
- package/dist/esm/components/Calendar/hooks/useCalendarCellProps.js +21 -16
- package/dist/esm/components/Calendar/hooks/useCalendarGridProps.js +2 -7
- package/dist/esm/components/Calendar/hooks/useCalendarProps.js +6 -3
- package/dist/esm/components/Calendar/hooks/useCalendarState.js +70 -27
- package/dist/esm/components/Calendar/hooks/useRangeCalendarState.js +16 -11
- package/dist/esm/components/Calendar/utils.d.ts +3 -1
- package/dist/esm/components/Calendar/utils.js +6 -0
- package/dist/esm/components/DateField/hooks/useDateFieldProps.js +23 -16
- package/dist/esm/components/DateField/hooks/useDateFieldState.d.ts +2 -0
- package/dist/esm/components/DateField/hooks/useDateFieldState.js +41 -158
- package/dist/esm/components/DateField/types.d.ts +1 -1
- package/dist/esm/components/DateField/utils.d.ts +12 -9
- package/dist/esm/components/DateField/utils.js +162 -21
- package/dist/esm/components/DatePicker/DatePicker.css +6 -0
- package/dist/esm/components/DatePicker/DatePicker.d.ts +4 -1
- package/dist/esm/components/DatePicker/DatePicker.js +8 -35
- package/dist/esm/components/DatePicker/MobileCalendar.js +1 -1
- package/dist/esm/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
- package/dist/esm/components/DatePicker/hooks/useDatePickerProps.js +127 -0
- package/dist/esm/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
- package/dist/esm/components/DatePicker/hooks/useDatePickerState.js +17 -7
- package/dist/esm/components/DatePicker/index.d.ts +1 -0
- package/dist/esm/components/DatePicker/index.js +1 -0
- package/dist/esm/components/RelativeDatePicker/RelativeDatePicker.css +1 -0
- package/dist/esm/components/RelativeDatePicker/RelativeDatePicker.d.ts +3 -0
- package/dist/esm/components/RelativeDatePicker/RelativeDatePicker.js +1 -1
- package/dist/esm/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +35 -27
- package/dist/esm/components/utils/dates.d.ts +9 -0
- package/dist/esm/components/utils/dates.js +22 -0
- package/package.json +8 -7
- package/dist/cjs/components/DatePicker/DesktopCalendar.d.ts +0 -15
- package/dist/cjs/components/DatePicker/DesktopCalendar.js +0 -56
- package/dist/esm/components/DatePicker/DesktopCalendar.d.ts +0 -15
- package/dist/esm/components/DatePicker/DesktopCalendar.js +0 -48
|
@@ -6,7 +6,7 @@ export function useCalendarGridProps(state) {
|
|
|
6
6
|
state.setFocused(isFocused);
|
|
7
7
|
},
|
|
8
8
|
});
|
|
9
|
-
const gridProps = Object.assign(Object.assign({ role: 'grid', 'aria-label': state.mode === 'years'
|
|
9
|
+
const gridProps = Object.assign(Object.assign({ role: 'grid', 'aria-label': state.mode === 'years' || state.mode === 'quarters'
|
|
10
10
|
? `${state.startDate.year()} — ${state.endDate.year()}`
|
|
11
11
|
: state.focusedDate.format(state.mode === 'days' ? 'MMMM YYYY' : 'YYYY'), 'aria-disabled': state.disabled ? 'true' : undefined, 'aria-readonly': state.readOnly ? 'true' : undefined }, focusWithinProps), { onKeyDown: (e) => {
|
|
12
12
|
if (e.key === 'ArrowRight') {
|
|
@@ -40,12 +40,7 @@ export function useCalendarGridProps(state) {
|
|
|
40
40
|
state.zoomIn();
|
|
41
41
|
}
|
|
42
42
|
else if (e.key === 'Enter' || e.key === ' ') {
|
|
43
|
-
|
|
44
|
-
state.selectFocusedDate();
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
state.setMode(state.mode === 'months' ? 'days' : 'months');
|
|
48
|
-
}
|
|
43
|
+
state.selectDate(state.focusedDate);
|
|
49
44
|
}
|
|
50
45
|
} });
|
|
51
46
|
return {
|
|
@@ -4,7 +4,7 @@ import { i18n } from '../i18n';
|
|
|
4
4
|
const buttonDisabledClassName = 'yc-button_disabled g-button_disabled';
|
|
5
5
|
// eslint-disable-next-line complexity
|
|
6
6
|
export function useCalendarProps(props, state) {
|
|
7
|
-
const title = state.mode === 'years'
|
|
7
|
+
const title = state.mode === 'years' || state.mode === 'quarters'
|
|
8
8
|
? `${state.startDate.year()} — ${state.endDate.year()}`
|
|
9
9
|
: state.focusedDate.format(state.mode === 'days' ? 'MMMM YYYY' : 'YYYY');
|
|
10
10
|
const { focusWithinProps } = useFocusWithin({
|
|
@@ -12,7 +12,10 @@ export function useCalendarProps(props, state) {
|
|
|
12
12
|
onBlurWithin: props.onBlur,
|
|
13
13
|
});
|
|
14
14
|
const calendarProps = Object.assign({ role: 'group', id: props.id, 'aria-label': [props['aria-label'], title].filter(Boolean).join(', '), 'aria-labelledby': props['aria-labelledby'] || undefined, 'aria-describedby': props['aria-describedby'] || undefined, 'aria-details': props['aria-details'] || undefined, 'aria-disabled': state.disabled || undefined }, focusWithinProps);
|
|
15
|
-
const
|
|
15
|
+
const modeIndex = state.availableModes.indexOf(state.mode);
|
|
16
|
+
const isModeLast = modeIndex + 1 === state.availableModes.length;
|
|
17
|
+
const isNextModeLast = modeIndex + 2 === state.availableModes.length;
|
|
18
|
+
const modeDisabled = state.disabled || isModeLast;
|
|
16
19
|
const modeButtonProps = {
|
|
17
20
|
disabled: state.disabled,
|
|
18
21
|
// FIXME: do not use button class name
|
|
@@ -21,7 +24,7 @@ export function useCalendarProps(props, state) {
|
|
|
21
24
|
? undefined
|
|
22
25
|
: () => {
|
|
23
26
|
state.zoomOut();
|
|
24
|
-
if (
|
|
27
|
+
if (isNextModeLast) {
|
|
25
28
|
state.setFocused(true);
|
|
26
29
|
}
|
|
27
30
|
},
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { dateTime } from '@gravity-ui/date-utils';
|
|
3
2
|
import { useControlledState } from '../../hooks/useControlledState';
|
|
4
|
-
import {
|
|
3
|
+
import { createPlaceholderValue } from '../../utils/dates';
|
|
4
|
+
import { calendarLayouts, constrainValue } from '../utils';
|
|
5
|
+
const defaultModes = {
|
|
6
|
+
days: true,
|
|
7
|
+
months: true,
|
|
8
|
+
quarters: false,
|
|
9
|
+
years: true,
|
|
10
|
+
};
|
|
5
11
|
export function useCalendarState(props) {
|
|
6
|
-
const { disabled, readOnly, minValue, maxValue, timeZone } = props;
|
|
12
|
+
const { disabled, readOnly, minValue, maxValue, timeZone, modes = defaultModes } = props;
|
|
7
13
|
const [value, setValue] = useControlledState(props.value, props.defaultValue, props.onUpdate);
|
|
8
14
|
const [mode, setMode] = useControlledState(props.mode, props.defaultMode, props.onUpdateMode);
|
|
9
|
-
const
|
|
15
|
+
const availableModes = calendarLayouts.filter((l) => modes[l]);
|
|
16
|
+
const minMode = availableModes[0] || 'days';
|
|
17
|
+
const currentMode = mode && availableModes.includes(mode) ? mode : minMode;
|
|
10
18
|
const focusedValue = React.useMemo(() => {
|
|
11
19
|
if (!props.focusedValue) {
|
|
12
20
|
return props.focusedValue;
|
|
@@ -14,17 +22,18 @@ export function useCalendarState(props) {
|
|
|
14
22
|
return constrainValue(props.focusedValue, minValue, maxValue);
|
|
15
23
|
}, [props.focusedValue, minValue, maxValue]);
|
|
16
24
|
const defaultFocusedValue = React.useMemo(() => {
|
|
17
|
-
const defaultValue = (props.defaultFocusedValue ? props.defaultFocusedValue : value) ||
|
|
25
|
+
const defaultValue = (props.defaultFocusedValue ? props.defaultFocusedValue : value) ||
|
|
26
|
+
createPlaceholderValue({ timeZone }).startOf(minMode);
|
|
18
27
|
return constrainValue(defaultValue, minValue, maxValue);
|
|
19
|
-
}, [maxValue, minValue, props.defaultFocusedValue, timeZone, value]);
|
|
28
|
+
}, [maxValue, minValue, props.defaultFocusedValue, timeZone, value, minMode]);
|
|
20
29
|
const [focusedDateInner, setFocusedDate] = useControlledState(focusedValue, defaultFocusedValue, props.onFocusUpdate);
|
|
21
|
-
const focusedDate = focusedDateInner !== null && focusedDateInner !== void 0 ? focusedDateInner : constrainValue(
|
|
30
|
+
const focusedDate = focusedDateInner !== null && focusedDateInner !== void 0 ? focusedDateInner : constrainValue(createPlaceholderValue({ timeZone }).startOf(minMode), minValue, maxValue);
|
|
22
31
|
if (isInvalid(focusedDate, minValue, maxValue)) {
|
|
23
32
|
// If the focused date was moved to an invalid value, it can't be focused, so constrain it.
|
|
24
33
|
setFocusedDate(constrainValue(focusedDate, minValue, maxValue));
|
|
25
34
|
}
|
|
26
35
|
function focusCell(date) {
|
|
27
|
-
setFocusedDate(constrainValue(date, minValue, maxValue));
|
|
36
|
+
setFocusedDate(constrainValue(date.startOf(currentMode), minValue, maxValue));
|
|
28
37
|
}
|
|
29
38
|
const [isFocused, setFocused] = React.useState(props.autoFocus || false);
|
|
30
39
|
const startDate = getStartDate(focusedDate, currentMode);
|
|
@@ -35,13 +44,21 @@ export function useCalendarState(props) {
|
|
|
35
44
|
value,
|
|
36
45
|
setValue,
|
|
37
46
|
timeZone,
|
|
38
|
-
selectDate(date) {
|
|
39
|
-
if (!disabled
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
selectDate(date, force = false) {
|
|
48
|
+
if (!disabled) {
|
|
49
|
+
if (!readOnly && (force || this.mode === minMode)) {
|
|
50
|
+
const newValue = constrainValue(date, minValue, maxValue);
|
|
51
|
+
if (this.isCellUnavailable(newValue)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
setValue(newValue);
|
|
55
|
+
if (force && currentMode !== minMode) {
|
|
56
|
+
setMode(minMode);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
this.zoomIn();
|
|
43
61
|
}
|
|
44
|
-
setValue(constrainValue(newValue, minValue, maxValue));
|
|
45
62
|
}
|
|
46
63
|
},
|
|
47
64
|
minValue,
|
|
@@ -54,41 +71,53 @@ export function useCalendarState(props) {
|
|
|
54
71
|
setFocused(true);
|
|
55
72
|
},
|
|
56
73
|
focusNextCell() {
|
|
57
|
-
focusCell(focusedDate.add(
|
|
74
|
+
focusCell(focusedDate.add(1, this.mode));
|
|
58
75
|
},
|
|
59
76
|
focusPreviousCell() {
|
|
60
|
-
focusCell(focusedDate.subtract(
|
|
77
|
+
focusCell(focusedDate.subtract(1, this.mode));
|
|
61
78
|
},
|
|
62
79
|
focusNextRow() {
|
|
63
80
|
if (this.mode === 'days') {
|
|
64
81
|
focusCell(focusedDate.add(1, 'week'));
|
|
65
82
|
}
|
|
83
|
+
else if (this.mode === 'quarters') {
|
|
84
|
+
focusCell(focusedDate.add(1, 'years'));
|
|
85
|
+
}
|
|
66
86
|
else {
|
|
67
|
-
focusCell(focusedDate.add(
|
|
87
|
+
focusCell(focusedDate.add(3, this.mode));
|
|
68
88
|
}
|
|
69
89
|
},
|
|
70
90
|
focusPreviousRow() {
|
|
71
91
|
if (this.mode === 'days') {
|
|
72
92
|
focusCell(focusedDate.subtract(1, 'week'));
|
|
73
93
|
}
|
|
94
|
+
else if (this.mode === 'quarters') {
|
|
95
|
+
focusCell(focusedDate.subtract(1, 'years'));
|
|
96
|
+
}
|
|
74
97
|
else {
|
|
75
|
-
focusCell(focusedDate.subtract(
|
|
98
|
+
focusCell(focusedDate.subtract(3, this.mode));
|
|
76
99
|
}
|
|
77
100
|
},
|
|
78
101
|
focusNextPage(larger) {
|
|
79
102
|
if (this.mode === 'days') {
|
|
80
103
|
focusCell(focusedDate.add({ months: larger ? 12 : 1 }));
|
|
81
104
|
}
|
|
105
|
+
else if (this.mode === 'quarters') {
|
|
106
|
+
focusCell(focusedDate.add(4, 'years'));
|
|
107
|
+
}
|
|
82
108
|
else {
|
|
83
|
-
focusCell(focusedDate.add(
|
|
109
|
+
focusCell(focusedDate.add(12, this.mode));
|
|
84
110
|
}
|
|
85
111
|
},
|
|
86
112
|
focusPreviousPage(larger) {
|
|
87
113
|
if (this.mode === 'days') {
|
|
88
114
|
focusCell(focusedDate.subtract({ months: larger ? 12 : 1 }));
|
|
89
115
|
}
|
|
116
|
+
else if (this.mode === 'quarters') {
|
|
117
|
+
focusCell(focusedDate.subtract(4, 'years'));
|
|
118
|
+
}
|
|
90
119
|
else {
|
|
91
|
-
focusCell(focusedDate.subtract(
|
|
120
|
+
focusCell(focusedDate.subtract(12, this.mode));
|
|
92
121
|
}
|
|
93
122
|
},
|
|
94
123
|
focusSectionStart() {
|
|
@@ -98,13 +127,19 @@ export function useCalendarState(props) {
|
|
|
98
127
|
focusCell(getEndDate(focusedDate, this.mode));
|
|
99
128
|
},
|
|
100
129
|
zoomIn() {
|
|
101
|
-
|
|
130
|
+
const index = availableModes.indexOf(this.mode) - 1;
|
|
131
|
+
if (index >= 0) {
|
|
132
|
+
this.setMode(availableModes[index]);
|
|
133
|
+
}
|
|
102
134
|
},
|
|
103
135
|
zoomOut() {
|
|
104
|
-
|
|
136
|
+
const index = availableModes.indexOf(this.mode) + 1;
|
|
137
|
+
if (index < availableModes.length) {
|
|
138
|
+
this.setMode(availableModes[index]);
|
|
139
|
+
}
|
|
105
140
|
},
|
|
106
141
|
selectFocusedDate() {
|
|
107
|
-
this.selectDate(focusedDate);
|
|
142
|
+
this.selectDate(focusedDate, true);
|
|
108
143
|
},
|
|
109
144
|
isFocused,
|
|
110
145
|
setFocused,
|
|
@@ -112,11 +147,11 @@ export function useCalendarState(props) {
|
|
|
112
147
|
return isInvalid(date, this.minValue, this.maxValue, this.mode);
|
|
113
148
|
},
|
|
114
149
|
isPreviousPageInvalid() {
|
|
115
|
-
const prev = this.startDate.
|
|
150
|
+
const prev = this.startDate.subtract(1, 'day');
|
|
116
151
|
return this.isInvalid(prev);
|
|
117
152
|
},
|
|
118
153
|
isNextPageInvalid() {
|
|
119
|
-
const next = this.endDate.add(
|
|
154
|
+
const next = this.endDate.endOf(this.mode).add(1, 'day');
|
|
120
155
|
return this.isInvalid(next);
|
|
121
156
|
},
|
|
122
157
|
isSelected(date) {
|
|
@@ -125,7 +160,7 @@ export function useCalendarState(props) {
|
|
|
125
160
|
!this.isCellDisabled(date));
|
|
126
161
|
},
|
|
127
162
|
isCellUnavailable(date) {
|
|
128
|
-
if (this.mode ===
|
|
163
|
+
if (this.mode === minMode) {
|
|
129
164
|
return Boolean(props.isDateUnavailable && props.isDateUnavailable(date));
|
|
130
165
|
}
|
|
131
166
|
else {
|
|
@@ -143,6 +178,7 @@ export function useCalendarState(props) {
|
|
|
143
178
|
},
|
|
144
179
|
mode: currentMode,
|
|
145
180
|
setMode,
|
|
181
|
+
availableModes,
|
|
146
182
|
};
|
|
147
183
|
}
|
|
148
184
|
function getStartDate(date, mode) {
|
|
@@ -152,6 +188,10 @@ function getStartDate(date, mode) {
|
|
|
152
188
|
if (mode === 'months') {
|
|
153
189
|
return date.startOf('year');
|
|
154
190
|
}
|
|
191
|
+
if (mode === 'quarters') {
|
|
192
|
+
const year = Math.floor(date.year() / 4) * 4;
|
|
193
|
+
return date.startOf('year').set('year', year);
|
|
194
|
+
}
|
|
155
195
|
const year = Math.floor(date.year() / 12) * 12;
|
|
156
196
|
return date.startOf('year').set('year', year);
|
|
157
197
|
}
|
|
@@ -160,9 +200,12 @@ function getEndDate(date, mode) {
|
|
|
160
200
|
return date.endOf('month').startOf('day');
|
|
161
201
|
}
|
|
162
202
|
if (mode === 'months') {
|
|
163
|
-
return date.endOf('
|
|
203
|
+
return date.endOf('year').startOf('month');
|
|
164
204
|
}
|
|
165
205
|
const startDate = getStartDate(date, mode);
|
|
206
|
+
if (mode === 'quarters') {
|
|
207
|
+
return startDate.add(15, 'quarters');
|
|
208
|
+
}
|
|
166
209
|
return startDate.add({ [mode]: 11 });
|
|
167
210
|
}
|
|
168
211
|
function isInvalid(date, minValue, maxValue, mode = 'days') {
|
|
@@ -20,10 +20,18 @@ export function useRangeCalendarState(props) {
|
|
|
20
20
|
const [anchorDate, setAnchorDateState] = React.useState();
|
|
21
21
|
const calendar = useCalendarState(Object.assign(Object.assign({}, calendarProps), { value: (_a = value === null || value === void 0 ? void 0 : value.start) !== null && _a !== void 0 ? _a : null }));
|
|
22
22
|
const highlightedRange = anchorDate
|
|
23
|
-
? makeRange(anchorDate, calendar.focusedDate)
|
|
24
|
-
: (_b = (value && makeRange(value.start, value.end))) !== null && _b !== void 0 ? _b : undefined;
|
|
25
|
-
const
|
|
26
|
-
|
|
23
|
+
? makeRange(anchorDate, calendar.focusedDate, calendar.mode)
|
|
24
|
+
: (_b = (value && makeRange(value.start, value.end, calendar.mode))) !== null && _b !== void 0 ? _b : undefined;
|
|
25
|
+
const minMode = calendar.availableModes[0];
|
|
26
|
+
const selectDate = (date, force = false) => {
|
|
27
|
+
if (props.disabled) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (!force && calendar.mode !== minMode) {
|
|
31
|
+
calendar.zoomIn();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (props.readOnly) {
|
|
27
35
|
return;
|
|
28
36
|
}
|
|
29
37
|
date = constrainValue(date, props.minValue, props.maxValue);
|
|
@@ -31,7 +39,7 @@ export function useRangeCalendarState(props) {
|
|
|
31
39
|
return;
|
|
32
40
|
}
|
|
33
41
|
if (anchorDate) {
|
|
34
|
-
const range = makeRange(anchorDate, date);
|
|
42
|
+
const range = makeRange(anchorDate, date, calendar.mode);
|
|
35
43
|
setValue(range);
|
|
36
44
|
setAnchorDateState(undefined);
|
|
37
45
|
}
|
|
@@ -43,9 +51,6 @@ export function useRangeCalendarState(props) {
|
|
|
43
51
|
setValue,
|
|
44
52
|
selectDate,
|
|
45
53
|
anchorDate, setAnchorDate: setAnchorDateState, highlightedRange,
|
|
46
|
-
selectFocusedDate() {
|
|
47
|
-
selectDate(calendar.focusedDate);
|
|
48
|
-
},
|
|
49
54
|
isSelected(date) {
|
|
50
55
|
if (!highlightedRange) {
|
|
51
56
|
return false;
|
|
@@ -61,15 +66,15 @@ export function useRangeCalendarState(props) {
|
|
|
61
66
|
}
|
|
62
67
|
} });
|
|
63
68
|
}
|
|
64
|
-
function makeRange(start, end) {
|
|
69
|
+
function makeRange(start, end, mode) {
|
|
65
70
|
if (start.isBefore(end)) {
|
|
66
71
|
return {
|
|
67
72
|
start,
|
|
68
|
-
end,
|
|
73
|
+
end: end.endOf(mode),
|
|
69
74
|
};
|
|
70
75
|
}
|
|
71
76
|
return {
|
|
72
77
|
start: end,
|
|
73
|
-
end: start,
|
|
78
|
+
end: start.endOf(mode),
|
|
74
79
|
};
|
|
75
80
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { DateTime } from '@gravity-ui/date-utils';
|
|
2
|
+
import type { CalendarLayout } from './hooks/types';
|
|
2
3
|
export declare function constrainValue(value: DateTime, minValue: DateTime | undefined, maxValue: DateTime | undefined): DateTime;
|
|
3
|
-
export declare function getDaysInPeriod(startDate: DateTime, _endDate: DateTime, mode:
|
|
4
|
+
export declare function getDaysInPeriod(startDate: DateTime, _endDate: DateTime, mode: CalendarLayout): DateTime[];
|
|
4
5
|
export declare function getWeekDays(): DateTime[];
|
|
6
|
+
export declare const calendarLayouts: CalendarLayout[];
|
|
@@ -16,6 +16,11 @@ export function getDaysInPeriod(startDate, _endDate, mode) {
|
|
|
16
16
|
days.push(currentDate.add({ days: i }));
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
+
else if (mode === 'quarters') {
|
|
20
|
+
for (let i = 0; i < 16; i++) {
|
|
21
|
+
days.push(startDate.add(i, 'quarters'));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
19
24
|
else {
|
|
20
25
|
for (let i = 0; i < 12; i++) {
|
|
21
26
|
days.push(startDate.add({ [mode]: i }));
|
|
@@ -32,3 +37,4 @@ export function getWeekDays() {
|
|
|
32
37
|
}
|
|
33
38
|
return weekDays;
|
|
34
39
|
}
|
|
40
|
+
export const calendarLayouts = ['days', 'months', 'quarters', 'years'];
|
|
@@ -80,12 +80,16 @@ export function useDateFieldProps(state, props) {
|
|
|
80
80
|
if (state.selectedSectionIndexes !== null) {
|
|
81
81
|
return;
|
|
82
82
|
}
|
|
83
|
-
const input =
|
|
83
|
+
const input = e.target;
|
|
84
|
+
const isAutofocus = !inputRef.current;
|
|
84
85
|
setTimeout(() => {
|
|
85
86
|
if (!input || input !== inputRef.current) {
|
|
86
87
|
return;
|
|
87
88
|
}
|
|
88
|
-
if (
|
|
89
|
+
if (isAutofocus) {
|
|
90
|
+
state.focusSectionInPosition(0);
|
|
91
|
+
}
|
|
92
|
+
else if (
|
|
89
93
|
// avoid selecting all sections when focusing empty field without value
|
|
90
94
|
input.value.length &&
|
|
91
95
|
Number(input.selectionEnd) - Number(input.selectionStart) ===
|
|
@@ -115,11 +119,11 @@ export function useDateFieldProps(state, props) {
|
|
|
115
119
|
}
|
|
116
120
|
else if (e.key === 'Home') {
|
|
117
121
|
e.preventDefault();
|
|
118
|
-
state.
|
|
122
|
+
state.decrementToMin();
|
|
119
123
|
}
|
|
120
124
|
else if (e.key === 'End') {
|
|
121
125
|
e.preventDefault();
|
|
122
|
-
state.
|
|
126
|
+
state.incrementToMax();
|
|
123
127
|
}
|
|
124
128
|
else if (e.key === 'ArrowUp' && !e.altKey) {
|
|
125
129
|
e.preventDefault();
|
|
@@ -163,32 +167,35 @@ export function useDateFieldProps(state, props) {
|
|
|
163
167
|
onBeforeInput(e) {
|
|
164
168
|
e.preventDefault();
|
|
165
169
|
// @ts-expect-error
|
|
166
|
-
const key = e.
|
|
167
|
-
|
|
168
|
-
if (key != null) {
|
|
170
|
+
const key = e.data;
|
|
171
|
+
if (key !== undefined && key !== null) {
|
|
169
172
|
state.onInput(key);
|
|
170
173
|
}
|
|
171
174
|
},
|
|
172
175
|
onPaste(e) {
|
|
176
|
+
e.preventDefault();
|
|
173
177
|
if (state.readOnly) {
|
|
174
|
-
e.preventDefault();
|
|
175
178
|
return;
|
|
176
179
|
}
|
|
177
180
|
const pastedValue = e.clipboardData.getData('text');
|
|
178
|
-
if (state.
|
|
179
|
-
e.preventDefault();
|
|
180
|
-
}
|
|
181
|
-
else if (state.selectedSectionIndexes &&
|
|
181
|
+
if (state.selectedSectionIndexes &&
|
|
182
182
|
state.selectedSectionIndexes.startIndex ===
|
|
183
183
|
state.selectedSectionIndexes.endIndex) {
|
|
184
184
|
const activeSection = state.sections[state.selectedSectionIndexes.startIndex];
|
|
185
|
+
const digitsOnly = /^\d+$/.test(pastedValue);
|
|
186
|
+
const lettersOnly = /^[a-zA-Z]+$/.test(pastedValue);
|
|
185
187
|
const isValidValue = Boolean(activeSection) &&
|
|
186
|
-
((activeSection.contentType === 'digit' &&
|
|
187
|
-
activeSection.contentType === 'letter');
|
|
188
|
-
if (
|
|
189
|
-
|
|
188
|
+
((activeSection.contentType === 'digit' && digitsOnly) ||
|
|
189
|
+
(activeSection.contentType === 'letter' && lettersOnly));
|
|
190
|
+
if (isValidValue) {
|
|
191
|
+
state.onInput(pastedValue);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (digitsOnly || lettersOnly) {
|
|
195
|
+
return;
|
|
190
196
|
}
|
|
191
197
|
}
|
|
198
|
+
state.setValueFromString(pastedValue);
|
|
192
199
|
},
|
|
193
200
|
},
|
|
194
201
|
},
|
|
@@ -56,6 +56,8 @@ export type DateFieldState = {
|
|
|
56
56
|
* Upon reaching the minimum or maximum value, the value wraps around to the opposite limit.
|
|
57
57
|
*/
|
|
58
58
|
decrementPage: () => void;
|
|
59
|
+
incrementToMax: () => void;
|
|
60
|
+
decrementToMin: () => void;
|
|
59
61
|
/** Clears the value of the currently selected segment, reverting it to the placeholder. */
|
|
60
62
|
clearSection: () => void;
|
|
61
63
|
/** Clears all segments, reverting them to the placeholder. */
|