@frank-auth/react
Version:
Flexible and customizable React UI components for Frank Authentication
382 lines (381 loc) • 10.2 kB
JavaScript
'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