lynx-form-x
Version:
LynxFormX is a lightweight and intuitive form library built for the Lynx framework for mobile development. It streamlines form management by automatically binding fields, handling validation, and providing easy-to-use hooks for custom field manipulation—a
78 lines (77 loc) • 3.1 kB
JSX
import { useCallback, useReducer } from '@lynx-js/react';
import { ZodObject, ZodTransformer } from 'zod';
import { reset, setError, setIsSubmitting, setTouched, setValue, } from '../reducers/formActions.js';
import { formReducer, } from '../reducers/formReducer.jsx';
export const useForm = (onSubmit, initialValues, validate, schema) => {
const [state, dispatch] = useReducer((formReducer), {
values: initialValues || {},
errors: {},
touched: {},
isSubmitting: false,
});
const validateField = useCallback((field, value) => {
if (schema) {
const result = schema.safeParse(value !== undefined
? { ...state.values, [field]: value }
: state.values);
console.log(result.error?.format());
setFormError(field, (result.error?.format())[field]?._errors[0] || '');
}
else if (validate) {
const errors = validate({ ...state.values, [field]: value });
setFormError(field, errors[field] || '');
}
}, [validate, schema, setFormError]);
const handleInput = useCallback((field) => (e) => {
const value = e.detail.value;
setFormValue(field, value);
validateField(field, value);
}, [state.values, validateField]);
const handleBlur = useCallback((field) => () => {
setTouched(dispatch, field, true);
validateField(field);
}, [state.values, validateField]);
const handleSubmit = useCallback(() => {
if (schema) {
const errors = schema.safeParse(state.values).error?.format();
if (errors) {
for (const [field, value] of Object.entries(errors)) {
const parsedValue = value;
if (parsedValue?._errors)
setFormError(field, parsedValue?._errors[0]);
}
return;
}
}
else if (validate) {
const errors = validate(state.values);
if (Object.keys(errors).length > 0) {
Object.keys(errors).forEach((field) => {
setFormError(field, errors[field] || '');
});
return;
}
}
setIsSubmitting(dispatch, true);
Promise.resolve(onSubmit(state.values, { setValue: setFormValue, setError: setFormError })).finally(() => setIsSubmitting(dispatch, false));
}, [validate, schema, state.values, onSubmit, setFormError, setFormValue]);
const resetForm = useCallback(() => reset(dispatch, initialValues), [initialValues]);
function setFormValue(field, value) {
setValue(dispatch, field, value);
}
function setFormError(field, error) {
setError(dispatch, field, error);
}
return {
values: state.values,
errors: state.errors,
touched: state.touched,
handleInput,
handleBlur,
handleSubmit,
resetForm,
setValue: setFormValue,
setError: setFormError,
isSubmitting: state.isSubmitting,
};
};