@vtaits/react-hook-form-schema
Version:
Integration of react-hook-form and @vtaits/form-schema
323 lines (317 loc) • 7.87 kB
JavaScript
// src/core/constants.ts
var CLIENT_ERROR = "__CLIENT_ERROR__";
var SERVER_ERROR = "__SERVER_ERROR__";
// src/core/getFieldPath.ts
function getFieldPath(fieldName, parents) {
if (!parents || parents.length === 0) {
return fieldName;
}
return [
...parents.map(({ name }) => name).filter((name) => ["string", "number"].includes(typeof name)),
fieldName
].join(".");
}
// src/core/renderBySchema.tsx
import { isEqual, isPromise } from "es-toolkit";
import {
useEffect,
useMemo,
useRef,
useState
} from "react";
import { useAsync } from "react-async-hook";
import { jsx } from "react/jsx-runtime";
function FieldProxy({
formResult,
getFieldSchema,
getFieldType,
getValues,
name,
payload = void 0,
parents = void 0
}) {
const fieldSchema = getFieldSchema(name);
const fieldType = getFieldType(fieldSchema);
const { createGetFieldSchema } = fieldType;
const render = fieldSchema.render || fieldType.render;
const values = getValues();
const providedParents = parents || [
{
values
}
];
if (fieldSchema.getDependencies) {
formResult.watch();
}
const dependencies = fieldSchema.getDependencies?.({
values,
phase: "render",
getFieldSchema,
getFieldType,
parents: providedParents
});
const countCreateGetFieldSchema = () => {
if (createGetFieldSchema) {
return createGetFieldSchema({
fieldSchema,
getFieldSchema,
getFieldType,
values,
phase: "render",
parents: providedParents,
dependencies
});
}
return getFieldSchema;
};
const [createGetFieldSchemaResult, setCreateGetFieldSchemaResult] = useState(
() => countCreateGetFieldSchema()
);
const { result: createGetFieldSchemaResultAsync } = useAsync(async () => {
const res = await createGetFieldSchemaResult;
return res;
}, [createGetFieldSchemaResult]);
const childGetFieldSchema = useMemo(() => {
if (isPromise(createGetFieldSchemaResult)) {
return createGetFieldSchemaResultAsync;
}
return createGetFieldSchemaResult;
}, [createGetFieldSchemaResult, createGetFieldSchemaResultAsync]);
const isFirstRenderCheckDependenciesRef = useRef(true);
const prevDependenciesRef = useRef(dependencies);
useEffect(() => {
if (isFirstRenderCheckDependenciesRef.current) {
isFirstRenderCheckDependenciesRef.current = false;
return;
}
if (!isEqual(prevDependenciesRef.current, dependencies)) {
setCreateGetFieldSchemaResult(countCreateGetFieldSchema());
prevDependenciesRef.current = dependencies;
}
}, [dependencies]);
if (!childGetFieldSchema) {
return null;
}
return render(
{
fieldPath: getFieldPath(name, providedParents),
name,
payload,
parents: providedParents,
getFieldSchema: childGetFieldSchema,
getFieldType,
fieldSchema,
dependencies
},
formResult
);
}
function renderBySchema(formResult, getFieldSchema, getFieldType, getValues, name, payload, parents) {
return /* @__PURE__ */ jsx(
FieldProxy,
{
formResult,
getFieldSchema,
getFieldType,
getValues,
name,
payload,
parents
}
);
}
// src/core/useFormSchema.ts
import {
parse,
serialize,
setFieldErrors,
setValues as setValuesBase,
validateBeforeSubmit
} from "@vtaits/form-schema";
import { useCallback, useMemo as useMemo2 } from "react";
import {
useForm
} from "react-hook-form";
// src/core/makeSetError.ts
function makeSetError(setError, errorType, onError) {
return (fieldName, parents, error) => {
onError();
if (parents) {
setError(
`${[
...parents.filter((parent) => typeof parent.name !== "undefined").map((parent) => parent.name),
fieldName
].join(".")}`,
{
type: errorType,
message: error
}
);
} else {
setError(fieldName, {
type: errorType,
message: error
});
}
};
}
// src/core/useFormSchema.ts
var defaultGetFieldSchema = (fieldSchema) => fieldSchema;
var defaultMapErrors = (errors) => errors;
function useFormSchema(props) {
const {
defaultValues,
getFieldSchema = defaultGetFieldSchema,
getFieldType,
mapErrors = defaultMapErrors,
names,
...rest
} = props;
const parseValues = useCallback(
(values) => parse({
values,
names,
getFieldSchema,
getFieldType,
parents: [
{
values
}
]
}),
[getFieldSchema, getFieldType, names]
);
const parsedDefaultValues = useMemo2(() => {
if (typeof defaultValues === "function") {
const asyncDefaultValues = defaultValues;
return () => asyncDefaultValues().then((rawInitialValues2) => parseValues(rawInitialValues2)).then((result) => result || {});
}
const rawInitialValues = defaultValues || {};
const parseResult = parseValues(rawInitialValues);
return () => parseResult;
}, [defaultValues, parseValues]);
const formResult = useForm({
...rest,
defaultValues: parsedDefaultValues
});
const { handleSubmit, ...restResult } = formResult;
const { getValues, setValue, setError } = restResult;
const setValues = useCallback(
(values) => setValuesBase({
setValue,
values,
names,
getFieldSchema,
getFieldType,
parents: [
{
values
}
]
}),
[getFieldSchema, getFieldType, names, setValue]
);
const parseAndSetValues = useCallback(
async (rawValues) => {
const values = await parseValues(rawValues);
setValues(values);
},
[parseValues, setValues]
);
const onSubmitBySchema = useCallback(
async (onSubmit, values, event) => {
let hasCleintError = false;
await validateBeforeSubmit({
setError: makeSetError(setError, CLIENT_ERROR, () => {
hasCleintError = true;
}),
values,
names,
getFieldSchema,
getFieldType,
parents: [
{
values
}
]
});
if (hasCleintError) {
return;
}
const valuesForSubmit = await serialize({
values,
names,
getFieldSchema,
getFieldType,
parents: [
{
values
}
]
});
const rawErrors = await onSubmit(valuesForSubmit, values, event);
if (!rawErrors) {
return;
}
const preparedErrors = mapErrors(
rawErrors,
valuesForSubmit,
values
);
await setFieldErrors({
setError: makeSetError(setError, SERVER_ERROR, () => {
}),
errors: preparedErrors,
names,
getFieldSchema,
getFieldType,
values: valuesForSubmit,
rawValues: values,
parents: [
{
values
}
]
});
},
[names, getFieldSchema, getFieldType, mapErrors, setError]
);
const handleSubmitBySchema = useCallback(
(onSubmit, onError) => {
const submitHandler = (values, event) => onSubmitBySchema(onSubmit, values, event);
return handleSubmit(
submitHandler,
onError
);
},
[handleSubmit, onSubmitBySchema]
);
const renderField = useCallback(
(name, payload, parents) => renderBySchema(
formResult,
getFieldSchema,
getFieldType,
getValues,
name,
payload,
parents
),
[formResult, getFieldSchema, getFieldType, getValues]
);
return {
...restResult,
handleSubmit: handleSubmitBySchema,
parseValues,
setValues,
parseAndSetValues,
renderField
};
}
export {
CLIENT_ERROR,
SERVER_ERROR,
getFieldPath,
renderBySchema,
useFormSchema
};
//# sourceMappingURL=chunk-VHBMH3GH.js.map