mui-one-time-password-input
Version:
A One-Time Password input designed for the React library MUI
170 lines (169 loc) • 5 kB
JavaScript
import e from "react";
import { styled as t } from "@mui/material/styles";
import n from "@mui/material/TextField";
import { jsx as r } from "react/jsx-runtime";
import i from "@mui/material/Box";
//#region src/components/TextFieldBox/TextFieldBox.styled.ts
var a = t(n)`
input {
text-align: center;
}
`, o = (e) => /* @__PURE__ */ r(a, { ...e }), s = {
left: "ArrowLeft",
right: "ArrowRight",
backspace: "Backspace",
home: "Home",
end: "End"
};
//#endregion
//#region src/shared/helpers/array.ts
function c(e, t) {
return e <= 0 ? [] : Array.from({ length: e }, t);
}
function l(e, t, n) {
return e.map((e, r) => t === r ? n : e);
}
function u(e) {
return e.join("");
}
function d(e, t) {
return [...e, t];
}
function f(e, t, n) {
return e.reduce((e, t, r) => {
let { characters: i, restArrayMerged: a } = e;
if (r < n) return {
restArrayMerged: a,
characters: d(i, t)
};
let [o, ...s] = a;
return {
restArrayMerged: s,
characters: d(i, o || "")
};
}, {
restArrayMerged: t,
characters: []
}).characters;
}
//#endregion
//#region src/shared/helpers/react.ts
function p(e) {
return (t) => {
for (let n of e) typeof n == "function" ? n(t) : n != null && (n.current = t);
};
}
//#endregion
//#region src/shared/helpers/string.ts
function m(e) {
return e.split("");
}
//#endregion
//#region src/shared/hooks/useEvent.ts
function h(t) {
let n = e.useRef(() => {
throw Error("Cannot call an event handler while rendering.");
});
return e.useInsertionEffect(() => {
n.current = t;
}), e.useCallback((...e) => n.current?.(...e), []);
}
//#endregion
//#region src/index.tsx
var g = () => !0, _ = {
display: "flex",
gap: "20px",
alignItems: "center"
}, v = e.forwardRef((t, n) => {
let { value: a = "", length: d = 4, autoFocus: v = !1, onChange: y, TextFieldsProps: b, onComplete: x, validateChar: S = g, className: C, onBlur: w, sx: T, ...E } = t, D = e.useRef(a), O = h(x), k = h((e) => {
let t = e.slice(0, d);
return {
isCompleted: t.length === d,
finalValue: t
};
});
e.useEffect(() => {
let { isCompleted: e, finalValue: t } = k(D.current);
e && O(t);
}, [
d,
O,
k
]);
let A = c(d, (t, n) => ({
character: a[n] || "",
inputRef: e.createRef()
})), j = (e) => A.findIndex(({ inputRef: t }) => t.current === e), M = () => A.map(({ character: e }) => e), N = (e, t) => u(l(M(), e, t)), P = (e) => {
A[e]?.inputRef.current?.focus();
}, F = (e) => {
A[e]?.inputRef.current?.select();
}, I = (e) => {
e + 1 !== d && (A[e + 1].character ? F(e + 1) : P(e + 1));
}, L = (e, t) => typeof S == "function" ? S(e, t) : !0, R = (e) => {
let t = j(e.target);
if (t === 0 && e.target.value.length > 1) {
let { finalValue: t, isCompleted: n } = k(e.target.value);
y?.(t), n && x?.(t), F(t.length - 1);
return;
}
let n = e.target.value[0] || "", r = n;
r && !L(r, t) && (r = "");
let i = N(t, r);
y?.(i);
let { isCompleted: a, finalValue: o } = k(i);
a && x?.(o), r === "" ? n === "" && i.length <= t && F(t - 1) : i.length - 1 < t ? F(i.length) : I(t);
}, z = (e) => {
let t = e.target, n = t.selectionStart, r = t.selectionEnd, i = j(t), a = n === 0 && r === 0;
if (t.value === e.key) e.preventDefault(), I(i);
else if (s.backspace === e.key) {
if (!t.value) e.preventDefault(), F(i - 1);
else if (a) {
e.preventDefault();
let t = N(i, "");
y?.(t), t.length <= i && F(i - 1);
}
} else s.left === e.key ? (e.preventDefault(), F(i - 1)) : s.right === e.key ? (e.preventDefault(), F(i + 1)) : s.home === e.key ? (e.preventDefault(), F(0)) : s.end === e.key && (e.preventDefault(), F(A.length - 1));
}, B = (e) => {
let t = e.clipboardData.getData("text/plain"), n = e.target, r = A.findIndex(({ character: e, inputRef: t }) => e === "" || t.current === n), i = u(f(M(), m(t), r).map((e, t) => L(e, t) ? e : ""));
y?.(i);
let { isCompleted: a, finalValue: o } = k(i);
a ? (x?.(o), F(d - 1)) : F(i.length);
}, V = (e) => {
if (!A.some(({ inputRef: t }) => t.current === e.relatedTarget)) {
let { isCompleted: e, finalValue: t } = k(a);
w?.(t, e);
}
};
return /* @__PURE__ */ r(i, {
sx: [_, ...T ? [T].flat() : []],
ref: n,
className: `MuiOtpInput-Box ${C || ""}`,
...E,
children: A.map(({ character: e, inputRef: t }, n) => {
let { onPaste: i, onFocus: a, onKeyDown: s, className: c, onBlur: l, inputRef: u, ...d } = typeof b == "function" ? b(n) || {} : b || {};
return /* @__PURE__ */ r(o, {
autoFocus: v ? n === 0 : !1,
autoComplete: "one-time-code",
value: e,
inputRef: p([t, u]),
className: `MuiOtpInput-TextField MuiOtpInput-TextField-${n + 1} ${c || ""}`,
onPaste: (e) => {
e.preventDefault(), B(e), i?.(e);
},
onFocus: (e) => {
e.preventDefault(), e.target.select(), a?.(e);
},
onChange: R,
onKeyDown: (e) => {
z(e), s?.(e);
},
onBlur: (e) => {
l?.(e), V(e);
},
...d
}, n);
})
});
});
//#endregion
export { v as MuiOtpInput };