@frank-auth/react
Version:
Flexible and customizable React UI components for Frank Authentication
286 lines (285 loc) • 8.81 kB
JavaScript
'use client';
import { jsx as t, jsxs as g } from "react/jsx-runtime";
import "@emotion/styled";
import { Button as ne } from "../ui/button/button.js";
import { Input as le } from "../ui/input/input.js";
import { Progress as ue } from "../ui/progress/progress.js";
import { AnimatePresence as O, motion as Q } from "framer-motion";
import a from "react";
import { useConfig as fe } from "../../hooks/use-config.js";
import { FieldError as me } from "./field-error.js";
import { useFormField as pe } from "./form-wrapper.js";
function Ie({
name: w = "verificationCode",
label: A = "Verification Code",
length: s = 6,
value: C = "",
onChange: k,
onComplete: N,
onBlur: V,
onFocus: I,
required: P = !1,
disabled: o = !1,
autoFocus: b = !0,
size: j = "md",
variant: U = "bordered",
className: Z = "",
error: d,
description: x,
placeholder: $ = "○",
type: m = "numeric",
allowPaste: R = !0,
separator: K = !1,
groupSize: S = 3,
separatorChar: T = "-",
canResend: E = !1,
onResend: F,
resendCountdown: M = 0,
isLoading: v = !1,
isSuccess: H = !1,
inputMode: L = "numeric",
autoComplete: W = "one-time-code"
}) {
const { components: X } = fe(), i = pe(w), _ = X.VerificationCode;
if (_)
return /* @__PURE__ */ t(
_,
{
name: w,
label: A,
length: s,
value: C,
onChange: k,
onComplete: N,
onBlur: V,
onFocus: I,
required: P,
disabled: o,
autoFocus: b,
size: j,
variant: U,
className: Z,
error: d,
description: x,
placeholder: $,
type: m,
allowPaste: R,
separator: K,
groupSize: S,
separatorChar: T,
canResend: E,
onResend: F,
resendCountdown: M,
isLoading: v,
isSuccess: H,
inputMode: L,
autoComplete: W
}
);
const [Y, q] = a.useState(C), [he, l] = a.useState(0), [de, G] = a.useState(!1), n = a.useRef([]), B = k ? C : Y, f = a.useMemo(() => {
const e = B.split("").slice(0, s);
return [
...e,
...Array(Math.max(0, s - e.length)).fill("")
];
}, [B, s]), z = a.useMemo(() => {
const e = [];
return d && (Array.isArray(d) ? e.push(...d) : e.push(d)), i.error && (Array.isArray(i.error) ? e.push(...i.error) : e.push(i.error)), e.length > 0 ? e : null;
}, [d, i.error]), p = a.useCallback(
(e) => {
const r = m === "numeric" ? e.replace(/[^0-9]/g, "") : e.replace(/[^a-zA-Z0-9]/g, "").toUpperCase();
k ? k(r) : q(r), i.clearError && i.clearError(), r.length === s && N && N(r);
},
[k, i, s, N, m]
), ee = a.useCallback(
(e, r) => {
if (o) return;
const c = [...f], u = m === "numeric" ? r.replace(/[^0-9]/g, "") : r.replace(/[^a-zA-Z0-9]/g, "").toUpperCase();
if (u.length > 1) {
const D = u.split("");
for (let y = 0; y < D.length && e + y < s; y++)
c[e + y] = D[y];
const J = Math.min(e + D.length, s - 1);
l(J), n.current[J]?.focus();
} else
c[e] = u, u && e < s - 1 && (l(e + 1), n.current[e + 1]?.focus());
const h = c.join("");
p(h);
},
[f, o, s, m, p]
), re = a.useCallback(
(e, r) => {
if (!o)
switch (r.key) {
case "Backspace":
if (!f[e] && e > 0)
r.preventDefault(), l(e - 1), n.current[e - 1]?.focus();
else if (f[e]) {
const h = [...f];
h[e] = "";
const D = h.join("");
p(D);
}
break;
case "Delete":
const c = [...f];
c[e] = "";
const u = c.join("");
p(u);
break;
case "ArrowLeft":
r.preventDefault(), e > 0 && (l(e - 1), n.current[e - 1]?.focus());
break;
case "ArrowRight":
r.preventDefault(), e < s - 1 && (l(e + 1), n.current[e + 1]?.focus());
break;
case "Home":
r.preventDefault(), l(0), n.current[0]?.focus();
break;
case "End":
r.preventDefault(), l(s - 1), n.current[s - 1]?.focus();
break;
}
},
[f, o, s, p]
), te = a.useCallback(
(e) => {
if (!R || o) return;
e.preventDefault();
const r = e.clipboardData.getData("text"), c = m === "numeric" ? r.replace(/[^0-9]/g, "") : r.replace(/[^a-zA-Z0-9]/g, "").toUpperCase();
if (c) {
const u = c.slice(0, s);
p(u);
const h = Math.min(u.length - 1, s - 1);
l(h), n.current[h]?.focus();
}
},
[R, o, m, s, p]
), se = a.useCallback(
(e) => {
l(e), G(!0), I?.();
},
[I]
), ce = a.useCallback(() => {
G(!1), i.setTouched && i.setTouched(!0), V?.();
}, [i, V]);
a.useEffect(() => {
b && !o && n.current[0]?.focus();
}, [b, o]);
const ae = {
sm: "w-8 h-8 text-sm",
md: "w-10 h-10 text-base",
lg: "w-12 h-12 text-lg"
}, ie = (e) => !K || (e + 1) % S !== 0 || e === s - 1 ? null : /* @__PURE__ */ t("span", { className: "text-default-400 text-xl font-mono mx-1", children: T }), oe = () => !E || !F ? null : /* @__PURE__ */ t("div", { className: "flex items-center justify-center mt-4", children: M === 0 && !v ? /* @__PURE__ */ t(
ne,
{
variant: "light",
color: "primary",
size: "sm",
onPress: F,
isDisabled: v,
children: "Resend Code"
}
) : /* @__PURE__ */ g("div", { className: "text-sm text-default-500", children: [
"Resend code in ",
M,
"s"
] }) });
return /* @__PURE__ */ g("div", { className: `space-y-4 ${Z}`, children: [
A && /* @__PURE__ */ g("div", { className: "text-sm font-medium text-foreground", children: [
A,
P && /* @__PURE__ */ t("span", { className: "text-danger ml-1", children: "*" })
] }),
x && /* @__PURE__ */ t("div", { className: "text-sm text-default-500", children: x }),
/* @__PURE__ */ t("div", { className: "flex items-center justify-center gap-2 flex-wrap", children: f.map((e, r) => /* @__PURE__ */ g(a.Fragment, { children: [
/* @__PURE__ */ t(
le,
{
ref: (c) => {
n.current[r] = c;
},
value: e,
onChange: (c) => ee(r, c.target.value),
onKeyDown: (c) => re(r, c),
onFocus: () => se(r),
onBlur: ce,
onPaste: te,
maxLength: 1,
className: `${ae[j]} text-center font-mono`,
size: j,
variant: U,
isDisabled: o || v,
isInvalid: !!z,
placeholder: $,
inputMode: L,
autoComplete: r === 0 ? W : "off",
type: "text"
}
),
ie(r)
] }, r)) }),
/* @__PURE__ */ t(O, { children: v && /* @__PURE__ */ t(
Q.div,
{
initial: { opacity: 0, height: 0 },
animate: { opacity: 1, height: "auto" },
exit: { opacity: 0, height: 0 },
children: /* @__PURE__ */ t(
ue,
{
size: "sm",
isIndeterminate: !0,
color: "primary",
className: "w-full",
label: "Verifying..."
}
)
}
) }),
/* @__PURE__ */ t(O, { children: H && /* @__PURE__ */ g(
Q.div,
{
initial: { opacity: 0, scale: 0.8 },
animate: { opacity: 1, scale: 1 },
className: "flex items-center justify-center gap-2 text-success-600",
children: [
/* @__PURE__ */ t(
"svg",
{
className: "w-5 h-5",
fill: "none",
stroke: "currentColor",
viewBox: "0 0 24 24",
children: /* @__PURE__ */ t(
"path",
{
strokeLinecap: "round",
strokeLinejoin: "round",
strokeWidth: 2,
d: "M5 13l4 4L19 7"
}
)
}
),
/* @__PURE__ */ t("span", { className: "text-sm font-medium", children: "Verified!" })
]
}
) }),
z && /* @__PURE__ */ t(me, { error: z, fieldName: w }),
/* @__PURE__ */ t(oe, {}),
/* @__PURE__ */ t("div", { className: "flex justify-center", children: /* @__PURE__ */ t("div", { className: "flex gap-1", children: Array.from({ length: s }, (e, r) => /* @__PURE__ */ t(
"div",
{
className: `
w-2 h-1 rounded-full transition-colors duration-200
${r < B.length ? "bg-primary" : "bg-default-200 dark:bg-default-800"}
`
},
r
)) }) })
] });
}
export {
Ie as VerificationCode
};
//# sourceMappingURL=verification-code.js.map