@matthew.ngo/reform
Version:
A flexible and powerful React form management library with advanced validation, state observation, and multi-group support
175 lines (157 loc) • 5.1 kB
text/typescript
import { useMemo } from "react";
import { ObjectSchema, object as yupObject, AnyObject, Maybe, ValidationError } from "yup";
import { YupSchemaConfig } from "./types";
import { useYupContext } from "./useYupContext";
import { useYupTransformers } from "./useYupTransformers";
import { ReformReturn } from "../../../types";
import { ReformYupIntegration } from "../types";
/**
* Hook for enhanced Yup integration with Reform
*
* @template T - The type of form data
* @param reform - The Reform hook return value
* @returns Object with enhanced Yup integration utilities
*
* @example
* // Basic usage
* const reform = useReform(config);
* const yupIntegration = useReformYupIntegration(reform);
*
* // Create an enhanced schema with transformers and context
* const enhancedSchema = yupIntegration.createEnhancedSchema(baseSchema);
*
* // Register a transformer for date fields
* useEffect(() => {
* const unregister = yupIntegration.registerTransformer({
* field: 'birthDate',
* transformer: (value) => value instanceof Date ? value : new Date(value),
* transformOn: 'input'
* });
*
* return unregister;
* }, []);
*
* // Validate with context
* const validateGroup = async (groupIndex) => {
* const result = await yupIntegration.validateWithContext(
* reform.getGroupData(groupIndex),
* groupIndex
* );
*
* if (result.error) {
* console.log(result.error);
* }
* };
*/
export const useReformYupIntegration = <T extends Record<string, any> & AnyObject>(
reform: ReformReturn<T>
): ReformYupIntegration<T> => {
// Get form groups from reform
const groups = reform.getGroups();
// Initialize Yup context and transformers hooks
const yupContext = useYupContext<T>(groups);
const yupTransformers = useYupTransformers<T>(groups);
/**
* Create an enhanced schema with both transformers and context
*/
const createEnhancedSchema = useMemo(
() =>
(baseSchema: ObjectSchema<T>, config?: Partial<YupSchemaConfig<T>>) => {
// First apply transformers
const schemaWithTransformers =
yupTransformers.createSchemaWithTransformers(baseSchema);
// Then add context support
const enhancedSchema = yupContext.createSchemaWithContext(
schemaWithTransformers
);
return enhancedSchema;
},
[yupContext, yupTransformers]
);
/**
* Validate data with context for a specific group
*/
const validateWithContext = useMemo(
() => async (data: T, groupIndex: number, fieldPath?: string): Promise<{ value: T | null; error: any }> => {
// Create validation context
const context = yupContext.createValidationContext(
groupIndex,
fieldPath as any
);
// Ưu tiên sử dụng groupSchema nếu có
let groupSchema = reform.config.groupSchema;
// Nếu không có groupSchema, thử sử dụng groupsSchema
if (!groupSchema && reform.config.groupsSchema) {
// groupsSchema là schema cho mảng các group, không phải cho một group
// Không thể sử dụng trực tiếp
console.warn(
"groupsSchema is for array of groups, not for a single group"
);
}
// Nếu không có schema nào phù hợp, trả về data mà không validate
if (!groupSchema) {
return { value: data, error: null };
}
try {
// Create enhanced schema
const enhancedSchema = createEnhancedSchema(groupSchema);
// Validate with context
const result = await (enhancedSchema as any).validateWithContext(
data,
context
);
return result;
} catch (error) {
// Format validation error with enhanced context
const formattedError = yupContext.formatValidationError(
error as ValidationError,
groupIndex
);
return { value: null, error: formattedError };
}
},
[
reform.config.groupSchema,
reform.config.groupsSchema,
yupContext,
createEnhancedSchema,
]
);
/**
* Update context data for both context and transformers
*/
const updateContextData = useMemo(
() => (data: Record<string, any>) => {
yupContext.updateContextData(data);
yupTransformers.updateContextData(data);
},
[yupContext, yupTransformers]
);
return useMemo(
() => ({
// Expose methods from both hooks
...yupContext,
...yupTransformers,
// Enhanced methods
createEnhancedSchema,
validateWithContext,
updateContextData,
// Helper method to validate all groups
validateAllGroups: async () => {
const results: Array<{ value: T | null; error: any }> = [];
for (let i = 0; i < groups.length; i++) {
results.push(await validateWithContext(groups[i].data, i));
}
return results;
},
}),
[
yupContext,
yupTransformers,
createEnhancedSchema,
validateWithContext,
updateContextData,
groups,
]
);
};