@explita/daily-toolset-form
Version:
A lightweight form toolkit for React built with developer ergonomics in mind. Includes a flexible Form component, useForm, useField, and useFormContext hooks for managing form state and validation with ease. Designed to simplify complex forms while remain
79 lines (78 loc) • 3.89 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.useFormContext = useFormContext;
const react_1 = require("react");
const form_1 = require("../providers/form");
function isZodSchema(schema) {
return typeof schema === "object" && schema !== null && "_def" in schema;
}
/**
* useFormContext is a hook that provides a form instance. The form instance
* contains the form state and methods to update the form state. The hook is
* generic and can be used with any schema type.
*
* The hook will use the schema and default values provided in the props to
* update the form state. If the `schema` prop is provided, the hook will
* validate the form state using the provided schema. If the `defaultValues`
* prop is provided, the hook will update the form state with the provided
* default values.
*
* The hook will also accept an `errors` prop, which should be an object with
* the same shape as the form state. The hook will update the form errors with
* the provided errors.
*
* The hook must be used within a Form component.
*
* @param {Object} [props] - The props for useFormContext.
* @param {Schema} [props.schema] - The schema to use for form validation.
* @param {DefaultValues} [props.defaultValues] - The default values for the form.
* @param {Record<keyof DefaultValues, string | undefined>} [props.errors] - The errors for the form.
* @returns {UseFormHook<DefaultValues>} The form instance.
*/
function useFormContext(props) {
const form = (0, react_1.use)(form_1.FormContext);
if (!form) {
throw new Error("useFormContext must be used within a FormProvider");
}
const previousErrorsRef = (0, react_1.useRef)({});
const previousDefaultValuesRef = (0, react_1.useRef)({});
(0, react_1.useEffect)(() => {
if ((props === null || props === void 0 ? void 0 : props.schema) && isZodSchema(props.schema)) {
form.setSchema(props.schema);
}
}, [form, props === null || props === void 0 ? void 0 : props.schema]);
(0, react_1.useEffect)(() => {
if (props === null || props === void 0 ? void 0 : props.defaultValues) {
const previousDefaultValues = previousDefaultValuesRef.current;
const valuesEqual = Object.keys(previousDefaultValues).length ===
Object.keys(props.defaultValues).length &&
Object.keys(props.defaultValues).every((key) => previousDefaultValues[key] === props.defaultValues[key]);
if (!valuesEqual) {
form.setValues(props.defaultValues);
previousDefaultValuesRef.current = props.defaultValues; // Update the ref to the new state
}
}
}, [form, props === null || props === void 0 ? void 0 : props.defaultValues]);
(0, react_1.useEffect)(() => {
if (props === null || props === void 0 ? void 0 : props.errors) {
if (Object.keys(props.errors).length === 0) {
// Only clear errors if they are different from the previous state
if (Object.keys(previousErrorsRef.current).length > 0) {
form.setErrors({});
previousErrorsRef.current = {}; // Update the ref to the new state
}
}
else {
const hasErrorsChanged = Object.keys(props.errors).length !==
Object.keys(previousErrorsRef.current).length ||
Object.keys(props.errors).some((key) => previousErrorsRef.current[key] !== props.errors[key]);
if (hasErrorsChanged) {
form.setErrors(props.errors);
previousErrorsRef.current = props.errors; // Update the ref to the new state
}
}
}
}, [form, props === null || props === void 0 ? void 0 : props.errors]);
// @ts-ignore
return form;
}