@matthew.ngo/reform
Version:
A flexible and powerful React form management library with advanced validation, state observation, and multi-group support
86 lines (79 loc) • 2.6 kB
text/typescript
import * as yup from 'yup';
import { ObjectSchema, AnyObject, Schema } from 'yup';
/**
* Type representing the Reform data structure
*/
export type ReformSchema<T> = { groups: Array<{ data: T }> };
/**
* Creates a Yup schema compatible with Reform's data structure
* Supports multiple ways of defining schemas to match user preferences
*
* @template T - The type of form data
* @param schemaDefinition - Schema definition in various formats
* @returns Yup schema for the entire Reform structure
*
* @example
* // Method 1: Using field-by-field schema definition
* const userSchema = createReformSchema({
* name: yup.string().required(),
* age: yup.number().min(18),
* tags: yup.array().of(yup.string())
* });
*
* @example
* // Method 2: Using a pre-defined Yup object schema
* const fieldSchema = yup.object({
* name: yup.string().required(),
* age: yup.number().min(18)
* });
* const userSchema = createReformSchema(fieldSchema);
*
* @example
* // Method 3: Using a schema builder function
* const userSchema = createReformSchema(fields => ({
* name: fields.string().required(),
* email: fields.string().email(),
* preferences: fields.object({
* theme: fields.string(),
* notifications: fields.boolean()
* })
* }));
*/
export function createReformSchema<T extends Record<string, any>>(
schemaDefinition:
| Record<string, Schema<any>>
| ObjectSchema<T>
| ((fields: typeof yup) => Record<string, Schema<any>>)
): ObjectSchema<{ groups: Array<{ data: T }> }, AnyObject, any> {
// Determine the data schema based on the input type
let dataSchema: ObjectSchema<T>;
if (typeof schemaDefinition === 'function') {
// Handle schema builder function
const fieldSchemas = schemaDefinition(yup);
dataSchema = yup.object().shape(fieldSchemas) as ObjectSchema<T>;
} else if (schemaDefinition instanceof yup.ObjectSchema) {
// Handle pre-defined object schema
dataSchema = schemaDefinition;
} else {
// Handle field-by-field schema definition
dataSchema = yup.object().shape(schemaDefinition) as ObjectSchema<T>;
}
// Create the schema for a group (which contains data)
const groupSchema = yup.object({
data: dataSchema,
});
// Create the full Reform schema (which contains groups)
const schema = yup.object({
groups: yup
.array()
.of(groupSchema)
.required()
.min(1),
});
// Use a more explicit type assertion to ensure compatibility
return (schema as unknown) as ObjectSchema<
{ groups: Array<{ data: T }> },
AnyObject,
any
>;
}