react-fatless-form
Version:
A lightweight React form package designed for simplicity that simplifies form handling and validation without unnecessary complexity or bloat.
111 lines (110 loc) • 5.69 kB
TypeScript
export interface UseForm<T> {
values: T;
errors: Partial<Record<keyof T, string>>;
touched: Partial<Record<keyof T, boolean>>;
submissionStatus: "idle" | "submitting" | "success" | "error";
setFieldValue: (field: keyof T, value: T[keyof T]) => void;
setFieldArrayValue: (field: keyof T, value: string | string[]) => void;
setFieldError: (field: keyof T, error: string) => void;
setFieldTouched: (field: keyof T, touched: boolean) => void;
validate: (validateFn: (values: T) => Partial<Record<keyof T, string>>) => boolean;
resetForm: () => void;
updateSubmissionStatus: (status: "idle" | "submitting" | "success" | "error") => void;
resetSubmissionStatus: () => void;
}
export interface FormState<T> {
values: T;
errors: Partial<Record<keyof T, string>>;
touched: Partial<Record<keyof T, boolean>>;
}
export type FormSubmissionStatus = "idle" | "submitting" | "success" | "error";
/**
* A custom React hook for managing form state, validation, submission lifecycle, and interactions.
*
* This hook provides a robust solution for handling form values, validation, errors, submission status,
* and user interactions. It is designed to be flexible and reusable for various form use cases.
*
* @template T - The shape of the form's values, defining keys and their respective types.
*
* @param {T} initialValues - The initial state of the form's values, determining the default structure of the form.
*
* @returns {object} A collection of state and functions for managing the form:
*
* **State:**
* - **values** (`T`): The current state of the form's values.
* - **errors** (`Partial<Record<keyof T, string>>`): An object storing validation errors for each field.
* - **touched** (`Partial<Record<keyof T, boolean>>`): An object tracking whether a field has been interacted with.
* - **submissionStatus** (`"idle" | "submitting" | "success" | "error"`): The current status of the form submission.
*
* **Functions:**
* - **setFieldValue** (`(field: keyof T, value: T[keyof T]) => void`): Updates the value of a specific field.
* - **batchSetfieldValues** (`(newValues: Partial<T>) => void`): Updates multiple field values at once.
* - **setFieldArrayValue** (`(field: keyof T, value: string | string[]) => void`): Sets the value of a field as a string or an array of strings.
* - **setFieldError** (`(field: keyof T, error: string) => void`): Sets an error message for a specific field.
* - **setFieldTouched** (`(field: keyof T, touched: boolean) => void`): Marks a field as touched or untouched.
* - **validate** (`(validateFn: (values: T) => Partial<Record<keyof T, string>>) => boolean`):
* Validates the form using a custom validation function.
* - `validateFn` receives the current `values` and should return an object with field-specific error messages.
* - Returns `true` if validation passes (no errors), otherwise `false`.
* - **resetForm** (`() => void`): Resets the form's values, errors, and touched fields to their initial state.
* - **updateSubmissionStatus** (`(status: "idle" | "submitting" | "success" | "error") => void`): Updates the `submissionStatus` to reflect the current state of submission.
* - **resetSubmissionStatus** (`() => void`): Resets the `submissionStatus` to `"idle"`. Useful for reusing the form or clearing transient submission states.
*
* **Design Philosophy:**
* - **Separation of Concerns**: Core responsibilities like state updates and validation are modular and reusable.
* - **Flexibility**: Provides developers full control over the submission and validation process.
* - **Future-Proofing**: Allows for evolving workflows without tightly coupling submission logic to form state management.
*
* @example
* ```tsx
* const form = useForm({ username: "", age: 0 });
*
* const validateForm = (values) => {
* const errors = {};
* if (!values.username) errors.username = "Username is required";
* if (values.age <= 0) errors.age = "Age must be positive";
* return errors;
* };
*
* const handleSubmit = async () => {
* if (!form.validate(validateForm(form.values))) {
* console.warn("Validation failed");
* return;
* }
* form.updateSubmissionStatus("submitting");
* try {
* await apiCall(form.values);
* form.updateSubmissionStatus("success");
* } catch (error) {
* console.error("Error during submission:", error);
* form.updateSubmissionStatus("error");
* }
* };
*
* return (
* <form onSubmit={(e) => { e.preventDefault(); handleSubmit(); }}>
* <input
* value={form.values.username}
* onChange={(e) => form.setFieldValue("username", e.target.value)}
* />
* {form.errors.username && <span>{form.errors.username}</span>}
* <button type="submit">Submit</button>
* </form>
* );
* ```
*/
export declare function useForm<T>(initialValues: T): {
submissionStatus: FormSubmissionStatus;
setFieldValue: (field: keyof T, value: T[keyof T]) => void;
batchSetfieldValues: (newValues: Partial<T>) => void;
setFieldArrayValue: (field: keyof T, value: string | string[]) => void;
setFieldError: (field: keyof T, error: string) => void;
setFieldTouched: (field: keyof T, touched: boolean) => void;
validate: (validateFn: (values: T) => Partial<Record<keyof T, string>>) => boolean;
resetForm: () => void;
updateSubmissionStatus: (status: "idle" | "submitting" | "success" | "error") => void;
resetSubmissionStatus: () => void;
values: T;
errors: Partial<Record<keyof T, string>>;
touched: Partial<Record<keyof T, boolean>>;
};