react-otp-custom
Version:
Customizable React OTP input component
63 lines (62 loc) • 2.62 kB
JavaScript
(function(){"use strict";try{if(typeof document<"u"){var e=document.createElement("style");e.appendChild(document.createTextNode(".otp-container{display:flex;gap:8px}.otp-input{width:40px;height:40px;font-size:20px;text-align:center;border:1px solid #ccc;border-radius:4px}.otp-square{border-radius:4px}.otp-circle{border-radius:50%}.otp-light:focus{border-color:#000;outline:none}.otp-dark{background-color:#000!important;color:#fff!important;border:1px solid white}.otp-dark:focus{border:2px solid whitesmoke;outline:none}")),document.head.appendChild(e)}}catch(o){console.error("vite-plugin-css-injected-by-js",o)}})();
import { jsx as m } from "react/jsx-runtime";
import { useState as O, useRef as v, useEffect as D } from "react";
import p from "prop-types";
const b = ({ length: u = 6, onChange: h, isNumeric: f = !0, theme: y = "light", shape: g = "square", fontSize: l = 24 }) => {
const [s, i] = O(Array(u).fill("")), c = v([]);
D(() => {
h(s.join(""));
}, [s, h]);
const w = (n, t) => {
var a;
const e = n.target.value;
if (f && !/^\d*$/.test(e)) return;
const o = [...s], r = e.slice(-1);
o[t] = r, i(o), r && s[t] === "" && t < u - 1 && ((a = c.current[t + 1]) == null || a.focus());
}, $ = (n, t) => {
var e, o, r;
if (n.key === "Backspace") {
const a = [...s];
s[t] ? (a[t] = "", i(a)) : t > 0 && ((e = c.current[t - 1]) == null || e.focus());
} else n.key === "ArrowLeft" && t > 0 ? (o = c.current[t - 1]) == null || o.focus() : n.key === "ArrowRight" && t < u - 1 && ((r = c.current[t + 1]) == null || r.focus());
};
return /* @__PURE__ */ m("div", { className: "otp-container", onPaste: (n) => {
var o;
n.preventDefault();
const t = n.clipboardData.getData("text").slice(0, u).split(""), e = [...s];
t.forEach((r, a) => {
f && !/^[0-9]$/.test(r) || (e[a] = r);
}), i(e), (o = c.current[t.length - 1]) == null || o.focus();
}, children: s.map((n, t) => /* @__PURE__ */ m(
"input",
{
ref: (e) => c.current[t] = e,
type: "text",
inputMode: f ? "numeric" : "text",
autoFocus: t === 0,
maxLength: 2,
value: n,
onChange: (e) => w(e, t),
onKeyDown: (e) => $(e, t),
className: `otp-input otp-${y} otp-${g}`,
style: {
fontSize: `${l}px`,
width: `${l * 2}px`,
height: `${l * 2}px`
}
},
t
)) });
};
b.propTypes = {
length: p.number,
onChange: p.func.isRequired,
isNumeric: p.bool,
theme: p.string,
shape: p.oneOf(["square", "circle"]),
fontSize: p.number
};
export {
b as OtpInput,
b as default
};