@frank-auth/react
Version:
Flexible and customizable React UI components for Frank Authentication
1 lines • 28.3 kB
Source Map (JSON)
{"version":3,"file":"form-wrapper.cjs","sources":["../../../../src/components/forms/form-wrapper.tsx"],"sourcesContent":["/**\n * @frank-auth/react - Form Wrapper Component (Fully Optimized)\n *\n * Form container that provides validation context, error handling, and consistent\n * styling for authentication forms. Supports organization theming and customization.\n * Completely optimized to prevent ANY unnecessary re-renders.\n */\n\n\"use client\";\n\nimport { Card, CardBody, CardHeader } from \"@/components/ui\";\nimport { cn } from \"@/lib/utils\";\nimport type { RadiusT, SizeT } from \"@/types\";\nimport { getTitleAlignment } from \"@/utils\";\nimport { motion } from \"framer-motion\";\nimport React, {\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseMemo,\n\tuseRef,\n} from \"react\";\nimport { useConfig } from \"../../hooks/use-config\";\nimport { useTheme } from \"../../hooks/use-theme\";\nimport { FieldError } from \"./field-error\";\n\n// ============================================================================\n// Form Context\n// ============================================================================\n\ninterface FormContextValue {\n\tisSubmitting: boolean;\n\terrors: Record<string, string | string[]>;\n\ttouched: Record<string, boolean>;\n\tsetFieldError: (field: string, error: string | string[] | null) => void;\n\tsetFieldTouched: (field: string, touched?: boolean) => void;\n\tclearFieldError: (field: string) => void;\n\tclearAllErrors: () => void;\n\thasErrors: boolean;\n\tgetFieldError: (field: string) => string | string[] | null;\n\tgetFieldTouched: (field: string) => boolean;\n}\n\nconst FormContext = createContext<FormContextValue | null>(null);\n\n// ============================================================================\n// Animation Component (Defined Outside to Prevent Recreation)\n// ============================================================================\n\nconst AnimatedContent = React.memo(\n\t({\n\t\tchildren,\n\t\tdisableAnimations,\n\t}: {\n\t\tchildren: React.ReactNode;\n\t\tdisableAnimations: boolean;\n\t}) => {\n\t\tif (disableAnimations) return <>{children}</>;\n\n\t\treturn (\n\t\t\t<motion.div\n\t\t\t\tinitial={{ opacity: 0, y: 20 }}\n\t\t\t\tanimate={{ opacity: 1, y: 0 }}\n\t\t\t\ttransition={{ duration: 0.3, ease: \"easeOut\" }}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</motion.div>\n\t\t);\n\t},\n);\n\nAnimatedContent.displayName = \"AnimatedContent\";\n\n// ============================================================================\n// Form State Provider (Separated for Performance)\n// ============================================================================\n\ninterface FormStateProviderProps {\n\tchildren: React.ReactNode;\n\tisSubmitting: boolean;\n\tinitialErrors: Record<string, string | string[]>;\n}\n\nconst FormStateProvider = React.memo(\n\t({ children, isSubmitting, initialErrors }: FormStateProviderProps) => {\n\t\t// Use refs for state that doesn't need to trigger re-renders immediately\n\t\tconst errorsRef = useRef<Record<string, string | string[]>>(initialErrors);\n\t\tconst touchedRef = useRef<Record<string, boolean>>({});\n\n\t\t// Initialize refs only once\n\t\tReact.useEffect(() => {\n\t\t\terrorsRef.current = initialErrors;\n\t\t}, []); // Only on mount\n\n\t\t// Force re-render hook\n\t\tconst [, forceUpdate] = React.useReducer((x) => x + 1, 0);\n\n\t\t// Stable callback functions that don't change on every render\n\t\tconst setFieldError = useCallback(\n\t\t\t(field: string, fieldError: string | string[] | null) => {\n\t\t\t\tif (fieldError === null) {\n\t\t\t\t\tif (errorsRef.current[field] !== undefined) {\n\t\t\t\t\t\tconst newErrors = { ...errorsRef.current };\n\t\t\t\t\t\tdelete newErrors[field];\n\t\t\t\t\t\terrorsRef.current = newErrors;\n\t\t\t\t\t\tforceUpdate();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (errorsRef.current[field] !== fieldError) {\n\t\t\t\t\t\terrorsRef.current = { ...errorsRef.current, [field]: fieldError };\n\t\t\t\t\t\tforceUpdate();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t[],\n\t\t);\n\n\t\tconst setFieldTouched = useCallback(\n\t\t\t(field: string, fieldTouched = true) => {\n\t\t\t\tif (touchedRef.current[field] !== fieldTouched) {\n\t\t\t\t\ttouchedRef.current = { ...touchedRef.current, [field]: fieldTouched };\n\t\t\t\t\tforceUpdate();\n\t\t\t\t}\n\t\t\t},\n\t\t\t[],\n\t\t);\n\n\t\tconst clearFieldError = useCallback(\n\t\t\t(field: string) => {\n\t\t\t\tsetFieldError(field, null);\n\t\t\t},\n\t\t\t[setFieldError],\n\t\t);\n\n\t\tconst clearAllErrors = useCallback(() => {\n\t\t\tif (Object.keys(errorsRef.current).length > 0) {\n\t\t\t\terrorsRef.current = {};\n\t\t\t\tforceUpdate();\n\t\t\t}\n\t\t}, []);\n\n\t\tconst getFieldError = useCallback((field: string) => {\n\t\t\treturn errorsRef.current[field] || null;\n\t\t}, []);\n\n\t\tconst getFieldTouched = useCallback((field: string) => {\n\t\t\treturn touchedRef.current[field] || false;\n\t\t}, []);\n\n\t\t// Memoize the context value with minimal dependencies\n\t\tconst contextValue = useMemo(\n\t\t\t() => ({\n\t\t\t\tisSubmitting,\n\t\t\t\terrors: errorsRef.current,\n\t\t\t\ttouched: touchedRef.current,\n\t\t\t\tsetFieldError,\n\t\t\t\tsetFieldTouched,\n\t\t\t\tclearFieldError,\n\t\t\t\tclearAllErrors,\n\t\t\t\thasErrors: Object.keys(errorsRef.current).length > 0,\n\t\t\t\tgetFieldError,\n\t\t\t\tgetFieldTouched,\n\t\t\t}),\n\t\t\t[\n\t\t\t\tisSubmitting, // Only dependency that should change\n\t\t\t\tsetFieldError,\n\t\t\t\tsetFieldTouched,\n\t\t\t\tclearFieldError,\n\t\t\t\tclearAllErrors,\n\t\t\t\tgetFieldError,\n\t\t\t\tgetFieldTouched,\n\t\t\t\t// Deliberately NOT including errorsRef.current or touchedRef.current\n\t\t\t],\n\t\t);\n\n\t\treturn (\n\t\t\t<FormContext.Provider value={contextValue}>\n\t\t\t\t{children}\n\t\t\t</FormContext.Provider>\n\t\t);\n\t},\n);\n\nFormStateProvider.displayName = \"FormStateProvider\";\n\n// ============================================================================\n// Form Wrapper Interface\n// ============================================================================\n\nexport interface FormWrapperProps {\n\t/**\n\t * Form content\n\t */\n\tchildren: React.ReactNode;\n\n\t/**\n\t * Form title\n\t */\n\ttitle?: string;\n\n\t/**\n\t * Form subtitle or description\n\t */\n\tsubtitle?: string;\n\n\tdesc?: React.ReactNode;\n\n\t/**\n\t * Form header content (overrides title/subtitle)\n\t */\n\theader?: React.ReactNode;\n\n\t/**\n\t * Form footer content\n\t */\n\tfooter?: React.ReactNode;\n\n\t/**\n\t * Whether form is currently submitting\n\t */\n\tisSubmitting?: boolean;\n\n\t/**\n\t * Global form error message\n\t */\n\terror?: string | null;\n\n\t/**\n\t * Success message\n\t */\n\tsuccess?: string | null;\n\n\t/**\n\t * Form submission handler\n\t */\n\tonSubmit?: (event: React.FormEvent<HTMLFormElement>) => void | Promise<void>;\n\n\t/**\n\t * Initial field errors\n\t */\n\tinitialErrors?: Record<string, string | string[]>;\n\n\t/**\n\t * Custom className\n\t */\n\tclassName?: string;\n\n\t/**\n\t * Card variant\n\t */\n\tvariant?: \"default\" | \"bordered\" | \"shadow\" | \"flat\";\n\n\t/**\n\t * Card size\n\t */\n\tsize?: SizeT;\n\tradius?: RadiusT;\n\n\t/**\n\t * Whether to show the card wrapper\n\t */\n\tshowCard?: boolean;\n\n\t/**\n\t * Custom card props\n\t */\n\tcardProps?: any;\n\n\t/**\n\t * Loading state content\n\t */\n\tloadingContent?: React.ReactNode;\n\n\t/**\n\t * Organization logo\n\t */\n\tlogo?: string | React.ReactNode;\n\n\t/**\n\t * Form width\n\t */\n\twidth?: \"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\";\n\n\t/**\n\t * Center the form\n\t */\n\tcentered?: boolean;\n\n\t/**\n\t * Disable animations\n\t */\n\tdisableAnimations?: boolean;\n\n\ttitleAlignment?: \"left\" | \"center\" | \"right\";\n}\n\n// ============================================================================\n// Form Content Component (Memoized)\n// ============================================================================\n\ninterface FormContentProps {\n\tchildren: React.ReactNode;\n\tfooter?: React.ReactNode;\n\tonSubmit?: (event: React.FormEvent<HTMLFormElement>) => void | Promise<void>;\n\tisSubmitting: boolean;\n\tloadingContent?: React.ReactNode;\n\twidth: \"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\";\n\tcentered: boolean;\n}\n\nconst FormContent = React.memo(\n\t({\n\t\tchildren,\n\t\tfooter,\n\t\tonSubmit,\n\t\tisSubmitting,\n\t\tloadingContent,\n\t\twidth,\n\t\tcentered,\n\t}: FormContentProps) => {\n\t\tconst { clearAllErrors } = useFormContext();\n\n\t\t// Handle form submission\n\t\tconst handleSubmit = useCallback(\n\t\t\tasync (event: React.FormEvent<HTMLFormElement>) => {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tclearAllErrors();\n\n\t\t\t\tif (onSubmit) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait onSubmit(event);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t// Let parent component handle the error\n\t\t\t\t\t\tconsole.error(\"Form submission error:\", err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t[onSubmit, clearAllErrors],\n\t\t);\n\n\t\t// Width classes (memoized to prevent recreation)\n\t\tconst widthClasses = useMemo(\n\t\t\t() => ({\n\t\t\t\tsm: \"w-full max-w-sm\",\n\t\t\t\tmd: \"w-full max-w-md\",\n\t\t\t\tlg: \"w-full max-w-lg\",\n\t\t\t\txl: \"w-full max-w-xl\",\n\t\t\t\tfull: \"w-full\",\n\t\t\t}),\n\t\t\t[],\n\t\t);\n\n\t\t// Container className (memoized)\n\t\tconst containerClassName = useMemo(\n\t\t\t() => `relative ${widthClasses[width]} ${centered ? \"mx-auto\" : \"\"}`,\n\t\t\t[widthClasses, width, centered],\n\t\t);\n\n\t\t// Loading overlay (memoized)\n\t\tconst loadingOverlay = useMemo(() => {\n\t\t\tif (!isSubmitting) return null;\n\n\t\t\treturn (\n\t\t\t\t<div className=\"absolute inset-0 bg-background/50 backdrop-blur-sm flex items-center justify-center z-50 rounded-inherit\">\n\t\t\t\t\t{loadingContent || (\n\t\t\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t\t\t<div className=\"w-6 h-6 border-2 border-primary border-t-transparent rounded-full animate-spin\" />\n\t\t\t\t\t\t\t<span className=\"text-sm text-foreground\">Processing...</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t);\n\t\t}, [isSubmitting, loadingContent]);\n\n\t\treturn (\n\t\t\t<div className={containerClassName}>\n\t\t\t\t{/* Form */}\n\t\t\t\t<form onSubmit={handleSubmit} className=\"space-y-4\" noValidate>\n\t\t\t\t\t{children}\n\t\t\t\t\t{footer}\n\t\t\t\t</form>\n\n\t\t\t\t{/* Loading Overlay */}\n\t\t\t\t{loadingOverlay}\n\t\t\t</div>\n\t\t);\n\t},\n);\n\nFormContent.displayName = \"FormContent\";\n\n// ============================================================================\n// Messages Component (Memoized)\n// ============================================================================\n\ninterface MessagesProps {\n\tsuccess?: string | null;\n\terror?: string | null;\n\tdisableAnimations: boolean;\n}\n\nconst Messages = React.memo(\n\t({ success, error, disableAnimations }: MessagesProps) => {\n\t\t// Early return if no messages\n\t\tif (!success && !error) return null;\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{/* Global Success Message */}\n\t\t\t\t{success && (\n\t\t\t\t\t<motion.div\n\t\t\t\t\t\tinitial={disableAnimations ? false : { opacity: 0, y: -10 }}\n\t\t\t\t\t\tanimate={{ opacity: 1, y: 0 }}\n\t\t\t\t\t\tclassName=\"mb-4 p-3 bg-success-50 dark:bg-success-100/10 border border-success-200 dark:border-success-800 rounded-lg\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\tclassName=\"w-5 h-5 text-success-600 dark:text-success-400\"\n\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\t\t\tstrokeWidth={2}\n\t\t\t\t\t\t\t\t\td=\"M5 13l4 4L19 7\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t<p className=\"text-sm text-success-700 dark:text-success-300\">\n\t\t\t\t\t\t\t\t{success}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</motion.div>\n\t\t\t\t)}\n\n\t\t\t\t{/* Global Error Message */}\n\t\t\t\t{error && (\n\t\t\t\t\t<FieldError\n\t\t\t\t\t\terror={error}\n\t\t\t\t\t\tvariant=\"default\"\n\t\t\t\t\t\tclassName=\"mb-4 p-3 bg-danger-50 dark:bg-danger-100/10 border border-danger-200 dark:border-danger-800 rounded-lg\"\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</>\n\t\t);\n\t},\n);\n\nMessages.displayName = \"Messages\";\n\n// ============================================================================\n// Header Component (Memoized)\n// ============================================================================\n\ninterface HeaderProps {\n\theader?: React.ReactNode;\n\ttitle?: string;\n\tsubtitle?: string;\n\tdesc?: React.ReactNode;\n\tshowCard: boolean;\n\ttitleAlignment?: \"left\" | \"center\" | \"right\";\n}\n\nconst Header = React.memo(\n\t({\n\t\theader,\n\t\ttitle,\n\t\tsubtitle,\n\t\tshowCard,\n\t\tdesc,\n\t\ttitleAlignment,\n\t}: HeaderProps) => {\n\t\t// Early return if no header content\n\t\tif (header) return <>{header}</>;\n\t\tif (!title && !subtitle) return null;\n\n\t\tif (!showCard) {\n\t\t\treturn (\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"flex flex-col text-center pb-2\",\n\t\t\t\t\t\tgetTitleAlignment(titleAlignment ?? \"center\"),\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t{title && (\n\t\t\t\t\t\t<h1 className=\"text-2xl font-bold text-foreground mb-2\">{title}</h1>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{subtitle && <p className=\"text-default-500\">{subtitle}</p>}\n\n\t\t\t\t\t{desc}\n\t\t\t\t</div>\n\t\t\t);\n\t\t}\n\n\t\treturn (\n\t\t\t<CardHeader className=\"flex flex-col items-center text-center pb-2\">\n\t\t\t\t{title && (\n\t\t\t\t\t<h1 className=\"text-2xl font-bold text-foreground mb-2\">{title}</h1>\n\t\t\t\t)}\n\t\t\t\t{subtitle && <p className=\"text-default-500 text-sm\">{subtitle}</p>}\n\t\t\t</CardHeader>\n\t\t);\n\t},\n);\n\nHeader.displayName = \"Header\";\n\n// ============================================================================\n// Logo Component (Memoized)\n// ============================================================================\n\ninterface LogoProps {\n\tlogo?: string | React.ReactNode;\n\torgLogoUrl?: string;\n}\n\nconst Logo = React.memo(({ logo, orgLogoUrl }: LogoProps) => {\n\tif (!logo) {\n\t\t// Use organization logo if available\n\t\tif (orgLogoUrl) {\n\t\t\treturn (\n\t\t\t\t<img\n\t\t\t\t\tsrc={orgLogoUrl}\n\t\t\t\t\talt=\"Organization Logo\"\n\t\t\t\t\tclassName=\"h-8 w-auto mx-auto mb-6\"\n\t\t\t\t/>\n\t\t\t);\n\t\t}\n\t\treturn null;\n\t}\n\n\tif (typeof logo === \"string\") {\n\t\treturn <img src={logo} alt=\"Logo\" className=\"h-8 w-auto mx-auto mb-6\" />;\n\t}\n\n\treturn <div className=\"flex justify-center mb-6\">{logo}</div>;\n});\n\nLogo.displayName = \"Logo\";\n\n// ============================================================================\n// Form Wrapper Component\n// ============================================================================\n\nexport function FormWrapper({\n\tchildren,\n\ttitle,\n\tsubtitle,\n\tdesc,\n\theader,\n\tfooter,\n\tisSubmitting = false,\n\terror,\n\tsuccess,\n\tonSubmit,\n\tinitialErrors = {},\n\tclassName = \"\",\n\tvariant = \"shadow\",\n\tsize = \"md\",\n\tshowCard = true,\n\tcardProps = {},\n\tloadingContent,\n\tlogo,\n\twidth = \"md\",\n\tcentered = true,\n\tdisableAnimations = false,\n\ttitleAlignment,\n}: FormWrapperProps) {\n\tconst { theme } = useTheme();\n\tconst { components, organizationSettings } = useConfig();\n\n\t// Custom component override\n\tconst CustomFormWrapper = components.FormWrapper;\n\tif (CustomFormWrapper) {\n\t\treturn (\n\t\t\t<CustomFormWrapper\n\t\t\t\t{...{\n\t\t\t\t\tchildren,\n\t\t\t\t\ttitle,\n\t\t\t\t\tsubtitle,\n\t\t\t\t\theader,\n\t\t\t\t\tfooter,\n\t\t\t\t\tisSubmitting,\n\t\t\t\t\terror,\n\t\t\t\t\tsuccess,\n\t\t\t\t\tonSubmit,\n\t\t\t\t\tinitialErrors,\n\t\t\t\t\tclassName,\n\t\t\t\t\tvariant,\n\t\t\t\t\tsize,\n\t\t\t\t\tshowCard,\n\t\t\t\t\tcardProps,\n\t\t\t\t\tloadingContent,\n\t\t\t\t\tlogo,\n\t\t\t\t\twidth,\n\t\t\t\t\tcentered,\n\t\t\t\t\tdisableAnimations,\n\t\t\t\t}}\n\t\t\t/>\n\t\t);\n\t}\n\n\t// Memoized components with stable props\n\tconst logoElement = useMemo(\n\t\t() => (\n\t\t\t<Logo logo={logo} orgLogoUrl={organizationSettings?.branding?.logoUrl} />\n\t\t),\n\t\t[logo, organizationSettings?.branding?.logoUrl],\n\t);\n\n\tconst headerElement = useMemo(\n\t\t() => (\n\t\t\t<Header\n\t\t\t\theader={header}\n\t\t\t\ttitle={title}\n\t\t\t\tsubtitle={subtitle}\n\t\t\t\tdesc={desc}\n\t\t\t\tshowCard={showCard}\n\t\t\t\ttitleAlignment={titleAlignment}\n\t\t\t/>\n\t\t),\n\t\t[header, title, subtitle, showCard, titleAlignment],\n\t);\n\n\tconst messagesElement = useMemo(\n\t\t() => (\n\t\t\t<Messages\n\t\t\t\tsuccess={success}\n\t\t\t\terror={error}\n\t\t\t\tdisableAnimations={disableAnimations}\n\t\t\t/>\n\t\t),\n\t\t[success, error, disableAnimations],\n\t);\n\n\t// Memoize the form content JSX to prevent recreation\n\tconst formContent = useMemo(\n\t\t() => (\n\t\t\t<FormStateProvider\n\t\t\t\tisSubmitting={isSubmitting}\n\t\t\t\tinitialErrors={initialErrors}\n\t\t\t>\n\t\t\t\t{logoElement}\n\t\t\t\t{messagesElement}\n\t\t\t\t<FormContent\n\t\t\t\t\tonSubmit={onSubmit}\n\t\t\t\t\tisSubmitting={isSubmitting}\n\t\t\t\t\tloadingContent={loadingContent}\n\t\t\t\t\twidth={width}\n\t\t\t\t\tcentered={centered}\n\t\t\t\t\tfooter={footer}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</FormContent>\n\t\t\t</FormStateProvider>\n\t\t),\n\t\t[\n\t\t\tisSubmitting,\n\t\t\tinitialErrors,\n\t\t\tlogoElement,\n\t\t\tmessagesElement,\n\t\t\tonSubmit,\n\t\t\tloadingContent,\n\t\t\twidth,\n\t\t\tcentered,\n\t\t\tfooter,\n\t\t\tchildren,\n\t\t],\n\t);\n\n\t// Render without card\n\tif (!showCard) {\n\t\treturn (\n\t\t\t<AnimatedContent disableAnimations={disableAnimations}>\n\t\t\t\t<div className={className}>\n\t\t\t\t\t{headerElement}\n\t\t\t\t\t<div className=\"pt-0\">{formContent}</div>\n\t\t\t\t</div>\n\t\t\t</AnimatedContent>\n\t\t);\n\t}\n\n\t// Render with card\n\treturn (\n\t\t<AnimatedContent disableAnimations={disableAnimations}>\n\t\t\t<Card variant={variant} className={className} {...cardProps}>\n\t\t\t\t{headerElement}\n\t\t\t\t<CardBody className=\"pt-0\">{formContent}</CardBody>\n\t\t\t</Card>\n\t\t</AnimatedContent>\n\t);\n}\n\n// ============================================================================\n// Form Context Hook\n// ============================================================================\n\n/**\n * Hook to access form context\n */\nexport function useFormContext(): FormContextValue {\n\tconst context = useContext(FormContext);\n\tif (!context) {\n\t\tthrow new Error(\"useFormContext must be used within a FormWrapper\");\n\t}\n\treturn context;\n}\n\n/**\n * Hook to manage individual field state (optimized to prevent unnecessary re-renders)\n */\nexport function useFormField(name: string) {\n\tconst context = useFormContext();\n\n\t// Stable callback functions\n\tconst setError = useCallback(\n\t\t(error: string | string[] | null) => {\n\t\t\tcontext.setFieldError(name, error);\n\t\t},\n\t\t[context.setFieldError, name],\n\t);\n\n\tconst setTouched = useCallback(\n\t\t(touched = true) => {\n\t\t\tcontext.setFieldTouched(name, touched);\n\t\t},\n\t\t[context.setFieldTouched, name],\n\t);\n\n\tconst clearError = useCallback(() => {\n\t\tcontext.clearFieldError(name);\n\t}, [context.clearFieldError, name]);\n\n\t// Memoize the return object to prevent recreating it\n\treturn useMemo(\n\t\t() => ({\n\t\t\tname,\n\t\t\terror: context.getFieldError(name),\n\t\t\ttouched: context.getFieldTouched(name),\n\t\t\tshowError: context.getFieldTouched(name) && !!context.getFieldError(name),\n\t\t\tsetError,\n\t\t\tsetTouched,\n\t\t\tclearError,\n\t\t\tisSubmitting: context.isSubmitting,\n\t\t}),\n\t\t[\n\t\t\tname,\n\t\t\tcontext.getFieldError(name),\n\t\t\tcontext.getFieldTouched(name),\n\t\t\tsetError,\n\t\t\tsetTouched,\n\t\t\tclearError,\n\t\t\tcontext.isSubmitting,\n\t\t],\n\t);\n}\n\n// ============================================================================\n// Export\n// ============================================================================\n\nexport default FormWrapper;\nexport { FormContext };\n"],"names":["FormContext","createContext","AnimatedContent","React","children","disableAnimations","jsx","Fragment","motion","FormStateProvider","isSubmitting","initialErrors","errorsRef","useRef","touchedRef","forceUpdate","x","setFieldError","useCallback","field","fieldError","newErrors","setFieldTouched","fieldTouched","clearFieldError","clearAllErrors","getFieldError","getFieldTouched","contextValue","useMemo","FormContent","footer","onSubmit","loadingContent","width","centered","useFormContext","handleSubmit","event","err","widthClasses","containerClassName","loadingOverlay","jsxs","Messages","success","error","FieldError","Header","header","title","subtitle","showCard","desc","titleAlignment","CardHeader","cn","getTitleAlignment","Logo","logo","orgLogoUrl","FormWrapper","className","variant","size","cardProps","theme","useTheme","components","organizationSettings","useConfig","CustomFormWrapper","logoElement","headerElement","messagesElement","formContent","Card","CardBody","context","useContext","useFormField","name","setError","setTouched","touched","clearError","form_wrapper_default"],"mappings":"8dA2CMA,EAAcC,gBAAuC,IAAI,EAMzDC,EAAkBC,EAAM,QAAA,KAC7B,CAAC,CACA,SAAAC,EACA,kBAAAC,CAAA,IAKIA,EAA0BC,EAAAA,IAAAC,EAAAA,SAAA,CAAG,SAAAH,CAAS,CAAA,EAGzCE,EAAA,IAACE,EAAAA,OAAO,IAAP,CACA,QAAS,CAAE,QAAS,EAAG,EAAG,EAAG,EAC7B,QAAS,CAAE,QAAS,EAAG,EAAG,CAAE,EAC5B,WAAY,CAAE,SAAU,GAAK,KAAM,SAAU,EAE5C,SAAAJ,CAAA,CACF,CAGH,EAEAF,EAAgB,YAAc,kBAY9B,MAAMO,EAAoBN,EAAM,QAAA,KAC/B,CAAC,CAAE,SAAAC,EAAU,aAAAM,EAAc,cAAAC,KAA4C,CAEhE,MAAAC,EAAYC,SAA0CF,CAAa,EACnEG,EAAaD,EAAgC,OAAA,EAAE,EAGrDV,EAAA,QAAM,UAAU,IAAM,CACrBS,EAAU,QAAUD,CACrB,EAAG,EAAE,EAGC,KAAA,CAAG,CAAAI,CAAW,EAAIZ,UAAM,WAAYa,GAAMA,EAAI,EAAG,CAAC,EAGlDC,EAAgBC,EAAA,YACrB,CAACC,EAAeC,IAAyC,CACxD,GAAIA,IAAe,MAClB,GAAIR,EAAU,QAAQO,CAAK,IAAM,OAAW,CAC3C,MAAME,EAAY,CAAE,GAAGT,EAAU,OAAQ,EACzC,OAAOS,EAAUF,CAAK,EACtBP,EAAU,QAAUS,EACRN,EAAA,CAAA,OAGTH,EAAU,QAAQO,CAAK,IAAMC,IACtBR,EAAA,QAAU,CAAE,GAAGA,EAAU,QAAS,CAACO,CAAK,EAAGC,CAAW,EACpDL,EAAA,EAGf,EACA,CAAA,CACD,EAEMO,EAAkBJ,EAAA,YACvB,CAACC,EAAeI,EAAe,KAAS,CACnCT,EAAW,QAAQK,CAAK,IAAMI,IACtBT,EAAA,QAAU,CAAE,GAAGA,EAAW,QAAS,CAACK,CAAK,EAAGI,CAAa,EACxDR,EAAA,EAEd,EACA,CAAA,CACD,EAEMS,EAAkBN,EAAA,YACtBC,GAAkB,CAClBF,EAAcE,EAAO,IAAI,CAC1B,EACA,CAACF,CAAa,CACf,EAEMQ,EAAiBP,EAAAA,YAAY,IAAM,CACpC,OAAO,KAAKN,EAAU,OAAO,EAAE,OAAS,IAC3CA,EAAU,QAAU,CAAC,EACTG,EAAA,EAEd,EAAG,EAAE,EAECW,EAAgBR,cAAaC,GAC3BP,EAAU,QAAQO,CAAK,GAAK,KACjC,EAAE,EAECQ,EAAkBT,cAAaC,GAC7BL,EAAW,QAAQK,CAAK,GAAK,GAClC,EAAE,EAGCS,EAAeC,EAAA,QACpB,KAAO,CACN,aAAAnB,EACA,OAAQE,EAAU,QAClB,QAASE,EAAW,QACpB,cAAAG,EACA,gBAAAK,EACA,gBAAAE,EACA,eAAAC,EACA,UAAW,OAAO,KAAKb,EAAU,OAAO,EAAE,OAAS,EACnD,cAAAc,EACA,gBAAAC,CAAA,GAED,CACCjB,EACAO,EACAK,EACAE,EACAC,EACAC,EACAC,CAAA,CAGF,EAEA,aACE3B,EAAY,SAAZ,CAAqB,MAAO4B,EAC3B,SAAAxB,EACF,CAAA,CAGH,EAEAK,EAAkB,YAAc,oBA+HhC,MAAMqB,EAAc3B,EAAM,QAAA,KACzB,CAAC,CACA,SAAAC,EACA,OAAA2B,EACA,SAAAC,EACA,aAAAtB,EACA,eAAAuB,EACA,MAAAC,EACA,SAAAC,CAAA,IACuB,CACjB,KAAA,CAAE,eAAAV,CAAe,EAAIW,EAAe,EAGpCC,EAAenB,EAAA,YACpB,MAAOoB,GAA4C,CAIlD,GAHAA,EAAM,eAAe,EACNb,EAAA,EAEXO,EACC,GAAA,CACH,MAAMA,EAASM,CAAK,QACZC,EAAK,CAEL,QAAA,MAAM,yBAA0BA,CAAG,CAAA,CAG9C,EACA,CAACP,EAAUP,CAAc,CAC1B,EAGMe,EAAeX,EAAA,QACpB,KAAO,CACN,GAAI,kBACJ,GAAI,kBACJ,GAAI,kBACJ,GAAI,kBACJ,KAAM,QAAA,GAEP,CAAA,CACD,EAGMY,EAAqBZ,EAAA,QAC1B,IAAM,YAAYW,EAAaN,CAAK,CAAC,IAAIC,EAAW,UAAY,EAAE,GAClE,CAACK,EAAcN,EAAOC,CAAQ,CAC/B,EAGMO,EAAiBb,EAAAA,QAAQ,IACzBnB,EAGJJ,EAAA,IAAC,OAAI,UAAU,2GACb,YACCqC,EAAAA,KAAA,MAAA,CAAI,UAAU,0BACd,SAAA,CAACrC,EAAAA,IAAA,MAAA,CAAI,UAAU,gFAAiF,CAAA,EAC/FA,EAAA,IAAA,OAAA,CAAK,UAAU,0BAA0B,SAAa,eAAA,CAAA,CAAA,CAAA,CACxD,CAEF,CAAA,EAVyB,KAYxB,CAACI,EAAcuB,CAAc,CAAC,EAGhC,OAAAU,EAAA,KAAC,MAAI,CAAA,UAAWF,EAEf,SAAA,CAAAE,OAAC,QAAK,SAAUN,EAAc,UAAU,YAAY,WAAU,GAC5D,SAAA,CAAAjC,EACA2B,CAAA,EACF,EAGCW,CAAA,EACF,CAAA,CAGH,EAEAZ,EAAY,YAAc,cAY1B,MAAMc,EAAWzC,EAAM,QAAA,KACtB,CAAC,CAAE,QAAA0C,EAAS,MAAAC,EAAO,kBAAAzC,KAEd,CAACwC,GAAW,CAACC,EAAc,KAK5BH,EAAA,KAAApC,WAAA,CAAA,SAAA,CACAsC,GAAAvC,EAAA,IAACE,EAAAA,OAAO,IAAP,CACA,QAASH,EAAoB,GAAQ,CAAE,QAAS,EAAG,EAAG,GAAI,EAC1D,QAAS,CAAE,QAAS,EAAG,EAAG,CAAE,EAC5B,UAAU,6GAEV,SAAAsC,EAAA,KAAC,MAAI,CAAA,UAAU,0BACd,SAAA,CAAArC,EAAA,IAAC,MAAA,CACA,UAAU,iDACV,KAAK,OACL,OAAO,eACP,QAAQ,YAER,SAAAA,EAAA,IAAC,OAAA,CACA,cAAc,QACd,eAAe,QACf,YAAa,EACb,EAAE,gBAAA,CAAA,CACH,CACD,EACCA,EAAA,IAAA,IAAA,CAAE,UAAU,iDACX,SACFuC,CAAA,CAAA,CAAA,CACD,CAAA,CAAA,CACD,EAIAC,GACAxC,EAAA,IAACyC,EAAA,WAAA,CACA,MAAAD,EACA,QAAQ,UACR,UAAU,wGAAA,CAAA,CACX,EAEF,CAGH,EAEAF,EAAS,YAAc,WAevB,MAAMI,EAAS7C,EAAM,QAAA,KACpB,CAAC,CACA,OAAA8C,EACA,MAAAC,EACA,SAAAC,EACA,SAAAC,EACA,KAAAC,EACA,eAAAC,CAAA,IAGIL,EAAe3C,EAAA,IAAAC,EAAA,SAAA,CAAG,SAAO0C,EAAA,EACzB,CAACC,GAAS,CAACC,EAAiB,KAE3BC,EAoBJT,EAAA,KAACY,EAAW,WAAA,CAAA,UAAU,8CACpB,SAAA,CAAAL,GACC5C,EAAA,IAAA,KAAA,CAAG,UAAU,0CAA2C,SAAM4C,EAAA,EAE/DC,GAAY7C,EAAA,IAAC,IAAE,CAAA,UAAU,2BAA4B,SAAS6C,CAAA,CAAA,CAAA,EAChE,EAvBCR,EAAA,KAAC,MAAA,CACA,UAAWa,EAAA,GACV,iCACAC,EAAA,kBAAkBH,GAAkB,QAAQ,CAC7C,EAEC,SAAA,CAAAJ,GACC5C,EAAA,IAAA,KAAA,CAAG,UAAU,0CAA2C,SAAM4C,EAAA,EAG/DC,GAAY7C,EAAA,IAAC,IAAE,CAAA,UAAU,mBAAoB,SAAS6C,EAAA,EAEtDE,CAAA,CAAA,CACF,CAaJ,EAEAL,EAAO,YAAc,SAWrB,MAAMU,EAAOvD,EAAM,QAAA,KAAK,CAAC,CAAE,KAAAwD,EAAM,WAAAC,KAC3BD,EAcD,OAAOA,GAAS,eACX,MAAI,CAAA,IAAKA,EAAM,IAAI,OAAO,UAAU,0BAA0B,EAG/DrD,EAAAA,IAAA,MAAA,CAAI,UAAU,2BAA4B,SAAKqD,EAAA,EAhBlDC,EAEFtD,EAAA,IAAC,MAAA,CACA,IAAKsD,EACL,IAAI,oBACJ,UAAU,yBAAA,CACX,EAGK,IAQR,EAEDF,EAAK,YAAc,OAMZ,SAASG,EAAY,CAC3B,SAAAzD,EACA,MAAA8C,EACA,SAAAC,EACA,KAAAE,EACA,OAAAJ,EACA,OAAAlB,EACA,aAAArB,EAAe,GACf,MAAAoC,EACA,QAAAD,EACA,SAAAb,EACA,cAAArB,EAAgB,CAAC,EACjB,UAAAmD,EAAY,GACZ,QAAAC,EAAU,SACV,KAAAC,EAAO,KACP,SAAAZ,EAAW,GACX,UAAAa,EAAY,CAAC,EACb,eAAAhC,EACA,KAAA0B,EACA,MAAAzB,EAAQ,KACR,SAAAC,EAAW,GACX,kBAAA9B,EAAoB,GACpB,eAAAiD,CACD,EAAqB,CACd,KAAA,CAAE,MAAAY,CAAM,EAAIC,WAAS,EACrB,CAAE,WAAAC,EAAY,qBAAAC,CAAqB,EAAIC,YAAU,EAGjDC,EAAoBH,EAAW,YACrC,GAAIG,EAEF,OAAAjE,EAAA,IAACiE,EAAA,CAEC,SAAAnE,EACA,MAAA8C,EACA,SAAAC,EACA,OAAAF,EACA,OAAAlB,EACA,aAAArB,EACA,MAAAoC,EACA,QAAAD,EACA,SAAAb,EACA,cAAArB,EACA,UAAAmD,EACA,QAAAC,EACA,KAAAC,EACA,SAAAZ,EACA,UAAAa,EACA,eAAAhC,EACA,KAAA0B,EACA,MAAAzB,EACA,SAAAC,EACA,kBAAA9B,CACD,CACD,EAKF,MAAMmE,EAAc3C,EAAA,QACnB,IACEvB,EAAA,IAAAoD,EAAA,CAAK,KAAAC,EAAY,WAAYU,GAAsB,UAAU,QAAS,EAExE,CAACV,EAAMU,GAAsB,UAAU,OAAO,CAC/C,EAEMI,EAAgB5C,EAAA,QACrB,IACCvB,EAAA,IAAC0C,EAAA,CACA,OAAAC,EACA,MAAAC,EACA,SAAAC,EACA,KAAAE,EACA,SAAAD,EACA,eAAAE,CAAA,CACD,EAED,CAACL,EAAQC,EAAOC,EAAUC,EAAUE,CAAc,CACnD,EAEMoB,EAAkB7C,EAAA,QACvB,IACCvB,EAAA,IAACsC,EAAA,CACA,QAAAC,EACA,MAAAC,EACA,kBAAAzC,CAAA,CACD,EAED,CAACwC,EAASC,EAAOzC,CAAiB,CACnC,EAGMsE,EAAc9C,EAAA,QACnB,IACCc,EAAA,KAAClC,EAAA,CACA,aAAAC,EACA,cAAAC,EAEC,SAAA,CAAA6D,EACAE,EACDpE,EAAA,IAACwB,EAAA,CACA,SAAAE,EACA,aAAAtB,EACA,eAAAuB,EACA,MAAAC,EACA,SAAAC,EACA,OAAAJ,EAEC,SAAA3B,CAAA,CAAA,CACF,CAAA,CACD,EAED,CACCM,EACAC,EACA6D,EACAE,EACA1C,EACAC,EACAC,EACAC,EACAJ,EACA3B,CAAA,CAEF,EAGA,OAAKgD,EAaJ9C,MAACJ,GAAgB,kBAAAG,EAChB,SAAAsC,EAAAA,KAACiC,QAAK,QAAAb,EAAkB,UAAAD,EAAuB,GAAGG,EAChD,SAAA,CAAAQ,EACAnE,EAAA,IAAAuE,EAAA,SAAA,CAAS,UAAU,OAAQ,SAAYF,CAAA,CAAA,CAAA,CAAA,CACzC,CACD,CAAA,EAhBErE,EAAA,IAAAJ,EAAA,CAAgB,kBAAAG,EAChB,SAAAsC,EAAAA,KAAC,OAAI,UAAAmB,EACH,SAAA,CAAAW,EACAnE,EAAA,IAAA,MAAA,CAAI,UAAU,OAAQ,SAAYqE,CAAA,CAAA,CAAA,CAAA,CACpC,CACD,CAAA,CAaH,CASO,SAASvC,GAAmC,CAC5C,MAAA0C,EAAUC,aAAW/E,CAAW,EACtC,GAAI,CAAC8E,EACE,MAAA,IAAI,MAAM,kDAAkD,EAE5D,OAAAA,CACR,CAKO,SAASE,EAAaC,EAAc,CAC1C,MAAMH,EAAU1C,EAAe,EAGzB8C,EAAWhE,EAAA,YACf4B,GAAoC,CAC5BgC,EAAA,cAAcG,EAAMnC,CAAK,CAClC,EACA,CAACgC,EAAQ,cAAeG,CAAI,CAC7B,EAEME,EAAajE,EAAA,YAClB,CAACkE,EAAU,KAAS,CACXN,EAAA,gBAAgBG,EAAMG,CAAO,CACtC,EACA,CAACN,EAAQ,gBAAiBG,CAAI,CAC/B,EAEMI,EAAanE,EAAAA,YAAY,IAAM,CACpC4D,EAAQ,gBAAgBG,CAAI,CAC1B,EAAA,CAACH,EAAQ,gBAAiBG,CAAI,CAAC,EAG3B,OAAApD,EAAA,QACN,KAAO,CACN,KAAAoD,EACA,MAAOH,EAAQ,cAAcG,CAAI,EACjC,QAASH,EAAQ,gBAAgBG,CAAI,EACrC,UAAWH,EAAQ,gBAAgBG,CAAI,GAAK,CAAC,CAACH,EAAQ,cAAcG,CAAI,EACxE,SAAAC,EACA,WAAAC,EACA,WAAAE,EACA,aAAcP,EAAQ,YAAA,GAEvB,CACCG,EACAH,EAAQ,cAAcG,CAAI,EAC1BH,EAAQ,gBAAgBG,CAAI,EAC5BC,EACAC,EACAE,EACAP,EAAQ,YAAA,CAEV,CACD,CAMA,IAAOQ,EAAQzB"}