@matthew.ngo/reform
Version:
A flexible and powerful React form management library with advanced validation, state observation, and multi-group support
188 lines (170 loc) • 4.54 kB
text/typescript
// @ts-nocheck
import { DeepPartial, ExtractObjects, useForm } from 'react-hook-form';
import { AnyObjectSchema } from 'yup';
import { useReformGroups } from './useReformGroups';
// import { useFormValidation } from '../validation/base/useFormValidation';
import { useFormState } from './useFormState';
// import { useFormHandlers } from './useFormHandlers';
import { DynamicFormConfig, ReformReturn } from '../../types';
import { yupResolver } from '@hookform/resolvers/yup';
import { useFormController } from './useFormController';
import { useFieldArrayHelpers } from '../../features/field-array/useFieldArrayHelpers';
import { useConditionalFields } from '../../features/conditional/useConditionalFields';
import { useFormReset } from './useFormReset';
import { useMemo } from 'react';
import { useReformYupIntegration } from '../validation/yup/useReformYupIntegration';
import { FormGroup } from './form-groups';
import { ValidationConfig } from '../validation';
export const useReform = <T extends Record<string, any>>(
config: DynamicFormConfig<T> & ValidationConfig<T>
): ReformReturn<T> => {
const memoizedConfig = useMemo(() => {
const {
value,
onChange,
minGroups = 1,
maxGroups = Infinity,
defaultData = {} as T,
schema,
validationMode = 'onChange',
reValidateMode = 'onChange',
criteriaMode = 'firstError',
labels,
yupConfig = {},
} = config;
return {
value,
onChange,
minGroups,
maxGroups,
defaultData,
schema,
validationMode,
reValidateMode,
criteriaMode,
labels,
yupConfig,
};
}, [
config.value,
config.onChange,
config.minGroups,
config.maxGroups,
JSON.stringify(config.defaultData),
config.schema,
config.validationMode,
config.reValidateMode,
config.criteriaMode,
JSON.stringify(config.labels),
JSON.stringify(config.yupConfig),
]);
const {
value,
onChange,
minGroups,
maxGroups,
defaultData,
schema,
validationMode,
reValidateMode,
criteriaMode,
labels,
yupConfig,
} = memoizedConfig;
type FormType = { groups: FormGroup<T>[] };
const defaultValues = useMemo(() => {
return {
groups:
value ??
Array(minGroups)
.fill(null)
.map(() => ({
id: Math.random()
.toString(36)
.substr(2, 9),
data: defaultData as ExtractObjects<T> extends never
? T
: DeepPartial<T>,
})),
};
}, [value, minGroups, defaultData]);
const methods = useForm<FormType>({
defaultValues,
mode: validationMode,
reValidateMode,
criteriaMode,
resolver: schema
? yupResolver((schema as unknown) as AnyObjectSchema)
: undefined,
shouldUnregister: false,
delayError: 0,
});
// const validation = useFormValidation(
// { schema, validationMode, reValidateMode, criteriaMode, labels },
// methods
// );
const groupsManager = useReformGroups({
methods,
minGroups,
maxGroups,
defaultData,
onChange,
});
const formState = useFormState(methods);
// const handlers = useFormHandlers({
// methods,
// config,
// validation,
// });
const controller = useFormController<T>(methods);
const fieldArrayHelpers = useFieldArrayHelpers({
methods,
onChange,
});
const conditionalFields = useConditionalFields({
methods,
});
const resetManager = useFormReset({
methods,
defaultData,
minGroups,
});
const partialReform = useMemo(
() => ({
getGroups: () => methods.getValues().groups,
getGroupData: (index: number) => methods.getValues().groups[index]?.data,
config: memoizedConfig,
}),
[methods, memoizedConfig]
);
const yupIntegration = useReformYupIntegration(partialReform as any);
return useMemo(() => {
const reformReturn: ReformReturn<T> = {
formMethods: methods,
...groupsManager,
// ...validation,
...formState,
// ...handlers,
...controller,
...fieldArrayHelpers,
...conditionalFields,
...resetManager,
config: memoizedConfig,
// @ts-ignore
yup: yupIntegration,
};
return reformReturn;
}, [
methods,
groupsManager,
// validation,
formState,
// handlers,
controller,
fieldArrayHelpers,
conditionalFields,
resetManager,
memoizedConfig,
yupIntegration,
]);
};