UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

401 lines (400 loc) 9.65 kB
'use client'; import { jsx as n, jsxs as P } from "react/jsx-runtime"; import "@emotion/styled"; import { Button as te } from "../ui/button/button.js"; import { Input as oe } from "../ui/input/input.js"; import { Chip as re } from "../ui/chip/chip.js"; import { Select as ae } from "../ui/select/select.js"; import i from "react"; import { useConfig as le } from "../../hooks/use-config.js"; import { FieldError as ne } from "./field-error.js"; import { useFormField as ie } from "./form-wrapper.js"; const x = [ { code: "US", name: "United States", dialCode: "+1", flag: "🇺🇸", format: "(###) ###-####" }, { code: "CA", name: "Canada", dialCode: "+1", flag: "🇨🇦", format: "(###) ###-####" }, { code: "GB", name: "United Kingdom", dialCode: "+44", flag: "🇬🇧", format: "#### ### ####" }, { code: "AU", name: "Australia", dialCode: "+61", flag: "🇦🇺", format: "#### ### ###" }, { code: "DE", name: "Germany", dialCode: "+49", flag: "🇩🇪", format: "### ### ####" }, { code: "FR", name: "France", dialCode: "+33", flag: "🇫🇷", format: "## ## ## ## ##" }, { code: "ES", name: "Spain", dialCode: "+34", flag: "🇪🇸", format: "### ### ###" }, { code: "IT", name: "Italy", dialCode: "+39", flag: "🇮🇹", format: "### ### ####" }, { code: "JP", name: "Japan", dialCode: "+81", flag: "🇯🇵", format: "###-####-####" }, { code: "KR", name: "South Korea", dialCode: "+82", flag: "🇰🇷", format: "###-####-####" }, { code: "CN", name: "China", dialCode: "+86", flag: "🇨🇳", format: "### #### ####" }, { code: "IN", name: "India", dialCode: "+91", flag: "🇮🇳", format: "##### #####" }, { code: "BR", name: "Brazil", dialCode: "+55", flag: "🇧🇷", format: "(##) #####-####" }, { code: "MX", name: "Mexico", dialCode: "+52", flag: "🇲🇽", format: "### ### ####" }, { code: "AR", name: "Argentina", dialCode: "+54", flag: "🇦🇷", format: "### ###-####" }, { code: "RU", name: "Russia", dialCode: "+7", flag: "🇷🇺", format: "### ###-##-##" }, { code: "ZA", name: "South Africa", dialCode: "+27", flag: "🇿🇦", format: "## ### ####" }, { code: "EG", name: "Egypt", dialCode: "+20", flag: "🇪🇬", format: "### ### ####" }, { code: "NG", name: "Nigeria", dialCode: "+234", flag: "🇳🇬", format: "### ### ####" }, { code: "SG", name: "Singapore", dialCode: "+65", flag: "🇸🇬", format: "#### ####" } ]; function O(s, r) { const a = [], o = s.replace(/[^\d+]/g, ""); let t = o, h = o; o.startsWith("+") ? (h = o, o.startsWith(r.dialCode) ? t = o.substring(r.dialCode.length) : a.push("Phone number does not match selected country")) : (h = r.dialCode + o, t = o), t.length < 7 ? a.push("Phone number is too short") : t.length > 15 && a.push("Phone number is too long"); let g = t; return r.format && t.length >= 7 && (g = se(t, r.format)), { isValid: a.length === 0, e164: h, national: t, formatted: `${r.dialCode} ${g}`, errors: a }; } function se(s, r) { let a = r, o = 0; for (let t = 0; t < r.length && o < s.length; t++) r[t] === "#" && (a = a.substring(0, t) + s[o] + a.substring(t + 1), o++); return a.substring(0, a.lastIndexOf("#") + 1); } function X(s) { const r = s.replace(/[^\d+]/g, ""); if (!r.startsWith("+")) return null; const a = [...x].sort( (o, t) => t.dialCode.length - o.dialCode.length ); for (const o of a) if (r.startsWith(o.dialCode)) return o; return null; } function be({ name: s = "phone", label: r = "Phone Number", placeholder: a = "Enter your phone number", value: o = "", onChange: t, onBlur: h, onFocus: g, defaultCountry: E = "US", preferredCountries: S = ["US", "CA", "GB"], allowedCountries: k = [], blockedCountries: y = [], required: D = !1, disabled: I = !1, validateFormat: B = !0, size: F = "md", variant: R = "bordered", className: K = "", autoFocus: L = !1, autoComplete: T = "tel", error: p, description: $, showVerificationStatus: U = !1, isVerified: G = !1, onRequestVerification: A, endContent: v }) { const { components: Z, organizationSettings: M } = le(), d = ie(s), z = Z.PhoneField; if (z) return /* @__PURE__ */ n( z, { name: s, label: r, placeholder: a, value: o, onChange: t, onBlur: h, onFocus: g, defaultCountry: E, preferredCountries: S, allowedCountries: k, blockedCountries: y, required: D, disabled: I, validateFormat: B, size: F, variant: R, className: K, autoFocus: L, autoComplete: T, error: p, description: $, showVerificationStatus: U, isVerified: G, onRequestVerification: A, endContent: v } ); const [w, H] = i.useState(o), [C, J] = i.useState(() => { if (o) { const e = X(o); if (e) return e; } return x.find((e) => e.code === E) || x[0]; }), f = t ? o : w, N = i.useMemo(() => { const e = M?.phoneRestrictions?.allowedCountries; return e && e.length > 0 ? e : k; }, [k, M]), W = i.useMemo(() => { const e = M?.phoneRestrictions?.blockedCountries; return e && e.length > 0 ? [...y, ...e] : y; }, [y, M]), b = i.useMemo(() => { let e = x; N.length > 0 && (e = e.filter( (u) => N.includes(u.code) )), W.length > 0 && (e = e.filter( (u) => !W.includes(u.code) )); const m = e.filter( (u) => S.includes(u.code) ), c = e.filter((u) => !S.includes(u.code)); return [...m, ...c]; }, [ N, W, S ]), l = i.useMemo(() => !f || !B ? null : O(f, C), [f, C, B]), j = i.useMemo(() => { const e = []; return p && (Array.isArray(p) ? e.push(...p) : e.push(p)), d.error && (Array.isArray(d.error) ? e.push(...d.error) : e.push(d.error)), l && !l.isValid && e.push(...l.errors), e.length > 0 ? e : null; }, [p, d.error, l]), Q = i.useCallback( (e) => { const m = X(e); if (m && b.includes(m) && J(m), t && l) t(l.e164, l.formatted); else if (t) { const c = e.replace(/[^\d+]/g, ""), u = c.startsWith("+") ? c : C.dialCode + c.replace(/^\d/, ""); t(u, e); } else H(e); d.clearError && d.clearError(); }, [t, l, d, C, b] ), V = i.useCallback( (e) => { const m = b.find((c) => c.code === e); if (m && (J(m), f)) { const c = O(f, m); t && t(c.e164, c.formatted); } }, [b, f, t] ), Y = i.useCallback(() => { d.setTouched && d.setTouched(!0), h?.(); }, [d, h]), _ = i.useCallback(() => { g?.(); }, [g]), q = i.useMemo(() => !U || v ? null : G ? /* @__PURE__ */ n( re, { size: "sm", color: "success", variant: "flat", startContent: /* @__PURE__ */ n( "svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ n( "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" } ) } ), children: "Verified" } ) : f && l?.isValid && A ? /* @__PURE__ */ n( te, { size: "sm", variant: "flat", color: "primary", onPress: A, children: "Send SMS" } ) : null, [ U, v, G, f, l, A ]), ee = /* @__PURE__ */ n( ae, { value: C.code, onChange: (e) => V(e.target.value), className: "min-w-32", size: F, variant: R, isDisabled: I, placeholder: "Country", options: b.map((e) => ({ label: e.name, value: e.code })) } ); return /* @__PURE__ */ P("div", { className: `space-y-2 ${K}`, children: [ /* @__PURE__ */ P("div", { className: "flex gap-2", children: [ /* @__PURE__ */ n("div", { className: "shrink-0", children: ee }), /* @__PURE__ */ n("div", { className: "flex-1", children: /* @__PURE__ */ n( oe, { name: s, label: r, placeholder: a, value: f, onValueChange: Q, onBlur: Y, onFocus: _, type: "tel", isRequired: D, isDisabled: I, size: F, variant: R, autoFocus: L, autoComplete: T, description: $, isInvalid: !!j, errorMessage: "", endContent: v || q } ) }) ] }), j && /* @__PURE__ */ n(ne, { error: j, fieldName: s }), l && l.isValid && /* @__PURE__ */ P("div", { className: "text-xs text-default-500", children: [ /* @__PURE__ */ n("span", { className: "font-medium", children: "Format:" }), " ", l.formatted ] }), N.length > 0 && /* @__PURE__ */ P("div", { className: "text-xs text-default-500", children: [ /* @__PURE__ */ n("span", { className: "font-medium", children: "Allowed countries:" }), " ", N.join(", ") ] }) ] }); } export { be as PhoneField }; //# sourceMappingURL=phone-field.js.map