@snack-uikit/fields 0.29.2-preview-eb3592d8.0 → 0.29.2
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/CHANGELOG.md +9 -0
- package/README.md +2 -8
- package/dist/components/FieldDate/FieldDate.d.ts +3 -10
- package/dist/components/FieldDate/FieldDate.js +15 -15
- package/dist/components/FieldDate/constants.d.ts +5 -12
- package/dist/components/FieldDate/constants.js +11 -36
- package/dist/components/FieldDate/hooks/useDateField.d.ts +3 -5
- package/dist/components/FieldDate/hooks/useDateField.js +23 -34
- package/dist/components/FieldDate/hooks/useDateFieldHelpers.js +5 -5
- package/dist/components/FieldDate/types.d.ts +0 -3
- package/dist/components/FieldDate/utils.d.ts +4 -9
- package/dist/components/FieldDate/utils.js +8 -70
- package/package.json +4 -4
- package/src/components/FieldDate/FieldDate.tsx +17 -25
- package/src/components/FieldDate/constants.ts +15 -59
- package/src/components/FieldDate/hooks/useDateField.ts +28 -51
- package/src/components/FieldDate/hooks/useDateFieldHelpers.ts +5 -5
- package/src/components/FieldDate/types.ts +0 -6
- package/src/components/FieldDate/utils.ts +10 -80
- package/dist/components/FieldDate/hooks/useDateTimeFieldHelpers.d.ts +0 -10
- package/dist/components/FieldDate/hooks/useDateTimeFieldHelpers.js +0 -75
- package/src/components/FieldDate/hooks/useDateTimeFieldHelpers.ts +0 -109
|
@@ -38,9 +38,9 @@ import { useDateField } from './hooks';
|
|
|
38
38
|
import { useFocusHandlers } from './hooks/useFocusHandlers';
|
|
39
39
|
import { useHandlers } from './hooks/useHandlers';
|
|
40
40
|
import styles from './styles.module.scss';
|
|
41
|
-
import {
|
|
41
|
+
import { parseDate } from './utils';
|
|
42
42
|
|
|
43
|
-
type InputProps = Pick<InputPrivateProps, 'id' | 'name' | 'disabled' | 'readonly' | 'onFocus' | 'onBlur'>;
|
|
43
|
+
type InputProps = Pick<InputPrivateProps, 'id' | 'name' | 'value' | 'disabled' | 'readonly' | 'onFocus' | 'onBlur'>;
|
|
44
44
|
|
|
45
45
|
type WrapperProps = Pick<
|
|
46
46
|
FieldDecoratorProps,
|
|
@@ -62,10 +62,8 @@ type FieldDateOwnProps = {
|
|
|
62
62
|
open?: boolean;
|
|
63
63
|
/** Колбек открытия пикера */
|
|
64
64
|
onOpenChange?(value: boolean): void;
|
|
65
|
-
/** Значение поля */
|
|
66
|
-
value?: Date;
|
|
67
65
|
/** Колбек смены значения */
|
|
68
|
-
onChange?(value:
|
|
66
|
+
onChange?(value: string): void;
|
|
69
67
|
/** Отображение кнопки копирования */
|
|
70
68
|
showCopyButton?: boolean;
|
|
71
69
|
/**
|
|
@@ -75,7 +73,6 @@ type FieldDateOwnProps = {
|
|
|
75
73
|
showClearButton?: boolean;
|
|
76
74
|
/** Текущая локаль календаря */
|
|
77
75
|
locale?: Intl.Locale;
|
|
78
|
-
mode: Mode;
|
|
79
76
|
} & Pick<CalendarProps, 'buildCellProps'>;
|
|
80
77
|
|
|
81
78
|
export type FieldDateProps = WithSupportProps<FieldDateOwnProps & InputProps & WrapperProps>;
|
|
@@ -83,7 +80,7 @@ export type FieldDateProps = WithSupportProps<FieldDateOwnProps & InputProps & W
|
|
|
83
80
|
const CALENDAR_SIZE_MAP: Record<Size, CalendarProps['size']> = {
|
|
84
81
|
[SIZE.S]: 's',
|
|
85
82
|
[SIZE.M]: 'm',
|
|
86
|
-
[SIZE.L]: '
|
|
83
|
+
[SIZE.L]: 'm',
|
|
87
84
|
};
|
|
88
85
|
|
|
89
86
|
export const FieldDate = forwardRef<HTMLInputElement, FieldDateProps>(
|
|
@@ -114,7 +111,6 @@ export const FieldDate = forwardRef<HTMLInputElement, FieldDateProps>(
|
|
|
114
111
|
locale = DEFAULT_LOCALE,
|
|
115
112
|
buildCellProps,
|
|
116
113
|
error,
|
|
117
|
-
mode,
|
|
118
114
|
...rest
|
|
119
115
|
},
|
|
120
116
|
ref,
|
|
@@ -143,7 +139,7 @@ export const FieldDate = forwardRef<HTMLInputElement, FieldDateProps>(
|
|
|
143
139
|
);
|
|
144
140
|
|
|
145
141
|
const handleClear = useCallback(() => {
|
|
146
|
-
onChange && onChange(
|
|
142
|
+
onChange && onChange('');
|
|
147
143
|
if (localRef.current?.value) {
|
|
148
144
|
localRef.current.value = '';
|
|
149
145
|
}
|
|
@@ -157,9 +153,8 @@ export const FieldDate = forwardRef<HTMLInputElement, FieldDateProps>(
|
|
|
157
153
|
}
|
|
158
154
|
}, [onChange, required, setIsOpen]);
|
|
159
155
|
|
|
160
|
-
const valueToCopy = (mode === 'date' ? valueProp?.toLocaleDateString() : valueProp?.toLocaleString()) ?? '';
|
|
161
156
|
const clearButtonSettings = useClearButton({ clearButtonRef, showClearButton, size, onClear: handleClear });
|
|
162
|
-
const copyButtonSettings = useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy });
|
|
157
|
+
const copyButtonSettings = useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy: valueProp || '' });
|
|
163
158
|
const calendarIcon: ButtonProps = useMemo(
|
|
164
159
|
() => ({
|
|
165
160
|
active: false,
|
|
@@ -191,13 +186,9 @@ export const FieldDate = forwardRef<HTMLInputElement, FieldDateProps>(
|
|
|
191
186
|
readonly,
|
|
192
187
|
locale,
|
|
193
188
|
setIsOpen,
|
|
194
|
-
mode,
|
|
195
189
|
});
|
|
196
190
|
|
|
197
|
-
const setInputFocusFromButtons = useCallback(
|
|
198
|
-
() => setInputFocus(mode === 'date' ? SlotKey.Year : SlotKey.Seconds),
|
|
199
|
-
[mode, setInputFocus],
|
|
200
|
-
);
|
|
191
|
+
const setInputFocusFromButtons = useCallback(() => setInputFocus(SlotKey.Year), [setInputFocus]);
|
|
201
192
|
|
|
202
193
|
const {
|
|
203
194
|
postfixButtons,
|
|
@@ -213,15 +204,11 @@ export const FieldDate = forwardRef<HTMLInputElement, FieldDateProps>(
|
|
|
213
204
|
submitKeys: ['Enter', 'Space', 'Tab'],
|
|
214
205
|
});
|
|
215
206
|
|
|
207
|
+
// TODO: do not hardcode locale here
|
|
216
208
|
const handleSelectDate = (date: Date) => {
|
|
217
|
-
onChange && onChange(date);
|
|
209
|
+
onChange && onChange(date.toLocaleDateString(DEFAULT_LOCALE));
|
|
218
210
|
localRef.current?.focus();
|
|
219
211
|
setIsOpen(false);
|
|
220
|
-
|
|
221
|
-
if (localRef.current) {
|
|
222
|
-
localRef.current.value =
|
|
223
|
-
mode === 'date' ? date.toLocaleDateString(DEFAULT_LOCALE) : date.toLocaleString(DEFAULT_LOCALE);
|
|
224
|
-
}
|
|
225
212
|
};
|
|
226
213
|
|
|
227
214
|
const handleCalendarFocusLeave: CalendarProps['onFocusLeave'] = () => {
|
|
@@ -246,6 +233,12 @@ export const FieldDate = forwardRef<HTMLInputElement, FieldDateProps>(
|
|
|
246
233
|
}
|
|
247
234
|
}, [open]);
|
|
248
235
|
|
|
236
|
+
useEffect(() => {
|
|
237
|
+
if (localRef.current) {
|
|
238
|
+
localRef.current.value = valueProp;
|
|
239
|
+
}
|
|
240
|
+
}, [valueProp]);
|
|
241
|
+
|
|
249
242
|
const onFocusByKeyboard = useCallback(
|
|
250
243
|
(e: FocusEvent<HTMLInputElement>) => {
|
|
251
244
|
setInputFocus();
|
|
@@ -303,9 +296,9 @@ export const FieldDate = forwardRef<HTMLInputElement, FieldDateProps>(
|
|
|
303
296
|
content={
|
|
304
297
|
<div className={styles.calendarWrapper} data-size={size}>
|
|
305
298
|
<Calendar
|
|
306
|
-
mode=
|
|
299
|
+
mode='date'
|
|
307
300
|
size={CALENDAR_SIZE_MAP[size]}
|
|
308
|
-
value={valueProp}
|
|
301
|
+
value={valueProp ? parseDate(valueProp) : undefined}
|
|
309
302
|
onChangeValue={handleSelectDate}
|
|
310
303
|
buildCellProps={buildCellProps}
|
|
311
304
|
navigationStartRef={element => {
|
|
@@ -317,7 +310,6 @@ export const FieldDate = forwardRef<HTMLInputElement, FieldDateProps>(
|
|
|
317
310
|
onFocusLeave={handleCalendarFocusLeave}
|
|
318
311
|
locale={locale}
|
|
319
312
|
data-test-id='field-date__calendar'
|
|
320
|
-
fitToContainer={false}
|
|
321
313
|
/>
|
|
322
314
|
</div>
|
|
323
315
|
}
|
|
@@ -1,77 +1,33 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Slot } from './types';
|
|
2
2
|
|
|
3
3
|
export enum SlotKey {
|
|
4
4
|
Day = 'D',
|
|
5
5
|
Month = 'M',
|
|
6
6
|
Year = 'Y',
|
|
7
|
-
Hours = 'h',
|
|
8
|
-
Minutes = 'm',
|
|
9
|
-
Seconds = 's',
|
|
10
7
|
}
|
|
11
8
|
|
|
12
|
-
export const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} as const;
|
|
16
|
-
|
|
17
|
-
export const MASK: Record<Mode, Record<string, string>> = {
|
|
18
|
-
[MODES.Date]: {
|
|
19
|
-
'ru-RU': 'ДД.ММ.ГГГГ',
|
|
20
|
-
'en-US': 'DD.MM.YYYY',
|
|
21
|
-
},
|
|
22
|
-
[MODES.DateTime]: {
|
|
23
|
-
'ru-RU': 'ДД.ММ.ГГГГ, чч:мм:сс',
|
|
24
|
-
'en-US': 'DD.MM.YYYY, hh:mm:ss',
|
|
25
|
-
},
|
|
9
|
+
export const MASK: Record<string, string> = {
|
|
10
|
+
'ru-RU': 'ДД.ММ.ГГГГ',
|
|
11
|
+
'en-US': 'DD.MM.YYYY',
|
|
26
12
|
};
|
|
27
13
|
|
|
28
14
|
export const DEFAULT_LOCALE = new Intl.Locale('ru-RU');
|
|
29
15
|
|
|
30
|
-
const
|
|
16
|
+
export const SLOTS: Record<SlotKey | string, Slot> = {
|
|
31
17
|
[SlotKey.Day]: { start: 0, end: 2, max: 31, min: 1 },
|
|
32
18
|
[SlotKey.Month]: { start: 3, end: 5, max: 12, min: 1 },
|
|
33
19
|
[SlotKey.Year]: { start: 6, end: 10, max: 2100, min: 1900 },
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const SLOTS: Record<Mode, Record<SlotKey | string, Slot>> = {
|
|
37
|
-
[MODES.Date]: DATE_SLOTS,
|
|
38
|
-
[MODES.DateTime]: {
|
|
39
|
-
...DATE_SLOTS,
|
|
40
|
-
[SlotKey.Hours]: { start: 12, end: 14, max: 23, min: 0 },
|
|
41
|
-
[SlotKey.Minutes]: { start: 15, end: 17, max: 59, min: 0 },
|
|
42
|
-
[SlotKey.Seconds]: { start: 18, end: 20, max: 59, min: 0 },
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const RU_DATE_SLOTS_PLACEHOLDER = {
|
|
47
|
-
[SlotKey.Day]: 'ДД',
|
|
48
|
-
[SlotKey.Month]: 'ММ',
|
|
49
|
-
[SlotKey.Year]: 'ГГГГ',
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const EN_DATE_SLOTS_PLACEHOLDER = {
|
|
53
|
-
[SlotKey.Day]: 'DD',
|
|
54
|
-
[SlotKey.Month]: 'MM',
|
|
55
|
-
[SlotKey.Year]: 'YYYY',
|
|
56
|
-
};
|
|
20
|
+
} as const;
|
|
57
21
|
|
|
58
|
-
export const SLOTS_PLACEHOLDER: Record<
|
|
59
|
-
|
|
60
|
-
'
|
|
61
|
-
'
|
|
22
|
+
export const SLOTS_PLACEHOLDER: Record<string, Record<string, string>> = {
|
|
23
|
+
'ru-RU': {
|
|
24
|
+
[SlotKey.Day]: 'ДД',
|
|
25
|
+
[SlotKey.Month]: 'ММ',
|
|
26
|
+
[SlotKey.Year]: 'ГГГГ',
|
|
62
27
|
},
|
|
63
|
-
|
|
64
|
-
'
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
[SlotKey.Minutes]: 'мм',
|
|
68
|
-
[SlotKey.Seconds]: 'сс',
|
|
69
|
-
},
|
|
70
|
-
'en-US': {
|
|
71
|
-
...EN_DATE_SLOTS_PLACEHOLDER,
|
|
72
|
-
[SlotKey.Hours]: 'hh',
|
|
73
|
-
[SlotKey.Minutes]: 'mm',
|
|
74
|
-
[SlotKey.Seconds]: 'ss',
|
|
75
|
-
},
|
|
28
|
+
'en-US': {
|
|
29
|
+
[SlotKey.Day]: 'DD',
|
|
30
|
+
[SlotKey.Month]: 'MM',
|
|
31
|
+
[SlotKey.Year]: 'YYYY',
|
|
76
32
|
},
|
|
77
33
|
};
|
|
@@ -3,48 +3,29 @@ import { ChangeEvent, FocusEventHandler, KeyboardEvent, RefObject, useCallback,
|
|
|
3
3
|
import { isBrowser } from '@snack-uikit/utils';
|
|
4
4
|
|
|
5
5
|
import { DEFAULT_LOCALE, MASK, SlotKey, SLOTS, SLOTS_PLACEHOLDER } from '../constants';
|
|
6
|
-
import {
|
|
7
|
-
import { getNextSlotKey, getPrevSlotKey, getSlotKey, parseDate } from '../utils';
|
|
6
|
+
import { getNextSlotKey, getPrevSlotKey, getSlotKey } from '../utils';
|
|
8
7
|
import { useDateFieldHelpers } from './useDateFieldHelpers';
|
|
9
|
-
import { useDateTimeFieldHelpers } from './useDateTimeFieldHelpers';
|
|
10
8
|
|
|
11
9
|
type UseDateFieldProps = {
|
|
12
10
|
inputRef: RefObject<HTMLInputElement>;
|
|
13
|
-
onChange?(value:
|
|
11
|
+
onChange?(value: string): void;
|
|
14
12
|
readonly?: boolean;
|
|
15
13
|
locale?: Intl.Locale;
|
|
16
14
|
setIsOpen(v: boolean): void;
|
|
17
|
-
mode: Mode;
|
|
18
15
|
};
|
|
19
16
|
|
|
20
|
-
type FocusSlot = SlotKey.Day | SlotKey.Year |
|
|
21
|
-
|
|
22
|
-
export function useDateField({
|
|
23
|
-
inputRef,
|
|
24
|
-
onChange,
|
|
25
|
-
readonly,
|
|
26
|
-
locale = DEFAULT_LOCALE,
|
|
27
|
-
setIsOpen,
|
|
28
|
-
mode,
|
|
29
|
-
}: UseDateFieldProps) {
|
|
30
|
-
const dateHelpers = useDateFieldHelpers(inputRef);
|
|
31
|
-
const dateTimeHelpers = useDateTimeFieldHelpers(inputRef);
|
|
32
|
-
|
|
33
|
-
const { setFocus, updateSlot, getSlot, isLikeDate, isAllSelected, tryToCompleteInput, isValidInput } =
|
|
34
|
-
mode === 'date' ? dateHelpers : dateTimeHelpers;
|
|
17
|
+
type FocusSlot = SlotKey.Day | SlotKey.Year | 'auto';
|
|
35
18
|
|
|
19
|
+
export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LOCALE, setIsOpen }: UseDateFieldProps) {
|
|
20
|
+
const { setFocus, updateSlot, getSlot, isLikeDate, isAllSelected, isValidInput, tryToCompleteInput } =
|
|
21
|
+
useDateFieldHelpers(inputRef);
|
|
36
22
|
const focusSlotRef = useRef<FocusSlot>(SlotKey.Day);
|
|
37
23
|
|
|
38
|
-
const mask = useMemo(
|
|
39
|
-
() => MASK[mode][locale.baseName] || MASK[mode][DEFAULT_LOCALE.baseName],
|
|
40
|
-
[locale.baseName, mode],
|
|
41
|
-
);
|
|
42
|
-
const getNextSlotKeyHandler = getNextSlotKey(mode);
|
|
43
|
-
const getPrevSlotKeyHandler = getPrevSlotKey(mode);
|
|
24
|
+
const mask = useMemo(() => MASK[locale.baseName] || MASK[DEFAULT_LOCALE.baseName], [locale]);
|
|
44
25
|
|
|
45
|
-
const
|
|
46
|
-
() => SLOTS_PLACEHOLDER[
|
|
47
|
-
[locale.baseName
|
|
26
|
+
const slotsPlaceHolder = useMemo(
|
|
27
|
+
() => SLOTS_PLACEHOLDER[locale.baseName] || SLOTS_PLACEHOLDER[DEFAULT_LOCALE.baseName],
|
|
28
|
+
[locale.baseName],
|
|
48
29
|
);
|
|
49
30
|
|
|
50
31
|
const setInputFocus = useCallback(
|
|
@@ -76,14 +57,14 @@ export function useDateField({
|
|
|
76
57
|
return;
|
|
77
58
|
}
|
|
78
59
|
|
|
79
|
-
const slotKey = getSlotKey(inputRef.current.selectionStart
|
|
60
|
+
const slotKey = getSlotKey(inputRef.current.selectionStart);
|
|
80
61
|
|
|
81
62
|
if (slotKey) {
|
|
82
|
-
const { start, end } = SLOTS[
|
|
63
|
+
const { start, end } = SLOTS[slotKey];
|
|
83
64
|
inputRef.current.setSelectionRange(start, end);
|
|
84
65
|
}
|
|
85
66
|
},
|
|
86
|
-
[inputRef, isLikeDate, mask,
|
|
67
|
+
[inputRef, isLikeDate, mask, readonly, setFocus],
|
|
87
68
|
);
|
|
88
69
|
|
|
89
70
|
const handleClick = useCallback(() => {
|
|
@@ -91,35 +72,35 @@ export function useDateField({
|
|
|
91
72
|
}, [setInputFocus]);
|
|
92
73
|
|
|
93
74
|
const handleChange: (value: string, e?: ChangeEvent<HTMLInputElement> | undefined) => void = () => {
|
|
94
|
-
onChange && isLikeDate() && onChange(
|
|
75
|
+
onChange && isLikeDate() && onChange(inputRef.current?.value || '');
|
|
95
76
|
};
|
|
96
77
|
|
|
97
78
|
const checkInputAndGoNext = useCallback(
|
|
98
79
|
(slotKey: string) => {
|
|
99
|
-
if (slotKey ===
|
|
80
|
+
if (slotKey === SlotKey.Year && tryToCompleteInput()) {
|
|
100
81
|
return;
|
|
101
82
|
}
|
|
102
83
|
|
|
103
84
|
if (isValidInput()) {
|
|
104
|
-
setFocus(
|
|
85
|
+
setFocus(getNextSlotKey(slotKey));
|
|
105
86
|
return;
|
|
106
87
|
}
|
|
107
88
|
|
|
108
89
|
switch (slotKey) {
|
|
109
90
|
case SlotKey.Day:
|
|
110
|
-
updateSlot(SlotKey.Month,
|
|
91
|
+
updateSlot(SlotKey.Month, slotsPlaceHolder[SlotKey.Month]);
|
|
111
92
|
setFocus(SlotKey.Month);
|
|
112
93
|
return;
|
|
113
94
|
case SlotKey.Year:
|
|
114
95
|
case SlotKey.Month:
|
|
115
|
-
updateSlot(SlotKey.Day,
|
|
96
|
+
updateSlot(SlotKey.Day, slotsPlaceHolder[SlotKey.Day]);
|
|
116
97
|
setFocus(SlotKey.Day);
|
|
117
98
|
return;
|
|
118
99
|
default:
|
|
119
|
-
setFocus(
|
|
100
|
+
setFocus(getNextSlotKey(slotKey));
|
|
120
101
|
}
|
|
121
102
|
},
|
|
122
|
-
[
|
|
103
|
+
[tryToCompleteInput, isValidInput, setFocus, slotsPlaceHolder, updateSlot],
|
|
123
104
|
);
|
|
124
105
|
|
|
125
106
|
const handleKeyDown = useCallback(
|
|
@@ -144,25 +125,25 @@ export function useDateField({
|
|
|
144
125
|
}
|
|
145
126
|
|
|
146
127
|
const clickIndex = inputRef.current.selectionStart;
|
|
147
|
-
const slotKey = getSlotKey(clickIndex
|
|
128
|
+
const slotKey = getSlotKey(clickIndex);
|
|
148
129
|
|
|
149
130
|
if (slotKey) {
|
|
150
131
|
const value = getSlot(slotKey);
|
|
151
|
-
const { max } = SLOTS[
|
|
132
|
+
const { max } = SLOTS[slotKey];
|
|
152
133
|
|
|
153
134
|
const numberValue = Number(value) || 0;
|
|
154
135
|
|
|
155
136
|
if (e.key === 'ArrowRight') {
|
|
156
|
-
if (isAllSelected() || slotKey ===
|
|
137
|
+
if (isAllSelected() || slotKey === SlotKey.Year) {
|
|
157
138
|
inputRef.current.selectionStart = inputRef.current.value.length;
|
|
158
139
|
return;
|
|
159
140
|
}
|
|
160
|
-
setFocus(
|
|
141
|
+
setFocus(getNextSlotKey(slotKey));
|
|
161
142
|
return;
|
|
162
143
|
}
|
|
163
144
|
|
|
164
145
|
if (e.key === 'ArrowLeft') {
|
|
165
|
-
setFocus(
|
|
146
|
+
setFocus(getPrevSlotKey(slotKey));
|
|
166
147
|
return;
|
|
167
148
|
}
|
|
168
149
|
|
|
@@ -171,7 +152,7 @@ export function useDateField({
|
|
|
171
152
|
inputRef.current.value = mask;
|
|
172
153
|
setFocus(SlotKey.Day);
|
|
173
154
|
} else {
|
|
174
|
-
updateSlot(slotKey,
|
|
155
|
+
updateSlot(slotKey, slotsPlaceHolder[slotKey]);
|
|
175
156
|
}
|
|
176
157
|
}
|
|
177
158
|
|
|
@@ -208,26 +189,22 @@ export function useDateField({
|
|
|
208
189
|
}
|
|
209
190
|
}
|
|
210
191
|
}
|
|
211
|
-
|
|
212
|
-
onChange?.(newDate);
|
|
192
|
+
onChange?.(isLikeDate() ? inputRef.current.value : '');
|
|
213
193
|
}
|
|
214
194
|
}
|
|
215
195
|
},
|
|
216
196
|
[
|
|
217
197
|
checkInputAndGoNext,
|
|
218
|
-
getNextSlotKeyHandler,
|
|
219
|
-
getPrevSlotKeyHandler,
|
|
220
198
|
getSlot,
|
|
221
199
|
inputRef,
|
|
222
200
|
isAllSelected,
|
|
223
201
|
isLikeDate,
|
|
224
202
|
mask,
|
|
225
|
-
mode,
|
|
226
203
|
onChange,
|
|
227
204
|
readonly,
|
|
228
205
|
setFocus,
|
|
229
206
|
setIsOpen,
|
|
230
|
-
|
|
207
|
+
slotsPlaceHolder,
|
|
231
208
|
tryToCompleteInput,
|
|
232
209
|
updateSlot,
|
|
233
210
|
],
|
|
@@ -6,7 +6,7 @@ export function useDateFieldHelpers(inputRef: RefObject<HTMLInputElement>) {
|
|
|
6
6
|
const setFocus = useCallback(
|
|
7
7
|
(slotKey: string) => {
|
|
8
8
|
if (inputRef.current) {
|
|
9
|
-
const { start, end } = SLOTS
|
|
9
|
+
const { start, end } = SLOTS[slotKey];
|
|
10
10
|
|
|
11
11
|
inputRef.current.setSelectionRange(start, end);
|
|
12
12
|
}
|
|
@@ -22,7 +22,7 @@ export function useDateFieldHelpers(inputRef: RefObject<HTMLInputElement>) {
|
|
|
22
22
|
const getSlot = useCallback(
|
|
23
23
|
(slotKey: string) => {
|
|
24
24
|
if (inputRef.current) {
|
|
25
|
-
return inputRef.current.value.slice(SLOTS
|
|
25
|
+
return inputRef.current.value.slice(SLOTS[slotKey].start, SLOTS[slotKey].end);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
return '';
|
|
@@ -32,7 +32,7 @@ export function useDateFieldHelpers(inputRef: RefObject<HTMLInputElement>) {
|
|
|
32
32
|
|
|
33
33
|
const isLikeDate = useCallback(() => {
|
|
34
34
|
if (inputRef.current) {
|
|
35
|
-
return Object.keys(SLOTS
|
|
35
|
+
return Object.keys(SLOTS).every(slotKey => getSlot(slotKey) && Number.isInteger(Number(getSlot(slotKey))));
|
|
36
36
|
}
|
|
37
37
|
return false;
|
|
38
38
|
}, [getSlot, inputRef]);
|
|
@@ -56,7 +56,7 @@ export function useDateFieldHelpers(inputRef: RefObject<HTMLInputElement>) {
|
|
|
56
56
|
const month = parseInt(getSlot(SlotKey.Month), 10);
|
|
57
57
|
const year = parseInt(getSlot(SlotKey.Year), 10);
|
|
58
58
|
|
|
59
|
-
const { min, max } = SLOTS
|
|
59
|
+
const { min, max } = SLOTS[SlotKey.Year];
|
|
60
60
|
|
|
61
61
|
const isCompleted = Boolean(day && month && year >= min && year <= max);
|
|
62
62
|
|
|
@@ -72,7 +72,7 @@ export function useDateFieldHelpers(inputRef: RefObject<HTMLInputElement>) {
|
|
|
72
72
|
const updateSlot = useCallback(
|
|
73
73
|
(slotKey: string, slotValue: number | string) => {
|
|
74
74
|
if (inputRef.current) {
|
|
75
|
-
const { start, end, max } = SLOTS
|
|
75
|
+
const { start, end, max } = SLOTS[slotKey];
|
|
76
76
|
|
|
77
77
|
inputRef.current.value =
|
|
78
78
|
inputRef.current.value.slice(0, start) +
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { SlotKey, SLOTS } from './constants';
|
|
2
|
-
import { Mode } from './types';
|
|
3
2
|
|
|
4
|
-
export function getSlotKey(index: number | null
|
|
3
|
+
export function getSlotKey(index: number | null) {
|
|
5
4
|
if (index !== null) {
|
|
6
|
-
for (const key in SLOTS
|
|
7
|
-
if (index >= SLOTS[
|
|
8
|
-
return key
|
|
5
|
+
for (const key in SLOTS) {
|
|
6
|
+
if (index >= SLOTS[key].start && index <= SLOTS[key].end) {
|
|
7
|
+
return key;
|
|
9
8
|
}
|
|
10
9
|
}
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
return null;
|
|
14
13
|
}
|
|
15
|
-
|
|
14
|
+
|
|
15
|
+
export function getNextSlotKey(slotKey: string | null) {
|
|
16
16
|
switch (slotKey) {
|
|
17
17
|
case SlotKey.Day: {
|
|
18
18
|
return SlotKey.Month;
|
|
@@ -25,7 +25,7 @@ export function getNextSlotKeyWithDate(slotKey: string | null) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export function
|
|
28
|
+
export function getPrevSlotKey(slotKey: string | null) {
|
|
29
29
|
switch (slotKey) {
|
|
30
30
|
case SlotKey.Year: {
|
|
31
31
|
return SlotKey.Month;
|
|
@@ -38,82 +38,12 @@ export function getPrevSlotKeyWithDate(slotKey: string | null) {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
export function getNextSlotKeyWithTime(slotKey: string | null) {
|
|
42
|
-
switch (slotKey) {
|
|
43
|
-
case SlotKey.Day: {
|
|
44
|
-
return SlotKey.Month;
|
|
45
|
-
}
|
|
46
|
-
case SlotKey.Month: {
|
|
47
|
-
return SlotKey.Year;
|
|
48
|
-
}
|
|
49
|
-
case SlotKey.Year: {
|
|
50
|
-
return SlotKey.Hours;
|
|
51
|
-
}
|
|
52
|
-
case SlotKey.Hours: {
|
|
53
|
-
return SlotKey.Minutes;
|
|
54
|
-
}
|
|
55
|
-
case SlotKey.Minutes:
|
|
56
|
-
case SlotKey.Seconds:
|
|
57
|
-
default: {
|
|
58
|
-
return SlotKey.Seconds;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function getPrevSlotKeyWithTime(slotKey: string | null) {
|
|
64
|
-
switch (slotKey) {
|
|
65
|
-
case SlotKey.Seconds: {
|
|
66
|
-
return SlotKey.Minutes;
|
|
67
|
-
}
|
|
68
|
-
case SlotKey.Minutes: {
|
|
69
|
-
return SlotKey.Hours;
|
|
70
|
-
}
|
|
71
|
-
case SlotKey.Hours: {
|
|
72
|
-
return SlotKey.Year;
|
|
73
|
-
}
|
|
74
|
-
case SlotKey.Year: {
|
|
75
|
-
return SlotKey.Month;
|
|
76
|
-
}
|
|
77
|
-
case SlotKey.Month:
|
|
78
|
-
case SlotKey.Day:
|
|
79
|
-
default: {
|
|
80
|
-
return SlotKey.Day;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function getNextSlotKey(mode: Mode) {
|
|
86
|
-
return mode === 'date' ? getNextSlotKeyWithDate : getNextSlotKeyWithTime;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function getPrevSlotKey(mode: Mode) {
|
|
90
|
-
return mode === 'date' ? getPrevSlotKeyWithDate : getPrevSlotKeyWithTime;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
41
|
/**
|
|
94
42
|
* Преобразует строковое значение поля FieldDate в тип Date
|
|
95
43
|
* @function helper
|
|
96
44
|
*/
|
|
97
45
|
|
|
98
|
-
export function parseDate(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const [date, time] = value.split(', ');
|
|
104
|
-
const dateValues = date.split('.');
|
|
105
|
-
const year = Number(dateValues[2]);
|
|
106
|
-
const month = Number(dateValues[1]) - 1;
|
|
107
|
-
const day = Number(dateValues[0]);
|
|
108
|
-
|
|
109
|
-
if (time) {
|
|
110
|
-
const timeValues = time.split(':');
|
|
111
|
-
const hours = timeValues[0] ? Number(timeValues[0]) : undefined;
|
|
112
|
-
const minutes = timeValues[1] ? Number(timeValues[1]) : undefined;
|
|
113
|
-
const seconds = timeValues[2] ? Number(timeValues[2]) : undefined;
|
|
114
|
-
|
|
115
|
-
return new Date(year, month, day, hours, minutes, seconds);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return new Date(year, month, day);
|
|
46
|
+
export function parseDate(date: string) {
|
|
47
|
+
const values = date.split('.');
|
|
48
|
+
return new Date(Number(values[2]), Number(values[1]) - 1, Number(values[0]));
|
|
119
49
|
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { RefObject } from 'react';
|
|
2
|
-
export declare function useDateTimeFieldHelpers(inputRef: RefObject<HTMLInputElement>): {
|
|
3
|
-
isAllSelected: () => boolean;
|
|
4
|
-
tryToCompleteInput: () => boolean;
|
|
5
|
-
getSlot: (slotKey: string) => string;
|
|
6
|
-
updateSlot: (slotKey: string, slotValue: number | string) => void;
|
|
7
|
-
setFocus: (slotKey: string) => void;
|
|
8
|
-
isLikeDate: () => boolean;
|
|
9
|
-
isValidInput: () => boolean;
|
|
10
|
-
};
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
|
-
import { SlotKey, SLOTS } from '../constants';
|
|
3
|
-
export function useDateTimeFieldHelpers(inputRef) {
|
|
4
|
-
const setFocus = useCallback((slotKey) => {
|
|
5
|
-
if (inputRef.current) {
|
|
6
|
-
const { start, end } = SLOTS['date-time'][slotKey];
|
|
7
|
-
inputRef.current.setSelectionRange(start, end);
|
|
8
|
-
}
|
|
9
|
-
}, [inputRef]);
|
|
10
|
-
const isAllSelected = useCallback(() => { var _a, _b, _c; return ((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.value.length) === ((_b = inputRef.current) === null || _b === void 0 ? void 0 : _b.selectionEnd) && ((_c = inputRef.current) === null || _c === void 0 ? void 0 : _c.selectionStart) === 0; }, [inputRef]);
|
|
11
|
-
const getSlot = useCallback((slotKey) => {
|
|
12
|
-
if (inputRef.current) {
|
|
13
|
-
return inputRef.current.value.slice(SLOTS['date-time'][slotKey].start, SLOTS['date-time'][slotKey].end);
|
|
14
|
-
}
|
|
15
|
-
return '';
|
|
16
|
-
}, [inputRef]);
|
|
17
|
-
const isLikeDate = useCallback(() => {
|
|
18
|
-
if (inputRef.current) {
|
|
19
|
-
return Object.keys(SLOTS['date-time']).every(slotKey => getSlot(slotKey) && Number.isInteger(Number(getSlot(slotKey))));
|
|
20
|
-
}
|
|
21
|
-
return false;
|
|
22
|
-
}, [getSlot, inputRef]);
|
|
23
|
-
const isValidInput = useCallback(() => {
|
|
24
|
-
const day = parseInt(getSlot(SlotKey.Day), 10);
|
|
25
|
-
const month = parseInt(getSlot(SlotKey.Month), 10);
|
|
26
|
-
const year = parseInt(getSlot(SlotKey.Year), 10);
|
|
27
|
-
if (!month || !day) {
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
const date = new Date(year || /* високосный год = */ 2020, month - 1, day);
|
|
31
|
-
return date.getDate() === day;
|
|
32
|
-
}, [getSlot]);
|
|
33
|
-
const tryToCompleteInput = useCallback(() => {
|
|
34
|
-
var _a;
|
|
35
|
-
const day = parseInt(getSlot(SlotKey.Day), 10);
|
|
36
|
-
const month = parseInt(getSlot(SlotKey.Month), 10);
|
|
37
|
-
const year = parseInt(getSlot(SlotKey.Year), 10);
|
|
38
|
-
const hours = parseInt(getSlot(SlotKey.Hours), 10);
|
|
39
|
-
const minutes = parseInt(getSlot(SlotKey.Minutes), 10);
|
|
40
|
-
const seconds = parseInt(getSlot(SlotKey.Seconds), 10);
|
|
41
|
-
const { min, max } = SLOTS['date-time'][SlotKey.Year];
|
|
42
|
-
const isCompleted = Boolean(day &&
|
|
43
|
-
month &&
|
|
44
|
-
year >= min &&
|
|
45
|
-
year <= max &&
|
|
46
|
-
hours !== undefined &&
|
|
47
|
-
minutes !== undefined &&
|
|
48
|
-
seconds !== undefined);
|
|
49
|
-
if (isCompleted && inputRef.current) {
|
|
50
|
-
const lastPosition = (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.value.length;
|
|
51
|
-
inputRef.current.selectionStart = lastPosition;
|
|
52
|
-
inputRef.current.selectionEnd = lastPosition;
|
|
53
|
-
}
|
|
54
|
-
return isCompleted;
|
|
55
|
-
}, [getSlot, inputRef]);
|
|
56
|
-
const updateSlot = useCallback((slotKey, slotValue) => {
|
|
57
|
-
if (inputRef.current) {
|
|
58
|
-
const { start, end, max } = SLOTS['date-time'][slotKey];
|
|
59
|
-
inputRef.current.value =
|
|
60
|
-
inputRef.current.value.slice(0, start) +
|
|
61
|
-
slotValue.toString().padStart(max.toString().length, '0') +
|
|
62
|
-
inputRef.current.value.slice(end);
|
|
63
|
-
setFocus(slotKey);
|
|
64
|
-
}
|
|
65
|
-
}, [inputRef, setFocus]);
|
|
66
|
-
return {
|
|
67
|
-
isAllSelected,
|
|
68
|
-
tryToCompleteInput,
|
|
69
|
-
getSlot,
|
|
70
|
-
updateSlot,
|
|
71
|
-
setFocus,
|
|
72
|
-
isLikeDate,
|
|
73
|
-
isValidInput,
|
|
74
|
-
};
|
|
75
|
-
}
|