@matin_mortazavi/react-otp-input 1.0.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/LICENSE +21 -0
- package/README.md +251 -0
- package/example/index.html +14 -0
- package/example/package.json +23 -0
- package/example/src/App.tsx +137 -0
- package/example/src/index.css +216 -0
- package/example/src/main.tsx +10 -0
- package/example/src/vite-env.d.ts +1 -0
- package/example/tsconfig.json +21 -0
- package/example/tsconfig.node.json +9 -0
- package/example/vite.config.ts +8 -0
- package/example/yarn.lock +787 -0
- package/lib/index.cjs +186 -0
- package/lib/index.cjs.map +1 -0
- package/lib/index.d.ts +39 -0
- package/lib/index.esm.js +180 -0
- package/lib/index.esm.js.map +1 -0
- package/package.json +59 -0
- package/rollup.config.js +19 -0
- package/tsconfig.json +21 -0
package/lib/index.cjs
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
var React = require('react');
|
4
|
+
|
5
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
6
|
+
|
7
|
+
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
8
|
+
|
9
|
+
var isStyleObject = function (obj) { return typeof obj === 'object' && obj !== null; };
|
10
|
+
var OTPInput = function (_a) {
|
11
|
+
var _b = _a.value, value = _b === void 0 ? '' : _b, _c = _a.numInputs, numInputs = _c === void 0 ? 4 : _c, onChange = _a.onChange, onPaste = _a.onPaste, shouldBlurOnFinish = _a.shouldBlurOnFinish, renderInput = _a.renderInput, _d = _a.shouldAutoFocus, shouldAutoFocus = _d === void 0 ? false : _d, _e = _a.inputType, inputType = _e === void 0 ? 'text' : _e, renderSeparator = _a.renderSeparator, placeholder = _a.placeholder, containerStyle = _a.containerStyle, inputStyle = _a.inputStyle, _f = _a.skipDefaultStyles, skipDefaultStyles = _f === void 0 ? false : _f;
|
12
|
+
var _g = React__default["default"].useState(0), activeInput = _g[0], setActiveInput = _g[1];
|
13
|
+
var inputRefs = React__default["default"].useRef([]);
|
14
|
+
var getOTPValue = function () { return (value ? value.toString().split('') : []); };
|
15
|
+
var isInputNum = inputType === 'number' || inputType === 'tel';
|
16
|
+
React__default["default"].useEffect(function () {
|
17
|
+
inputRefs.current = inputRefs.current.slice(0, numInputs);
|
18
|
+
}, [numInputs]);
|
19
|
+
React__default["default"].useEffect(function () {
|
20
|
+
var _a;
|
21
|
+
if (shouldAutoFocus) {
|
22
|
+
(_a = inputRefs.current[0]) === null || _a === void 0 ? void 0 : _a.focus();
|
23
|
+
}
|
24
|
+
}, [shouldAutoFocus]);
|
25
|
+
React__default["default"].useEffect(function () {
|
26
|
+
var _a;
|
27
|
+
if (shouldBlurOnFinish && numInputs === (value === null || value === void 0 ? void 0 : value.length)) {
|
28
|
+
(_a = inputRefs.current[numInputs]) === null || _a === void 0 ? void 0 : _a.blur();
|
29
|
+
}
|
30
|
+
}, [shouldBlurOnFinish, numInputs, value]);
|
31
|
+
var getPlaceholderValue = function () {
|
32
|
+
if (typeof placeholder === 'string') {
|
33
|
+
if (placeholder.length === numInputs) {
|
34
|
+
return placeholder;
|
35
|
+
}
|
36
|
+
if (placeholder.length > 0) {
|
37
|
+
console.error('Length of the placeholder should be equal to the number of inputs.');
|
38
|
+
}
|
39
|
+
}
|
40
|
+
return undefined;
|
41
|
+
};
|
42
|
+
var isInputValueValid = function (value) {
|
43
|
+
var isTypeValid = isInputNum ? !isNaN(Number(value)) : typeof value === 'string';
|
44
|
+
return isTypeValid && value.trim().length === 1;
|
45
|
+
};
|
46
|
+
var handleChange = function (event) {
|
47
|
+
var value = event.target.value;
|
48
|
+
if (isInputValueValid(value)) {
|
49
|
+
changeCodeAtFocus(value);
|
50
|
+
focusInput(activeInput + 1);
|
51
|
+
}
|
52
|
+
};
|
53
|
+
var handleInputChange = function (event) {
|
54
|
+
var nativeEvent = event.nativeEvent;
|
55
|
+
var value = event.target.value;
|
56
|
+
if (!isInputValueValid(value)) {
|
57
|
+
// Pasting from the native autofill suggestion on a mobile device can pass
|
58
|
+
// the pasted string as one long input to one of the cells. This ensures
|
59
|
+
// that we handle the full input and not just the first character.
|
60
|
+
if (value.length === numInputs) {
|
61
|
+
var hasInvalidInput = value.split('').some(function (cellInput) { return !isInputValueValid(cellInput); });
|
62
|
+
if (!hasInvalidInput) {
|
63
|
+
handleOTPChange(value.split(''));
|
64
|
+
focusInput(numInputs - 1);
|
65
|
+
}
|
66
|
+
}
|
67
|
+
// @ts-expect-error - This was added previously to handle and edge case
|
68
|
+
// for dealing with keyCode "229 Unidentified" on Android. Check if this is
|
69
|
+
// still needed.
|
70
|
+
if (nativeEvent.data === null && nativeEvent.inputType === 'deleteContentBackward') {
|
71
|
+
event.preventDefault();
|
72
|
+
changeCodeAtFocus('');
|
73
|
+
focusInput(activeInput - 1);
|
74
|
+
}
|
75
|
+
// Clear the input if it's not valid value because firefox allows
|
76
|
+
// pasting non-numeric characters in a number type input
|
77
|
+
event.target.value = '';
|
78
|
+
}
|
79
|
+
};
|
80
|
+
var handleFocus = function (event) { return function (index) {
|
81
|
+
setActiveInput(index);
|
82
|
+
event.target.select();
|
83
|
+
}; };
|
84
|
+
var handleBlur = function () {
|
85
|
+
setActiveInput(activeInput - 1);
|
86
|
+
};
|
87
|
+
var handleKeyDown = function (event) {
|
88
|
+
var otp = getOTPValue();
|
89
|
+
if ([event.code, event.key].includes('Backspace')) {
|
90
|
+
event.preventDefault();
|
91
|
+
changeCodeAtFocus('');
|
92
|
+
focusInput(activeInput - 1);
|
93
|
+
}
|
94
|
+
else if (event.code === 'Delete') {
|
95
|
+
event.preventDefault();
|
96
|
+
changeCodeAtFocus('');
|
97
|
+
}
|
98
|
+
else if (event.code === 'ArrowLeft') {
|
99
|
+
event.preventDefault();
|
100
|
+
focusInput(activeInput - 1);
|
101
|
+
}
|
102
|
+
else if (event.code === 'ArrowRight') {
|
103
|
+
event.preventDefault();
|
104
|
+
focusInput(activeInput + 1);
|
105
|
+
}
|
106
|
+
// React does not trigger onChange when the same value is entered
|
107
|
+
// again. So we need to focus the next input manually in this case.
|
108
|
+
else if (event.key === otp[activeInput]) {
|
109
|
+
event.preventDefault();
|
110
|
+
focusInput(activeInput + 1);
|
111
|
+
}
|
112
|
+
else if (event.code === 'Spacebar' ||
|
113
|
+
event.code === 'Space' ||
|
114
|
+
event.code === 'ArrowUp' ||
|
115
|
+
event.code === 'ArrowDown') {
|
116
|
+
event.preventDefault();
|
117
|
+
}
|
118
|
+
};
|
119
|
+
var focusInput = function (index) {
|
120
|
+
var _a, _b;
|
121
|
+
var activeInput = Math.max(Math.min(numInputs - 1, index), 0);
|
122
|
+
if (inputRefs.current[activeInput]) {
|
123
|
+
(_a = inputRefs.current[activeInput]) === null || _a === void 0 ? void 0 : _a.focus();
|
124
|
+
(_b = inputRefs.current[activeInput]) === null || _b === void 0 ? void 0 : _b.select();
|
125
|
+
setActiveInput(activeInput);
|
126
|
+
}
|
127
|
+
};
|
128
|
+
var changeCodeAtFocus = function (value) {
|
129
|
+
var otp = getOTPValue();
|
130
|
+
otp[activeInput] = value[0];
|
131
|
+
handleOTPChange(otp);
|
132
|
+
};
|
133
|
+
var handleOTPChange = function (otp) {
|
134
|
+
var otpValue = otp.join('');
|
135
|
+
onChange(otpValue);
|
136
|
+
};
|
137
|
+
var handlePaste = function (event) {
|
138
|
+
var _a;
|
139
|
+
event.preventDefault();
|
140
|
+
var otp = getOTPValue();
|
141
|
+
var nextActiveInput = activeInput;
|
142
|
+
// Get pastedData in an array of max size (num of inputs - current position)
|
143
|
+
var pastedData = event.clipboardData
|
144
|
+
.getData('text/plain')
|
145
|
+
.slice(0, numInputs - activeInput)
|
146
|
+
.split('');
|
147
|
+
// Prevent pasting if the clipboard data contains non-numeric values for number inputs
|
148
|
+
if (isInputNum && pastedData.some(function (value) { return isNaN(Number(value)); })) {
|
149
|
+
return;
|
150
|
+
}
|
151
|
+
// Paste data from focused input onwards
|
152
|
+
for (var pos = 0; pos < numInputs; ++pos) {
|
153
|
+
if (pos >= activeInput && pastedData.length > 0) {
|
154
|
+
otp[pos] = (_a = pastedData.shift()) !== null && _a !== void 0 ? _a : '';
|
155
|
+
nextActiveInput++;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
focusInput(nextActiveInput);
|
159
|
+
handleOTPChange(otp);
|
160
|
+
};
|
161
|
+
return (React__default["default"].createElement("div", { style: Object.assign({ display: 'flex', alignItems: 'center' }, isStyleObject(containerStyle) && containerStyle), className: typeof containerStyle === 'string' ? containerStyle : undefined, onPaste: onPaste }, Array.from({ length: numInputs }, function (_, index) { return index; }).map(function (index) {
|
162
|
+
var _a, _b, _c;
|
163
|
+
return (React__default["default"].createElement(React__default["default"].Fragment, { key: index },
|
164
|
+
renderInput({
|
165
|
+
value: (_a = getOTPValue()[index]) !== null && _a !== void 0 ? _a : '',
|
166
|
+
placeholder: (_c = (_b = getPlaceholderValue()) === null || _b === void 0 ? void 0 : _b[index]) !== null && _c !== void 0 ? _c : undefined,
|
167
|
+
ref: function (element) { return (inputRefs.current[index] = element); },
|
168
|
+
onChange: handleChange,
|
169
|
+
onFocus: function (event) { return handleFocus(event)(index); },
|
170
|
+
onBlur: handleBlur,
|
171
|
+
onKeyDown: handleKeyDown,
|
172
|
+
onPaste: handlePaste,
|
173
|
+
autoComplete: 'off',
|
174
|
+
'aria-label': "Please enter OTP character ".concat(index + 1),
|
175
|
+
style: Object.assign(!skipDefaultStyles ? { width: '1em', textAlign: 'center' } : {}, isStyleObject(inputStyle) ? inputStyle : {}),
|
176
|
+
className: typeof inputStyle === 'string' ? inputStyle : undefined,
|
177
|
+
type: inputType,
|
178
|
+
inputMode: isInputNum ? 'numeric' : 'text',
|
179
|
+
onInput: handleInputChange,
|
180
|
+
}, index),
|
181
|
+
index < numInputs - 1 && (typeof renderSeparator === 'function' ? renderSeparator(index) : renderSeparator)));
|
182
|
+
})));
|
183
|
+
};
|
184
|
+
|
185
|
+
module.exports = OTPInput;
|
186
|
+
//# sourceMappingURL=index.cjs.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/index.tsx"],"sourcesContent":["import React from 'react';\r\n\r\ntype AllowedInputTypes = 'password' | 'text' | 'number' | 'tel';\r\n\r\ntype InputProps = Required<\r\n Pick<\r\n React.InputHTMLAttributes<HTMLInputElement>,\r\n | 'value'\r\n | 'onChange'\r\n | 'onFocus'\r\n | 'onBlur'\r\n | 'onKeyDown'\r\n | 'onPaste'\r\n | 'aria-label'\r\n | 'autoComplete'\r\n | 'style'\r\n | 'inputMode'\r\n | 'onInput'\r\n > & {\r\n ref: React.RefCallback<HTMLInputElement>;\r\n placeholder: string | undefined;\r\n className: string | undefined;\r\n type: AllowedInputTypes;\r\n }\r\n>;\r\n\r\ninterface OTPInputProps {\r\n /** Value of the OTP input */\r\n value?: string;\r\n /** Number of OTP inputs to be rendered */\r\n numInputs?: number;\r\n /** Blur after last char entered (close keyboard on mobile) */\r\n shouldBlurOnFinish?: boolean;\r\n /** Callback to be called when the OTP value changes */\r\n onChange: (otp: string) => void;\r\n /** Callback to be called when pasting content into the component */\r\n onPaste?: (event: React.ClipboardEvent<HTMLDivElement>) => void;\r\n /** Function to render the input */\r\n renderInput: (inputProps: InputProps, index: number) => React.ReactNode;\r\n /** Whether the first input should be auto focused */\r\n shouldAutoFocus?: boolean;\r\n /** Placeholder for the inputs */\r\n placeholder?: string;\r\n /** Function to render the separator */\r\n renderSeparator?: ((index: number) => React.ReactNode) | React.ReactNode;\r\n /** Style for the container */\r\n containerStyle?: React.CSSProperties | string;\r\n /** Style for the input */\r\n inputStyle?: React.CSSProperties | string;\r\n /** The type that will be passed to the input being rendered */\r\n inputType?: AllowedInputTypes;\r\n /** Do not apply the default styles to the inputs, will be removed in future versions */\r\n skipDefaultStyles?: boolean; // TODO: Remove in next major release\r\n}\r\n\r\nconst isStyleObject = (obj: unknown) => typeof obj === 'object' && obj !== null;\r\n\r\nconst OTPInput = ({\r\n value = '',\r\n numInputs = 4,\r\n onChange,\r\n onPaste,\r\n shouldBlurOnFinish,\r\n renderInput,\r\n shouldAutoFocus = false,\r\n inputType = 'text',\r\n renderSeparator,\r\n placeholder,\r\n containerStyle,\r\n inputStyle,\r\n skipDefaultStyles = false,\r\n}: OTPInputProps) => {\r\n const [activeInput, setActiveInput] = React.useState(0);\r\n const inputRefs = React.useRef<Array<HTMLInputElement | null>>([]);\r\n\r\n const getOTPValue = () => (value ? value.toString().split('') : []);\r\n\r\n const isInputNum = inputType === 'number' || inputType === 'tel';\r\n\r\n React.useEffect(() => {\r\n inputRefs.current = inputRefs.current.slice(0, numInputs);\r\n }, [numInputs]);\r\n\r\n React.useEffect(() => {\r\n if (shouldAutoFocus) {\r\n inputRefs.current[0]?.focus();\r\n }\r\n }, [shouldAutoFocus]);\r\n\r\n React.useEffect(() => {\r\n if (shouldBlurOnFinish && numInputs === value?.length) {\r\n inputRefs.current[numInputs]?.blur();\r\n }\r\n }, [shouldBlurOnFinish, numInputs, value]);\r\n\r\n const getPlaceholderValue = () => {\r\n if (typeof placeholder === 'string') {\r\n if (placeholder.length === numInputs) {\r\n return placeholder;\r\n }\r\n\r\n if (placeholder.length > 0) {\r\n console.error('Length of the placeholder should be equal to the number of inputs.');\r\n }\r\n }\r\n return undefined;\r\n };\r\n\r\n const isInputValueValid = (value: string) => {\r\n const isTypeValid = isInputNum ? !isNaN(Number(value)) : typeof value === 'string';\r\n return isTypeValid && value.trim().length === 1;\r\n };\r\n\r\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\r\n const { value } = event.target;\r\n\r\n if (isInputValueValid(value)) {\r\n changeCodeAtFocus(value);\r\n focusInput(activeInput + 1);\r\n }\r\n };\r\n\r\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\r\n const { nativeEvent } = event;\r\n const value = event.target.value;\r\n\r\n if (!isInputValueValid(value)) {\r\n // Pasting from the native autofill suggestion on a mobile device can pass\r\n // the pasted string as one long input to one of the cells. This ensures\r\n // that we handle the full input and not just the first character.\r\n if (value.length === numInputs) {\r\n const hasInvalidInput = value.split('').some((cellInput) => !isInputValueValid(cellInput));\r\n if (!hasInvalidInput) {\r\n handleOTPChange(value.split(''));\r\n focusInput(numInputs - 1);\r\n }\r\n }\r\n\r\n // @ts-expect-error - This was added previously to handle and edge case\r\n // for dealing with keyCode \"229 Unidentified\" on Android. Check if this is\r\n // still needed.\r\n if (nativeEvent.data === null && nativeEvent.inputType === 'deleteContentBackward') {\r\n event.preventDefault();\r\n changeCodeAtFocus('');\r\n focusInput(activeInput - 1);\r\n }\r\n\r\n // Clear the input if it's not valid value because firefox allows\r\n // pasting non-numeric characters in a number type input\r\n event.target.value = '';\r\n }\r\n };\r\n\r\n const handleFocus = (event: React.FocusEvent<HTMLInputElement>) => (index: number) => {\r\n setActiveInput(index);\r\n event.target.select();\r\n };\r\n\r\n const handleBlur = () => {\r\n setActiveInput(activeInput - 1);\r\n };\r\n\r\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\r\n const otp = getOTPValue();\r\n if ([event.code, event.key].includes('Backspace')) {\r\n event.preventDefault();\r\n changeCodeAtFocus('');\r\n focusInput(activeInput - 1);\r\n } else if (event.code === 'Delete') {\r\n event.preventDefault();\r\n changeCodeAtFocus('');\r\n } else if (event.code === 'ArrowLeft') {\r\n event.preventDefault();\r\n focusInput(activeInput - 1);\r\n } else if (event.code === 'ArrowRight') {\r\n event.preventDefault();\r\n focusInput(activeInput + 1);\r\n }\r\n // React does not trigger onChange when the same value is entered\r\n // again. So we need to focus the next input manually in this case.\r\n else if (event.key === otp[activeInput]) {\r\n event.preventDefault();\r\n focusInput(activeInput + 1);\r\n } else if (\r\n event.code === 'Spacebar' ||\r\n event.code === 'Space' ||\r\n event.code === 'ArrowUp' ||\r\n event.code === 'ArrowDown'\r\n ) {\r\n event.preventDefault();\r\n }\r\n };\r\n\r\n const focusInput = (index: number) => {\r\n const activeInput = Math.max(Math.min(numInputs - 1, index), 0);\r\n\r\n if (inputRefs.current[activeInput]) {\r\n inputRefs.current[activeInput]?.focus();\r\n inputRefs.current[activeInput]?.select();\r\n setActiveInput(activeInput);\r\n }\r\n };\r\n\r\n const changeCodeAtFocus = (value: string) => {\r\n const otp = getOTPValue();\r\n otp[activeInput] = value[0];\r\n handleOTPChange(otp);\r\n };\r\n\r\n const handleOTPChange = (otp: Array<string>) => {\r\n const otpValue = otp.join('');\r\n onChange(otpValue);\r\n };\r\n\r\n const handlePaste = (event: React.ClipboardEvent<HTMLInputElement>) => {\r\n event.preventDefault();\r\n\r\n const otp = getOTPValue();\r\n let nextActiveInput = activeInput;\r\n\r\n // Get pastedData in an array of max size (num of inputs - current position)\r\n const pastedData = event.clipboardData\r\n .getData('text/plain')\r\n .slice(0, numInputs - activeInput)\r\n .split('');\r\n\r\n // Prevent pasting if the clipboard data contains non-numeric values for number inputs\r\n if (isInputNum && pastedData.some((value) => isNaN(Number(value)))) {\r\n return;\r\n }\r\n\r\n // Paste data from focused input onwards\r\n for (let pos = 0; pos < numInputs; ++pos) {\r\n if (pos >= activeInput && pastedData.length > 0) {\r\n otp[pos] = pastedData.shift() ?? '';\r\n nextActiveInput++;\r\n }\r\n }\r\n\r\n focusInput(nextActiveInput);\r\n handleOTPChange(otp);\r\n };\r\n\r\n return (\r\n <div\r\n style={Object.assign({ display: 'flex', alignItems: 'center' }, isStyleObject(containerStyle) && containerStyle)}\r\n className={typeof containerStyle === 'string' ? containerStyle : undefined}\r\n onPaste={onPaste}\r\n >\r\n {Array.from({ length: numInputs }, (_, index) => index).map((index) => (\r\n <React.Fragment key={index}>\r\n {renderInput(\r\n {\r\n value: getOTPValue()[index] ?? '',\r\n placeholder: getPlaceholderValue()?.[index] ?? undefined,\r\n ref: (element) => (inputRefs.current[index] = element),\r\n onChange: handleChange,\r\n onFocus: (event) => handleFocus(event)(index),\r\n onBlur: handleBlur,\r\n onKeyDown: handleKeyDown,\r\n onPaste: handlePaste,\r\n autoComplete: 'off',\r\n 'aria-label': `Please enter OTP character ${index + 1}`,\r\n style: Object.assign(\r\n !skipDefaultStyles ? ({ width: '1em', textAlign: 'center' } as const) : {},\r\n isStyleObject(inputStyle) ? inputStyle : {}\r\n ),\r\n className: typeof inputStyle === 'string' ? inputStyle : undefined,\r\n type: inputType,\r\n inputMode: isInputNum ? 'numeric' : 'text',\r\n onInput: handleInputChange,\r\n },\r\n index\r\n )}\r\n {index < numInputs - 1 && (typeof renderSeparator === 'function' ? renderSeparator(index) : renderSeparator)}\r\n </React.Fragment>\r\n ))}\r\n </div>\r\n );\r\n};\r\n\r\nexport type { OTPInputProps, InputProps, AllowedInputTypes };\r\nexport default OTPInput;\r\n"],"names":["React"],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
type AllowedInputTypes = 'password' | 'text' | 'number' | 'tel';
|
3
|
+
type InputProps = Required<Pick<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'onFocus' | 'onBlur' | 'onKeyDown' | 'onPaste' | 'aria-label' | 'autoComplete' | 'style' | 'inputMode' | 'onInput'> & {
|
4
|
+
ref: React.RefCallback<HTMLInputElement>;
|
5
|
+
placeholder: string | undefined;
|
6
|
+
className: string | undefined;
|
7
|
+
type: AllowedInputTypes;
|
8
|
+
}>;
|
9
|
+
interface OTPInputProps {
|
10
|
+
/** Value of the OTP input */
|
11
|
+
value?: string;
|
12
|
+
/** Number of OTP inputs to be rendered */
|
13
|
+
numInputs?: number;
|
14
|
+
/** Blur after last char entered (close keyboard on mobile) */
|
15
|
+
shouldBlurOnFinish?: boolean;
|
16
|
+
/** Callback to be called when the OTP value changes */
|
17
|
+
onChange: (otp: string) => void;
|
18
|
+
/** Callback to be called when pasting content into the component */
|
19
|
+
onPaste?: (event: React.ClipboardEvent<HTMLDivElement>) => void;
|
20
|
+
/** Function to render the input */
|
21
|
+
renderInput: (inputProps: InputProps, index: number) => React.ReactNode;
|
22
|
+
/** Whether the first input should be auto focused */
|
23
|
+
shouldAutoFocus?: boolean;
|
24
|
+
/** Placeholder for the inputs */
|
25
|
+
placeholder?: string;
|
26
|
+
/** Function to render the separator */
|
27
|
+
renderSeparator?: ((index: number) => React.ReactNode) | React.ReactNode;
|
28
|
+
/** Style for the container */
|
29
|
+
containerStyle?: React.CSSProperties | string;
|
30
|
+
/** Style for the input */
|
31
|
+
inputStyle?: React.CSSProperties | string;
|
32
|
+
/** The type that will be passed to the input being rendered */
|
33
|
+
inputType?: AllowedInputTypes;
|
34
|
+
/** Do not apply the default styles to the inputs, will be removed in future versions */
|
35
|
+
skipDefaultStyles?: boolean;
|
36
|
+
}
|
37
|
+
declare const OTPInput: ({ value, numInputs, onChange, onPaste, shouldBlurOnFinish, renderInput, shouldAutoFocus, inputType, renderSeparator, placeholder, containerStyle, inputStyle, skipDefaultStyles, }: OTPInputProps) => JSX.Element;
|
38
|
+
export type { OTPInputProps, InputProps, AllowedInputTypes };
|
39
|
+
export default OTPInput;
|
package/lib/index.esm.js
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
var isStyleObject = function (obj) { return typeof obj === 'object' && obj !== null; };
|
4
|
+
var OTPInput = function (_a) {
|
5
|
+
var _b = _a.value, value = _b === void 0 ? '' : _b, _c = _a.numInputs, numInputs = _c === void 0 ? 4 : _c, onChange = _a.onChange, onPaste = _a.onPaste, shouldBlurOnFinish = _a.shouldBlurOnFinish, renderInput = _a.renderInput, _d = _a.shouldAutoFocus, shouldAutoFocus = _d === void 0 ? false : _d, _e = _a.inputType, inputType = _e === void 0 ? 'text' : _e, renderSeparator = _a.renderSeparator, placeholder = _a.placeholder, containerStyle = _a.containerStyle, inputStyle = _a.inputStyle, _f = _a.skipDefaultStyles, skipDefaultStyles = _f === void 0 ? false : _f;
|
6
|
+
var _g = React.useState(0), activeInput = _g[0], setActiveInput = _g[1];
|
7
|
+
var inputRefs = React.useRef([]);
|
8
|
+
var getOTPValue = function () { return (value ? value.toString().split('') : []); };
|
9
|
+
var isInputNum = inputType === 'number' || inputType === 'tel';
|
10
|
+
React.useEffect(function () {
|
11
|
+
inputRefs.current = inputRefs.current.slice(0, numInputs);
|
12
|
+
}, [numInputs]);
|
13
|
+
React.useEffect(function () {
|
14
|
+
var _a;
|
15
|
+
if (shouldAutoFocus) {
|
16
|
+
(_a = inputRefs.current[0]) === null || _a === void 0 ? void 0 : _a.focus();
|
17
|
+
}
|
18
|
+
}, [shouldAutoFocus]);
|
19
|
+
React.useEffect(function () {
|
20
|
+
var _a;
|
21
|
+
if (shouldBlurOnFinish && numInputs === (value === null || value === void 0 ? void 0 : value.length)) {
|
22
|
+
(_a = inputRefs.current[numInputs]) === null || _a === void 0 ? void 0 : _a.blur();
|
23
|
+
}
|
24
|
+
}, [shouldBlurOnFinish, numInputs, value]);
|
25
|
+
var getPlaceholderValue = function () {
|
26
|
+
if (typeof placeholder === 'string') {
|
27
|
+
if (placeholder.length === numInputs) {
|
28
|
+
return placeholder;
|
29
|
+
}
|
30
|
+
if (placeholder.length > 0) {
|
31
|
+
console.error('Length of the placeholder should be equal to the number of inputs.');
|
32
|
+
}
|
33
|
+
}
|
34
|
+
return undefined;
|
35
|
+
};
|
36
|
+
var isInputValueValid = function (value) {
|
37
|
+
var isTypeValid = isInputNum ? !isNaN(Number(value)) : typeof value === 'string';
|
38
|
+
return isTypeValid && value.trim().length === 1;
|
39
|
+
};
|
40
|
+
var handleChange = function (event) {
|
41
|
+
var value = event.target.value;
|
42
|
+
if (isInputValueValid(value)) {
|
43
|
+
changeCodeAtFocus(value);
|
44
|
+
focusInput(activeInput + 1);
|
45
|
+
}
|
46
|
+
};
|
47
|
+
var handleInputChange = function (event) {
|
48
|
+
var nativeEvent = event.nativeEvent;
|
49
|
+
var value = event.target.value;
|
50
|
+
if (!isInputValueValid(value)) {
|
51
|
+
// Pasting from the native autofill suggestion on a mobile device can pass
|
52
|
+
// the pasted string as one long input to one of the cells. This ensures
|
53
|
+
// that we handle the full input and not just the first character.
|
54
|
+
if (value.length === numInputs) {
|
55
|
+
var hasInvalidInput = value.split('').some(function (cellInput) { return !isInputValueValid(cellInput); });
|
56
|
+
if (!hasInvalidInput) {
|
57
|
+
handleOTPChange(value.split(''));
|
58
|
+
focusInput(numInputs - 1);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
// @ts-expect-error - This was added previously to handle and edge case
|
62
|
+
// for dealing with keyCode "229 Unidentified" on Android. Check if this is
|
63
|
+
// still needed.
|
64
|
+
if (nativeEvent.data === null && nativeEvent.inputType === 'deleteContentBackward') {
|
65
|
+
event.preventDefault();
|
66
|
+
changeCodeAtFocus('');
|
67
|
+
focusInput(activeInput - 1);
|
68
|
+
}
|
69
|
+
// Clear the input if it's not valid value because firefox allows
|
70
|
+
// pasting non-numeric characters in a number type input
|
71
|
+
event.target.value = '';
|
72
|
+
}
|
73
|
+
};
|
74
|
+
var handleFocus = function (event) { return function (index) {
|
75
|
+
setActiveInput(index);
|
76
|
+
event.target.select();
|
77
|
+
}; };
|
78
|
+
var handleBlur = function () {
|
79
|
+
setActiveInput(activeInput - 1);
|
80
|
+
};
|
81
|
+
var handleKeyDown = function (event) {
|
82
|
+
var otp = getOTPValue();
|
83
|
+
if ([event.code, event.key].includes('Backspace')) {
|
84
|
+
event.preventDefault();
|
85
|
+
changeCodeAtFocus('');
|
86
|
+
focusInput(activeInput - 1);
|
87
|
+
}
|
88
|
+
else if (event.code === 'Delete') {
|
89
|
+
event.preventDefault();
|
90
|
+
changeCodeAtFocus('');
|
91
|
+
}
|
92
|
+
else if (event.code === 'ArrowLeft') {
|
93
|
+
event.preventDefault();
|
94
|
+
focusInput(activeInput - 1);
|
95
|
+
}
|
96
|
+
else if (event.code === 'ArrowRight') {
|
97
|
+
event.preventDefault();
|
98
|
+
focusInput(activeInput + 1);
|
99
|
+
}
|
100
|
+
// React does not trigger onChange when the same value is entered
|
101
|
+
// again. So we need to focus the next input manually in this case.
|
102
|
+
else if (event.key === otp[activeInput]) {
|
103
|
+
event.preventDefault();
|
104
|
+
focusInput(activeInput + 1);
|
105
|
+
}
|
106
|
+
else if (event.code === 'Spacebar' ||
|
107
|
+
event.code === 'Space' ||
|
108
|
+
event.code === 'ArrowUp' ||
|
109
|
+
event.code === 'ArrowDown') {
|
110
|
+
event.preventDefault();
|
111
|
+
}
|
112
|
+
};
|
113
|
+
var focusInput = function (index) {
|
114
|
+
var _a, _b;
|
115
|
+
var activeInput = Math.max(Math.min(numInputs - 1, index), 0);
|
116
|
+
if (inputRefs.current[activeInput]) {
|
117
|
+
(_a = inputRefs.current[activeInput]) === null || _a === void 0 ? void 0 : _a.focus();
|
118
|
+
(_b = inputRefs.current[activeInput]) === null || _b === void 0 ? void 0 : _b.select();
|
119
|
+
setActiveInput(activeInput);
|
120
|
+
}
|
121
|
+
};
|
122
|
+
var changeCodeAtFocus = function (value) {
|
123
|
+
var otp = getOTPValue();
|
124
|
+
otp[activeInput] = value[0];
|
125
|
+
handleOTPChange(otp);
|
126
|
+
};
|
127
|
+
var handleOTPChange = function (otp) {
|
128
|
+
var otpValue = otp.join('');
|
129
|
+
onChange(otpValue);
|
130
|
+
};
|
131
|
+
var handlePaste = function (event) {
|
132
|
+
var _a;
|
133
|
+
event.preventDefault();
|
134
|
+
var otp = getOTPValue();
|
135
|
+
var nextActiveInput = activeInput;
|
136
|
+
// Get pastedData in an array of max size (num of inputs - current position)
|
137
|
+
var pastedData = event.clipboardData
|
138
|
+
.getData('text/plain')
|
139
|
+
.slice(0, numInputs - activeInput)
|
140
|
+
.split('');
|
141
|
+
// Prevent pasting if the clipboard data contains non-numeric values for number inputs
|
142
|
+
if (isInputNum && pastedData.some(function (value) { return isNaN(Number(value)); })) {
|
143
|
+
return;
|
144
|
+
}
|
145
|
+
// Paste data from focused input onwards
|
146
|
+
for (var pos = 0; pos < numInputs; ++pos) {
|
147
|
+
if (pos >= activeInput && pastedData.length > 0) {
|
148
|
+
otp[pos] = (_a = pastedData.shift()) !== null && _a !== void 0 ? _a : '';
|
149
|
+
nextActiveInput++;
|
150
|
+
}
|
151
|
+
}
|
152
|
+
focusInput(nextActiveInput);
|
153
|
+
handleOTPChange(otp);
|
154
|
+
};
|
155
|
+
return (React.createElement("div", { style: Object.assign({ display: 'flex', alignItems: 'center' }, isStyleObject(containerStyle) && containerStyle), className: typeof containerStyle === 'string' ? containerStyle : undefined, onPaste: onPaste }, Array.from({ length: numInputs }, function (_, index) { return index; }).map(function (index) {
|
156
|
+
var _a, _b, _c;
|
157
|
+
return (React.createElement(React.Fragment, { key: index },
|
158
|
+
renderInput({
|
159
|
+
value: (_a = getOTPValue()[index]) !== null && _a !== void 0 ? _a : '',
|
160
|
+
placeholder: (_c = (_b = getPlaceholderValue()) === null || _b === void 0 ? void 0 : _b[index]) !== null && _c !== void 0 ? _c : undefined,
|
161
|
+
ref: function (element) { return (inputRefs.current[index] = element); },
|
162
|
+
onChange: handleChange,
|
163
|
+
onFocus: function (event) { return handleFocus(event)(index); },
|
164
|
+
onBlur: handleBlur,
|
165
|
+
onKeyDown: handleKeyDown,
|
166
|
+
onPaste: handlePaste,
|
167
|
+
autoComplete: 'off',
|
168
|
+
'aria-label': "Please enter OTP character ".concat(index + 1),
|
169
|
+
style: Object.assign(!skipDefaultStyles ? { width: '1em', textAlign: 'center' } : {}, isStyleObject(inputStyle) ? inputStyle : {}),
|
170
|
+
className: typeof inputStyle === 'string' ? inputStyle : undefined,
|
171
|
+
type: inputType,
|
172
|
+
inputMode: isInputNum ? 'numeric' : 'text',
|
173
|
+
onInput: handleInputChange,
|
174
|
+
}, index),
|
175
|
+
index < numInputs - 1 && (typeof renderSeparator === 'function' ? renderSeparator(index) : renderSeparator)));
|
176
|
+
})));
|
177
|
+
};
|
178
|
+
|
179
|
+
export { OTPInput as default };
|
180
|
+
//# sourceMappingURL=index.esm.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../../src/index.tsx"],"sourcesContent":["import React from 'react';\r\n\r\ntype AllowedInputTypes = 'password' | 'text' | 'number' | 'tel';\r\n\r\ntype InputProps = Required<\r\n Pick<\r\n React.InputHTMLAttributes<HTMLInputElement>,\r\n | 'value'\r\n | 'onChange'\r\n | 'onFocus'\r\n | 'onBlur'\r\n | 'onKeyDown'\r\n | 'onPaste'\r\n | 'aria-label'\r\n | 'autoComplete'\r\n | 'style'\r\n | 'inputMode'\r\n | 'onInput'\r\n > & {\r\n ref: React.RefCallback<HTMLInputElement>;\r\n placeholder: string | undefined;\r\n className: string | undefined;\r\n type: AllowedInputTypes;\r\n }\r\n>;\r\n\r\ninterface OTPInputProps {\r\n /** Value of the OTP input */\r\n value?: string;\r\n /** Number of OTP inputs to be rendered */\r\n numInputs?: number;\r\n /** Blur after last char entered (close keyboard on mobile) */\r\n shouldBlurOnFinish?: boolean;\r\n /** Callback to be called when the OTP value changes */\r\n onChange: (otp: string) => void;\r\n /** Callback to be called when pasting content into the component */\r\n onPaste?: (event: React.ClipboardEvent<HTMLDivElement>) => void;\r\n /** Function to render the input */\r\n renderInput: (inputProps: InputProps, index: number) => React.ReactNode;\r\n /** Whether the first input should be auto focused */\r\n shouldAutoFocus?: boolean;\r\n /** Placeholder for the inputs */\r\n placeholder?: string;\r\n /** Function to render the separator */\r\n renderSeparator?: ((index: number) => React.ReactNode) | React.ReactNode;\r\n /** Style for the container */\r\n containerStyle?: React.CSSProperties | string;\r\n /** Style for the input */\r\n inputStyle?: React.CSSProperties | string;\r\n /** The type that will be passed to the input being rendered */\r\n inputType?: AllowedInputTypes;\r\n /** Do not apply the default styles to the inputs, will be removed in future versions */\r\n skipDefaultStyles?: boolean; // TODO: Remove in next major release\r\n}\r\n\r\nconst isStyleObject = (obj: unknown) => typeof obj === 'object' && obj !== null;\r\n\r\nconst OTPInput = ({\r\n value = '',\r\n numInputs = 4,\r\n onChange,\r\n onPaste,\r\n shouldBlurOnFinish,\r\n renderInput,\r\n shouldAutoFocus = false,\r\n inputType = 'text',\r\n renderSeparator,\r\n placeholder,\r\n containerStyle,\r\n inputStyle,\r\n skipDefaultStyles = false,\r\n}: OTPInputProps) => {\r\n const [activeInput, setActiveInput] = React.useState(0);\r\n const inputRefs = React.useRef<Array<HTMLInputElement | null>>([]);\r\n\r\n const getOTPValue = () => (value ? value.toString().split('') : []);\r\n\r\n const isInputNum = inputType === 'number' || inputType === 'tel';\r\n\r\n React.useEffect(() => {\r\n inputRefs.current = inputRefs.current.slice(0, numInputs);\r\n }, [numInputs]);\r\n\r\n React.useEffect(() => {\r\n if (shouldAutoFocus) {\r\n inputRefs.current[0]?.focus();\r\n }\r\n }, [shouldAutoFocus]);\r\n\r\n React.useEffect(() => {\r\n if (shouldBlurOnFinish && numInputs === value?.length) {\r\n inputRefs.current[numInputs]?.blur();\r\n }\r\n }, [shouldBlurOnFinish, numInputs, value]);\r\n\r\n const getPlaceholderValue = () => {\r\n if (typeof placeholder === 'string') {\r\n if (placeholder.length === numInputs) {\r\n return placeholder;\r\n }\r\n\r\n if (placeholder.length > 0) {\r\n console.error('Length of the placeholder should be equal to the number of inputs.');\r\n }\r\n }\r\n return undefined;\r\n };\r\n\r\n const isInputValueValid = (value: string) => {\r\n const isTypeValid = isInputNum ? !isNaN(Number(value)) : typeof value === 'string';\r\n return isTypeValid && value.trim().length === 1;\r\n };\r\n\r\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\r\n const { value } = event.target;\r\n\r\n if (isInputValueValid(value)) {\r\n changeCodeAtFocus(value);\r\n focusInput(activeInput + 1);\r\n }\r\n };\r\n\r\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\r\n const { nativeEvent } = event;\r\n const value = event.target.value;\r\n\r\n if (!isInputValueValid(value)) {\r\n // Pasting from the native autofill suggestion on a mobile device can pass\r\n // the pasted string as one long input to one of the cells. This ensures\r\n // that we handle the full input and not just the first character.\r\n if (value.length === numInputs) {\r\n const hasInvalidInput = value.split('').some((cellInput) => !isInputValueValid(cellInput));\r\n if (!hasInvalidInput) {\r\n handleOTPChange(value.split(''));\r\n focusInput(numInputs - 1);\r\n }\r\n }\r\n\r\n // @ts-expect-error - This was added previously to handle and edge case\r\n // for dealing with keyCode \"229 Unidentified\" on Android. Check if this is\r\n // still needed.\r\n if (nativeEvent.data === null && nativeEvent.inputType === 'deleteContentBackward') {\r\n event.preventDefault();\r\n changeCodeAtFocus('');\r\n focusInput(activeInput - 1);\r\n }\r\n\r\n // Clear the input if it's not valid value because firefox allows\r\n // pasting non-numeric characters in a number type input\r\n event.target.value = '';\r\n }\r\n };\r\n\r\n const handleFocus = (event: React.FocusEvent<HTMLInputElement>) => (index: number) => {\r\n setActiveInput(index);\r\n event.target.select();\r\n };\r\n\r\n const handleBlur = () => {\r\n setActiveInput(activeInput - 1);\r\n };\r\n\r\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\r\n const otp = getOTPValue();\r\n if ([event.code, event.key].includes('Backspace')) {\r\n event.preventDefault();\r\n changeCodeAtFocus('');\r\n focusInput(activeInput - 1);\r\n } else if (event.code === 'Delete') {\r\n event.preventDefault();\r\n changeCodeAtFocus('');\r\n } else if (event.code === 'ArrowLeft') {\r\n event.preventDefault();\r\n focusInput(activeInput - 1);\r\n } else if (event.code === 'ArrowRight') {\r\n event.preventDefault();\r\n focusInput(activeInput + 1);\r\n }\r\n // React does not trigger onChange when the same value is entered\r\n // again. So we need to focus the next input manually in this case.\r\n else if (event.key === otp[activeInput]) {\r\n event.preventDefault();\r\n focusInput(activeInput + 1);\r\n } else if (\r\n event.code === 'Spacebar' ||\r\n event.code === 'Space' ||\r\n event.code === 'ArrowUp' ||\r\n event.code === 'ArrowDown'\r\n ) {\r\n event.preventDefault();\r\n }\r\n };\r\n\r\n const focusInput = (index: number) => {\r\n const activeInput = Math.max(Math.min(numInputs - 1, index), 0);\r\n\r\n if (inputRefs.current[activeInput]) {\r\n inputRefs.current[activeInput]?.focus();\r\n inputRefs.current[activeInput]?.select();\r\n setActiveInput(activeInput);\r\n }\r\n };\r\n\r\n const changeCodeAtFocus = (value: string) => {\r\n const otp = getOTPValue();\r\n otp[activeInput] = value[0];\r\n handleOTPChange(otp);\r\n };\r\n\r\n const handleOTPChange = (otp: Array<string>) => {\r\n const otpValue = otp.join('');\r\n onChange(otpValue);\r\n };\r\n\r\n const handlePaste = (event: React.ClipboardEvent<HTMLInputElement>) => {\r\n event.preventDefault();\r\n\r\n const otp = getOTPValue();\r\n let nextActiveInput = activeInput;\r\n\r\n // Get pastedData in an array of max size (num of inputs - current position)\r\n const pastedData = event.clipboardData\r\n .getData('text/plain')\r\n .slice(0, numInputs - activeInput)\r\n .split('');\r\n\r\n // Prevent pasting if the clipboard data contains non-numeric values for number inputs\r\n if (isInputNum && pastedData.some((value) => isNaN(Number(value)))) {\r\n return;\r\n }\r\n\r\n // Paste data from focused input onwards\r\n for (let pos = 0; pos < numInputs; ++pos) {\r\n if (pos >= activeInput && pastedData.length > 0) {\r\n otp[pos] = pastedData.shift() ?? '';\r\n nextActiveInput++;\r\n }\r\n }\r\n\r\n focusInput(nextActiveInput);\r\n handleOTPChange(otp);\r\n };\r\n\r\n return (\r\n <div\r\n style={Object.assign({ display: 'flex', alignItems: 'center' }, isStyleObject(containerStyle) && containerStyle)}\r\n className={typeof containerStyle === 'string' ? containerStyle : undefined}\r\n onPaste={onPaste}\r\n >\r\n {Array.from({ length: numInputs }, (_, index) => index).map((index) => (\r\n <React.Fragment key={index}>\r\n {renderInput(\r\n {\r\n value: getOTPValue()[index] ?? '',\r\n placeholder: getPlaceholderValue()?.[index] ?? undefined,\r\n ref: (element) => (inputRefs.current[index] = element),\r\n onChange: handleChange,\r\n onFocus: (event) => handleFocus(event)(index),\r\n onBlur: handleBlur,\r\n onKeyDown: handleKeyDown,\r\n onPaste: handlePaste,\r\n autoComplete: 'off',\r\n 'aria-label': `Please enter OTP character ${index + 1}`,\r\n style: Object.assign(\r\n !skipDefaultStyles ? ({ width: '1em', textAlign: 'center' } as const) : {},\r\n isStyleObject(inputStyle) ? inputStyle : {}\r\n ),\r\n className: typeof inputStyle === 'string' ? inputStyle : undefined,\r\n type: inputType,\r\n inputMode: isInputNum ? 'numeric' : 'text',\r\n onInput: handleInputChange,\r\n },\r\n index\r\n )}\r\n {index < numInputs - 1 && (typeof renderSeparator === 'function' ? renderSeparator(index) : renderSeparator)}\r\n </React.Fragment>\r\n ))}\r\n </div>\r\n );\r\n};\r\n\r\nexport type { OTPInputProps, InputProps, AllowedInputTypes };\r\nexport default OTPInput;\r\n"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
{
|
2
|
+
"name": "@matin_mortazavi/react-otp-input",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "A fully customizable, one-time password input component for the web built with React",
|
5
|
+
"main": "lib/index.js",
|
6
|
+
"module": "lib/index.esm.js",
|
7
|
+
"types": "lib/index.d.ts",
|
8
|
+
"scripts": {
|
9
|
+
"build": "rollup -c",
|
10
|
+
"format": "prettier --write \"**/*.{html,css,js,jsx}\"",
|
11
|
+
"lint": "eslint 'src/**/*.{js,jsx}' --quiet",
|
12
|
+
"lint:fix": "eslint 'src/**/*.{js,jsx}' --fix",
|
13
|
+
"prepublishOnly": "rm -rf dist && npm run build",
|
14
|
+
"example:build": "cd example && yarn && yarn build"
|
15
|
+
},
|
16
|
+
"keywords": [
|
17
|
+
"otp",
|
18
|
+
"input",
|
19
|
+
"code",
|
20
|
+
"passcode",
|
21
|
+
"component"
|
22
|
+
],
|
23
|
+
"peerDependencies": {
|
24
|
+
"react": ">=16.8.6 || ^17.0.0 || ^18.0.0",
|
25
|
+
"react-dom": ">=16.8.6 || ^17.0.0 || ^18.0.0"
|
26
|
+
},
|
27
|
+
"devDependencies": {
|
28
|
+
"@rollup/plugin-typescript": "11.0.0",
|
29
|
+
"@types/react": "18.0.28",
|
30
|
+
"@types/react-dom": "18.0.11",
|
31
|
+
"@typescript-eslint/eslint-plugin": "5.55.0",
|
32
|
+
"@typescript-eslint/parser": "5.55.0",
|
33
|
+
"concurrently": "6.2.0",
|
34
|
+
"eslint": "7.27.0",
|
35
|
+
"eslint-config-prettier": "8.3.0",
|
36
|
+
"eslint-plugin-import": "2.23.3",
|
37
|
+
"eslint-plugin-jsx-a11y": "6.4.1",
|
38
|
+
"eslint-plugin-prettier": "3.4.0",
|
39
|
+
"eslint-plugin-react": "7.23.2",
|
40
|
+
"eslint-plugin-react-hooks": "4.2.0",
|
41
|
+
"gh-pages": "3.2.3",
|
42
|
+
"prettier": "2.3.0",
|
43
|
+
"react": "18.2.0",
|
44
|
+
"react-dom": "18.2.0",
|
45
|
+
"rollup": "2.79.1",
|
46
|
+
"rollup-plugin-peer-deps-external": "2.2.4",
|
47
|
+
"typescript": "5.0.2"
|
48
|
+
},
|
49
|
+
"author": "Matin Mortazavi",
|
50
|
+
"license": "MIT",
|
51
|
+
"homepage": "https://github.com/matin-mortazavi/react-otp-input",
|
52
|
+
"repository": {
|
53
|
+
"type": "git",
|
54
|
+
"url": "https://github.com/matin-mortazavi/react-otp-input"
|
55
|
+
},
|
56
|
+
"bugs": {
|
57
|
+
"url": "https://github.com/matin-mortazavi/react-otp-input/issues"
|
58
|
+
}
|
59
|
+
}
|
package/rollup.config.js
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
|
2
|
+
import typescript from '@rollup/plugin-typescript';
|
3
|
+
|
4
|
+
export default {
|
5
|
+
input: 'src/index.tsx',
|
6
|
+
output: [
|
7
|
+
{
|
8
|
+
file: 'lib/index.cjs',
|
9
|
+
format: 'cjs',
|
10
|
+
sourcemap: true,
|
11
|
+
},
|
12
|
+
{
|
13
|
+
file: 'lib/index.esm.js',
|
14
|
+
format: 'esm',
|
15
|
+
sourcemap: true,
|
16
|
+
},
|
17
|
+
],
|
18
|
+
plugins: [peerDepsExternal(), typescript()],
|
19
|
+
};
|
package/tsconfig.json
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
"outDir": "lib/esm",
|
4
|
+
"module": "esnext",
|
5
|
+
"declaration": true,
|
6
|
+
"target": "es5",
|
7
|
+
"lib": ["es6", "dom", "es2016", "es2017"],
|
8
|
+
"jsx": "react",
|
9
|
+
"moduleResolution": "node",
|
10
|
+
"noUnusedLocals": true,
|
11
|
+
"noUnusedParameters": true,
|
12
|
+
"esModuleInterop": true,
|
13
|
+
"noImplicitReturns": true,
|
14
|
+
"noImplicitThis": true,
|
15
|
+
"noImplicitAny": true,
|
16
|
+
"strictNullChecks": true,
|
17
|
+
"allowSyntheticDefaultImports": true
|
18
|
+
},
|
19
|
+
"include": ["src"],
|
20
|
+
"exclude": ["node_modules"]
|
21
|
+
}
|