mimir-ui-kit 0.0.19 → 0.0.21
Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,12 @@
|
|
1
1
|
import { TInputProps } from '../Input';
|
2
2
|
|
3
|
-
|
3
|
+
/**
|
4
|
+
* Компонент ввода одноразового пароля (OTP).
|
5
|
+
*
|
6
|
+
* Компонент представляет собой набор вводов, каждый из которых может содержать только цифры.
|
7
|
+
* Пользователь может вводить цифры в каждый ввод, и при вводе каждой цифры происходит автоматическое переключение на следующий ввод.
|
8
|
+
*/
|
9
|
+
export declare const OtpInput: import('react').ForwardRefExoticComponent<Omit<TInputProps, "label" | "onChange"> & {
|
4
10
|
value?: string;
|
5
11
|
/**
|
6
12
|
* Количество полей ввода.
|
@@ -14,15 +20,4 @@ type TProps = Omit<TInputProps, 'onChange' | 'label'> & {
|
|
14
20
|
* Флаг, показывающий нужно ли отображать разделитель между вводами.
|
15
21
|
*/
|
16
22
|
needSeparator?: boolean;
|
17
|
-
}
|
18
|
-
/**
|
19
|
-
* Компонент ввода одноразового пароля (OTP).
|
20
|
-
*
|
21
|
-
* Компонент представляет собой набор вводов, каждый из которых может содержать только цифры.
|
22
|
-
* Пользователь может вводить цифры в каждый ввод, и при вводе каждой цифры происходит автоматическое переключение на следующий ввод.
|
23
|
-
*/
|
24
|
-
export declare const OtpInput: {
|
25
|
-
({ value, valueLength, needSeparator, onChange, ...props }: TProps): import("react/jsx-runtime").JSX.Element;
|
26
|
-
displayName: string;
|
27
|
-
};
|
28
|
-
export {};
|
23
|
+
} & import('react').RefAttributes<unknown>>;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
2
|
-
import { useRef, useMemo, Fragment } from "react";
|
2
|
+
import { forwardRef, useRef, useImperativeHandle, useMemo, Fragment } from "react";
|
3
3
|
import { c as classNames } from "../../index-CweZ_OcN.js";
|
4
4
|
import { Input } from "../Input/Input.js";
|
5
5
|
import { RE_DIGIT, ITEMS_PER_SEPARATOR, DEFAULT_VALUE_LENGTH } from "./constants.js";
|
@@ -12,121 +12,129 @@ const cls = {
|
|
12
12
|
input,
|
13
13
|
separator
|
14
14
|
};
|
15
|
-
const OtpInput = (
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
if (RE_DIGIT.test(char)) {
|
29
|
-
items.push(char);
|
30
|
-
} else {
|
31
|
-
items.push("");
|
15
|
+
const OtpInput = forwardRef(
|
16
|
+
({
|
17
|
+
value = "",
|
18
|
+
valueLength = DEFAULT_VALUE_LENGTH,
|
19
|
+
needSeparator = true,
|
20
|
+
onChange,
|
21
|
+
...props
|
22
|
+
}, ref) => {
|
23
|
+
const inputRefs = useRef([]);
|
24
|
+
useImperativeHandle(ref, () => ({
|
25
|
+
focus: () => {
|
26
|
+
var _a;
|
27
|
+
(_a = inputRefs.current[0]) == null ? void 0 : _a.focus();
|
32
28
|
}
|
33
|
-
}
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
}
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
return;
|
58
|
-
}
|
59
|
-
targetValue = isTargetValueDigit ? targetValue : " ";
|
60
|
-
const targetValueLength = targetValue.length;
|
61
|
-
if (targetValueLength === 1) {
|
62
|
-
const newValue = value.substring(0, index) + targetValue + value.substring(index + 1);
|
63
|
-
onChange == null ? void 0 : onChange(newValue);
|
64
|
-
if (isTargetValueDigit) {
|
65
|
-
handleFocusToNextInput(index);
|
29
|
+
}));
|
30
|
+
const valueItems = useMemo(() => {
|
31
|
+
const valueArray = value.split("");
|
32
|
+
const items = [];
|
33
|
+
for (let i = 0; i < valueLength; i++) {
|
34
|
+
const char = valueArray[i];
|
35
|
+
if (RE_DIGIT.test(char)) {
|
36
|
+
items.push(char);
|
37
|
+
} else {
|
38
|
+
items.push("");
|
39
|
+
}
|
40
|
+
}
|
41
|
+
return items;
|
42
|
+
}, [value, valueLength]);
|
43
|
+
const handleFocusToNextInput = (index) => {
|
44
|
+
var _a;
|
45
|
+
if (index < valueLength - 1) {
|
46
|
+
(_a = inputRefs.current[index + 1]) == null ? void 0 : _a.focus();
|
47
|
+
}
|
48
|
+
};
|
49
|
+
const handleFocusToPrevInput = (index) => {
|
50
|
+
var _a;
|
51
|
+
if (index > 0) {
|
52
|
+
(_a = inputRefs.current[index - 1]) == null ? void 0 : _a.focus();
|
66
53
|
}
|
67
|
-
}
|
68
|
-
|
69
|
-
target.
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
const target = e.target;
|
75
|
-
switch (key) {
|
76
|
-
case "ArrowRight":
|
77
|
-
case "ArrowDown": {
|
78
|
-
e.preventDefault();
|
79
|
-
return handleFocusToNextInput(index);
|
54
|
+
};
|
55
|
+
const handleChange = (e, index) => {
|
56
|
+
const target = e.target;
|
57
|
+
let targetValue = target.value.trim();
|
58
|
+
const isTargetValueDigit = RE_DIGIT.test(targetValue);
|
59
|
+
if (!isTargetValueDigit && targetValue !== "") {
|
60
|
+
return;
|
80
61
|
}
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
return handleFocusToPrevInput(index);
|
62
|
+
const nextInputEl = inputRefs.current[index + 1];
|
63
|
+
if (!isTargetValueDigit && nextInputEl && nextInputEl.value !== "") {
|
64
|
+
return;
|
85
65
|
}
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
onChange == null ? void 0 : onChange(newValue);
|
94
|
-
handleFocusToPrevInput(index);
|
95
|
-
};
|
96
|
-
const handleFocus = (e, index) => {
|
97
|
-
const target = e.target;
|
98
|
-
const prevInputEl = inputRefs.current[index - 1];
|
99
|
-
if (prevInputEl && prevInputEl.value === "") {
|
100
|
-
prevInputEl.focus();
|
101
|
-
}
|
102
|
-
target.setSelectionRange(0, target.value.length);
|
103
|
-
};
|
104
|
-
return /* @__PURE__ */ jsx("div", { className: classNames(cls.otp), children: valueItems.map((digit, idx) => {
|
105
|
-
const nextIndex = idx + 1;
|
106
|
-
const showSeparator = needSeparator && nextIndex % ITEMS_PER_SEPARATOR === 0 && nextIndex !== valueItems.length;
|
107
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
108
|
-
/* @__PURE__ */ jsx(
|
109
|
-
Input,
|
110
|
-
{
|
111
|
-
ref: (el) => inputRefs.current[idx] = el,
|
112
|
-
type: "text",
|
113
|
-
inputMode: "numeric",
|
114
|
-
autoComplete: "one-time-code",
|
115
|
-
pattern: "\\d{1}",
|
116
|
-
maxLength: 1,
|
117
|
-
value: digit,
|
118
|
-
className: cls.input,
|
119
|
-
wrapperClassName: cls["input-wrapper"],
|
120
|
-
onChange: (e) => handleChange(e, idx),
|
121
|
-
onKeyDown: (e) => handleKeyDown(e, idx),
|
122
|
-
onFocus: (e) => handleFocus(e, idx),
|
123
|
-
...props
|
66
|
+
targetValue = isTargetValueDigit ? targetValue.trim() : " ";
|
67
|
+
const targetValueLength = targetValue.length;
|
68
|
+
if (targetValueLength === 1) {
|
69
|
+
const newValue = value.substring(0, index) + targetValue + value.substring(index + 1);
|
70
|
+
onChange == null ? void 0 : onChange(newValue.trim());
|
71
|
+
if (isTargetValueDigit) {
|
72
|
+
handleFocusToNextInput(index);
|
124
73
|
}
|
125
|
-
)
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
};
|
74
|
+
} else if (targetValueLength === valueLength) {
|
75
|
+
onChange == null ? void 0 : onChange(targetValue.trim());
|
76
|
+
target.blur();
|
77
|
+
}
|
78
|
+
};
|
79
|
+
const handleKeyDown = (e, index) => {
|
80
|
+
const { key } = e;
|
81
|
+
const target = e.target;
|
82
|
+
switch (key) {
|
83
|
+
case "ArrowRight":
|
84
|
+
case "ArrowDown": {
|
85
|
+
e.preventDefault();
|
86
|
+
return handleFocusToNextInput(index);
|
87
|
+
}
|
88
|
+
case "ArrowLeft":
|
89
|
+
case "ArrowUp": {
|
90
|
+
e.preventDefault();
|
91
|
+
return handleFocusToPrevInput(index);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
const targetValue = target.value.trim();
|
95
|
+
target.setSelectionRange(0, targetValue.length);
|
96
|
+
if (e.key !== "Backspace" || targetValue !== "") {
|
97
|
+
return;
|
98
|
+
}
|
99
|
+
const newValue = `${value.substring(0, index - 1)} ${value.substring(index)}`;
|
100
|
+
onChange == null ? void 0 : onChange(newValue.trim());
|
101
|
+
handleFocusToPrevInput(index);
|
102
|
+
};
|
103
|
+
const handleFocus = (e, index) => {
|
104
|
+
const target = e.target;
|
105
|
+
const prevInputEl = inputRefs.current[index - 1];
|
106
|
+
if (prevInputEl && prevInputEl.value === "") {
|
107
|
+
prevInputEl.focus();
|
108
|
+
}
|
109
|
+
target.setSelectionRange(0, target.value.length);
|
110
|
+
};
|
111
|
+
return /* @__PURE__ */ jsx("div", { className: classNames(cls.otp), children: valueItems.map((digit, idx) => {
|
112
|
+
const nextIndex = idx + 1;
|
113
|
+
const showSeparator = needSeparator && nextIndex % ITEMS_PER_SEPARATOR === 0 && nextIndex !== valueItems.length;
|
114
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
115
|
+
/* @__PURE__ */ jsx(
|
116
|
+
Input,
|
117
|
+
{
|
118
|
+
ref: (el) => inputRefs.current[idx] = el,
|
119
|
+
type: "text",
|
120
|
+
inputMode: "numeric",
|
121
|
+
autoComplete: "one-time-code",
|
122
|
+
pattern: "\\d{1}",
|
123
|
+
maxLength: 1,
|
124
|
+
value: digit,
|
125
|
+
className: cls.input,
|
126
|
+
wrapperClassName: cls["input-wrapper"],
|
127
|
+
onChange: (e) => handleChange(e, idx),
|
128
|
+
onKeyDown: (e) => handleKeyDown(e, idx),
|
129
|
+
onFocus: (e) => handleFocus(e, idx),
|
130
|
+
...props
|
131
|
+
}
|
132
|
+
),
|
133
|
+
showSeparator && /* @__PURE__ */ jsx("span", { className: classNames(cls.separator) })
|
134
|
+
] }, idx);
|
135
|
+
}) });
|
136
|
+
}
|
137
|
+
);
|
130
138
|
OtpInput.displayName = "OtpInput";
|
131
139
|
export {
|
132
140
|
OtpInput
|