@matthew.ngo/reform
Version:
A flexible and powerful React form management library with advanced validation, state observation, and multi-group support
215 lines (196 loc) • 7.25 kB
text/typescript
export {}
// import { FieldError, UseFormReturn } from 'react-hook-form';
// import { FormDataPath } from '../../../types';
// import {
// FormValidation,
// BaseValidationContext as ValidationContext,
// } from './types';
// import { debounce } from '../../../utils/debounce';
// import { FieldPath, FormGroup } from '../../form/form-groups';
// import { useRef } from 'react';
// import { ValidationConfig, ValidationResult } from '../types';
// export const useFormValidation = <T extends Record<string, any>>(
// config: ValidationConfig<T>,
// methods: UseFormReturn<{ groups: FormGroup<T>[] }>
// ): FormValidation<T> => {
// // Ref to store custom field validators
// const customValidatorsRef = useRef<
// Record<string, (value: any, groupIndex: number) => boolean | string>
// >({});
// const transformFieldError = (error: FieldError): string => {
// return error.message || 'Invalid field';
// };
// const transformErrors = (
// errors: Record<string, FieldError> | undefined
// ): Record<string, string> | undefined => {
// if (!errors) return undefined;
// return Object.entries(errors).reduce(
// (acc, [key, error]) => ({
// ...acc,
// [key]: transformFieldError(error),
// }),
// {}
// );
// };
// /**
// * Register a custom field validator
// *
// * @param field - Field path to validate
// * @param validator - Validation function
// */
// const registerFieldValidator = <K extends FieldPath<T>>(
// field: K,
// validator: (value: any, groupIndex: number) => boolean | string
// ): void => {
// customValidatorsRef.current[field] = validator;
// };
// // Modify validateField to use custom validators if registered
// const validateField = async <K extends keyof T>(
// fieldName: K,
// value: T[K],
// groupIndex: number
// ): Promise<ValidationResult> => {
// const fieldPath = `groups.${groupIndex}.data.${String(
// fieldName
// )}` as FormDataPath<T>;
// try {
// // Check if there's a custom validator for this field
// const customValidator = customValidatorsRef.current[fieldName as string];
// if (customValidator) {
// const result = customValidator(value, groupIndex);
// if (result === false || typeof result === 'string') {
// const message =
// typeof result === 'string' ? result : 'Validation failed';
// methods.setError(fieldPath, {
// type: 'custom',
// message,
// });
// return {
// isValid: false,
// message,
// errors: { [String(fieldName)]: message },
// };
// }
// }
// // Continue with standard validation
// const isValid = await methods.trigger(fieldPath);
// const fieldState = methods.getFieldState(fieldPath);
// // Handle async validation if configured
// if (isValid && config.fields?.[fieldName]?.asyncValidate) {
// const groupPath = `groups.${groupIndex}.data` as FormDataPath<T>;
// const context: ValidationContext<T, K> = {
// formData: methods.getValues(groupPath) as T,
// groupIndex,
// fieldName,
// allGroups: methods.getValues().groups,
// };
// const asyncError = await config.fields[fieldName].asyncValidate!(
// value,
// context
// );
// if (asyncError) {
// methods.setError(fieldPath, {
// type: 'async',
// message: asyncError,
// });
// return {
// isValid: false,
// message: asyncError,
// };
// }
// }
// return {
// isValid: !fieldState.error,
// message: fieldState.error?.message,
// errors: fieldState.error
// ? { [String(fieldName)]: fieldState.error.message || 'Invalid field' }
// : undefined,
// };
// } catch (error) {
// const message =
// error instanceof Error ? error.message : 'Validation failed';
// methods.setError(fieldPath, { type: 'validation', message });
// return { isValid: false, message };
// }
// };
// const validateGroup = async (
// groupIndex: number
// ): Promise<ValidationResult> => {
// const groupPath = `groups.${groupIndex}.data` as FormDataPath<T>;
// try {
// const isValid = await methods.trigger(groupPath);
// const groupErrors = methods.formState.errors?.groups?.[groupIndex]?.data;
// return {
// isValid,
// errors: groupErrors
// ? transformErrors(groupErrors as Record<string, FieldError>)
// : undefined,
// message: isValid ? undefined : 'Group validation failed',
// };
// } catch (error) {
// const message =
// error instanceof Error ? error.message : 'Group validation failed';
// methods.setError(`groups.${groupIndex}`, { type: 'validation', message });
// return { isValid: false, message };
// }
// };
// const validateAllGroups = async (): Promise<ValidationResult> => {
// try {
// const isValid = await methods.trigger();
// const formErrors: Record<string, FieldError> = {};
// // Transform group errors into flat structure
// const groups = methods.formState.errors?.groups;
// if (Array.isArray(groups)) {
// groups.forEach((group, index) => {
// // Add field errors
// if (group?.data) {
// Object.entries(group.data).forEach(([field, error]) => {
// // Add type assertion to error
// if ((error as any)?.message) {
// formErrors[`groups.${index}.${field}`] = {
// type: 'manual',
// message: (error as any).message,
// };
// }
// });
// }
// // Add group level error
// if (group?.message) {
// formErrors[`group${index}`] = {
// type: 'manual',
// message: group.message,
// };
// }
// });
// }
// return {
// isValid,
// errors:
// Object.keys(formErrors).length > 0
// ? transformErrors(formErrors)
// : undefined,
// message: isValid ? undefined : 'Form validation failed',
// };
// } catch (error) {
// const message =
// error instanceof Error ? error.message : 'Form validation failed';
// methods.setError('root', { type: 'validation', message });
// return { isValid: false, message };
// }
// };
// const createDebouncedValidation = (delay: number = 500) => {
// return {
// validateField: debounce(validateField, delay),
// validateGroup: debounce(validateGroup, delay),
// validateAllGroups: debounce(validateAllGroups, delay),
// };
// };
// // Add registerFieldValidator to the return object
// return {
// validateField,
// validateGroup,
// validateAllGroups,
// createDebouncedValidation,
// registerFieldValidator,
// };
// };