UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

382 lines (381 loc) 10.2 kB
'use client'; import { jsx as t, jsxs as m, Fragment as T } from "react/jsx-runtime"; import "@emotion/styled"; import { Card as G, CardBody as I, CardHeader as J } from "../ui/card/card.js"; import { cn as K } from "../../lib/utils.js"; import { getTitleAlignment as Q } from "../../utils/format.js"; import { motion as P } from "framer-motion"; import F, { createContext as X, useCallback as u, useMemo as p, useContext as Y, useRef as H } from "react"; import { useConfig as Z } from "../../hooks/use-config.js"; import { useTheme as S } from "../../hooks/use-theme.js"; import { FieldError as ee } from "./field-error.js"; const U = X(null), C = F.memo( ({ children: e, disableAnimations: r }) => r ? /* @__PURE__ */ t(T, { children: e }) : /* @__PURE__ */ t( P.div, { initial: { opacity: 0, y: 20 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.3, ease: "easeOut" }, children: e } ) ); C.displayName = "AnimatedContent"; const B = F.memo( ({ children: e, isSubmitting: r, initialErrors: n }) => { const o = H(n), c = H({}); F.useEffect(() => { o.current = n; }, []); const [, l] = F.useReducer((s) => s + 1, 0), a = u( (s, d) => { if (d === null) { if (o.current[s] !== void 0) { const y = { ...o.current }; delete y[s], o.current = y, l(); } } else o.current[s] !== d && (o.current = { ...o.current, [s]: d }, l()); }, [] ), i = u( (s, d = !0) => { c.current[s] !== d && (c.current = { ...c.current, [s]: d }, l()); }, [] ), x = u( (s) => { a(s, null); }, [a] ), f = u(() => { Object.keys(o.current).length > 0 && (o.current = {}, l()); }, []), h = u((s) => o.current[s] || null, []), g = u((s) => c.current[s] || !1, []), N = p( () => ({ isSubmitting: r, errors: o.current, touched: c.current, setFieldError: a, setFieldTouched: i, clearFieldError: x, clearAllErrors: f, hasErrors: Object.keys(o.current).length > 0, getFieldError: h, getFieldTouched: g }), [ r, // Only dependency that should change a, i, x, f, h, g // Deliberately NOT including errorsRef.current or touchedRef.current ] ); return /* @__PURE__ */ t(U.Provider, { value: N, children: e }); } ); B.displayName = "FormStateProvider"; const V = F.memo( ({ children: e, footer: r, onSubmit: n, isSubmitting: o, loadingContent: c, width: l, centered: a }) => { const { clearAllErrors: i } = q(), x = u( async (N) => { if (N.preventDefault(), i(), n) try { await n(N); } catch (s) { console.error("Form submission error:", s); } }, [n, i] ), f = p( () => ({ sm: "w-full max-w-sm", md: "w-full max-w-md", lg: "w-full max-w-lg", xl: "w-full max-w-xl", full: "w-full" }), [] ), h = p( () => `relative ${f[l]} ${a ? "mx-auto" : ""}`, [f, l, a] ), g = p(() => o ? /* @__PURE__ */ t("div", { className: "absolute inset-0 bg-background/50 backdrop-blur-sm flex items-center justify-center z-50 rounded-inherit", children: c || /* @__PURE__ */ m("div", { className: "flex items-center gap-3", children: [ /* @__PURE__ */ t("div", { className: "w-6 h-6 border-2 border-primary border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ t("span", { className: "text-sm text-foreground", children: "Processing..." }) ] }) }) : null, [o, c]); return /* @__PURE__ */ m("div", { className: h, children: [ /* @__PURE__ */ m("form", { onSubmit: x, className: "space-y-4", noValidate: !0, children: [ e, r ] }), g ] }); } ); V.displayName = "FormContent"; const _ = F.memo( ({ success: e, error: r, disableAnimations: n }) => !e && !r ? null : /* @__PURE__ */ m(T, { children: [ e && /* @__PURE__ */ t( P.div, { initial: n ? !1 : { opacity: 0, y: -10 }, animate: { opacity: 1, y: 0 }, className: "mb-4 p-3 bg-success-50 dark:bg-success-100/10 border border-success-200 dark:border-success-800 rounded-lg", children: /* @__PURE__ */ m("div", { className: "flex items-center gap-2", children: [ /* @__PURE__ */ t( "svg", { className: "w-5 h-5 text-success-600 dark:text-success-400", 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("p", { className: "text-sm text-success-700 dark:text-success-300", children: e }) ] }) } ), r && /* @__PURE__ */ t( ee, { error: r, variant: "default", className: "mb-4 p-3 bg-danger-50 dark:bg-danger-100/10 border border-danger-200 dark:border-danger-800 rounded-lg" } ) ] }) ); _.displayName = "Messages"; const $ = F.memo( ({ header: e, title: r, subtitle: n, showCard: o, desc: c, titleAlignment: l }) => e ? /* @__PURE__ */ t(T, { children: e }) : !r && !n ? null : o ? /* @__PURE__ */ m(J, { className: "flex flex-col items-center text-center pb-2", children: [ r && /* @__PURE__ */ t("h1", { className: "text-2xl font-bold text-foreground mb-2", children: r }), n && /* @__PURE__ */ t("p", { className: "text-default-500 text-sm", children: n }) ] }) : /* @__PURE__ */ m( "div", { className: K( "flex flex-col text-center pb-2", Q(l ?? "center") ), children: [ r && /* @__PURE__ */ t("h1", { className: "text-2xl font-bold text-foreground mb-2", children: r }), n && /* @__PURE__ */ t("p", { className: "text-default-500", children: n }), c ] } ) ); $.displayName = "Header"; const D = F.memo(({ logo: e, orgLogoUrl: r }) => e ? typeof e == "string" ? /* @__PURE__ */ t("img", { src: e, alt: "Logo", className: "h-8 w-auto mx-auto mb-6" }) : /* @__PURE__ */ t("div", { className: "flex justify-center mb-6", children: e }) : r ? /* @__PURE__ */ t( "img", { src: r, alt: "Organization Logo", className: "h-8 w-auto mx-auto mb-6" } ) : null); D.displayName = "Logo"; function re({ children: e, title: r, subtitle: n, desc: o, header: c, footer: l, isSubmitting: a = !1, error: i, success: x, onSubmit: f, initialErrors: h = {}, className: g = "", variant: N = "shadow", size: s = "md", showCard: d = !0, cardProps: y = {}, loadingContent: v, logo: E, width: w = "md", centered: k = !0, disableAnimations: b = !1, titleAlignment: j }) { const { theme: te } = S(), { components: A, organizationSettings: L } = Z(), O = A.FormWrapper; if (O) return /* @__PURE__ */ t( O, { children: e, title: r, subtitle: n, header: c, footer: l, isSubmitting: a, error: i, success: x, onSubmit: f, initialErrors: h, className: g, variant: N, size: s, showCard: d, cardProps: y, loadingContent: v, logo: E, width: w, centered: k, disableAnimations: b } ); const R = p( () => /* @__PURE__ */ t(D, { logo: E, orgLogoUrl: L?.branding?.logoUrl }), [E, L?.branding?.logoUrl] ), W = p( () => /* @__PURE__ */ t( $, { header: c, title: r, subtitle: n, desc: o, showCard: d, titleAlignment: j } ), [c, r, n, d, j] ), M = p( () => /* @__PURE__ */ t( _, { success: x, error: i, disableAnimations: b } ), [x, i, b] ), z = p( () => /* @__PURE__ */ m( B, { isSubmitting: a, initialErrors: h, children: [ R, M, /* @__PURE__ */ t( V, { onSubmit: f, isSubmitting: a, loadingContent: v, width: w, centered: k, footer: l, children: e } ) ] } ), [ a, h, R, M, f, v, w, k, l, e ] ); return d ? /* @__PURE__ */ t(C, { disableAnimations: b, children: /* @__PURE__ */ m(G, { variant: N, className: g, ...y, children: [ W, /* @__PURE__ */ t(I, { className: "pt-0", children: z }) ] }) }) : /* @__PURE__ */ t(C, { disableAnimations: b, children: /* @__PURE__ */ m("div", { className: g, children: [ W, /* @__PURE__ */ t("div", { className: "pt-0", children: z }) ] }) }); } function q() { const e = Y(U); if (!e) throw new Error("useFormContext must be used within a FormWrapper"); return e; } function fe(e) { const r = q(), n = u( (l) => { r.setFieldError(e, l); }, [r.setFieldError, e] ), o = u( (l = !0) => { r.setFieldTouched(e, l); }, [r.setFieldTouched, e] ), c = u(() => { r.clearFieldError(e); }, [r.clearFieldError, e]); return p( () => ({ name: e, error: r.getFieldError(e), touched: r.getFieldTouched(e), showError: r.getFieldTouched(e) && !!r.getFieldError(e), setError: n, setTouched: o, clearError: c, isSubmitting: r.isSubmitting }), [ e, r.getFieldError(e), r.getFieldTouched(e), n, o, c, r.isSubmitting ] ); } var pe = re; export { U as FormContext, re as FormWrapper, pe as default, q as useFormContext, fe as useFormField }; //# sourceMappingURL=form-wrapper.js.map