UNPKG

@docvhcmc/react-form-schema

Version:

A flexible React form schema manager with pluggable validation adapters (Zod, Yup, etc.)

277 lines (270 loc) 11.5 kB
declare enum ValidationCode { FIELD_UNKNOWN = "FIELD_UNKNOWN", UNEXPECTED = "UNEXPECTED" } /** * NonEmptyArray<T> * * A tuple-based type that ensures the array contains at least one element. * * - The first element is required: [T, ...] * - Any number of additional elements of type T can follow: [...T[]] * * This is useful for enforcing non-empty arrays at the type level, * such as when you want to guarantee at least one item in a list. * * Example: * const valid: NonEmptyArray<number> = [1, 2, 3]; // ✅ OK * const invalid: NonEmptyArray<number> = []; // ❌ Error: must have at least one element */ type NonEmptyArray<T> = [T, ...T[]]; /** * Defines the structure of a single field error. */ type FieldError = { /** * The field path that caused the error (e.g. "email", "user.name"). */ path: string; /** * A machine-readable error code (e.g. "REQUIRED", "INVALID_FORMAT"). */ code: string; /** * An optional default error message. This message can be used as a fallback * if no translation is found for the `code`, or for simpler cases where i18n * isn't strictly necessary or for quick debugging. When `code` is provided * and i18n is used, this message typically serves as a last resort. */ message?: string; origin?: string; /** * Additional parameters for i18n or dynamic formatting. */ params?: Record<string, unknown>; }; type SchemaInput<O> = Partial<O>; type ValidationRule<O> = { /** * The path to the field(s) affected by this rule. * Can be a single field name (string) or an array for nested fields or cross-field validation. * Examples: 'name', ['address', 'street'], ['password', 'confirmPassword'] */ path: keyof O | NonEmptyArray<keyof O>; /** * A unique error code for this specific rule. This code is **required** and serves as * the primary key for Internationalization (i18n) lookup. It enables translating * error messages and programmatically handling specific validation failures. * Example: 'FORM_AGE_TOO_YOUNG', 'STRING_MIN_LENGTH'. */ code: string; /** * Optional parameters or context data that can be used to dynamically * construct the error message. This is essential for parameterized messages * and Internationalization (i18n). * Example: `{ min: 5, max: 10 }` for a string length rule, or `{ fieldName: 'Name' }`. */ params?: Partial<Record<string, any>>; /** * An optional default error message. This message can be used as a fallback * if no translation is found for the `code`, or for simpler cases where i18n * isn't strictly necessary or for quick debugging. When `code` is provided * and i18n is used, this message typically serves as a last resort. */ message?: string; check: (data: O) => boolean | Promise<boolean>; }; /** * Interface for the FormErrorManager, responsible for handling validation errors. */ interface IFormErrorManager { /** * Sets all errors at once, replacing any existing errors. * @param errors An array of FieldError objects. */ setErrors(errors: FieldError[]): void; /** * Adds a single error to the current list of errors. * @param error The FieldError object to add. */ addError(error: FieldError): void; /** * Checks if any error exists for a specific field path, or if any error exists in general. * @param path Optional. The dot-notation path of the field (e.g., 'name', 'address.street'). * @returns `true` if an error exists for the specified path or if any error exists, `false` otherwise. */ hasError(path?: string): boolean; /** * Retrieves the first error message for a specific field. * @param path The dot-notation path of the field. * @returns The error message string, or `undefined` if the field has no error. */ getFirstFieldError(path: string): string | undefined; /** * Retrieves all error objects for a specific field. * @param path The dot-notation path of the field. * @returns An array of `FieldError` objects for the specified field. */ getErrorsForField(path: string): FieldError[]; /** * Retrieves all current error objects. * @returns An array of all `FieldError` objects. */ getAllErrors(): FieldError[]; /** * Clears all existing errors. */ clearErrors(): void; } /** * Manages validation errors for a form. */ declare class FormErrorManager implements IFormErrorManager { private _errors; constructor(initialErrors?: FieldError[]); /** * Sets all errors at once, replacing any existing errors. * @param errors An array of FieldError objects. */ setErrors(errors: FieldError[]): void; /** * Adds a single error to the current list of errors. * @param error The FieldError object to add. */ addError(error: FieldError): void; /** * Checks if any error exists for a specific field path, or if any error exists in general. * @param path Optional. The dot-notation path of the field (e.g., 'name', 'address.street'). * @returns `true` if an error exists for the specified path or if any error exists, `false` otherwise. */ hasError(path?: string): boolean; /** * Retrieves the first error message for a specific field. * @param path The dot-notation path of the field. * @returns The error message string, or `undefined` if the field has no error. */ getFirstFieldError(path: string): string | undefined; /** * Retrieves all error objects for a specific field. * @param path The dot-notation path of the field. * @returns An array of `FieldError` objects for the specified field. */ getErrorsForField(path: string): FieldError[]; /** * Retrieves all current error objects. * @returns An array of all `FieldError` objects. */ getAllErrors(): FieldError[]; /** * Clears all existing errors. */ clearErrors(): void; } /** * Custom error class for validation failures. * It provides structured access to field-specific errors. */ declare class ValidationError extends Error { fields: FieldError[]; /** * Optionally store the original error (e.g., ZodError) for debugging */ originalError?: unknown; /** * Creates an instance of ValidationError. * @param fields An array of FieldError objects. * @param originalError The original error object from the validator (optional). * @param message A custom error message (optional). If not provided, a default message is generated. */ constructor(fields: FieldError[], originalError?: unknown, message?: string); } /** * Interface defining the structure of the object returned by the `useFormSchema` hook. * @template O - Represents the inferred output type of the schema. */ interface UseFormSchemaReturn<O> { /** * The current raw (unvalidated and untransformed) input values of the form. */ rawInput: SchemaInput<O>; /** * Indicates whether the entire form is currently valid (has no validation errors). */ isValid: boolean; /** * An object providing comprehensive error management utilities. * It includes methods like `hasError`, `getFirstFieldError`, `getErrorsForField`, `getAllErrors`, and `clearErrors`. */ errors: { /** * Checks if any error exists for a specific field path, or if any error exists in general. * @param path Optional. The dot-notation path of the field. */ hasError: IFormErrorManager['hasError']; /** * Retrieves the first error message for a specific field. * @param path The dot-notation path of the field. */ getFirstFieldError: IFormErrorManager['getFirstFieldError']; /** * Retrieves all error objects for a specific field. * @param path The dot-notation path of the field. */ getErrorsForField: IFormErrorManager['getErrorsForField']; /** * Retrieves all current error objects. */ getAllErrors: IFormErrorManager['getAllErrors']; /** * Clears all existing errors. */ clearErrors: IFormErrorManager['clearErrors']; }; /** * A higher-order function that returns an `onSubmit` handler for HTML forms. * It performs full form validation and calls either `onSubmitValid` or `onSubmitInvalid` based on the validation result. * @param onSubmitValid A callback function executed when the form is valid and submitted. Receives the parsed and validated data. * @param onSubmitInvalid An optional callback function executed when the form is invalid. Receives an array of `FieldError` objects. * @returns An event handler function suitable for the `onSubmit` prop of a `<form>` element. */ handleSubmit: (onSubmitValid: (data: O) => void, onSubmitInvalid?: (errors: FieldError[]) => void) => (event: React.FormEvent) => void; /** * Resets the form's internal raw input state to its initial state or an empty state. * This clears current values and errors. * @param initialValues Optional. New initial values to reset the form to. If not provided, resets to empty. */ reset: (initialValues?: SchemaInput<O>) => void; /** * Returns a memoized setter function for a specific form field. * This setter updates the form's internal raw input state and triggers field-specific validation. * @param field The name of the field for which to create a setter. * @returns A function that takes a value (of Input type) and updates the corresponding field. */ setValueFor: <F extends keyof O>(field: F) => (value: SchemaInput<O>[F]) => void; /** * Overwrites the entire raw input state of the form with the new values. * Triggers a full form validation. * @param newValues The new raw input values to set. */ /** * Overwrites the entire raw input state of the form with the new values. * Triggers a full form validation. * @param newValues The new raw input values to set. */ setRawValue: (newValues: SchemaInput<O>) => void; /** * Merges the provided partial values into the existing raw input state. * Existing fields not present in `partialValues` will be retained. Triggers a full form validation. * @param partialValues The partial raw input values to merge. */ mergeRawValue: (partialValues: SchemaInput<O>) => void; /** * Manually triggers validation for the entire form or a specific field. * Updates the internal error state and notifies subscribers. * @param field Optional. The name of the field to validate, or a partial input object for external validation. * @param value Optional. The value for a specific field when `field` is a field name. * @returns A Promise that resolves to `undefined` if validation passes, or an `Error` instance if validation fails. */ validate: (field?: keyof O | SchemaInput<O>, value?: SchemaInput<O>[keyof O]) => Promise<undefined | Error>; } export { FormErrorManager as F, type SchemaInput as S, type UseFormSchemaReturn as U, type ValidationRule as V, ValidationError as a, type FieldError as b, ValidationCode as c };