UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

286 lines (285 loc) 8.81 kB
'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