89 lines
2.6 KiB
TypeScript

"use client";
import { Button } from "../button";
import { Form } from "../form";
import type { FieldConfig } from "./types";
import type { ZodObjectOrWrapped } from "./utils";
import { getDefaultValues, getObjectFormSchema } from "./utils";
import AutoFormObject from "@/components/ui/auto-form/fields/object";
import { ScrollArea } from "@/components/ui/scroll-area";
import { cn } from "@/lib/utils";
import { zodResolver } from "@hookform/resolvers/zod";
import type { DefaultValues } from "react-hook-form";
import { useForm } from "react-hook-form";
import type { z } from "zod";
export function AutoFormSubmit({ children }: { children?: React.ReactNode }) {
return <Button type="submit">{children ?? "Submit"}</Button>;
}
function AutoForm<SchemaType extends ZodObjectOrWrapped>({
formSchema,
values: valuesProp,
onValuesChange: onValuesChangeProp,
onParsedValuesChange,
onSubmit: onSubmitProp,
fieldConfig,
children,
className,
}: {
formSchema: SchemaType;
values?: Partial<z.infer<SchemaType>>;
onValuesChange?: (values: Partial<z.infer<SchemaType>>) => void;
onParsedValuesChange?: (values: Partial<z.infer<SchemaType>>) => void;
onSubmit?: (values: z.infer<SchemaType>) => void;
fieldConfig?: FieldConfig<z.infer<SchemaType>>;
children?: React.ReactNode;
className?: string;
}) {
const objectFormSchema = getObjectFormSchema(formSchema);
const defaultValues: DefaultValues<z.infer<typeof objectFormSchema>> =
getDefaultValues(objectFormSchema);
const form = useForm<z.infer<typeof objectFormSchema>>({
resolver: zodResolver(formSchema),
defaultValues,
values: valuesProp,
});
function onSubmit(values: z.infer<typeof formSchema>) {
const parsedValues = formSchema.safeParse(values);
if (parsedValues.success) {
onSubmitProp?.(parsedValues.data);
}
}
return (
<Form {...form}>
<form
onSubmit={(e) => {
form.handleSubmit(onSubmit)(e);
}}
onChange={() => {
const values = form.getValues();
onValuesChangeProp?.(values);
const parsedValues = formSchema.safeParse(values);
if (parsedValues.success) {
onParsedValuesChange?.(parsedValues.data);
}
}}
className={cn("space-y-5", className)}
>
<ScrollArea>
<div className="max-h-[400px] px-1 py-1 w-full">
<AutoFormObject
schema={objectFormSchema}
form={form}
fieldConfig={fieldConfig}
/>
</div>
</ScrollArea>
{children}
</form>
</Form>
);
}
export default AutoForm;