UNPKG

react-vite-themes

Version:

A test/experimental React theme system created for learning purposes. Features atomic design components, SCSS variables, and dark/light theme support. Not intended for production use.

169 lines (168 loc) 6.01 kB
import { useState, useCallback, useMemo } from 'react'; import { validateField, validateForm, isFormValid } from '../utils/validation'; export const useForm = (options = {}) => { const { initialValues = {}, validationSchema = {}, onSubmit, validateOnChange = false, validateOnBlur = true } = options; const [values, setValues] = useState(initialValues); const [errors, setErrors] = useState({}); const [touched, setTouched] = useState({}); const [isSubmitting, setIsSubmitting] = useState(false); // Validate a single field const validateFieldValue = useCallback((field, value) => { const rules = validationSchema[field]; if (!rules) { return { isValid: true, errors: [] }; } return validateField(value, rules); }, [validationSchema]); // Validate entire form const validateFormValues = useCallback(() => { const validationResults = validateForm(values, validationSchema); const newErrors = {}; Object.entries(validationResults).forEach(([field, result]) => { if (!result.isValid) { newErrors[field] = result.errors; } }); setErrors(newErrors); return isFormValid(validationResults); }, [values, validationSchema]); // Set a single field value const setValue = useCallback((field, value) => { setValues(prev => ({ ...prev, [field]: value })); if (validateOnChange) { const result = validateFieldValue(field, value); setErrors(prev => ({ ...prev, [field]: result.errors })); } }, [validateOnChange, validateFieldValue]); // Set multiple field values const setValuesHandler = useCallback((newValues) => { setValues(newValues); }, []); // Set field error const setFieldError = useCallback((field, error) => { setErrors(prev => ({ ...prev, [field]: [error] })); }, []); // Set multiple field errors const setFieldErrors = useCallback((newErrors) => { setErrors(newErrors); }, []); // Validate a single field const validateFieldHandler = useCallback((field) => { const result = validateFieldValue(field, values[field]); setErrors(prev => ({ ...prev, [field]: result.errors })); }, [validateFieldValue, values]); // Validate entire form const validateFormHandler = useCallback(() => { return validateFormValues(); }, [validateFormValues]); // Handle field blur const handleBlur = useCallback((field) => { setTouched(prev => ({ ...prev, [field]: true })); if (validateOnBlur) { validateFieldHandler(field); } }, [validateOnBlur, validateFieldHandler]); // Handle field change const handleChange = useCallback((field, value) => { setValue(field, value); }, [setValue]); // Handle form submission const handleSubmit = useCallback(async (e) => { if (e) { e.preventDefault(); } // Mark all fields as touched const allTouched = {}; Object.keys(validationSchema).forEach(field => { allTouched[field] = true; }); setTouched(allTouched); // Validate form const isValid = validateFormHandler(); if (isValid && onSubmit) { setIsSubmitting(true); try { const result = onSubmit(values); // If onSubmit returns a Promise, wait for it if (result instanceof Promise) { await result; } } finally { setIsSubmitting(false); } } }, [validationSchema, validateFormHandler, onSubmit, values]); // Reset form const reset = useCallback(() => { setValues(initialValues); setErrors({}); setTouched({}); setIsSubmitting(false); }, [initialValues]); // Reset errors const resetErrors = useCallback(() => { setErrors({}); }, []); // Get field props for easy integration with inputs const getFieldProps = useCallback((field) => { const fieldValue = values[field]; let displayValue = ''; // Convert value to string for display if (fieldValue !== undefined && fieldValue !== null) { if (typeof fieldValue === 'string' || typeof fieldValue === 'number') { displayValue = String(fieldValue); } else if (fieldValue instanceof Date) { displayValue = fieldValue.toISOString().split('T')[0]; } else { displayValue = String(fieldValue); } } return { value: displayValue, onChange: (value) => handleChange(field, value), onBlur: () => handleBlur(field), error: errors[field] || [], isInvalid: errors[field] && errors[field].length > 0, isTouched: touched[field] || false }; }, [values, errors, touched, handleChange, handleBlur]); // Check if form is valid const isValid = useMemo(() => { return Object.keys(validationSchema).length === 0 || Object.keys(validationSchema).every(field => { const result = validateFieldValue(field, values[field]); return result.isValid; }); }, [validationSchema, values, validateFieldValue]); return { values, errors, touched, isValid, isSubmitting, setValue, setValues: setValuesHandler, setFieldError, setFieldErrors, validateField: validateFieldHandler, validateForm: validateFormHandler, handleSubmit, handleBlur, handleChange, reset, resetErrors, getFieldProps }; };