UNPKG

el-form-react

Version:

React form components and hooks powered by Zod validation

1 lines 54.4 kB
{"version":3,"sources":["../src/useForm.ts","../src/utils/index.ts","../src/AutoForm.tsx"],"sourcesContent":["import { useState, useCallback, useRef } from \"react\";\nimport { z } from \"zod\";\nimport {\n FormState,\n UseFormOptions,\n UseFormReturn,\n FieldState,\n ResetOptions,\n SetFocusOptions,\n} from \"./types\";\nimport {\n parseZodErrors,\n setNestedValue,\n getNestedValue,\n removeArrayItem,\n} from \"el-form-core\";\nimport { addArrayItemReact } from \"./utils\";\n\nexport function useForm<T extends Record<string, any>>(\n options: UseFormOptions<T>\n): UseFormReturn<T> {\n const {\n schema,\n initialValues = {},\n validateOnChange = false,\n validateOnBlur = false,\n } = options;\n\n // Ref to store field refs for focus management\n const fieldRefs = useRef<\n Map<keyof T, HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>\n >(new Map());\n\n const [formState, setFormState] = useState<FormState<T>>({\n values: initialValues,\n errors: {},\n touched: {},\n isSubmitting: false,\n isValid: false,\n isDirty: false,\n });\n\n const validate = useCallback(\n (\n values: Partial<T>\n ): { isValid: boolean; errors: Record<keyof T, string> } => {\n try {\n schema.parse(values);\n return { isValid: true, errors: {} as Record<keyof T, string> };\n } catch (error) {\n if (error instanceof z.ZodError) {\n return {\n isValid: false,\n errors: parseZodErrors(error) as Record<keyof T, string>,\n };\n }\n return { isValid: false, errors: {} as Record<keyof T, string> };\n }\n },\n [schema]\n );\n\n // Helper function to check if form is dirty\n const checkIsDirty = useCallback(\n (currentValues: Partial<T>): boolean => {\n // Simple JSON comparison for now - can be optimized later\n return (\n JSON.stringify(initialValues || {}) !==\n JSON.stringify(currentValues || {})\n );\n },\n [initialValues]\n );\n\n // Helper function to check if specific field is dirty\n const checkFieldIsDirty = useCallback(\n (fieldName: keyof T): boolean => {\n const initialValue = (initialValues as any)[fieldName];\n const currentValue = (formState.values as any)[fieldName];\n return JSON.stringify(initialValue) !== JSON.stringify(currentValue);\n },\n [initialValues, formState.values]\n );\n\n const register = useCallback(\n (name: string) => {\n // Get field value using nested path support\n const fieldValue = name.includes(\".\")\n ? getNestedValue(formState.values, name)\n : formState.values[name as keyof T];\n\n const isCheckbox = typeof fieldValue === \"boolean\";\n\n const baseProps = {\n name,\n onChange: (e: React.ChangeEvent<any>) => {\n const target = e.target;\n const value =\n target.type === \"checkbox\"\n ? target.checked\n : target.type === \"number\"\n ? target.value\n ? Number(target.value)\n : undefined\n : target.value;\n\n setFormState((prev) => {\n // Use setNestedValue for nested paths, direct assignment for top-level\n const newValues = name.includes(\".\")\n ? setNestedValue(prev.values, name, value)\n : { ...prev.values, [name]: value };\n\n let newErrors = { ...prev.errors };\n\n // Clear error for this field (handle nested paths)\n if (name.includes(\".\")) {\n // For nested paths, we might need more sophisticated error clearing\n // For now, just clear the specific nested error if it exists\n const nestedError = getNestedValue(newErrors, name);\n if (nestedError) {\n newErrors = setNestedValue(newErrors, name, undefined);\n }\n } else {\n delete newErrors[name as keyof T];\n }\n\n // Run validation if validateOnChange is enabled\n if (validateOnChange) {\n const { errors } = validate(newValues);\n newErrors = errors;\n }\n\n return {\n ...prev,\n values: newValues,\n errors: newErrors,\n isDirty: checkIsDirty(newValues),\n };\n });\n },\n onBlur: (_e: React.FocusEvent<any>) => {\n setFormState((prev) => {\n // Handle touched state for nested paths\n const newTouched = name.includes(\".\")\n ? setNestedValue(prev.touched, name, true)\n : { ...prev.touched, [name]: true };\n\n let newErrors = prev.errors;\n\n // Run validation if validateOnBlur is enabled\n if (validateOnBlur) {\n const { errors } = validate(prev.values);\n newErrors = errors;\n }\n\n return {\n ...prev,\n touched: newTouched,\n errors: newErrors,\n isDirty: checkIsDirty(prev.values),\n };\n });\n },\n };\n\n // For checkboxes, use 'checked' instead of 'value'\n if (isCheckbox) {\n return {\n ...baseProps,\n checked: Boolean(fieldValue),\n };\n }\n\n // For other inputs, use 'value'\n return {\n ...baseProps,\n value: fieldValue || \"\",\n };\n },\n [formState.values, validateOnChange, validateOnBlur, validate, checkIsDirty]\n );\n\n const handleSubmit = useCallback(\n (\n onValid: (data: T) => void,\n onError?: (errors: Record<keyof T, string>) => void\n ) => {\n return (e: React.FormEvent) => {\n e.preventDefault();\n\n setFormState((prev) => ({ ...prev, isSubmitting: true }));\n\n const { isValid, errors } = validate(formState.values);\n\n setFormState((prev) => ({\n ...prev,\n errors,\n isValid,\n isSubmitting: false,\n isDirty: checkIsDirty(formState.values),\n }));\n\n if (isValid) {\n onValid(formState.values as T);\n } else {\n if (onError) {\n onError(errors);\n }\n }\n };\n },\n [formState.values, validate, checkIsDirty]\n );\n\n const reset = useCallback(\n (options?: ResetOptions<T>) => {\n const newValues = options?.values ?? initialValues;\n\n setFormState({\n values: newValues,\n errors: options?.keepErrors ? formState.errors : {},\n touched: options?.keepTouched ? formState.touched : {},\n isSubmitting: false,\n isValid: false,\n isDirty: options?.keepDirty ? formState.isDirty : false,\n });\n },\n [initialValues, formState]\n );\n\n // Enhanced setValue for nested paths\n const setValue = useCallback(\n (path: string, value: any) => {\n setFormState((prev) => {\n const newValues = setNestedValue(prev.values, path, value);\n const { errors } = validate(newValues);\n\n return {\n ...prev,\n values: newValues,\n errors,\n isDirty: checkIsDirty(newValues),\n };\n });\n },\n [validate, checkIsDirty]\n );\n\n // Add item to array at path\n const addArrayItemHandler = useCallback(\n (path: string, item: any) => {\n setFormState((prev) => {\n const newValues = addArrayItemReact(prev.values, path, item);\n const { errors } = validate(newValues);\n\n return {\n ...prev,\n values: newValues,\n errors,\n isDirty: checkIsDirty(newValues),\n };\n });\n },\n [validate, checkIsDirty]\n );\n\n // Remove item from array at path\n const removeArrayItemHandler = useCallback(\n (path: string, index: number) => {\n setFormState((prev) => {\n const newValues = removeArrayItem(prev.values, path, index);\n const { errors } = validate(newValues);\n\n return {\n ...prev,\n values: newValues,\n errors,\n isDirty: checkIsDirty(newValues),\n };\n });\n },\n [validate, checkIsDirty]\n );\n\n // Watch system - overloaded function\n const watch = useCallback(\n ((nameOrNames?: keyof T | (keyof T)[]) => {\n if (!nameOrNames) {\n // Watch all values\n return formState.values;\n }\n\n if (Array.isArray(nameOrNames)) {\n // Watch multiple fields\n const result: Partial<T> = {};\n nameOrNames.forEach((name) => {\n result[name] = formState.values[name];\n });\n return result;\n }\n\n // Watch single field\n return formState.values[nameOrNames];\n }) as UseFormReturn<T>[\"watch\"],\n [formState.values]\n );\n\n // Field state queries\n const isDirty = useCallback(\n <Name extends keyof T>(name?: Name): boolean => {\n if (name) {\n return checkFieldIsDirty(name);\n }\n // Check if form is dirty\n return formState.isDirty;\n },\n [formState.isDirty, checkFieldIsDirty]\n );\n\n const getFieldState = useCallback(\n <Name extends keyof T>(name: Name): FieldState => {\n return {\n isDirty: checkFieldIsDirty(name),\n isTouched: !!formState.touched[name],\n error: formState.errors[name],\n };\n },\n [formState, checkFieldIsDirty]\n );\n\n const getDirtyFields = useCallback((): Partial<Record<keyof T, boolean>> => {\n const dirtyFields: Partial<Record<keyof T, boolean>> = {};\n Object.keys(formState.values).forEach((key) => {\n const fieldName = key as keyof T;\n if (checkFieldIsDirty(fieldName)) {\n dirtyFields[fieldName] = true;\n }\n });\n return dirtyFields;\n }, [formState.values, checkFieldIsDirty]);\n\n const getTouchedFields = useCallback((): Partial<\n Record<keyof T, boolean>\n > => {\n return { ...formState.touched };\n }, [formState.touched]);\n\n // Validation control\n const trigger = useCallback(\n (async (nameOrNames?: keyof T | (keyof T)[]) => {\n if (!nameOrNames) {\n // Validate all fields\n const { isValid } = validate(formState.values);\n return isValid;\n }\n\n if (Array.isArray(nameOrNames)) {\n // Validate multiple fields\n const fieldsToValidate: Partial<T> = {};\n nameOrNames.forEach((name) => {\n fieldsToValidate[name] = formState.values[name];\n });\n const { isValid } = validate(fieldsToValidate);\n return isValid;\n }\n\n // Validate single field - create object with computed property\n const fieldToValidate = {} as Partial<T>;\n (fieldToValidate as any)[nameOrNames] = formState.values[nameOrNames];\n const { isValid } = validate(fieldToValidate);\n return isValid;\n }) as UseFormReturn<T>[\"trigger\"],\n [formState.values, validate]\n );\n\n const clearErrors = useCallback((name?: keyof T) => {\n setFormState((prev) => {\n if (name) {\n // Clear specific field error\n const newErrors = { ...prev.errors };\n delete newErrors[name];\n return { ...prev, errors: newErrors };\n }\n // Clear all errors\n return { ...prev, errors: {} };\n });\n }, []);\n\n const setError = useCallback(\n <Name extends keyof T>(name: Name, error: string) => {\n setFormState((prev) => ({\n ...prev,\n errors: { ...prev.errors, [name]: error },\n }));\n },\n []\n );\n\n // Focus management\n const setFocus = useCallback(\n <Name extends keyof T>(name: Name, options?: SetFocusOptions) => {\n const fieldRef = fieldRefs.current.get(name);\n if (fieldRef) {\n fieldRef.focus();\n if (options?.shouldSelect && \"select\" in fieldRef) {\n fieldRef.select();\n }\n }\n },\n []\n );\n\n const resetField = useCallback(\n <Name extends keyof T>(name: Name) => {\n setFormState((prev) => {\n const newValues = { ...prev.values };\n (newValues as any)[name] = (initialValues as any)[name];\n\n const newErrors = { ...prev.errors };\n delete newErrors[name];\n\n const newTouched = { ...prev.touched };\n delete newTouched[name];\n\n return {\n ...prev,\n values: newValues,\n errors: newErrors,\n touched: newTouched,\n isDirty: checkIsDirty(newValues),\n };\n });\n },\n [initialValues, checkIsDirty]\n );\n\n return {\n register,\n handleSubmit,\n formState,\n reset,\n setValue,\n watch,\n getFieldState,\n isDirty,\n getDirtyFields,\n getTouchedFields,\n trigger,\n clearErrors,\n setError,\n setFocus,\n addArrayItem: addArrayItemHandler,\n removeArrayItem: removeArrayItemHandler,\n resetField,\n };\n}\n","// React-specific utility functions\nimport {\n setNestedValue,\n getNestedValue,\n removeArrayItem,\n parseZodErrors,\n} from \"el-form-core\";\n\n// Re-export core utilities for convenience\nexport { setNestedValue, getNestedValue, removeArrayItem, parseZodErrors };\n\n// React-specific array manipulation (different name to avoid conflicts)\nexport function addArrayItemReact(obj: any, path: string, item: any): any {\n const result = { ...obj };\n\n // Handle array notation like employees[0].friends\n const normalizedPath = path.replace(/\\[(\\d+)\\]/g, \".$1\");\n const keys = normalizedPath.split(\".\").filter((key) => key !== \"\");\n let current = result;\n\n // Navigate to the parent object\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i];\n\n if (!isNaN(Number(key))) {\n // Array index\n if (Array.isArray(current)) {\n current[Number(key)] = Array.isArray(current[Number(key)])\n ? [...current[Number(key)]]\n : { ...current[Number(key)] };\n current = current[Number(key)];\n }\n } else {\n // Object key\n if (typeof current[key] !== \"object\" || current[key] === null) {\n current[key] = {};\n } else {\n current[key] = Array.isArray(current[key])\n ? [...current[key]]\n : { ...current[key] };\n }\n current = current[key];\n }\n }\n\n const arrayKey = keys[keys.length - 1];\n\n if (!isNaN(Number(arrayKey))) {\n // Adding to an array at a numeric index (shouldn't happen with this function)\n if (Array.isArray(current)) {\n current = [...current];\n current[Number(arrayKey)] = item;\n }\n } else {\n // Adding to an array property\n if (!Array.isArray(current[arrayKey])) {\n current[arrayKey] = [];\n } else {\n current[arrayKey] = [...current[arrayKey]]; // Create new array\n }\n current[arrayKey].push(item); // Now safe to push to the new array\n }\n\n return result;\n}\n","import * as React from \"react\";\nimport { useForm } from \"./useForm\";\nimport {\n AutoFormProps,\n AutoFormFieldConfig,\n AutoFormFieldProps,\n AutoFormErrorProps,\n GridColumns,\n} from \"./types\";\nimport { z } from \"zod\";\nimport \"./styles.css\";\n\n// Default error component\nconst DefaultErrorComponent: React.FC<AutoFormErrorProps> = ({\n errors,\n touched,\n}: AutoFormErrorProps) => {\n const errorEntries = Object.entries(errors).filter(\n ([field]) => touched[field]\n );\n\n if (errorEntries.length === 0) return null;\n\n return (\n <div className=\"el-form-error-summary\">\n <h3>⚠️ Please fix the following errors:</h3>\n <ul>\n {errorEntries.map(([field, error]) => (\n <li key={field}>\n <span style={{ color: \"#ef4444\", marginRight: \"0.5rem\" }}>•</span>\n <span style={{ textTransform: \"capitalize\" }}>{field}:</span>\n <span style={{ marginLeft: \"0.25rem\" }}>{String(error)}</span>\n </li>\n ))}\n </ul>\n </div>\n );\n};\n\n// Default field component\nconst DefaultField: React.FC<AutoFormFieldProps> = ({\n name,\n label,\n type = \"text\",\n placeholder,\n value,\n onChange,\n onBlur,\n error,\n touched,\n options,\n}: AutoFormFieldProps) => {\n const fieldId = `field-${name}`;\n\n if (type === \"checkbox\") {\n return (\n <div className=\"flex items-center gap-x-2\">\n <input\n id={fieldId}\n name={name}\n type=\"checkbox\"\n checked={!!value}\n onChange={onChange}\n onBlur={onBlur}\n className=\"h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500\"\n />\n <label htmlFor={fieldId} className=\"text-sm font-medium text-gray-900\">\n {label}\n </label>\n </div>\n );\n }\n\n const inputClasses = `\n w-full px-3 py-2 border rounded-md text-sm text-gray-900 placeholder-gray-500\n focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\n ${\n touched && error\n ? \"border-red-500 focus:ring-red-500 focus:border-red-500\"\n : \"border-gray-300\"\n }\n `\n .trim()\n .replace(/\\s+/g, \" \");\n\n return (\n <div className=\"space-y-1\">\n {label && (\n <label\n htmlFor={fieldId}\n className=\"block text-sm font-medium text-gray-700\"\n >\n {label}\n </label>\n )}\n\n {type === \"textarea\" ? (\n <textarea\n id={fieldId}\n name={name}\n value={value || \"\"}\n onChange={onChange}\n onBlur={onBlur}\n placeholder={placeholder}\n className={`${inputClasses} resize-none`}\n rows={4}\n />\n ) : type === \"select\" && options ? (\n <select\n id={fieldId}\n name={name}\n value={value || \"\"}\n onChange={onChange}\n onBlur={onBlur}\n className={inputClasses}\n >\n <option value=\"\">{placeholder || \"Select an option\"}</option>\n {options.map((option: { value: string; label: string }) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n ) : (\n <input\n id={fieldId}\n name={name}\n type={type}\n value={value || \"\"}\n onChange={onChange}\n onBlur={onBlur}\n placeholder={placeholder}\n className={inputClasses}\n />\n )}\n\n {touched && error && (\n <div className=\"text-red-500 text-xs mt-1\">{error}</div>\n )}\n </div>\n );\n};\n\n// Array Field Component for handling nested arrays\ninterface ArrayFieldProps {\n fieldConfig: AutoFormFieldConfig;\n value: any[];\n path: string;\n onAddItem: (path: string, item: any) => void;\n onRemoveItem: (path: string, index: number) => void;\n onValueChange: (path: string, value: any) => void;\n register: any;\n formState: any;\n}\n\nconst ArrayField: React.FC<ArrayFieldProps> = ({\n fieldConfig,\n value = [],\n path,\n onAddItem,\n onRemoveItem,\n onValueChange,\n register,\n formState,\n}: ArrayFieldProps) => {\n const arrayValue = Array.isArray(value) ? value : [];\n\n const createEmptyItem = () => {\n if (!fieldConfig.fields) return {};\n\n // Handle primitive arrays (like array of strings)\n if (\n fieldConfig.fields.length === 1 &&\n fieldConfig.fields[0].name === \"value\"\n ) {\n const fieldType = fieldConfig.fields[0].type;\n if (fieldType === \"number\") {\n return 0;\n } else if (fieldType === \"checkbox\") {\n return false;\n } else {\n return \"\";\n }\n }\n\n // Handle object arrays\n const emptyItem: any = {};\n fieldConfig.fields.forEach((field) => {\n if (field.type === \"array\") {\n emptyItem[field.name] = [];\n } else if (field.type === \"number\") {\n emptyItem[field.name] = 0;\n } else {\n emptyItem[field.name] = \"\";\n }\n });\n return emptyItem;\n };\n\n const handleAddItem = () => {\n onAddItem(path, createEmptyItem());\n };\n\n const handleRemoveItem = (index: number) => {\n onRemoveItem(path, index);\n };\n\n const renderNestedField = (\n nestedFieldConfig: AutoFormFieldConfig,\n itemIndex: number,\n itemPath: string\n ) => {\n // Handle primitive arrays (like array of strings)\n if (nestedFieldConfig.name === \"value\") {\n const fieldValue = arrayValue[itemIndex] || \"\";\n\n return (\n <div key={itemPath} className=\"space-y-1\">\n <input\n type={nestedFieldConfig.type || \"text\"}\n value={fieldValue}\n onChange={(e) => {\n const newValue =\n nestedFieldConfig.type === \"number\"\n ? e.target.value\n ? Number(e.target.value)\n : 0\n : e.target.value;\n onValueChange(itemPath, newValue);\n }}\n placeholder={nestedFieldConfig.placeholder || \"Enter value\"}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n );\n }\n\n // Handle object arrays\n const fieldPath = `${itemPath}.${nestedFieldConfig.name}`;\n const fieldValue = arrayValue[itemIndex]?.[nestedFieldConfig.name] || \"\";\n\n if (nestedFieldConfig.type === \"array\") {\n return (\n <ArrayField\n key={fieldPath}\n fieldConfig={nestedFieldConfig}\n value={fieldValue}\n path={fieldPath}\n onAddItem={onAddItem}\n onRemoveItem={onRemoveItem}\n onValueChange={onValueChange}\n register={register}\n formState={formState}\n />\n );\n }\n\n return (\n <div key={fieldPath} className=\"space-y-1\">\n {nestedFieldConfig.label && (\n <label className=\"block text-sm font-medium text-gray-700\">\n {nestedFieldConfig.label}\n </label>\n )}\n <input\n type={nestedFieldConfig.type || \"text\"}\n value={fieldValue}\n onChange={(e) => {\n const newValue =\n nestedFieldConfig.type === \"number\"\n ? e.target.value\n ? Number(e.target.value)\n : 0\n : e.target.value;\n onValueChange(fieldPath, newValue);\n }}\n placeholder={nestedFieldConfig.placeholder}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n );\n };\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <label className=\"block text-sm font-medium text-gray-700\">\n {fieldConfig.label || fieldConfig.name}\n </label>\n <button\n type=\"button\"\n onClick={handleAddItem}\n className=\"px-3 py-1 bg-green-600 text-white text-xs rounded-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500\"\n >\n + Add {fieldConfig.label || fieldConfig.name}\n </button>\n </div>\n\n <div className=\"space-y-4\">\n {arrayValue.map((_, index) => {\n const itemPath = `${path}[${index}]`;\n\n return (\n <div\n key={index}\n className=\"p-4 border border-gray-200 rounded-lg bg-gray-50\"\n >\n <div className=\"flex justify-between items-center mb-3\">\n <h4 className=\"text-sm font-medium text-gray-700\">\n {fieldConfig.label || fieldConfig.name} #{index + 1}\n </h4>\n <button\n type=\"button\"\n onClick={() => handleRemoveItem(index)}\n className=\"px-2 py-1 bg-red-600 text-white text-xs rounded hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500\"\n >\n Remove\n </button>\n </div>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-3\">\n {fieldConfig.fields?.map((nestedField) =>\n renderNestedField(nestedField, index, itemPath)\n )}\n </div>\n </div>\n );\n })}\n </div>\n\n {arrayValue.length === 0 && (\n <div className=\"text-gray-500 text-sm italic text-center py-4\">\n No {fieldConfig.label?.toLowerCase() || fieldConfig.name} added yet.\n Click \"Add\" to create one.\n </div>\n )}\n </div>\n );\n};\n\nfunction generateFieldsFromSchema<T extends z.ZodType<any, any>>(\n schema: T\n): AutoFormFieldConfig[] {\n if (!(schema instanceof z.ZodObject)) {\n return [];\n }\n\n const shape = (schema as z.ZodObject<any, any>).shape;\n const fields: AutoFormFieldConfig[] = [];\n\n for (const key in shape) {\n if (Object.prototype.hasOwnProperty.call(shape, key)) {\n const zodType = shape[key] as z.ZodTypeAny;\n const typeName = zodType._def.typeName;\n\n const fieldConfig: AutoFormFieldConfig = {\n name: key,\n label: key\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (str) => str.toUpperCase()),\n type: \"text\", // Default to text\n };\n\n if (typeName === \"ZodString\") {\n const checks = (zodType._def as any).checks || [];\n if (checks.some((c: { kind: string }) => c.kind === \"email\")) {\n fieldConfig.type = \"email\";\n } else if (checks.some((c: { kind: string }) => c.kind === \"url\")) {\n fieldConfig.type = \"url\";\n }\n } else if (typeName === \"ZodNumber\") {\n fieldConfig.type = \"number\";\n } else if (typeName === \"ZodBoolean\") {\n fieldConfig.type = \"checkbox\";\n } else if (typeName === \"ZodEnum\") {\n fieldConfig.type = \"select\";\n fieldConfig.options = (zodType._def as any).values.map((v: string) => ({\n value: v,\n label: v,\n }));\n } else if (typeName === \"ZodDate\") {\n fieldConfig.type = \"date\";\n } else if (typeName === \"ZodArray\") {\n fieldConfig.type = \"array\";\n const arrayElementType = (zodType._def as any).type;\n if (arrayElementType instanceof z.ZodObject) {\n fieldConfig.fields = generateFieldsFromSchema(arrayElementType);\n } else {\n // For primitive arrays (string, number, etc.), create a simple field config\n const elementTypeName = arrayElementType._def.typeName;\n let elementType: \"text\" | \"number\" | \"checkbox\" = \"text\";\n\n if (elementTypeName === \"ZodString\") {\n elementType = \"text\";\n } else if (elementTypeName === \"ZodNumber\") {\n elementType = \"number\";\n } else if (elementTypeName === \"ZodBoolean\") {\n elementType = \"checkbox\";\n }\n\n fieldConfig.fields = [\n {\n name: \"value\",\n type: elementType,\n label: \"Value\",\n },\n ];\n }\n }\n\n fields.push(fieldConfig);\n }\n }\n\n return fields;\n}\n\n// Merge auto-generated fields with manual field overrides\nfunction mergeFields(\n autoFields: AutoFormFieldConfig[],\n manualFields: AutoFormFieldConfig[]\n): AutoFormFieldConfig[] {\n const manualFieldsMap = new Map(\n manualFields.map((field) => [field.name, field])\n );\n\n // Start with auto-generated fields and override with manual ones\n const mergedFields = autoFields.map((autoField) => {\n const manualField = manualFieldsMap.get(autoField.name);\n if (manualField) {\n // Merge the manual field with auto-generated field (manual takes priority)\n return { ...autoField, ...manualField };\n }\n return autoField;\n });\n\n // Add any manual fields that don't exist in auto-generated fields\n manualFields.forEach((manualField) => {\n if (!autoFields.some((autoField) => autoField.name === manualField.name)) {\n mergedFields.push(manualField);\n }\n });\n\n return mergedFields;\n}\n\nexport function AutoForm<T extends Record<string, any>>({\n schema,\n fields,\n initialValues = {},\n layout = \"flex\",\n columns = 12,\n onSubmit,\n onError,\n children,\n customErrorComponent,\n componentMap,\n}: AutoFormProps<T>) {\n const formApi = useForm<T>({\n schema,\n initialValues,\n validateOnChange: true,\n validateOnBlur: true,\n });\n\n const {\n register,\n handleSubmit,\n formState,\n reset,\n setValue,\n addArrayItem,\n removeArrayItem,\n } = formApi;\n\n // Merge auto-generated fields with manual overrides\n const autoGeneratedFields = generateFieldsFromSchema(schema);\n const fieldsToRender = fields\n ? mergeFields(autoGeneratedFields, fields)\n : autoGeneratedFields;\n\n // Choose which error component to use\n const ErrorComponent = customErrorComponent || DefaultErrorComponent;\n\n const renderField = (fieldConfig: AutoFormFieldConfig) => {\n const fieldName = fieldConfig.name as keyof T;\n\n // Map colSpan to Tailwind classes\n const getColSpanClass = (colSpan?: GridColumns) => {\n const spanMap: Record<GridColumns, string> = {\n 1: \"col-span-1\",\n 2: \"col-span-2\",\n 3: \"col-span-3\",\n 4: \"col-span-4\",\n 5: \"col-span-5\",\n 6: \"col-span-6\",\n 7: \"col-span-7\",\n 8: \"col-span-8\",\n 9: \"col-span-9\",\n 10: \"col-span-10\",\n 11: \"col-span-11\",\n 12: \"col-span-12\",\n };\n return spanMap[colSpan || 1];\n };\n\n const getFlexClass = (colSpan?: GridColumns) => {\n const flexMap: Record<GridColumns, string> = {\n 1: \"w-1/12\",\n 2: \"w-2/12\",\n 3: \"w-3/12\",\n 4: \"w-4/12\",\n 5: \"w-5/12\",\n 6: \"w-6/12\",\n 7: \"w-7/12\",\n 8: \"w-8/12\",\n 9: \"w-9/12\",\n 10: \"w-10/12\",\n 11: \"w-11/12\",\n 12: \"w-full\",\n };\n return flexMap[colSpan || 12];\n };\n\n const fieldContainerClasses =\n layout === \"grid\"\n ? getColSpanClass(fieldConfig.colSpan)\n : `flex-none ${getFlexClass(fieldConfig.colSpan)}`;\n\n // Handle array fields\n if (fieldConfig.type === \"array\") {\n const fieldProps = register(String(fieldName));\n const fieldValue = \"value\" in fieldProps ? fieldProps.value : [];\n const arrayValue = Array.isArray(fieldValue) ? fieldValue : [];\n return (\n <div key={fieldConfig.name} className={fieldContainerClasses}>\n <ArrayField\n fieldConfig={fieldConfig}\n value={arrayValue}\n path={fieldConfig.name}\n onAddItem={addArrayItem}\n onRemoveItem={removeArrayItem}\n onValueChange={setValue}\n register={register}\n formState={formState}\n />\n </div>\n );\n }\n\n // Handle regular fields\n const fieldProps = register(String(fieldName));\n const error = formState.errors[fieldName];\n const touched = formState.touched[fieldName];\n\n // Get the field value, handling both checkbox (checked) and regular (value) fields\n const fieldValue =\n \"checked\" in fieldProps\n ? fieldProps.checked\n : \"value\" in fieldProps\n ? fieldProps.value\n : undefined;\n\n // Determine which component to use:\n // 1. Field-level component override (existing behavior)\n // 2. ComponentMap override based on field type\n // 3. Default field component\n const FieldComponent =\n fieldConfig.component ||\n (fieldConfig.type && componentMap?.[fieldConfig.type]) ||\n DefaultField;\n\n return (\n <div key={fieldConfig.name} className={fieldContainerClasses}>\n <FieldComponent\n name={fieldConfig.name}\n label={fieldConfig.label || fieldConfig.name}\n type={fieldConfig.type}\n placeholder={fieldConfig.placeholder}\n value={fieldValue}\n onChange={fieldProps.onChange}\n onBlur={fieldProps.onBlur}\n error={error}\n touched={touched}\n options={fieldConfig.options}\n />\n </div>\n );\n };\n\n // Map columns to Tailwind grid classes\n const getGridClass = (cols: GridColumns) => {\n const gridMap: Record<GridColumns, string> = {\n 1: \"grid-cols-1\",\n 2: \"grid-cols-2\",\n 3: \"grid-cols-3\",\n 4: \"grid-cols-4\",\n 5: \"grid-cols-5\",\n 6: \"grid-cols-6\",\n 7: \"grid-cols-7\",\n 8: \"grid-cols-8\",\n 9: \"grid-cols-9\",\n 10: \"grid-cols-10\",\n 11: \"grid-cols-11\",\n 12: \"grid-cols-12\",\n };\n return gridMap[cols];\n };\n\n const containerClasses =\n layout === \"grid\"\n ? `grid ${getGridClass(columns)} gap-4`\n : `flex flex-wrap gap-4`;\n\n // Default form rendering\n const defaultForm = (\n <form\n onSubmit={handleSubmit(\n (data) => onSubmit(data),\n onError ||\n ((errors) => console.error(\"Form validation errors:\", errors))\n )}\n className=\"w-full\"\n >\n {/* Error Summary Component */}\n <ErrorComponent\n errors={formState.errors as Record<string, string>}\n touched={formState.touched as Record<string, boolean>}\n />\n\n <div className={containerClasses}>\n {fieldsToRender.map(renderField)}\n\n <div\n className={`\n flex gap-3 mt-6\n ${layout === \"grid\" ? \"col-span-full\" : \"w-full\"}\n `\n .trim()\n .replace(/\\s+/g, \" \")}\n >\n <button\n type=\"submit\"\n disabled={formState.isSubmitting}\n className=\"p-2 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-60 disabled:cursor-not-allowed transition-colors duration-200 cursor-pointer\"\n >\n {formState.isSubmitting ? \"Submitting...\" : \"Submit\"}\n </button>\n\n <button\n type=\"button\"\n onClick={() => reset()}\n className=\"p-2 bg-gray-600 text-white rounded-md text-sm font-medium hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-colors duration-200 cursor-pointer\"\n >\n Reset\n </button>\n </div>\n </div>\n </form>\n );\n\n // If children render prop is provided, render it along with the form\n if (children) {\n return (\n <div className=\"w-full\">\n <form\n onSubmit={handleSubmit(\n (data) => onSubmit(data),\n onError ||\n ((errors) => console.error(\"Form validation errors:\", errors))\n )}\n className=\"w-full\"\n >\n {/* Error Summary Component */}\n <ErrorComponent\n errors={formState.errors as Record<string, string>}\n touched={formState.touched as Record<string, boolean>}\n />\n\n {children(formApi)}\n\n <div className={containerClasses}>\n {fieldsToRender.map(renderField)}\n </div>\n </form>\n </div>\n );\n }\n\n // Default rendering without render prop\n return defaultForm;\n}\n"],"mappings":"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