react-core-ts 1.1.22 → 1.1.24
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/ReactAutoComplete.js +3 -3
- package/dist/ReactAutoComplete.js.map +1 -1
- package/dist/ReactOTPInput.d.ts +16 -0
- package/dist/ReactOTPInput.js +125 -0
- package/dist/ReactOTPInput.js.map +1 -0
- package/dist/ReactRadioButton.d.ts +4 -0
- package/dist/ReactRadioButton.js +30 -0
- package/dist/ReactRadioButton.js.map +1 -0
- package/dist/commontypes.d.ts +10 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/styles/styles/components/autocomplete.css +602 -0
- package/dist/styles/styles/components/selectedautocomplete.css +122 -0
- package/dist/styles/styles/components/tooltip.css +441 -0
- package/dist/styles/styles/components/treedropdown.css +63 -0
- package/dist/styles/styles/global.css +8 -0
- package/package.json +1 -1
- package/src/ReactAutoComplete.tsx +3 -3
- package/src/ReactOTPInput.tsx +195 -0
- package/src/ReactRadioButton.tsx +62 -0
- package/src/commontypes.ts +10 -0
- package/src/index.tsx +2 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { FieldErrors } from "react-hook-form";
|
|
3
|
+
|
|
4
|
+
type OTPInputProps = {
|
|
5
|
+
BoxLength?: number;
|
|
6
|
+
value?: string;
|
|
7
|
+
onChangeOTP: (otp: string) => void;
|
|
8
|
+
label?: string;
|
|
9
|
+
errors?: FieldErrors;
|
|
10
|
+
name: string;
|
|
11
|
+
id: string;
|
|
12
|
+
labelTitle?: string;
|
|
13
|
+
initialTime?: number;
|
|
14
|
+
callbackFn?: (data: boolean) => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const OTPInput: React.FC<OTPInputProps> = ({
|
|
18
|
+
BoxLength = 6,
|
|
19
|
+
onChangeOTP,
|
|
20
|
+
value = "",
|
|
21
|
+
label,
|
|
22
|
+
errors,
|
|
23
|
+
name,
|
|
24
|
+
id,
|
|
25
|
+
labelTitle,
|
|
26
|
+
initialTime = 240,
|
|
27
|
+
callbackFn,
|
|
28
|
+
}) => {
|
|
29
|
+
// Initialize OTP state from value prop
|
|
30
|
+
const [otp, setOtp] = useState<string[]>(
|
|
31
|
+
value.split("").concat(Array(BoxLength - value.length).fill(""))
|
|
32
|
+
);
|
|
33
|
+
const inputRefs = useRef<(HTMLInputElement | null)[]>([]);
|
|
34
|
+
const [remainingTime, setRemainingTime] = useState<number>(initialTime);
|
|
35
|
+
const [isTimerCompleted, setIsTimerCompleted] = useState<boolean>(false);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
// Synchronize local otp state with value prop changes
|
|
39
|
+
setOtp(value.split("").concat(Array(BoxLength - value.length).fill("")));
|
|
40
|
+
}, [value, BoxLength]);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (otp) onChangeOTP(otp.join(""));
|
|
44
|
+
}, [otp]);
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (remainingTime > 0) {
|
|
48
|
+
const timerId = setInterval(() => {
|
|
49
|
+
setRemainingTime((prev) => prev - 1);
|
|
50
|
+
}, 1000);
|
|
51
|
+
|
|
52
|
+
return () => clearInterval(timerId);
|
|
53
|
+
} else {
|
|
54
|
+
setIsTimerCompleted(true);
|
|
55
|
+
}
|
|
56
|
+
}, [remainingTime]);
|
|
57
|
+
|
|
58
|
+
const formatTime = (time: number) => {
|
|
59
|
+
const minutes = Math.floor(time / 60);
|
|
60
|
+
const seconds = time % 60;
|
|
61
|
+
return `${minutes}:${seconds < 10 ? `0${seconds}` : seconds}`;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const handleChange = (
|
|
65
|
+
e: React.ChangeEvent<HTMLInputElement>,
|
|
66
|
+
index: number
|
|
67
|
+
) => {
|
|
68
|
+
const value = e.target.value;
|
|
69
|
+
if (/[^0-9]/.test(value)) return;
|
|
70
|
+
|
|
71
|
+
const newOtp = [...otp];
|
|
72
|
+
newOtp[index] = value;
|
|
73
|
+
setOtp(newOtp);
|
|
74
|
+
|
|
75
|
+
if (value !== "" && index < BoxLength - 1) {
|
|
76
|
+
inputRefs.current[index + 1]?.focus(); // Move focus to next input
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const handleKeyDown = (
|
|
81
|
+
e: React.KeyboardEvent<HTMLInputElement>,
|
|
82
|
+
index: number
|
|
83
|
+
) => {
|
|
84
|
+
if (e.key === "Backspace" && otp[index] === "" && index > 0) {
|
|
85
|
+
inputRefs.current[index - 1]?.focus(); // Move focus to previous input
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const handlePaste = (e: React.ClipboardEvent<HTMLInputElement>) => {
|
|
90
|
+
const pastedData = e.clipboardData.getData("Text").slice(0, BoxLength);
|
|
91
|
+
if (/[^0-9]/.test(pastedData)) return;
|
|
92
|
+
|
|
93
|
+
const newOtp = pastedData
|
|
94
|
+
.split("")
|
|
95
|
+
.concat(Array(BoxLength - pastedData.length).fill(""));
|
|
96
|
+
setOtp(newOtp);
|
|
97
|
+
|
|
98
|
+
// Move focus to the last filled input field
|
|
99
|
+
const lastIndex = newOtp.findIndex((val) => val === "");
|
|
100
|
+
if (lastIndex !== -1) {
|
|
101
|
+
inputRefs.current[lastIndex]?.focus();
|
|
102
|
+
} else {
|
|
103
|
+
inputRefs.current[BoxLength - 1]?.focus();
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const getErrors = (err: any) => {
|
|
108
|
+
let errMsg = "";
|
|
109
|
+
if (err.message) {
|
|
110
|
+
errMsg = err?.message;
|
|
111
|
+
}
|
|
112
|
+
return errMsg;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const handleError = (data: any) => {
|
|
116
|
+
if (
|
|
117
|
+
getErrors(data[name]) === "required" ||
|
|
118
|
+
getErrors(data[name]) === "Required"
|
|
119
|
+
) {
|
|
120
|
+
return `${label ?? labelTitle} is ${getErrors(data[name])}`;
|
|
121
|
+
} else {
|
|
122
|
+
return getErrors(data[name]) ?? "";
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Reset time function added
|
|
127
|
+
const resetTimer = () => {
|
|
128
|
+
setRemainingTime(initialTime);
|
|
129
|
+
setIsTimerCompleted(false);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const handleResend = () => {
|
|
133
|
+
if (isTimerCompleted) {
|
|
134
|
+
callbackFn?.(isTimerCompleted);
|
|
135
|
+
resetTimer();
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<div>
|
|
141
|
+
{label && (
|
|
142
|
+
<div className="mb-2 me-2">
|
|
143
|
+
<label className={`text-grey-label font-normal text-common`}>
|
|
144
|
+
{label}
|
|
145
|
+
</label>
|
|
146
|
+
</div>
|
|
147
|
+
)}
|
|
148
|
+
<div className="flex flex-col w-fit">
|
|
149
|
+
<div className="flex gap-x-5 ">
|
|
150
|
+
{Array(BoxLength)
|
|
151
|
+
.fill("")
|
|
152
|
+
.map((_, index) => (
|
|
153
|
+
<input
|
|
154
|
+
key={index}
|
|
155
|
+
name={name}
|
|
156
|
+
id={id}
|
|
157
|
+
type="text"
|
|
158
|
+
value={otp[index]}
|
|
159
|
+
onChange={(e) => handleChange(e, index)}
|
|
160
|
+
onKeyDown={(e) => handleKeyDown(e, index)}
|
|
161
|
+
onPaste={handlePaste}
|
|
162
|
+
ref={(el) => (inputRefs.current[index] = el)}
|
|
163
|
+
maxLength={1}
|
|
164
|
+
onFocus={(e) => (e.target.style.borderColor = "#667085")}
|
|
165
|
+
onBlur={(e) => (e.target.style.borderColor = "#D0D5DD")}
|
|
166
|
+
className="w-[54px] h-10 text-center text-lg border border-[#D0D5DD] focus:border-[#667085] transition-colors duration-200 outline-none rounded-sm"
|
|
167
|
+
/>
|
|
168
|
+
))}
|
|
169
|
+
</div>
|
|
170
|
+
<div className="flex items-center pt-3">
|
|
171
|
+
<p className="text-common text-[#475467]">Didn't receive a code? </p>
|
|
172
|
+
<span
|
|
173
|
+
className={`text-common text-[#003C71] ml-2 ${
|
|
174
|
+
!isTimerCompleted ? "cursor-not-allowed" : "cursor-pointer"
|
|
175
|
+
}`}
|
|
176
|
+
onClick={handleResend}
|
|
177
|
+
>
|
|
178
|
+
Resend Code
|
|
179
|
+
</span>
|
|
180
|
+
</div>
|
|
181
|
+
<div>
|
|
182
|
+
<span className="text-common text-[#475467]">
|
|
183
|
+
Remaining Time: {formatTime(remainingTime)}
|
|
184
|
+
</span>
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
<div className="flex justify-center items-center text-[#F94110] text-base font-medium ">
|
|
188
|
+
{errors && errors[name] && <span> {handleError(errors)}</span>}
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export default OTPInput;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React, { useRef } from "react";
|
|
2
|
+
|
|
3
|
+
import { RadioProps } from "./commontypes";
|
|
4
|
+
|
|
5
|
+
const Radio: React.FC<RadioProps> = ({
|
|
6
|
+
name,
|
|
7
|
+
id,
|
|
8
|
+
label,
|
|
9
|
+
checked,
|
|
10
|
+
value = undefined,
|
|
11
|
+
handleChange,
|
|
12
|
+
disabled = false,
|
|
13
|
+
customLabel,
|
|
14
|
+
}) => {
|
|
15
|
+
const radioRef = useRef<HTMLInputElement>(null);
|
|
16
|
+
const onChange = (e: any) => {
|
|
17
|
+
handleChange?.(e);
|
|
18
|
+
};
|
|
19
|
+
const labelClick = () => {
|
|
20
|
+
if (radioRef.current) {
|
|
21
|
+
radioRef.current.click();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
return (
|
|
25
|
+
<div
|
|
26
|
+
className={`labels label-text flex items-center justify-start ${
|
|
27
|
+
!customLabel && "gap-0"
|
|
28
|
+
} ${disabled ? " opacity-70" : ""} `}
|
|
29
|
+
>
|
|
30
|
+
<div>
|
|
31
|
+
<label
|
|
32
|
+
className={`radio-button ${
|
|
33
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
|
34
|
+
}`}
|
|
35
|
+
>
|
|
36
|
+
<input
|
|
37
|
+
type="radio"
|
|
38
|
+
checked={checked}
|
|
39
|
+
disabled={disabled}
|
|
40
|
+
ref={radioRef}
|
|
41
|
+
name={name}
|
|
42
|
+
data-testid="app-common-radio"
|
|
43
|
+
value={value}
|
|
44
|
+
id={id}
|
|
45
|
+
onChange={onChange}
|
|
46
|
+
/>
|
|
47
|
+
<span className="radio"></span>
|
|
48
|
+
</label>{" "}
|
|
49
|
+
</div>
|
|
50
|
+
<div
|
|
51
|
+
className={`text-common font-normal cursor-pointer ${
|
|
52
|
+
checked ? "text-secondary" : ""
|
|
53
|
+
}`}
|
|
54
|
+
onClick={labelClick}
|
|
55
|
+
>
|
|
56
|
+
{label}
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default Radio;
|
package/src/commontypes.ts
CHANGED
|
@@ -174,3 +174,13 @@ export interface CheckboxProps {
|
|
|
174
174
|
handleChange?: (e: any) => void;
|
|
175
175
|
value?: string | number;
|
|
176
176
|
}
|
|
177
|
+
export interface RadioProps {
|
|
178
|
+
id: string;
|
|
179
|
+
name: string;
|
|
180
|
+
label?: string;
|
|
181
|
+
value?: string | number;
|
|
182
|
+
checked?: boolean;
|
|
183
|
+
disabled?: boolean;
|
|
184
|
+
customLabel?: boolean;
|
|
185
|
+
handleChange?: (e: any) => void;
|
|
186
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -10,6 +10,8 @@ export type { AutoSuggestionInputProps } from "./commontypes";
|
|
|
10
10
|
export { default as ExpandableAutoComplete } from "./ExpandableAutoComplete";
|
|
11
11
|
export { default as ModernAutoComplete } from "./ReactAutoComplete";
|
|
12
12
|
export { default as ModernCheckBox } from "./ReactCheckbox";
|
|
13
|
+
export { default as ModernOtpInput } from "./ReactOTPInput";
|
|
14
|
+
export { default as ModernRadio } from "./ReactRadioButton";
|
|
13
15
|
export { default as ModernTextArea } from "./ReactTextArea";
|
|
14
16
|
export { default as ModernTextField } from "./ReactTextField";
|
|
15
17
|
export { deepEqual } from "./utilities/deepEqual";
|