diff --git a/src/components/form.tsx b/src/components/form.tsx
deleted file mode 100644
index e69de29..0000000
diff --git a/src/components/ui/auto-form/common/label.tsx b/src/components/ui/auto-form/common/label.tsx
deleted file mode 100644
index d570830..0000000
--- a/src/components/ui/auto-form/common/label.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { FormLabel } from "@/components/ui/form";
-import { cn } from "@/lib/utils";
-
-function AutoFormLabel({
- label,
- isRequired,
- className,
-}: {
- label: string;
- isRequired: boolean;
- className?: string;
-}) {
- return (
- <>
-
- {label}
- {isRequired && *}
-
- >
- );
-}
-
-export default AutoFormLabel;
diff --git a/src/components/ui/auto-form/common/tooltip.tsx b/src/components/ui/auto-form/common/tooltip.tsx
deleted file mode 100644
index cafdb79..0000000
--- a/src/components/ui/auto-form/common/tooltip.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-function AutoFormTooltip({ fieldConfigItem }: { fieldConfigItem: any }) {
- return (
- <>
- {fieldConfigItem?.description && (
-
- {fieldConfigItem.description}
-
- )}
- >
- );
-}
-
-export default AutoFormTooltip;
diff --git a/src/components/ui/auto-form/config.ts b/src/components/ui/auto-form/config.ts
deleted file mode 100644
index be416ba..0000000
--- a/src/components/ui/auto-form/config.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import AutoFormCheckbox from "./fields/checkbox";
-import AutoFormDate from "./fields/date";
-import AutoFormEnum from "./fields/enum";
-import AutoFormFile from "./fields/file";
-import AutoFormInput from "./fields/input";
-import AutoFormNumber from "./fields/number";
-import AutoFormRadioGroup from "./fields/radio-group";
-import AutoFormSwitch from "./fields/switch";
-import AutoFormTextarea from "./fields/textarea";
-
-export const INPUT_COMPONENTS = {
- checkbox: AutoFormCheckbox,
- date: AutoFormDate,
- select: AutoFormEnum,
- radio: AutoFormRadioGroup,
- switch: AutoFormSwitch,
- textarea: AutoFormTextarea,
- number: AutoFormNumber,
- file: AutoFormFile,
- fallback: AutoFormInput,
-};
-
-/**
- * Define handlers for specific Zod types.
- * You can expand this object to support more types.
- */
-export const DEFAULT_ZOD_HANDLERS: {
- [key: string]: keyof typeof INPUT_COMPONENTS;
-} = {
- ZodBoolean: "checkbox",
- ZodDate: "date",
- ZodEnum: "select",
- ZodNativeEnum: "select",
- ZodNumber: "number",
-};
diff --git a/src/components/ui/auto-form/dependencies.ts b/src/components/ui/auto-form/dependencies.ts
deleted file mode 100644
index 4d9cada..0000000
--- a/src/components/ui/auto-form/dependencies.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { FieldValues, UseFormWatch } from "react-hook-form";
-import { Dependency, DependencyType, EnumValues } from "./types";
-import * as z from "zod";
-
-export default function resolveDependencies<
- SchemaType extends z.infer>,
->(
- dependencies: Dependency[],
- currentFieldName: keyof SchemaType,
- watch: UseFormWatch,
-) {
- let isDisabled = false;
- let isHidden = false;
- let isRequired = false;
- let overrideOptions: EnumValues | undefined;
-
- const currentFieldValue = watch(currentFieldName as string);
-
- const currentFieldDependencies = dependencies.filter(
- (dependency) => dependency.targetField === currentFieldName,
- );
- for (const dependency of currentFieldDependencies) {
- const watchedValue = watch(dependency.sourceField as string);
-
- const conditionMet = dependency.when(watchedValue, currentFieldValue);
-
- switch (dependency.type) {
- case DependencyType.DISABLES:
- if (conditionMet) {
- isDisabled = true;
- }
- break;
- case DependencyType.REQUIRES:
- if (conditionMet) {
- isRequired = true;
- }
- break;
- case DependencyType.HIDES:
- if (conditionMet) {
- isHidden = true;
- }
- break;
- case DependencyType.SETS_OPTIONS:
- if (conditionMet) {
- overrideOptions = dependency.options;
- }
- break;
- }
- }
-
- return {
- isDisabled,
- isHidden,
- isRequired,
- overrideOptions,
- };
-}
diff --git a/src/components/ui/auto-form/fields/array.tsx b/src/components/ui/auto-form/fields/array.tsx
deleted file mode 100644
index c66e972..0000000
--- a/src/components/ui/auto-form/fields/array.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-import {
- AccordionContent,
- AccordionItem,
- AccordionTrigger,
-} from "@/components/ui/accordion";
-import { Button } from "@/components/ui/button";
-import { Separator } from "@/components/ui/separator";
-import { Plus, Trash } from "lucide-react";
-import { useFieldArray, useForm } from "react-hook-form";
-import * as z from "zod";
-import { beautifyObjectName } from "../utils";
-import AutoFormObject from "./object";
-
-function isZodArray(
- item: z.ZodArray | z.ZodDefault,
-): item is z.ZodArray {
- return item instanceof z.ZodArray;
-}
-
-function isZodDefault(
- item: z.ZodArray | z.ZodDefault,
-): item is z.ZodDefault {
- return item instanceof z.ZodDefault;
-}
-
-export default function AutoFormArray({
- name,
- item,
- form,
- path = [],
- fieldConfig,
-}: {
- name: string;
- item: z.ZodArray | z.ZodDefault;
- form: ReturnType;
- path?: string[];
- fieldConfig?: any;
-}) {
- const { fields, append, remove } = useFieldArray({
- control: form.control,
- name,
- });
- const title = item._def.description ?? beautifyObjectName(name);
-
- const itemDefType = isZodArray(item)
- ? item._def.type
- : isZodDefault(item)
- ? item._def.innerType._def.type
- : null;
-
- return (
-
- {title}
-
- {fields.map((_field, index) => {
- const key = _field.id;
- return (
-
-
}
- form={form}
- fieldConfig={fieldConfig}
- path={[...path, index.toString()]}
- />
-
-
-
-
-
-
- );
- })}
-
-
-
- );
-}
diff --git a/src/components/ui/auto-form/fields/checkbox.tsx b/src/components/ui/auto-form/fields/checkbox.tsx
deleted file mode 100644
index 2b0121c..0000000
--- a/src/components/ui/auto-form/fields/checkbox.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { Checkbox } from "@/components/ui/checkbox";
-import { FormControl, FormItem } from "@/components/ui/form";
-import AutoFormTooltip from "../common/tooltip";
-import { AutoFormInputComponentProps } from "../types";
-import AutoFormLabel from "../common/label";
-
-export default function AutoFormCheckbox({
- label,
- isRequired,
- field,
- fieldConfigItem,
- fieldProps,
-}: AutoFormInputComponentProps) {
- return (
-
- );
-}
diff --git a/src/components/ui/auto-form/fields/date.tsx b/src/components/ui/auto-form/fields/date.tsx
deleted file mode 100644
index 9c06cdc..0000000
--- a/src/components/ui/auto-form/fields/date.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { DatePicker } from "@/components/ui/date-picker";
-import { FormControl, FormItem, FormMessage } from "@/components/ui/form";
-import AutoFormLabel from "../common/label";
-import AutoFormTooltip from "../common/tooltip";
-import { AutoFormInputComponentProps } from "../types";
-
-export default function AutoFormDate({
- label,
- isRequired,
- field,
- fieldConfigItem,
- fieldProps,
-}: AutoFormInputComponentProps) {
- return (
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/src/components/ui/auto-form/fields/enum.tsx b/src/components/ui/auto-form/fields/enum.tsx
deleted file mode 100644
index d5a68db..0000000
--- a/src/components/ui/auto-form/fields/enum.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import { FormControl, FormItem, FormMessage } from "@/components/ui/form";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
-import * as z from "zod";
-import AutoFormLabel from "../common/label";
-import AutoFormTooltip from "../common/tooltip";
-import { AutoFormInputComponentProps } from "../types";
-import { getBaseSchema } from "../utils";
-
-export default function AutoFormEnum({
- label,
- isRequired,
- field,
- fieldConfigItem,
- zodItem,
- fieldProps,
-}: AutoFormInputComponentProps) {
- const baseValues = (getBaseSchema(zodItem) as unknown as z.ZodEnum)._def
- .values;
-
- let values: [string, string][] = [];
- if (!Array.isArray(baseValues)) {
- values = Object.entries(baseValues);
- } else {
- values = baseValues.map((value) => [value, value]);
- }
-
- function findItem(value: any) {
- return values.find((item) => item[0] === value);
- }
-
- return (
-
-
-
-
-
-
-
-
- );
-}
diff --git a/src/components/ui/auto-form/fields/file.tsx b/src/components/ui/auto-form/fields/file.tsx
deleted file mode 100644
index 058aab7..0000000
--- a/src/components/ui/auto-form/fields/file.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import { FormControl, FormItem, FormMessage } from "@/components/ui/form";
-import { Input } from "@/components/ui/input";
-import { Trash2 } from "lucide-react";
-import { ChangeEvent, useState } from "react";
-import AutoFormLabel from "../common/label";
-import AutoFormTooltip from "../common/tooltip";
-import { AutoFormInputComponentProps } from "../types";
-export default function AutoFormFile({
- label,
- isRequired,
- fieldConfigItem,
- fieldProps,
- field,
-}: AutoFormInputComponentProps) {
- const { showLabel: _showLabel, ...fieldPropsWithoutShowLabel } = fieldProps;
- const showLabel = _showLabel === undefined ? true : _showLabel;
- const [file, setFile] = useState(null);
- const [fileName, setFileName] = useState(null);
- const handleFileChange = (e: ChangeEvent) => {
- const file = e.target.files?.[0];
-
- if (file) {
- const reader = new FileReader();
- reader.onloadend = () => {
- setFile(reader.result as string);
- setFileName(file.name);
- field.onChange(reader.result as string);
- };
- reader.readAsDataURL(file);
- }
- };
-
- const handleRemoveClick = () => {
- setFile(null);
- };
-
- return (
-
- {showLabel && (
-
- )}
- {!file && (
-
-
-
- )}
- {file && (
-
- )}
-
-
-
- );
-}
diff --git a/src/components/ui/auto-form/fields/input.tsx b/src/components/ui/auto-form/fields/input.tsx
deleted file mode 100644
index 33fcd36..0000000
--- a/src/components/ui/auto-form/fields/input.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { FormControl, FormItem, FormMessage } from "@/components/ui/form";
-import { Input } from "@/components/ui/input";
-import AutoFormLabel from "../common/label";
-import AutoFormTooltip from "../common/tooltip";
-import { AutoFormInputComponentProps } from "../types";
-
-export default function AutoFormInput({
- label,
- isRequired,
- fieldConfigItem,
- fieldProps,
-}: AutoFormInputComponentProps) {
- const { showLabel: _showLabel, ...fieldPropsWithoutShowLabel } = fieldProps;
- const showLabel = _showLabel === undefined ? true : _showLabel;
- const type = fieldProps.type || "text";
-
- return (
-
- );
-}
diff --git a/src/components/ui/auto-form/fields/number.tsx b/src/components/ui/auto-form/fields/number.tsx
deleted file mode 100644
index 8637732..0000000
--- a/src/components/ui/auto-form/fields/number.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import { FormControl, FormItem, FormMessage } from "@/components/ui/form";
-import { Input } from "@/components/ui/input";
-import AutoFormLabel from "../common/label";
-import AutoFormTooltip from "../common/tooltip";
-import { AutoFormInputComponentProps } from "../types";
-
-export default function AutoFormNumber({
- label,
- isRequired,
- fieldConfigItem,
- fieldProps,
-}: AutoFormInputComponentProps) {
- const { showLabel: _showLabel, ...fieldPropsWithoutShowLabel } = fieldProps;
- const showLabel = _showLabel === undefined ? true : _showLabel;
-
- return (
-
- {showLabel && (
-
- )}
-
-
-
-
-
-
- );
-}
diff --git a/src/components/ui/auto-form/fields/object.tsx b/src/components/ui/auto-form/fields/object.tsx
deleted file mode 100644
index 5ec122d..0000000
--- a/src/components/ui/auto-form/fields/object.tsx
+++ /dev/null
@@ -1,183 +0,0 @@
-import {
- Accordion,
- AccordionContent,
- AccordionItem,
- AccordionTrigger,
-} from "@/components/ui/accordion";
-import { FormField } from "@/components/ui/form";
-import { useForm, useFormContext } from "react-hook-form";
-import * as z from "zod";
-import { DEFAULT_ZOD_HANDLERS, INPUT_COMPONENTS } from "../config";
-import { Dependency, FieldConfig, FieldConfigItem } from "../types";
-import {
- beautifyObjectName,
- getBaseSchema,
- getBaseType,
- zodToHtmlInputProps,
-} from "../utils";
-import AutoFormArray from "./array";
-import resolveDependencies from "../dependencies";
-
-function DefaultParent({ children }: { children: React.ReactNode }) {
- return <>{children}>;
-}
-
-export default function AutoFormObject<
- SchemaType extends z.ZodObject,
->({
- schema,
- form,
- fieldConfig,
- path = [],
- dependencies = [],
-}: {
- schema: SchemaType | z.ZodEffects;
- form: ReturnType;
- fieldConfig?: FieldConfig>;
- path?: string[];
- dependencies?: Dependency>[];
-}) {
- const { watch } = useFormContext(); // Use useFormContext to access the watch function
-
- if (!schema) {
- return null;
- }
- const { shape } = getBaseSchema(schema) || {};
-
- if (!shape) {
- return null;
- }
-
- const handleIfZodNumber = (item: z.ZodAny) => {
- const isZodNumber = (item as any)._def.typeName === "ZodNumber";
- const isInnerZodNumber =
- (item._def as any).innerType?._def?.typeName === "ZodNumber";
-
- if (isZodNumber) {
- (item as any)._def.coerce = true;
- } else if (isInnerZodNumber) {
- (item._def as any).innerType._def.coerce = true;
- }
-
- return item;
- };
-
- return (
-
- {Object.keys(shape).map((name) => {
- let item = shape[name] as z.ZodAny;
- item = handleIfZodNumber(item) as z.ZodAny;
- const zodBaseType = getBaseType(item);
- const itemName = item._def.description ?? beautifyObjectName(name);
- const key = [...path, name].join(".");
-
- const {
- isHidden,
- isDisabled,
- isRequired: isRequiredByDependency,
- overrideOptions,
- } = resolveDependencies(dependencies, name, watch);
- if (isHidden) {
- return null;
- }
-
- if (zodBaseType === "ZodObject") {
- return (
-
- {itemName}
-
- }
- form={form}
- fieldConfig={
- (fieldConfig?.[name] ?? {}) as FieldConfig<
- z.infer
- >
- }
- path={[...path, name]}
- />
-
-
- );
- }
- if (zodBaseType === "ZodArray") {
- return (
- }
- form={form}
- fieldConfig={fieldConfig?.[name] ?? {}}
- path={[...path, name]}
- />
- );
- }
-
- const fieldConfigItem: FieldConfigItem = fieldConfig?.[name] ?? {};
- const zodInputProps = zodToHtmlInputProps(item);
- const isRequired =
- isRequiredByDependency ||
- zodInputProps.required ||
- fieldConfigItem.inputProps?.required ||
- false;
-
- if (overrideOptions) {
- item = z.enum(overrideOptions) as unknown as z.ZodAny;
- }
-
- return (
- {
- const inputType =
- fieldConfigItem.fieldType ??
- DEFAULT_ZOD_HANDLERS[zodBaseType] ??
- "fallback";
-
- const InputComponent =
- typeof inputType === "function"
- ? inputType
- : INPUT_COMPONENTS[inputType];
-
- const ParentElement =
- fieldConfigItem.renderParent ?? DefaultParent;
-
- const defaultValue = fieldConfigItem.inputProps?.defaultValue;
- const value = field.value ?? defaultValue ?? "";
-
- const fieldProps = {
- ...zodToHtmlInputProps(item),
- ...field,
- ...fieldConfigItem.inputProps,
- disabled: fieldConfigItem.inputProps?.disabled || isDisabled,
- ref: undefined,
- value: value,
- };
-
- if (InputComponent === undefined) {
- return <>>;
- }
-
- return (
-
-
-
- );
- }}
- />
- );
- })}
-
- );
-}
diff --git a/src/components/ui/auto-form/fields/radio-group.tsx b/src/components/ui/auto-form/fields/radio-group.tsx
deleted file mode 100644
index fd192f0..0000000
--- a/src/components/ui/auto-form/fields/radio-group.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import {
- FormControl,
- FormItem,
- FormLabel,
- FormMessage,
-} from "@/components/ui/form";
-import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
-import * as z from "zod";
-import AutoFormLabel from "../common/label";
-import AutoFormTooltip from "../common/tooltip";
-import { AutoFormInputComponentProps } from "../types";
-import { getBaseSchema } from "../utils";
-
-export default function AutoFormRadioGroup({
- label,
- isRequired,
- field,
- zodItem,
- fieldProps,
- fieldConfigItem,
-}: AutoFormInputComponentProps) {
- const baseValues = (getBaseSchema(zodItem) as unknown as z.ZodEnum)._def
- .values;
-
- let values: string[] = [];
- if (!Array.isArray(baseValues)) {
- values = Object.entries(baseValues).map((item) => item[0]);
- } else {
- values = baseValues;
- }
-
- return (
-
-
-
-
-
- {values?.map((value: any) => (
-
-
-
-
- {value}
-
- ))}
-
-
-
-
-
-
- );
-}
diff --git a/src/components/ui/auto-form/fields/switch.tsx b/src/components/ui/auto-form/fields/switch.tsx
deleted file mode 100644
index 24ea9ff..0000000
--- a/src/components/ui/auto-form/fields/switch.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { FormControl, FormItem } from "@/components/ui/form";
-import { Switch } from "@/components/ui/switch";
-import AutoFormLabel from "../common/label";
-import AutoFormTooltip from "../common/tooltip";
-import { AutoFormInputComponentProps } from "../types";
-
-export default function AutoFormSwitch({
- label,
- isRequired,
- field,
- fieldConfigItem,
- fieldProps,
-}: AutoFormInputComponentProps) {
- return (
-
- );
-}
diff --git a/src/components/ui/auto-form/fields/textarea.tsx b/src/components/ui/auto-form/fields/textarea.tsx
deleted file mode 100644
index 2064551..0000000
--- a/src/components/ui/auto-form/fields/textarea.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { FormControl, FormItem, FormMessage } from "@/components/ui/form";
-import { Textarea } from "@/components/ui/textarea";
-import AutoFormLabel from "../common/label";
-import AutoFormTooltip from "../common/tooltip";
-import { AutoFormInputComponentProps } from "../types";
-
-export default function AutoFormTextarea({
- label,
- isRequired,
- fieldConfigItem,
- fieldProps,
-}: AutoFormInputComponentProps) {
- const { showLabel: _showLabel, ...fieldPropsWithoutShowLabel } = fieldProps;
- const showLabel = _showLabel === undefined ? true : _showLabel;
- return (
-
- {showLabel && (
-
- )}
-
-
-
-
-
-
- );
-}
diff --git a/src/components/ui/auto-form/index.tsx b/src/components/ui/auto-form/index.tsx
deleted file mode 100644
index 13e6edc..0000000
--- a/src/components/ui/auto-form/index.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-"use client";
-import { Form } from "@/components/ui/form";
-import React from "react";
-import { DefaultValues, FormState, useForm } from "react-hook-form";
-import { z } from "zod";
-
-import { Button } from "@/components/ui/button";
-import { cn } from "@/lib/utils";
-import { zodResolver } from "@hookform/resolvers/zod";
-
-import AutoFormObject from "./fields/object";
-import { Dependency, FieldConfig } from "./types";
-import {
- ZodObjectOrWrapped,
- getDefaultValues,
- getObjectFormSchema,
-} from "./utils";
-
-export function AutoFormSubmit({
- children,
- className,
- disabled,
-}: {
- children?: React.ReactNode;
- className?: string;
- disabled?: boolean;
-}) {
- return (
-
- );
-}
-
-function AutoForm({
- formSchema,
- values: valuesProp,
- onValuesChange: onValuesChangeProp,
- onParsedValuesChange,
- onSubmit: onSubmitProp,
- fieldConfig,
- children,
- className,
- dependencies,
-}: {
- formSchema: SchemaType;
- values?: Partial>;
- onValuesChange?: (values: Partial>) => void;
- onParsedValuesChange?: (values: Partial>) => void;
- onSubmit?: (values: z.infer) => void;
- fieldConfig?: FieldConfig>;
- children?:
- | React.ReactNode
- | ((formState: FormState>) => React.ReactNode);
- className?: string;
- dependencies?: Dependency>[];
-}) {
- const objectFormSchema = getObjectFormSchema(formSchema);
- const defaultValues: DefaultValues> | null =
- getDefaultValues(objectFormSchema, fieldConfig);
-
- const form = useForm>({
- resolver: zodResolver(formSchema),
- defaultValues: defaultValues ?? undefined,
- values: valuesProp,
- });
-
- function onSubmit(values: z.infer) {
- const parsedValues = formSchema.safeParse(values);
- if (parsedValues.success) {
- onSubmitProp?.(parsedValues.data);
- }
- }
-
- const values = form.watch();
- // valuesString is needed because form.watch() returns a new object every time
- const valuesString = JSON.stringify(values);
-
- React.useEffect(() => {
- onValuesChangeProp?.(values);
- const parsedValues = formSchema.safeParse(values);
- if (parsedValues.success) {
- onParsedValuesChange?.(parsedValues.data);
- }
- }, [valuesString]);
-
- const renderChildren =
- typeof children === "function"
- ? children(form.formState as FormState>)
- : children;
-
- return (
-
- );
-}
-
-export default AutoForm;
diff --git a/src/components/ui/auto-form/tests/basics.cy.tsx b/src/components/ui/auto-form/tests/basics.cy.tsx
deleted file mode 100644
index 9afd2a5..0000000
--- a/src/components/ui/auto-form/tests/basics.cy.tsx
+++ /dev/null
@@ -1,244 +0,0 @@
-import { z } from "zod";
-import AutoForm from "../index";
-
-describe("", () => {
- it("renders fields", () => {
- const formSchema = z.object({
- username: z.string().min(2, {
- message: "Username must be at least 2 characters.",
- }),
-
- password: z.string().describe("Your secure password").min(8, {
- message: "Password must be at least 8 characters.",
- }),
- });
-
- cy.mount();
- cy.get("input[name=username]").should("exist");
- cy.get("input[name=password]").should("exist");
- });
-
- it("renders fields with custom labels", () => {
- const formSchema = z.object({
- username: z.string().describe("Your username"),
- });
-
- cy.mount();
-
- cy.get("label").contains("Your username");
- });
-
- it("generates default labels", () => {
- const formSchema = z.object({
- someFieldName: z.string(),
- });
-
- cy.mount();
-
- cy.get("label").contains("Some Field Name");
- });
-
- it("allows setting custom field labels", () => {
- const formSchema = z.object({
- someFieldName: z.string(),
- });
-
- cy.mount(
- ,
- );
-
- cy.get("label").contains("My field name");
- });
-
- it("allows setting custom field props", () => {
- const formSchema = z.object({
- username: z.string(),
- });
-
- cy.mount(
- ,
- );
-
- cy.get("input[name=username]").should(
- "have.attr",
- "placeholder",
- "Enter your username",
- );
- });
-
- it("allows setting custom field type", () => {
- const formSchema = z.object({
- username: z.string(),
- });
-
- cy.mount(
- ,
- );
-
- cy.get("input").should("have.attr", "type", "number");
- });
-
- it("can submit valid forms", () => {
- const formSchema = z.object({
- username: z.string(),
- });
-
- cy.mount(
- {
- expect(values).to.deep.equal({
- username: "john",
- });
- }}
- >
-
- ,
- );
-
- cy.get("input[name=username]").type("john");
- cy.get("button[type=submit]").click();
- });
-
- it("shows error for invalid forms", () => {
- const formSchema = z.object({
- username: z.string(),
- });
-
- cy.mount(
- {
- expect.fail("Should not be called.");
- }}
- >
-
- ,
- );
-
- cy.get("button[type=submit]").click();
- });
-
- it("can set default values", () => {
- const formSchema = z.object({
- username: z.string().default("john"),
- });
-
- cy.mount();
-
- cy.get("input[name=username]").should("have.value", "john");
- });
-
- it("can submit with default values", () => {
- const formSchema = z.object({
- username: z.string().default("john"),
- });
-
- cy.mount(
- {
- expect(values).to.deep.equal({
- username: "john",
- });
- }}
- >
-
- ,
- );
-
- cy.get("button[type=submit]").click();
- });
-
- it("can set and submit optional values", () => {
- const formSchema = z.object({
- username: z.string().optional(),
- });
-
- cy.mount(
- {
- expect(values).to.deep.equal({
- username: undefined,
- });
- }}
- >
-
- ,
- );
-
- cy.get("input[name=username]").should("have.value", "");
- cy.get("button[type=submit]").click();
- });
-
- it("can add description", () => {
- const formSchema = z.object({
- username: z.string(),
- });
-
- cy.mount(
- ,
- );
-
- cy.get("p").contains("Your username here");
- });
-
- it("can set default values on array", () => {
- const formSchema = z.object({
- arr: z.array(z.object({ name: z.string(), age: z.number() })).default([
- { name: "Haykal", age: 21 },
- { name: "John", age: 20 },
- ]),
- });
-
- cy.mount();
-
- //get button with text Arr
- cy.get("button").contains("Arr").click();
- cy.get("input[name='arr.0.name']").should("have.value", "Haykal");
- cy.get("input[name='arr.0.age']").should("have.value", "21");
- cy.get("input[name='arr.1.name']").should("have.value", "John");
- cy.get("input[name='arr.1.age']").should("have.value", "20");
- });
-
- it("can set default value of number to 0", () => {
- const formSchema = z.object({
- number: z.number().default(0),
- });
-
- cy.mount();
-
- cy.get("input[name='number']").should("have.value", "0");
- });
-});
diff --git a/src/components/ui/auto-form/types.ts b/src/components/ui/auto-form/types.ts
deleted file mode 100644
index b977467..0000000
--- a/src/components/ui/auto-form/types.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import { ControllerRenderProps, FieldValues } from "react-hook-form";
-import * as z from "zod";
-import { INPUT_COMPONENTS } from "./config";
-
-export type FieldConfigItem = {
- description?: React.ReactNode;
- inputProps?: React.InputHTMLAttributes & {
- showLabel?: boolean;
- };
- label?: string;
- fieldType?:
- | keyof typeof INPUT_COMPONENTS
- | React.FC;
-
- renderParent?: (props: {
- children: React.ReactNode;
- }) => React.ReactElement | null;
-};
-
-export type FieldConfig>> = {
- // If SchemaType.key is an object, create a nested FieldConfig, otherwise FieldConfigItem
- [Key in keyof SchemaType]?: SchemaType[Key] extends object
- ? FieldConfig>
- : FieldConfigItem;
-};
-
-export enum DependencyType {
- DISABLES,
- REQUIRES,
- HIDES,
- SETS_OPTIONS,
-}
-
-type BaseDependency>> = {
- sourceField: keyof SchemaType;
- type: DependencyType;
- targetField: keyof SchemaType;
- when: (sourceFieldValue: any, targetFieldValue: any) => boolean;
-};
-
-export type ValueDependency>> =
- BaseDependency & {
- type:
- | DependencyType.DISABLES
- | DependencyType.REQUIRES
- | DependencyType.HIDES;
- };
-
-export type EnumValues = readonly [string, ...string[]];
-
-export type OptionsDependency<
- SchemaType extends z.infer>,
-> = BaseDependency & {
- type: DependencyType.SETS_OPTIONS;
-
- // Partial array of values from sourceField that will trigger the dependency
- options: EnumValues;
-};
-
-export type Dependency>> =
- | ValueDependency
- | OptionsDependency;
-
-/**
- * A FormInput component can handle a specific Zod type (e.g. "ZodBoolean")
- */
-export type AutoFormInputComponentProps = {
- zodInputProps: React.InputHTMLAttributes;
- field: ControllerRenderProps;
- fieldConfigItem: FieldConfigItem;
- label: string;
- isRequired: boolean;
- fieldProps: any;
- zodItem: z.ZodAny;
- className?: string;
-};
diff --git a/src/components/ui/auto-form/utils.ts b/src/components/ui/auto-form/utils.ts
deleted file mode 100644
index f8bfd4e..0000000
--- a/src/components/ui/auto-form/utils.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import React from "react";
-import { DefaultValues } from "react-hook-form";
-import { z } from "zod";
-import { FieldConfig } from "./types";
-
-// TODO: This should support recursive ZodEffects but TypeScript doesn't allow circular type definitions.
-export type ZodObjectOrWrapped =
- | z.ZodObject
- | z.ZodEffects>;
-
-/**
- * Beautify a camelCase string.
- * e.g. "myString" -> "My String"
- */
-export function beautifyObjectName(string: string) {
- // if numbers only return the string
- let output = string.replace(/([A-Z])/g, " $1");
- output = output.charAt(0).toUpperCase() + output.slice(1);
- return output;
-}
-
-/**
- * Get the lowest level Zod type.
- * This will unpack optionals, refinements, etc.
- */
-export function getBaseSchema<
- ChildType extends z.ZodAny | z.AnyZodObject = z.ZodAny,
->(schema: ChildType | z.ZodEffects): ChildType | null {
- if (!schema) return null;
- if ("innerType" in schema._def) {
- return getBaseSchema(schema._def.innerType as ChildType);
- }
- if ("schema" in schema._def) {
- return getBaseSchema(schema._def.schema as ChildType);
- }
-
- return schema as ChildType;
-}
-
-/**
- * Get the type name of the lowest level Zod type.
- * This will unpack optionals, refinements, etc.
- */
-export function getBaseType(schema: z.ZodAny): string {
- const baseSchema = getBaseSchema(schema);
- return baseSchema ? baseSchema._def.typeName : "";
-}
-
-/**
- * Search for a "ZodDefult" in the Zod stack and return its value.
- */
-export function getDefaultValueInZodStack(schema: z.ZodAny): any {
- const typedSchema = schema as unknown as z.ZodDefault<
- z.ZodNumber | z.ZodString
- >;
-
- if (typedSchema._def.typeName === "ZodDefault") {
- return typedSchema._def.defaultValue();
- }
-
- if ("innerType" in typedSchema._def) {
- return getDefaultValueInZodStack(
- typedSchema._def.innerType as unknown as z.ZodAny,
- );
- }
- if ("schema" in typedSchema._def) {
- return getDefaultValueInZodStack(
- (typedSchema._def as any).schema as z.ZodAny,
- );
- }
-
- return undefined;
-}
-
-/**
- * Get all default values from a Zod schema.
- */
-export function getDefaultValues>(
- schema: Schema,
- fieldConfig?: FieldConfig>,
-) {
- if (!schema) return null;
- const { shape } = schema;
- type DefaultValuesType = DefaultValues>>;
- const defaultValues = {} as DefaultValuesType;
- if (!shape) return defaultValues;
-
- for (const key of Object.keys(shape)) {
- const item = shape[key] as z.ZodAny;
-
- if (getBaseType(item) === "ZodObject") {
- const defaultItems = getDefaultValues(
- getBaseSchema(item) as unknown as z.ZodObject,
- fieldConfig?.[key] as FieldConfig>,
- );
-
- if (defaultItems !== null) {
- for (const defaultItemKey of Object.keys(defaultItems)) {
- const pathKey = `${key}.${defaultItemKey}` as keyof DefaultValuesType;
- defaultValues[pathKey] = defaultItems[defaultItemKey];
- }
- }
- } else {
- let defaultValue = getDefaultValueInZodStack(item);
- if (
- (defaultValue === null || defaultValue === "") &&
- fieldConfig?.[key]?.inputProps
- ) {
- defaultValue = (fieldConfig?.[key]?.inputProps as unknown as any)
- .defaultValue;
- }
- if (defaultValue !== undefined) {
- defaultValues[key as keyof DefaultValuesType] = defaultValue;
- }
- }
- }
-
- return defaultValues;
-}
-
-export function getObjectFormSchema(
- schema: ZodObjectOrWrapped,
-): z.ZodObject {
- if (schema?._def.typeName === "ZodEffects") {
- const typedSchema = schema as z.ZodEffects>;
- return getObjectFormSchema(typedSchema._def.schema);
- }
- return schema as z.ZodObject;
-}
-
-/**
- * Convert a Zod schema to HTML input props to give direct feedback to the user.
- * Once submitted, the schema will be validated completely.
- */
-export function zodToHtmlInputProps(
- schema:
- | z.ZodNumber
- | z.ZodString
- | z.ZodOptional
- | any,
-): React.InputHTMLAttributes {
- if (["ZodOptional", "ZodNullable"].includes(schema._def.typeName)) {
- const typedSchema = schema as z.ZodOptional;
- return {
- ...zodToHtmlInputProps(typedSchema._def.innerType),
- required: false,
- };
- }
- const typedSchema = schema as z.ZodNumber | z.ZodString;
-
- if (!("checks" in typedSchema._def))
- return {
- required: true,
- };
-
- const { checks } = typedSchema._def;
- const inputProps: React.InputHTMLAttributes = {
- required: true,
- };
- const type = getBaseType(schema);
-
- for (const check of checks) {
- if (check.kind === "min") {
- if (type === "ZodString") {
- inputProps.minLength = check.value;
- } else {
- inputProps.min = check.value;
- }
- }
- if (check.kind === "max") {
- if (type === "ZodString") {
- inputProps.maxLength = check.value;
- } else {
- inputProps.max = check.value;
- }
- }
- }
-
- return inputProps;
-}
diff --git a/src/components/ui/date-picker.tsx b/src/components/ui/date-picker.tsx
deleted file mode 100644
index 4217c2e..0000000
--- a/src/components/ui/date-picker.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-"use client";
-import { format } from "date-fns";
-import { Calendar as CalendarIcon } from "lucide-react";
-
-import { cn } from "@/lib/utils";
-import { Button } from "@/components/ui/button";
-import { Calendar } from "@/components/ui/calendar";
-import {
- Popover,
- PopoverContent,
- PopoverTrigger,
-} from "@/components/ui/popover";
-import { forwardRef } from "react";
-
-export const DatePicker = forwardRef<
- HTMLDivElement,
- {
- date?: Date;
- setDate: (date?: Date) => void;
- }
->(function DatePickerCmp({ date, setDate }, ref) {
- return (
-
-
-
-
-
-
-
-
- );
-});