@snack-uikit/fields 0.30.0 → 0.32.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/CHANGELOG.md +33 -0
- package/README.md +184 -152
- package/dist/cjs/components/FieldDate/FieldDate.d.ts +15 -24
- package/dist/cjs/components/FieldDate/FieldDate.js +53 -41
- package/dist/cjs/components/FieldDate/index.d.ts +0 -1
- package/dist/cjs/components/FieldDate/index.js +1 -9
- package/dist/cjs/components/FieldSecure/FieldSecure.d.ts +1 -1
- package/dist/cjs/components/FieldSelect/hooks.d.ts +2 -2
- package/dist/cjs/components/FieldSelect/hooks.js +7 -3
- package/dist/cjs/components/FieldSelect/styles.module.css +6 -18
- package/dist/cjs/components/FieldSlider/FieldSlider.d.ts +1 -1
- package/dist/cjs/components/FieldText/FieldText.d.ts +1 -1
- package/dist/cjs/components/FieldTextArea/FieldTextArea.d.ts +1 -1
- package/dist/cjs/components/FieldTime/FieldTime.d.ts +30 -0
- package/dist/cjs/components/FieldTime/FieldTime.js +298 -0
- package/dist/cjs/components/FieldTime/index.d.ts +1 -0
- package/dist/cjs/components/{FieldDate/hooks → FieldTime}/index.js +1 -1
- package/dist/cjs/components/FieldTime/styles.module.css +27 -0
- package/dist/cjs/components/index.d.ts +6 -5
- package/dist/cjs/components/index.js +6 -5
- package/dist/cjs/constants/dateFields.d.ts +24 -0
- package/dist/cjs/constants/dateFields.js +152 -0
- package/dist/cjs/constants/index.d.ts +2 -0
- package/dist/cjs/constants/index.js +26 -0
- package/dist/cjs/hooks/dateHandlers/index.d.ts +3 -0
- package/dist/cjs/hooks/dateHandlers/index.js +27 -0
- package/dist/cjs/{components/FieldDate/hooks → hooks/dateHandlers}/useDateField.d.ts +13 -5
- package/dist/cjs/{components/FieldDate/hooks → hooks/dateHandlers}/useDateField.js +49 -34
- package/dist/cjs/hooks/dateHandlers/useDateFieldHelpersForMode.d.ts +18 -0
- package/dist/cjs/hooks/dateHandlers/useDateFieldHelpersForMode.js +113 -0
- package/dist/cjs/hooks/index.d.ts +1 -0
- package/dist/cjs/hooks/index.js +1 -0
- package/dist/cjs/hooks/useCopyButton.js +1 -1
- package/dist/cjs/{types.d.ts → types/allFields.d.ts} +1 -1
- package/dist/cjs/types/dateFields.d.ts +11 -0
- package/dist/cjs/types/index.d.ts +2 -0
- package/dist/cjs/types/index.js +26 -0
- package/dist/cjs/utils/dateFields.d.ts +10 -0
- package/dist/cjs/utils/dateFields.js +71 -0
- package/dist/esm/components/FieldDate/FieldDate.d.ts +15 -24
- package/dist/esm/components/FieldDate/FieldDate.js +39 -31
- package/dist/esm/components/FieldDate/index.d.ts +0 -1
- package/dist/esm/components/FieldDate/index.js +0 -1
- package/dist/esm/components/FieldSecure/FieldSecure.d.ts +1 -1
- package/dist/esm/components/FieldSelect/hooks.d.ts +2 -2
- package/dist/esm/components/FieldSelect/hooks.js +9 -3
- package/dist/esm/components/FieldSelect/styles.module.css +6 -18
- package/dist/esm/components/FieldSlider/FieldSlider.d.ts +1 -1
- package/dist/esm/components/FieldText/FieldText.d.ts +1 -1
- package/dist/esm/components/FieldTextArea/FieldTextArea.d.ts +1 -1
- package/dist/esm/components/FieldTime/FieldTime.d.ts +30 -0
- package/dist/esm/components/FieldTime/FieldTime.js +161 -0
- package/dist/esm/components/FieldTime/index.d.ts +1 -0
- package/dist/esm/components/FieldTime/index.js +1 -0
- package/dist/esm/components/FieldTime/styles.module.css +27 -0
- package/dist/esm/components/index.d.ts +6 -5
- package/dist/esm/components/index.js +6 -5
- package/dist/esm/constants/dateFields.d.ts +24 -0
- package/dist/esm/constants/dateFields.js +103 -0
- package/dist/esm/constants/index.d.ts +2 -0
- package/dist/esm/constants/index.js +2 -0
- package/dist/esm/hooks/dateHandlers/index.d.ts +3 -0
- package/dist/esm/hooks/dateHandlers/index.js +3 -0
- package/dist/esm/{components/FieldDate/hooks → hooks/dateHandlers}/useDateField.d.ts +13 -5
- package/dist/esm/{components/FieldDate/hooks → hooks/dateHandlers}/useDateField.js +48 -35
- package/dist/esm/hooks/dateHandlers/useDateFieldHelpersForMode.d.ts +18 -0
- package/dist/esm/hooks/dateHandlers/useDateFieldHelpersForMode.js +95 -0
- package/dist/esm/hooks/index.d.ts +1 -0
- package/dist/esm/hooks/index.js +1 -0
- package/dist/esm/hooks/useCopyButton.js +1 -1
- package/dist/esm/{types.d.ts → types/allFields.d.ts} +1 -1
- package/dist/esm/types/dateFields.d.ts +11 -0
- package/dist/esm/types/index.d.ts +2 -0
- package/dist/esm/types/index.js +2 -0
- package/dist/esm/utils/dateFields.d.ts +10 -0
- package/dist/esm/utils/dateFields.js +59 -0
- package/package.json +16 -16
- package/src/components/FieldColor/styles.module.scss +9 -10
- package/src/components/FieldDate/FieldDate.tsx +72 -52
- package/src/components/FieldDate/index.ts +0 -1
- package/src/components/FieldDate/styles.module.scss +10 -11
- package/src/components/FieldDecorator/styles.module.scss +44 -45
- package/src/components/FieldSelect/hooks.ts +15 -3
- package/src/components/FieldSelect/styles.module.scss +20 -20
- package/src/components/FieldSlider/styles.module.scss +4 -4
- package/src/components/FieldTextArea/styles.module.scss +18 -18
- package/src/components/FieldTime/FieldTime.tsx +350 -0
- package/src/components/FieldTime/index.ts +1 -0
- package/src/components/FieldTime/styles.module.scss +41 -0
- package/src/components/index.ts +6 -5
- package/src/constants/dateFields.ts +127 -0
- package/src/constants/index.ts +2 -0
- package/src/helperComponents/ButtonCopyValue/styles.module.scss +2 -2
- package/src/helperComponents/ButtonField/styles.module.scss +9 -9
- package/src/helperComponents/ButtonFieldList/styles.module.scss +2 -2
- package/src/helperComponents/ButtonHideValue/styles.module.scss +2 -2
- package/src/helperComponents/FieldContainerPrivate/styles.module.scss +24 -26
- package/src/helperComponents/TextArea/styles.module.scss +5 -5
- package/src/hooks/dateHandlers/index.ts +3 -0
- package/src/{components/FieldDate/hooks → hooks/dateHandlers}/useDateField.ts +93 -47
- package/src/hooks/dateHandlers/useDateFieldHelpersForMode.ts +145 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/styles.module.scss +5 -5
- package/src/hooks/useCopyButton.tsx +1 -1
- package/src/styles.module.scss +15 -15
- package/src/{types.ts → types/allFields.ts} +1 -1
- package/src/types/dateFields.ts +14 -0
- package/src/types/index.ts +2 -0
- package/src/utils/dateFields.ts +75 -0
- package/dist/cjs/components/FieldDate/constants.d.ts +0 -10
- package/dist/cjs/components/FieldDate/constants.js +0 -49
- package/dist/cjs/components/FieldDate/hooks/index.d.ts +0 -1
- package/dist/cjs/components/FieldDate/hooks/useDateFieldHelpers.d.ts +0 -10
- package/dist/cjs/components/FieldDate/hooks/useDateFieldHelpers.js +0 -82
- package/dist/cjs/components/FieldDate/types.d.ts +0 -6
- package/dist/cjs/components/FieldDate/utils.d.ts +0 -9
- package/dist/cjs/components/FieldDate/utils.js +0 -56
- package/dist/esm/components/FieldDate/constants.d.ts +0 -10
- package/dist/esm/components/FieldDate/constants.js +0 -28
- package/dist/esm/components/FieldDate/hooks/index.d.ts +0 -1
- package/dist/esm/components/FieldDate/hooks/index.js +0 -1
- package/dist/esm/components/FieldDate/hooks/useDateFieldHelpers.d.ts +0 -10
- package/dist/esm/components/FieldDate/hooks/useDateFieldHelpers.js +0 -66
- package/dist/esm/components/FieldDate/types.d.ts +0 -6
- package/dist/esm/components/FieldDate/utils.d.ts +0 -9
- package/dist/esm/components/FieldDate/utils.js +0 -43
- package/src/components/FieldDate/constants.ts +0 -33
- package/src/components/FieldDate/hooks/index.ts +0 -1
- package/src/components/FieldDate/hooks/useDateFieldHelpers.ts +0 -96
- package/src/components/FieldDate/types.ts +0 -6
- package/src/components/FieldDate/utils.ts +0 -49
- /package/dist/cjs/{constants.d.ts → constants/allFields.d.ts} +0 -0
- /package/dist/cjs/{constants.js → constants/allFields.js} +0 -0
- /package/dist/cjs/{components/FieldDate/hooks → hooks/dateHandlers}/useFocusHandlers.d.ts +0 -0
- /package/dist/cjs/{components/FieldDate/hooks → hooks/dateHandlers}/useFocusHandlers.js +0 -0
- /package/dist/cjs/{components/FieldDate/hooks → hooks/dateHandlers}/useHandlers.d.ts +0 -0
- /package/dist/cjs/{components/FieldDate/hooks → hooks/dateHandlers}/useHandlers.js +0 -0
- /package/dist/cjs/{components/FieldDate/types.js → types/allFields.js} +0 -0
- /package/dist/cjs/{types.js → types/dateFields.js} +0 -0
- /package/dist/esm/{constants.d.ts → constants/allFields.d.ts} +0 -0
- /package/dist/esm/{constants.js → constants/allFields.js} +0 -0
- /package/dist/esm/{components/FieldDate/hooks → hooks/dateHandlers}/useFocusHandlers.d.ts +0 -0
- /package/dist/esm/{components/FieldDate/hooks → hooks/dateHandlers}/useFocusHandlers.js +0 -0
- /package/dist/esm/{components/FieldDate/hooks → hooks/dateHandlers}/useHandlers.d.ts +0 -0
- /package/dist/esm/{components/FieldDate/hooks → hooks/dateHandlers}/useHandlers.js +0 -0
- /package/dist/esm/{components/FieldDate/types.js → types/allFields.js} +0 -0
- /package/dist/esm/{types.js → types/dateFields.js} +0 -0
- /package/src/{constants.ts → constants/allFields.ts} +0 -0
- /package/src/{components/FieldDate/hooks → hooks/dateHandlers}/useFocusHandlers.ts +0 -0
- /package/src/{components/FieldDate/hooks → hooks/dateHandlers}/useHandlers.ts +0 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { RefObject, useCallback, useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { MODES, NO_SECONDS_MODE, SlotKey, SLOTS, TIME_MODES } from '../../constants';
|
|
4
|
+
import { Mode, NoSecondsMode, TimeMode } from '../../types';
|
|
5
|
+
import { getNextSlotKeyHandler, getPrevSlotKeyHandler, getSlotKeyFromIndexHandler } from '../../utils/dateFields';
|
|
6
|
+
|
|
7
|
+
export function useDateFieldHelpersForMode({
|
|
8
|
+
inputRef,
|
|
9
|
+
mode,
|
|
10
|
+
}: {
|
|
11
|
+
inputRef: RefObject<HTMLInputElement>;
|
|
12
|
+
mode: Mode | TimeMode | NoSecondsMode;
|
|
13
|
+
}) {
|
|
14
|
+
const setFocus = useCallback(
|
|
15
|
+
(slotKey: string) => {
|
|
16
|
+
if (inputRef.current) {
|
|
17
|
+
const { start, end } = SLOTS[mode][slotKey];
|
|
18
|
+
|
|
19
|
+
inputRef.current.setSelectionRange(start, end);
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
[mode, inputRef],
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const isAllSelected = useCallback(
|
|
26
|
+
() => inputRef.current?.value.length === inputRef.current?.selectionEnd && inputRef.current?.selectionStart === 0,
|
|
27
|
+
[inputRef],
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const getSlot = useCallback(
|
|
31
|
+
(slotKey: string) => {
|
|
32
|
+
if (inputRef.current) {
|
|
33
|
+
return inputRef.current.value.slice(SLOTS[mode][slotKey].start, SLOTS[mode][slotKey].end);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return '';
|
|
37
|
+
},
|
|
38
|
+
[mode, inputRef],
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const isLikeDate = useCallback(() => {
|
|
42
|
+
if (inputRef.current) {
|
|
43
|
+
return Object.keys(SLOTS[mode]).every(slotKey => getSlot(slotKey) && Number.isInteger(Number(getSlot(slotKey))));
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}, [mode, getSlot, inputRef]);
|
|
47
|
+
|
|
48
|
+
const isValidInput = useCallback((): boolean => {
|
|
49
|
+
const isTimeMode = Object.values(TIME_MODES).includes(mode as TimeMode);
|
|
50
|
+
|
|
51
|
+
if (isTimeMode) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const day = parseInt(getSlot(SlotKey.Day), 10);
|
|
56
|
+
const month = parseInt(getSlot(SlotKey.Month), 10);
|
|
57
|
+
const year = parseInt(getSlot(SlotKey.Year), 10);
|
|
58
|
+
|
|
59
|
+
if (!month || !day) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const date = new Date(year || /* високосный год = */ 2020, month - 1, day);
|
|
64
|
+
|
|
65
|
+
return date.getDate() === day;
|
|
66
|
+
}, [getSlot, mode]);
|
|
67
|
+
|
|
68
|
+
const tryToCompleteInput = useCallback((): boolean => {
|
|
69
|
+
let isCompleted: boolean;
|
|
70
|
+
|
|
71
|
+
const parsedSlotsData = Object.keys(SLOTS[mode]).reduce(
|
|
72
|
+
(res, key) => {
|
|
73
|
+
const slotKey = key as SlotKey;
|
|
74
|
+
res[slotKey] = parseInt(getSlot(slotKey), 10);
|
|
75
|
+
return res;
|
|
76
|
+
},
|
|
77
|
+
{} as Record<SlotKey, number>,
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const {
|
|
81
|
+
[SlotKey.Day]: day,
|
|
82
|
+
[SlotKey.Month]: month,
|
|
83
|
+
[SlotKey.Year]: year,
|
|
84
|
+
[SlotKey.Hours]: hours,
|
|
85
|
+
[SlotKey.Minutes]: minutes,
|
|
86
|
+
[SlotKey.Seconds]: seconds,
|
|
87
|
+
} = parsedSlotsData;
|
|
88
|
+
|
|
89
|
+
const yearSlotMeta = SLOTS[mode][SlotKey.Year];
|
|
90
|
+
const isDateCompleted = Boolean(day && month && year >= yearSlotMeta?.min && year <= yearSlotMeta?.max);
|
|
91
|
+
const isTimeCompleted = [
|
|
92
|
+
hours,
|
|
93
|
+
minutes,
|
|
94
|
+
...(mode === MODES.DateTime || mode === TIME_MODES.FullTime ? [seconds] : []),
|
|
95
|
+
].every(value => value !== undefined);
|
|
96
|
+
|
|
97
|
+
if (mode === MODES.DateTime || mode === NO_SECONDS_MODE) {
|
|
98
|
+
isCompleted = isDateCompleted && isTimeCompleted;
|
|
99
|
+
} else if (mode === TIME_MODES.FullTime || mode === TIME_MODES.NoSeconds) {
|
|
100
|
+
isCompleted = isTimeCompleted;
|
|
101
|
+
} else {
|
|
102
|
+
isCompleted = isDateCompleted;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (isCompleted && inputRef.current) {
|
|
106
|
+
const lastPosition = inputRef.current?.value.length;
|
|
107
|
+
inputRef.current.selectionStart = lastPosition;
|
|
108
|
+
inputRef.current.selectionEnd = lastPosition;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return isCompleted;
|
|
112
|
+
}, [getSlot, inputRef, mode]);
|
|
113
|
+
|
|
114
|
+
const updateSlot = useCallback(
|
|
115
|
+
(slotKey: string, slotValue: number | string) => {
|
|
116
|
+
if (inputRef.current) {
|
|
117
|
+
const { start, end, max } = SLOTS[mode][slotKey];
|
|
118
|
+
|
|
119
|
+
inputRef.current.value =
|
|
120
|
+
inputRef.current.value.slice(0, start) +
|
|
121
|
+
slotValue.toString().padStart(max.toString().length, '0') +
|
|
122
|
+
inputRef.current.value.slice(end);
|
|
123
|
+
setFocus(slotKey);
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
[inputRef, setFocus, mode],
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const getNextSlotKey = useMemo(() => getNextSlotKeyHandler(mode), [mode]);
|
|
130
|
+
const getPrevSlotKey = useMemo(() => getPrevSlotKeyHandler(mode), [mode]);
|
|
131
|
+
const getSlotKeyFromIndex = useMemo(() => getSlotKeyFromIndexHandler(mode), [mode]);
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
isAllSelected,
|
|
135
|
+
isValidInput,
|
|
136
|
+
tryToCompleteInput,
|
|
137
|
+
getSlot,
|
|
138
|
+
updateSlot,
|
|
139
|
+
setFocus,
|
|
140
|
+
isLikeDate,
|
|
141
|
+
getNextSlotKey,
|
|
142
|
+
getPrevSlotKey,
|
|
143
|
+
getSlotKeyFromIndex,
|
|
144
|
+
};
|
|
145
|
+
}
|
package/src/hooks/index.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
@
|
|
1
|
+
@use '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-fields';
|
|
2
2
|
|
|
3
3
|
.prefix {
|
|
4
|
-
color:
|
|
4
|
+
color: styles-tokens-fields.$sys-neutral-text-support;
|
|
5
5
|
|
|
6
6
|
&[data-disabled] {
|
|
7
|
-
opacity:
|
|
7
|
+
opacity: styles-tokens-fields.$opacity-a056;
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
.postfix {
|
|
12
|
-
color:
|
|
12
|
+
color: styles-tokens-fields.$sys-neutral-text-support;
|
|
13
13
|
|
|
14
14
|
&[data-disabled] {
|
|
15
|
-
opacity:
|
|
15
|
+
opacity: styles-tokens-fields.$opacity-a056;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
@@ -36,7 +36,7 @@ export function useCopyButton({
|
|
|
36
36
|
<ButtonCopyValue
|
|
37
37
|
{...props}
|
|
38
38
|
size={BUTTON_SIZE_MAP[size]}
|
|
39
|
-
valueToCopy={prefix + valueToCopy + postfix}
|
|
39
|
+
valueToCopy={(prefix ?? '') + valueToCopy + (postfix ?? '')}
|
|
40
40
|
onValueRequest={onValueRequest}
|
|
41
41
|
disabled={disabled}
|
|
42
42
|
/>
|
package/src/styles.module.scss
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
@
|
|
2
|
-
@
|
|
1
|
+
@use "@snack-uikit/figma-tokens/build/scss/components/styles-tokens-element";
|
|
2
|
+
@use "@snack-uikit/figma-tokens/build/scss/components/styles-tokens-fields";
|
|
3
3
|
|
|
4
4
|
$sizes: 's', 'm';
|
|
5
5
|
$icon-sizes: (
|
|
6
|
-
's':
|
|
7
|
-
'm':
|
|
6
|
+
's': styles-tokens-element.$icon-xs,
|
|
7
|
+
'm': styles-tokens-element.$icon-s
|
|
8
8
|
);
|
|
9
9
|
|
|
10
10
|
@mixin button-styles {
|
|
@@ -15,41 +15,41 @@ $icon-sizes: (
|
|
|
15
15
|
margin: 0;
|
|
16
16
|
padding: 0;
|
|
17
17
|
|
|
18
|
-
color:
|
|
18
|
+
color: styles-tokens-element.$sys-neutral-text-light;
|
|
19
19
|
|
|
20
20
|
background-color: transparent;
|
|
21
21
|
border: none;
|
|
22
22
|
|
|
23
23
|
@each $size in $sizes {
|
|
24
24
|
&[data-size='#{$size}'] {
|
|
25
|
-
@include composite-var(
|
|
25
|
+
@include styles-tokens-element.composite-var(styles-tokens-fields.$fields, 'buttons', $size);
|
|
26
26
|
|
|
27
27
|
svg {
|
|
28
|
-
width: simple-var($icon-sizes, $size) !important; /* stylelint-disable-line declaration-no-important */
|
|
29
|
-
height: simple-var($icon-sizes, $size) !important; /* stylelint-disable-line declaration-no-important */
|
|
28
|
+
width: styles-tokens-element.simple-var($icon-sizes, $size) !important; /* stylelint-disable-line declaration-no-important */
|
|
29
|
+
height: styles-tokens-element.simple-var($icon-sizes, $size) !important; /* stylelint-disable-line declaration-no-important */
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
&:hover {
|
|
35
35
|
cursor: pointer;
|
|
36
|
-
color:
|
|
36
|
+
color: styles-tokens-element.$sys-neutral-text-support;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
&:focus-visible {
|
|
40
|
-
@include outline-var(
|
|
40
|
+
@include styles-tokens-element.outline-var(styles-tokens-element.$container-focused-s);
|
|
41
41
|
|
|
42
|
-
color:
|
|
43
|
-
outline-color:
|
|
44
|
-
outline-offset:
|
|
42
|
+
color: styles-tokens-element.$sys-neutral-text-support;
|
|
43
|
+
outline-color: styles-tokens-element.$sys-available-complementary;
|
|
44
|
+
outline-offset: styles-tokens-element.$spacing-state-focus-offset;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
&:active {
|
|
48
|
-
color:
|
|
48
|
+
color: styles-tokens-element.$sys-neutral-text-main;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
&[data-disabled] {
|
|
52
52
|
cursor: not-allowed;
|
|
53
|
-
color:
|
|
53
|
+
color: styles-tokens-element.$sys-neutral-text-disabled;
|
|
54
54
|
}
|
|
55
55
|
}
|
|
@@ -3,7 +3,7 @@ import { ReactNode } from 'react';
|
|
|
3
3
|
import { DroplistProps, SelectionSingleState } from '@snack-uikit/list';
|
|
4
4
|
import { ValueOf } from '@snack-uikit/utils';
|
|
5
5
|
|
|
6
|
-
import { BUTTON_VARIANT, CONTAINER_VARIANT, VALIDATION_STATE } from '
|
|
6
|
+
import { BUTTON_VARIANT, CONTAINER_VARIANT, VALIDATION_STATE } from '../constants';
|
|
7
7
|
|
|
8
8
|
export type ValidationState = ValueOf<typeof VALIDATION_STATE>;
|
|
9
9
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ValueOf } from '@snack-uikit/utils';
|
|
2
|
+
|
|
3
|
+
import { MODES, NO_SECONDS_MODE, TIME_MODES } from '../constants';
|
|
4
|
+
|
|
5
|
+
export type Slot = {
|
|
6
|
+
start: number;
|
|
7
|
+
end: number;
|
|
8
|
+
max: number;
|
|
9
|
+
min: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type Mode = ValueOf<typeof MODES>;
|
|
13
|
+
export type TimeMode = ValueOf<typeof TIME_MODES>;
|
|
14
|
+
export type NoSecondsMode = typeof NO_SECONDS_MODE;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { SLOT_ORDER, SlotKey, SLOTS } from '../constants';
|
|
2
|
+
import { Mode, NoSecondsMode, TimeMode } from '../types';
|
|
3
|
+
|
|
4
|
+
export function getSlotKeyFromIndexHandler(mode: Mode | TimeMode | NoSecondsMode) {
|
|
5
|
+
return (index: number | null): SlotKey | undefined => {
|
|
6
|
+
if (index !== null) {
|
|
7
|
+
for (const key in SLOTS[mode]) {
|
|
8
|
+
if (index >= SLOTS[mode][key].start && index <= SLOTS[mode][key].end) {
|
|
9
|
+
return key as SlotKey;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return undefined;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getNextSlotKeyHandler(mode: Mode | TimeMode | NoSecondsMode) {
|
|
19
|
+
const order = SLOT_ORDER[mode];
|
|
20
|
+
|
|
21
|
+
return (slotKey: SlotKey | undefined) => {
|
|
22
|
+
const defaultIndex = order.length - 1;
|
|
23
|
+
const defaultSLot = order[defaultIndex];
|
|
24
|
+
const currentIndex = order.indexOf(slotKey as SlotKey);
|
|
25
|
+
return currentIndex === -1 || currentIndex === defaultIndex ? defaultSLot : order[currentIndex + 1];
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getPrevSlotKeyHandler(mode: Mode | TimeMode | NoSecondsMode) {
|
|
30
|
+
const order = SLOT_ORDER[mode];
|
|
31
|
+
|
|
32
|
+
return (slotKey: SlotKey | undefined) => {
|
|
33
|
+
const defaultIndex = 0;
|
|
34
|
+
const defaultSLot = order[defaultIndex];
|
|
35
|
+
const currentIndex = order.indexOf(slotKey as SlotKey);
|
|
36
|
+
return currentIndex === -1 || currentIndex === defaultIndex ? defaultSLot : order[currentIndex - 1];
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const DATE_STUB = new Date();
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Преобразует строковое значение поля FieldDate в тип Date
|
|
44
|
+
* @function helper
|
|
45
|
+
*/
|
|
46
|
+
export function parseDate(value: string) {
|
|
47
|
+
if (!value) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const splittedValue = value.split(', ');
|
|
52
|
+
const date = splittedValue[0];
|
|
53
|
+
let time = splittedValue[1];
|
|
54
|
+
|
|
55
|
+
let [day, month, year] = date.split('.').map(Number);
|
|
56
|
+
month -= 1;
|
|
57
|
+
|
|
58
|
+
if (date.includes(':')) {
|
|
59
|
+
time = date;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (time) {
|
|
63
|
+
if (isNaN(year) || isNaN(month) || isNaN(day)) {
|
|
64
|
+
year = DATE_STUB.getFullYear();
|
|
65
|
+
month = DATE_STUB.getMonth();
|
|
66
|
+
day = DATE_STUB.getDay();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const [hours = 0, minutes = 0, seconds = 0] = time.split(':').map(str => Number(str) ?? 0);
|
|
70
|
+
|
|
71
|
+
return new Date(year, month, day, hours, minutes, seconds);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return new Date(year, month, day);
|
|
75
|
+
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Slot } from './types';
|
|
2
|
-
export declare enum SlotKey {
|
|
3
|
-
Day = "D",
|
|
4
|
-
Month = "M",
|
|
5
|
-
Year = "Y"
|
|
6
|
-
}
|
|
7
|
-
export declare const MASK: Record<string, string>;
|
|
8
|
-
export declare const DEFAULT_LOCALE: Intl.Locale;
|
|
9
|
-
export declare const SLOTS: Record<SlotKey | string, Slot>;
|
|
10
|
-
export declare const SLOTS_PLACEHOLDER: Record<string, Record<string, string>>;
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.SLOTS_PLACEHOLDER = exports.SLOTS = exports.DEFAULT_LOCALE = exports.MASK = exports.SlotKey = void 0;
|
|
7
|
-
var SlotKey;
|
|
8
|
-
(function (SlotKey) {
|
|
9
|
-
SlotKey["Day"] = "D";
|
|
10
|
-
SlotKey["Month"] = "M";
|
|
11
|
-
SlotKey["Year"] = "Y";
|
|
12
|
-
})(SlotKey || (exports.SlotKey = SlotKey = {}));
|
|
13
|
-
exports.MASK = {
|
|
14
|
-
'ru-RU': 'ДД.ММ.ГГГГ',
|
|
15
|
-
'en-US': 'DD.MM.YYYY'
|
|
16
|
-
};
|
|
17
|
-
exports.DEFAULT_LOCALE = new Intl.Locale('ru-RU');
|
|
18
|
-
exports.SLOTS = {
|
|
19
|
-
[SlotKey.Day]: {
|
|
20
|
-
start: 0,
|
|
21
|
-
end: 2,
|
|
22
|
-
max: 31,
|
|
23
|
-
min: 1
|
|
24
|
-
},
|
|
25
|
-
[SlotKey.Month]: {
|
|
26
|
-
start: 3,
|
|
27
|
-
end: 5,
|
|
28
|
-
max: 12,
|
|
29
|
-
min: 1
|
|
30
|
-
},
|
|
31
|
-
[SlotKey.Year]: {
|
|
32
|
-
start: 6,
|
|
33
|
-
end: 10,
|
|
34
|
-
max: 2100,
|
|
35
|
-
min: 1900
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
exports.SLOTS_PLACEHOLDER = {
|
|
39
|
-
'ru-RU': {
|
|
40
|
-
[SlotKey.Day]: 'ДД',
|
|
41
|
-
[SlotKey.Month]: 'ММ',
|
|
42
|
-
[SlotKey.Year]: 'ГГГГ'
|
|
43
|
-
},
|
|
44
|
-
'en-US': {
|
|
45
|
-
[SlotKey.Day]: 'DD',
|
|
46
|
-
[SlotKey.Month]: 'MM',
|
|
47
|
-
[SlotKey.Year]: 'YYYY'
|
|
48
|
-
}
|
|
49
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './useDateField';
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { RefObject } from 'react';
|
|
2
|
-
export declare function useDateFieldHelpers(inputRef: RefObject<HTMLInputElement>): {
|
|
3
|
-
isAllSelected: () => boolean;
|
|
4
|
-
isValidInput: () => boolean;
|
|
5
|
-
tryToCompleteInput: () => boolean;
|
|
6
|
-
getSlot: (slotKey: string) => string;
|
|
7
|
-
updateSlot: (slotKey: string, slotValue: number | string) => void;
|
|
8
|
-
setFocus: (slotKey: string) => void;
|
|
9
|
-
isLikeDate: () => boolean;
|
|
10
|
-
};
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.useDateFieldHelpers = useDateFieldHelpers;
|
|
7
|
-
const react_1 = require("react");
|
|
8
|
-
const constants_1 = require("../constants");
|
|
9
|
-
function useDateFieldHelpers(inputRef) {
|
|
10
|
-
const setFocus = (0, react_1.useCallback)(slotKey => {
|
|
11
|
-
if (inputRef.current) {
|
|
12
|
-
const {
|
|
13
|
-
start,
|
|
14
|
-
end
|
|
15
|
-
} = constants_1.SLOTS[slotKey];
|
|
16
|
-
inputRef.current.setSelectionRange(start, end);
|
|
17
|
-
}
|
|
18
|
-
}, [inputRef]);
|
|
19
|
-
const isAllSelected = (0, react_1.useCallback)(() => {
|
|
20
|
-
var _a, _b, _c;
|
|
21
|
-
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;
|
|
22
|
-
}, [inputRef]);
|
|
23
|
-
const getSlot = (0, react_1.useCallback)(slotKey => {
|
|
24
|
-
if (inputRef.current) {
|
|
25
|
-
return inputRef.current.value.slice(constants_1.SLOTS[slotKey].start, constants_1.SLOTS[slotKey].end);
|
|
26
|
-
}
|
|
27
|
-
return '';
|
|
28
|
-
}, [inputRef]);
|
|
29
|
-
const isLikeDate = (0, react_1.useCallback)(() => {
|
|
30
|
-
if (inputRef.current) {
|
|
31
|
-
return Object.keys(constants_1.SLOTS).every(slotKey => getSlot(slotKey) && Number.isInteger(Number(getSlot(slotKey))));
|
|
32
|
-
}
|
|
33
|
-
return false;
|
|
34
|
-
}, [getSlot, inputRef]);
|
|
35
|
-
const isValidInput = (0, react_1.useCallback)(() => {
|
|
36
|
-
const day = parseInt(getSlot(constants_1.SlotKey.Day), 10);
|
|
37
|
-
const month = parseInt(getSlot(constants_1.SlotKey.Month), 10);
|
|
38
|
-
const year = parseInt(getSlot(constants_1.SlotKey.Year), 10);
|
|
39
|
-
if (!month || !day) {
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
const date = new Date(year || /* високосный год = */2020, month - 1, day);
|
|
43
|
-
return date.getDate() === day;
|
|
44
|
-
}, [getSlot]);
|
|
45
|
-
const tryToCompleteInput = (0, react_1.useCallback)(() => {
|
|
46
|
-
var _a;
|
|
47
|
-
const day = parseInt(getSlot(constants_1.SlotKey.Day), 10);
|
|
48
|
-
const month = parseInt(getSlot(constants_1.SlotKey.Month), 10);
|
|
49
|
-
const year = parseInt(getSlot(constants_1.SlotKey.Year), 10);
|
|
50
|
-
const {
|
|
51
|
-
min,
|
|
52
|
-
max
|
|
53
|
-
} = constants_1.SLOTS[constants_1.SlotKey.Year];
|
|
54
|
-
const isCompleted = Boolean(day && month && year >= min && year <= max);
|
|
55
|
-
if (isCompleted && inputRef.current) {
|
|
56
|
-
const lastPosition = (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.value.length;
|
|
57
|
-
inputRef.current.selectionStart = lastPosition;
|
|
58
|
-
inputRef.current.selectionEnd = lastPosition;
|
|
59
|
-
}
|
|
60
|
-
return isCompleted;
|
|
61
|
-
}, [getSlot, inputRef]);
|
|
62
|
-
const updateSlot = (0, react_1.useCallback)((slotKey, slotValue) => {
|
|
63
|
-
if (inputRef.current) {
|
|
64
|
-
const {
|
|
65
|
-
start,
|
|
66
|
-
end,
|
|
67
|
-
max
|
|
68
|
-
} = constants_1.SLOTS[slotKey];
|
|
69
|
-
inputRef.current.value = inputRef.current.value.slice(0, start) + slotValue.toString().padStart(max.toString().length, '0') + inputRef.current.value.slice(end);
|
|
70
|
-
setFocus(slotKey);
|
|
71
|
-
}
|
|
72
|
-
}, [inputRef, setFocus]);
|
|
73
|
-
return {
|
|
74
|
-
isAllSelected,
|
|
75
|
-
isValidInput,
|
|
76
|
-
tryToCompleteInput,
|
|
77
|
-
getSlot,
|
|
78
|
-
updateSlot,
|
|
79
|
-
setFocus,
|
|
80
|
-
isLikeDate
|
|
81
|
-
};
|
|
82
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { SlotKey } from './constants';
|
|
2
|
-
export declare function getSlotKey(index: number | null): string | null;
|
|
3
|
-
export declare function getNextSlotKey(slotKey: string | null): SlotKey.Month | SlotKey.Year;
|
|
4
|
-
export declare function getPrevSlotKey(slotKey: string | null): SlotKey.Day | SlotKey.Month;
|
|
5
|
-
/**
|
|
6
|
-
* Преобразует строковое значение поля FieldDate в тип Date
|
|
7
|
-
* @function helper
|
|
8
|
-
*/
|
|
9
|
-
export declare function parseDate(date: string): Date;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.getSlotKey = getSlotKey;
|
|
7
|
-
exports.getNextSlotKey = getNextSlotKey;
|
|
8
|
-
exports.getPrevSlotKey = getPrevSlotKey;
|
|
9
|
-
exports.parseDate = parseDate;
|
|
10
|
-
const constants_1 = require("./constants");
|
|
11
|
-
function getSlotKey(index) {
|
|
12
|
-
if (index !== null) {
|
|
13
|
-
for (const key in constants_1.SLOTS) {
|
|
14
|
-
if (index >= constants_1.SLOTS[key].start && index <= constants_1.SLOTS[key].end) {
|
|
15
|
-
return key;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
function getNextSlotKey(slotKey) {
|
|
22
|
-
switch (slotKey) {
|
|
23
|
-
case constants_1.SlotKey.Day:
|
|
24
|
-
{
|
|
25
|
-
return constants_1.SlotKey.Month;
|
|
26
|
-
}
|
|
27
|
-
case constants_1.SlotKey.Month:
|
|
28
|
-
case constants_1.SlotKey.Year:
|
|
29
|
-
default:
|
|
30
|
-
{
|
|
31
|
-
return constants_1.SlotKey.Year;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function getPrevSlotKey(slotKey) {
|
|
36
|
-
switch (slotKey) {
|
|
37
|
-
case constants_1.SlotKey.Year:
|
|
38
|
-
{
|
|
39
|
-
return constants_1.SlotKey.Month;
|
|
40
|
-
}
|
|
41
|
-
case constants_1.SlotKey.Month:
|
|
42
|
-
case constants_1.SlotKey.Day:
|
|
43
|
-
default:
|
|
44
|
-
{
|
|
45
|
-
return constants_1.SlotKey.Day;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Преобразует строковое значение поля FieldDate в тип Date
|
|
51
|
-
* @function helper
|
|
52
|
-
*/
|
|
53
|
-
function parseDate(date) {
|
|
54
|
-
const values = date.split('.');
|
|
55
|
-
return new Date(Number(values[2]), Number(values[1]) - 1, Number(values[0]));
|
|
56
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Slot } from './types';
|
|
2
|
-
export declare enum SlotKey {
|
|
3
|
-
Day = "D",
|
|
4
|
-
Month = "M",
|
|
5
|
-
Year = "Y"
|
|
6
|
-
}
|
|
7
|
-
export declare const MASK: Record<string, string>;
|
|
8
|
-
export declare const DEFAULT_LOCALE: Intl.Locale;
|
|
9
|
-
export declare const SLOTS: Record<SlotKey | string, Slot>;
|
|
10
|
-
export declare const SLOTS_PLACEHOLDER: Record<string, Record<string, string>>;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export var SlotKey;
|
|
2
|
-
(function (SlotKey) {
|
|
3
|
-
SlotKey["Day"] = "D";
|
|
4
|
-
SlotKey["Month"] = "M";
|
|
5
|
-
SlotKey["Year"] = "Y";
|
|
6
|
-
})(SlotKey || (SlotKey = {}));
|
|
7
|
-
export const MASK = {
|
|
8
|
-
'ru-RU': 'ДД.ММ.ГГГГ',
|
|
9
|
-
'en-US': 'DD.MM.YYYY',
|
|
10
|
-
};
|
|
11
|
-
export const DEFAULT_LOCALE = new Intl.Locale('ru-RU');
|
|
12
|
-
export const SLOTS = {
|
|
13
|
-
[SlotKey.Day]: { start: 0, end: 2, max: 31, min: 1 },
|
|
14
|
-
[SlotKey.Month]: { start: 3, end: 5, max: 12, min: 1 },
|
|
15
|
-
[SlotKey.Year]: { start: 6, end: 10, max: 2100, min: 1900 },
|
|
16
|
-
};
|
|
17
|
-
export const SLOTS_PLACEHOLDER = {
|
|
18
|
-
'ru-RU': {
|
|
19
|
-
[SlotKey.Day]: 'ДД',
|
|
20
|
-
[SlotKey.Month]: 'ММ',
|
|
21
|
-
[SlotKey.Year]: 'ГГГГ',
|
|
22
|
-
},
|
|
23
|
-
'en-US': {
|
|
24
|
-
[SlotKey.Day]: 'DD',
|
|
25
|
-
[SlotKey.Month]: 'MM',
|
|
26
|
-
[SlotKey.Year]: 'YYYY',
|
|
27
|
-
},
|
|
28
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './useDateField';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './useDateField';
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { RefObject } from 'react';
|
|
2
|
-
export declare function useDateFieldHelpers(inputRef: RefObject<HTMLInputElement>): {
|
|
3
|
-
isAllSelected: () => boolean;
|
|
4
|
-
isValidInput: () => boolean;
|
|
5
|
-
tryToCompleteInput: () => boolean;
|
|
6
|
-
getSlot: (slotKey: string) => string;
|
|
7
|
-
updateSlot: (slotKey: string, slotValue: number | string) => void;
|
|
8
|
-
setFocus: (slotKey: string) => void;
|
|
9
|
-
isLikeDate: () => boolean;
|
|
10
|
-
};
|