{
  "name": "auto-form",
  "dependencies": [
    "vee-validate",
    "@vee-validate/zod",
    "zod"
  ],
  "registryDependencies": [
    "form",
    "accordion",
    "button",
    "separator",
    "switch",
    "checkbox",
    "calendar",
    "popover",
    "utils",
    "select",
    "label",
    "radio-group",
    "input",
    "textarea"
  ],
  "files": [
    {
      "name": "AutoForm.vue",
      "content": "<script setup lang=\"ts\" generic=\"T extends ZodObjectOrWrapped\">\nimport { computed, toRefs } from 'vue'\nimport type { ZodAny, z } from 'zod'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport type { FormContext, GenericObject } from 'vee-validate'\nimport { type ZodObjectOrWrapped, getBaseSchema, getBaseType, getDefaultValueInZodStack, getObjectFormSchema } from './utils'\nimport type { Config, ConfigItem, Dependency, Shape } from './interface'\nimport AutoFormField from './AutoFormField.vue'\nimport { provideDependencies } from './dependencies'\nimport { Form } from '@/lib/registry/default/ui/form'\n\nconst props = defineProps<{\n  schema: T\n  form?: FormContext<GenericObject>\n  fieldConfig?: Config<z.infer<T>>\n  dependencies?: Dependency<z.infer<T>>[]\n}>()\n\nconst emits = defineEmits<{\n  submit: [event: GenericObject]\n}>()\n\nconst { dependencies } = toRefs(props)\nprovideDependencies(dependencies)\n\nconst shapes = computed(() => {\n  // @ts-expect-error ignore {} not assignable to object\n  const val: { [key in keyof T]: Shape } = {}\n  const baseSchema = getObjectFormSchema(props.schema)\n  const shape = baseSchema.shape\n  Object.keys(shape).forEach((name) => {\n    const item = shape[name] as ZodAny\n    const baseItem = getBaseSchema(item) as ZodAny\n    let options = (baseItem && 'values' in baseItem._def) ? baseItem._def.values as string[] : undefined\n    if (!Array.isArray(options) && typeof options === 'object')\n      options = Object.values(options)\n\n    val[name as keyof T] = {\n      type: getBaseType(item),\n      default: getDefaultValueInZodStack(item),\n      options,\n      required: !['ZodOptional', 'ZodNullable'].includes(item._def.typeName),\n      schema: baseItem,\n    }\n  })\n  return val\n})\n\nconst fields = computed(() => {\n  // @ts-expect-error ignore {} not assignable to object\n  const val: { [key in keyof z.infer<T>]: { shape: Shape, fieldName: string, config: ConfigItem } } = {}\n  for (const key in shapes.value) {\n    const shape = shapes.value[key]\n    val[key as keyof z.infer<T>] = {\n      shape,\n      config: props.fieldConfig?.[key] as ConfigItem,\n      fieldName: key,\n    }\n  }\n  return val\n})\n\nconst formComponent = computed(() => props.form ? 'form' : Form)\nconst formComponentProps = computed(() => {\n  if (props.form) {\n    return {\n      onSubmit: props.form.handleSubmit(val => emits('submit', val)),\n    }\n  }\n  else {\n    const formSchema = toTypedSchema(props.schema)\n    return {\n      keepValues: true,\n      validationSchema: formSchema,\n      onSubmit: (val: GenericObject) => emits('submit', val),\n    }\n  }\n})\n</script>\n\n<template>\n  <component\n    :is=\"formComponent\"\n    v-bind=\"formComponentProps\"\n  >\n    <slot name=\"customAutoForm\" :fields=\"fields\">\n      <template v-for=\"(shape, key) of shapes\" :key=\"key\">\n        <slot\n          :shape=\"shape\"\n          :name=\"key.toString() as keyof z.infer<T>\"\n          :field-name=\"key.toString()\"\n          :config=\"fieldConfig?.[key as keyof typeof fieldConfig] as ConfigItem\"\n        >\n          <AutoFormField\n            :config=\"fieldConfig?.[key as keyof typeof fieldConfig] as ConfigItem\"\n            :field-name=\"key.toString()\"\n            :shape=\"shape\"\n          />\n        </slot>\n      </template>\n    </slot>\n\n    <slot :shapes=\"shapes\" />\n  </component>\n</template>\n"
    },
    {
      "name": "AutoFormField.vue",
      "content": "<script setup lang=\"ts\" generic=\"U extends ZodAny\">\nimport type { ZodAny } from 'zod'\nimport { computed } from 'vue'\nimport type { Config, ConfigItem, Shape } from './interface'\nimport { DEFAULT_ZOD_HANDLERS, INPUT_COMPONENTS } from './constant'\nimport useDependencies from './dependencies'\n\nconst props = defineProps<{\n  fieldName: string\n  shape: Shape\n  config?: ConfigItem | Config<U>\n}>()\n\nfunction isValidConfig(config: any): config is ConfigItem {\n  return !!config?.component\n}\n\nconst delegatedProps = computed(() => {\n  if (['ZodObject', 'ZodArray'].includes(props.shape?.type))\n    return { schema: props.shape?.schema }\n  return undefined\n})\n\nconst { isDisabled, isHidden, isRequired, overrideOptions } = useDependencies(props.fieldName)\n</script>\n\n<template>\n  <component\n    :is=\"isValidConfig(config)\n      ? typeof config.component === 'string'\n        ? INPUT_COMPONENTS[config.component!]\n        : config.component\n      : INPUT_COMPONENTS[DEFAULT_ZOD_HANDLERS[shape.type]] \"\n    v-if=\"!isHidden\"\n    :field-name=\"fieldName\"\n    :label=\"shape.schema?.description\"\n    :required=\"isRequired || shape.required\"\n    :options=\"overrideOptions || shape.options\"\n    :disabled=\"isDisabled\"\n    :config=\"config\"\n    v-bind=\"delegatedProps\"\n  >\n    <slot />\n  </component>\n</template>\n"
    },
    {
      "name": "AutoFormFieldArray.vue",
      "content": "<script setup lang=\"ts\" generic=\"T extends z.ZodAny\">\nimport * as z from 'zod'\nimport { computed, provide } from 'vue'\nimport { PlusIcon, TrashIcon } from 'lucide-vue-next'\nimport { FieldArray, FieldContextKey, useField } from 'vee-validate'\nimport type { Config, ConfigItem } from './interface'\nimport { beautifyObjectName, getBaseType } from './utils'\nimport AutoFormField from './AutoFormField.vue'\nimport AutoFormLabel from './AutoFormLabel.vue'\nimport { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/lib/registry/default/ui/accordion'\nimport { Button } from '@/lib/registry/default/ui/button'\nimport { Separator } from '@/lib/registry/default/ui/separator'\nimport { FormItem, FormMessage } from '@/lib/registry/default/ui/form'\n\nconst props = defineProps<{\n  fieldName: string\n  required?: boolean\n  config?: Config<T>\n  schema?: z.ZodArray<T>\n  disabled?: boolean\n}>()\n\nfunction isZodArray(\n  item: z.ZodArray<any> | z.ZodDefault<any>,\n): item is z.ZodArray<any> {\n  return item instanceof z.ZodArray\n}\n\nfunction isZodDefault(\n  item: z.ZodArray<any> | z.ZodDefault<any>,\n): item is z.ZodDefault<any> {\n  return item instanceof z.ZodDefault\n}\n\nconst itemShape = computed(() => {\n  if (!props.schema)\n    return\n\n  const schema: z.ZodAny = isZodArray(props.schema)\n    ? props.schema._def.type\n    : isZodDefault(props.schema)\n    // @ts-expect-error missing schema\n      ? props.schema._def.innerType._def.type\n      : null\n\n  return {\n    type: getBaseType(schema),\n    schema,\n  }\n})\n\nconst fieldContext = useField(props.fieldName)\n// @ts-expect-error ignore missing `id`\nprovide(FieldContextKey, fieldContext)\n</script>\n\n<template>\n  <FieldArray v-slot=\"{ fields, remove, push }\" as=\"section\" :name=\"fieldName\">\n    <slot v-bind=\"props\">\n      <Accordion type=\"multiple\" class=\"w-full\" collapsible :disabled=\"disabled\" as-child>\n        <FormItem>\n          <AccordionItem :value=\"fieldName\" class=\"border-none\">\n            <AccordionTrigger>\n              <AutoFormLabel class=\"text-base\" :required=\"required\">\n                {{ schema?.description || beautifyObjectName(fieldName) }}\n              </AutoFormLabel>\n            </AccordionTrigger>\n\n            <AccordionContent>\n              <template v-for=\"(field, index) of fields\" :key=\"field.key\">\n                <div class=\"mb-4 p-1\">\n                  <AutoFormField\n                    :field-name=\"`${fieldName}[${index}]`\"\n                    :label=\"fieldName\"\n                    :shape=\"itemShape!\"\n                    :config=\"config as ConfigItem\"\n                  />\n\n                  <div class=\"!my-4 flex justify-end\">\n                    <Button\n                      type=\"button\"\n                      size=\"icon\"\n                      variant=\"secondary\"\n                      @click=\"remove(index)\"\n                    >\n                      <TrashIcon :size=\"16\" />\n                    </Button>\n                  </div>\n                  <Separator v-if=\"!field.isLast\" />\n                </div>\n              </template>\n\n              <Button\n                type=\"button\"\n                variant=\"secondary\"\n                class=\"mt-4 flex items-center\"\n                @click=\"push(null)\"\n              >\n                <PlusIcon class=\"mr-2\" :size=\"16\" />\n                Add\n              </Button>\n            </AccordionContent>\n\n            <FormMessage />\n          </AccordionItem>\n        </FormItem>\n      </Accordion>\n    </slot>\n  </FieldArray>\n</template>\n"
    },
    {
      "name": "AutoFormFieldBoolean.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { beautifyObjectName } from './utils'\nimport type { FieldProps } from './interface'\nimport AutoFormLabel from './AutoFormLabel.vue'\nimport { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/default/ui/form'\nimport { Switch } from '@/lib/registry/default/ui/switch'\nimport { Checkbox } from '@/lib/registry/default/ui/checkbox'\n\nconst props = defineProps<FieldProps>()\n\nconst booleanComponent = computed(() => props.config?.component === 'switch' ? Switch : Checkbox)\n</script>\n\n<template>\n  <FormField v-slot=\"slotProps\" :name=\"fieldName\">\n    <FormItem>\n      <div class=\"space-y-0 mb-3 flex items-center gap-3\">\n        <FormControl>\n          <slot v-bind=\"slotProps\">\n            <component\n              :is=\"booleanComponent\"\n              v-bind=\"{ ...slotProps.componentField }\"\n              :disabled=\"disabled\"\n              :checked=\"slotProps.componentField.modelValue\"\n              @update:checked=\"slotProps.componentField['onUpdate:modelValue']\"\n            />\n          </slot>\n        </FormControl>\n        <AutoFormLabel v-if=\"!config?.hideLabel\" :required=\"required\">\n          {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n        </AutoFormLabel>\n      </div>\n\n      <FormDescription v-if=\"config?.description\">\n        {{ config.description }}\n      </FormDescription>\n      <FormMessage />\n    </FormItem>\n  </FormField>\n</template>\n"
    },
    {
      "name": "AutoFormFieldDate.vue",
      "content": "<script setup lang=\"ts\">\nimport { DateFormatter, getLocalTimeZone } from '@internationalized/date'\nimport { CalendarIcon } from 'lucide-vue-next'\nimport { beautifyObjectName } from './utils'\nimport AutoFormLabel from './AutoFormLabel.vue'\nimport type { FieldProps } from './interface'\nimport { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/default/ui/form'\n\nimport { Calendar } from '@/lib/registry/default/ui/calendar'\nimport { Button } from '@/lib/registry/default/ui/button'\nimport { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/default/ui/popover'\nimport { cn } from '@/lib/utils'\n\ndefineProps<FieldProps>()\n\nconst df = new DateFormatter('en-US', {\n  dateStyle: 'long',\n})\n</script>\n\n<template>\n  <FormField v-slot=\"slotProps\" :name=\"fieldName\">\n    <FormItem>\n      <AutoFormLabel v-if=\"!config?.hideLabel\" :required=\"required\">\n        {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n      </AutoFormLabel>\n      <FormControl>\n        <slot v-bind=\"slotProps\">\n          <div>\n            <Popover>\n              <PopoverTrigger as-child :disabled=\"disabled\">\n                <Button\n                  variant=\"outline\"\n                  :class=\"cn(\n                    'w-full justify-start text-left font-normal',\n                    !slotProps.componentField.modelValue && 'text-muted-foreground',\n                  )\"\n                >\n                  <CalendarIcon class=\"mr-2 h-4 w-4\" :size=\"16\" />\n                  {{ slotProps.componentField.modelValue ? df.format(slotProps.componentField.modelValue.toDate(getLocalTimeZone())) : \"Pick a date\" }}\n                </Button>\n              </PopoverTrigger>\n              <PopoverContent class=\"w-auto p-0\">\n                <Calendar initial-focus v-bind=\"slotProps.componentField\" />\n              </PopoverContent>\n            </Popover>\n          </div>\n        </slot>\n      </FormControl>\n\n      <FormDescription v-if=\"config?.description\">\n        {{ config.description }}\n      </FormDescription>\n      <FormMessage />\n    </FormItem>\n  </FormField>\n</template>\n"
    },
    {
      "name": "AutoFormFieldEnum.vue",
      "content": "<script setup lang=\"ts\">\nimport AutoFormLabel from './AutoFormLabel.vue'\nimport { beautifyObjectName } from './utils'\nimport type { FieldProps } from './interface'\nimport { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/default/ui/form'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/lib/registry/default/ui/select'\nimport { Label } from '@/lib/registry/default/ui/label'\nimport { RadioGroup, RadioGroupItem } from '@/lib/registry/default/ui/radio-group'\n\ndefineProps<FieldProps & {\n  options?: string[]\n}>()\n</script>\n\n<template>\n  <FormField v-slot=\"slotProps\" :name=\"fieldName\">\n    <FormItem>\n      <AutoFormLabel v-if=\"!config?.hideLabel\" :required=\"required\">\n        {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n      </AutoFormLabel>\n      <FormControl>\n        <slot v-bind=\"slotProps\">\n          <RadioGroup v-if=\"config?.component === 'radio'\" :disabled=\"disabled\" :orientation=\"'vertical'\" v-bind=\"{ ...slotProps.componentField }\">\n            <div v-for=\"(option, index) in options\" :key=\"option\" class=\"mb-2 flex items-center gap-3 space-y-0\">\n              <RadioGroupItem :id=\"`${option}-${index}`\" :value=\"option\" />\n              <Label :for=\"`${option}-${index}`\">{{ beautifyObjectName(option) }}</Label>\n            </div>\n          </RadioGroup>\n\n          <Select v-else :disabled=\"disabled\" v-bind=\"{ ...slotProps.componentField }\">\n            <SelectTrigger class=\"w-full\">\n              <SelectValue :placeholder=\"config?.inputProps?.placeholder\" />\n            </SelectTrigger>\n            <SelectContent>\n              <SelectItem v-for=\"option in options\" :key=\"option\" :value=\"option\">\n                {{ beautifyObjectName(option) }}\n              </SelectItem>\n            </SelectContent>\n          </Select>\n        </slot>\n      </FormControl>\n\n      <FormDescription v-if=\"config?.description\">\n        {{ config.description }}\n      </FormDescription>\n      <FormMessage />\n    </FormItem>\n  </FormField>\n</template>\n"
    },
    {
      "name": "AutoFormFieldFile.vue",
      "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { TrashIcon } from 'lucide-vue-next'\nimport AutoFormLabel from './AutoFormLabel.vue'\nimport { beautifyObjectName } from './utils'\nimport type { FieldProps } from './interface'\nimport { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/default/ui/form'\nimport { Input } from '@/lib/registry/default/ui/input'\nimport { Button } from '@/lib/registry/default/ui/button'\n\ndefineProps<FieldProps>()\n\nconst inputFile = ref<File>()\nasync function parseFileAsString(file: File | undefined): Promise<string> {\n  return new Promise((resolve, reject) => {\n    if (file) {\n      const reader = new FileReader()\n      reader.onloadend = () => {\n        resolve(reader.result as string)\n      }\n      reader.onerror = (err) => {\n        reject(err)\n      }\n      reader.readAsDataURL(file)\n    }\n  })\n}\n</script>\n\n<template>\n  <FormField v-slot=\"slotProps\" :name=\"fieldName\">\n    <FormItem v-bind=\"$attrs\">\n      <AutoFormLabel v-if=\"!config?.hideLabel\" :required=\"required\">\n        {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n      </AutoFormLabel>\n      <FormControl>\n        <slot v-bind=\"slotProps\">\n          <Input\n            v-if=\"!inputFile\"\n            type=\"file\"\n            v-bind=\"{ ...config?.inputProps }\"\n            :disabled=\"disabled\"\n            @change=\"async (ev: InputEvent) => {\n              const file = (ev.target as HTMLInputElement).files?.[0]\n              inputFile = file\n              const parsed = await parseFileAsString(file)\n              slotProps.componentField.onInput(parsed)\n            }\"\n          />\n          <div v-else class=\"flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent pl-3 pr-1 py-1 text-sm shadow-sm transition-colors\">\n            <p>{{ inputFile?.name }}</p>\n            <Button\n              :size=\"'icon'\"\n              :variant=\"'ghost'\"\n              class=\"h-[26px] w-[26px]\"\n              aria-label=\"Remove file\"\n              type=\"button\"\n              @click=\"() => {\n                inputFile = undefined\n                slotProps.componentField.onInput(undefined)\n              }\"\n            >\n              <TrashIcon :size=\"16\" />\n            </Button>\n          </div>\n        </slot>\n      </FormControl>\n      <FormDescription v-if=\"config?.description\">\n        {{ config.description }}\n      </FormDescription>\n      <FormMessage />\n    </FormItem>\n  </FormField>\n</template>\n"
    },
    {
      "name": "AutoFormFieldInput.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport AutoFormLabel from './AutoFormLabel.vue'\nimport { beautifyObjectName } from './utils'\nimport type { FieldProps } from './interface'\nimport { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/default/ui/form'\nimport { Input } from '@/lib/registry/default/ui/input'\nimport { Textarea } from '@/lib/registry/default/ui/textarea'\n\nconst props = defineProps<FieldProps>()\nconst inputComponent = computed(() => props.config?.component === 'textarea' ? Textarea : Input)\n</script>\n\n<template>\n  <FormField v-slot=\"slotProps\" :name=\"fieldName\">\n    <FormItem v-bind=\"$attrs\">\n      <AutoFormLabel v-if=\"!config?.hideLabel\" :required=\"required\">\n        {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n      </AutoFormLabel>\n      <FormControl>\n        <slot v-bind=\"slotProps\">\n          <component\n            :is=\"inputComponent\"\n            type=\"text\"\n            v-bind=\"{ ...slotProps.componentField, ...config?.inputProps }\"\n            :disabled=\"disabled\"\n          />\n        </slot>\n      </FormControl>\n      <FormDescription v-if=\"config?.description\">\n        {{ config.description }}\n      </FormDescription>\n      <FormMessage />\n    </FormItem>\n  </FormField>\n</template>\n"
    },
    {
      "name": "AutoFormFieldNumber.vue",
      "content": "<script setup lang=\"ts\">\nimport AutoFormLabel from './AutoFormLabel.vue'\nimport { beautifyObjectName } from './utils'\nimport type { FieldProps } from './interface'\nimport { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/default/ui/form'\nimport { Input } from '@/lib/registry/default/ui/input'\n\ndefineOptions({\n  inheritAttrs: false,\n})\n\ndefineProps<FieldProps>()\n</script>\n\n<template>\n  <FormField v-slot=\"slotProps\" :name=\"fieldName\">\n    <FormItem>\n      <AutoFormLabel v-if=\"!config?.hideLabel\" :required=\"required\">\n        {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n      </AutoFormLabel>\n      <FormControl>\n        <slot v-bind=\"slotProps\">\n          <Input type=\"number\" v-bind=\"{ ...slotProps.componentField, ...config?.inputProps }\" :disabled=\"disabled\" />\n        </slot>\n      </FormControl>\n      <FormDescription v-if=\"config?.description\">\n        {{ config.description }}\n      </FormDescription>\n      <FormMessage />\n    </FormItem>\n  </FormField>\n</template>\n"
    },
    {
      "name": "AutoFormFieldObject.vue",
      "content": "<script setup lang=\"ts\" generic=\"T extends ZodRawShape\">\nimport type { ZodAny, ZodObject, ZodRawShape } from 'zod'\nimport { computed, provide } from 'vue'\nimport { FieldContextKey, useField } from 'vee-validate'\nimport AutoFormField from './AutoFormField.vue'\nimport type { Config, ConfigItem, Shape } from './interface'\nimport { beautifyObjectName, getBaseSchema, getBaseType, getDefaultValueInZodStack } from './utils'\nimport AutoFormLabel from './AutoFormLabel.vue'\nimport { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/lib/registry/default/ui/accordion'\nimport { FormItem } from '@/lib/registry/default/ui/form'\n\nconst props = defineProps<{\n  fieldName: string\n  required?: boolean\n  config?: Config<T>\n  schema?: ZodObject<T>\n  disabled?: boolean\n}>()\n\nconst shapes = computed(() => {\n  // @ts-expect-error ignore {} not assignable to object\n  const val: { [key in keyof T]: Shape } = {}\n\n  if (!props.schema)\n    return\n  const shape = getBaseSchema(props.schema)?.shape\n  if (!shape)\n    return\n  Object.keys(shape).forEach((name) => {\n    const item = shape[name] as ZodAny\n    const baseItem = getBaseSchema(item) as ZodAny\n    let options = (baseItem && 'values' in baseItem._def) ? baseItem._def.values as string[] : undefined\n    if (!Array.isArray(options) && typeof options === 'object')\n      options = Object.values(options)\n\n    val[name as keyof T] = {\n      type: getBaseType(item),\n      default: getDefaultValueInZodStack(item),\n      options,\n      required: !['ZodOptional', 'ZodNullable'].includes(item._def.typeName),\n      schema: item,\n    }\n  })\n  return val\n})\n\nconst fieldContext = useField(props.fieldName)\n// @ts-expect-error ignore missing `id`\nprovide(FieldContextKey, fieldContext)\n</script>\n\n<template>\n  <section>\n    <slot v-bind=\"props\">\n      <Accordion type=\"single\" as-child class=\"w-full\" collapsible :disabled=\"disabled\">\n        <FormItem>\n          <AccordionItem :value=\"fieldName\" class=\"border-none\">\n            <AccordionTrigger>\n              <AutoFormLabel class=\"text-base\" :required=\"required\">\n                {{ schema?.description || beautifyObjectName(fieldName) }}\n              </AutoFormLabel>\n            </AccordionTrigger>\n            <AccordionContent class=\"p-1 space-y-5\">\n              <template v-for=\"(shape, key) in shapes\" :key=\"key\">\n                <AutoFormField\n                  :config=\"config?.[key as keyof typeof config] as ConfigItem\"\n                  :field-name=\"`${fieldName}.${key.toString()}`\"\n                  :label=\"key.toString()\"\n                  :shape=\"shape\"\n                />\n              </template>\n            </AccordionContent>\n          </AccordionItem>\n        </FormItem>\n      </Accordion>\n    </slot>\n  </section>\n</template>\n"
    },
    {
      "name": "AutoFormLabel.vue",
      "content": "<script setup lang=\"ts\">\nimport { FormLabel } from '@/lib/registry/default/ui/form'\n\ndefineProps<{\n  required?: boolean\n}>()\n</script>\n\n<template>\n  <FormLabel>\n    <slot />\n    <span v-if=\"required\" class=\"text-destructive\"> *</span>\n  </FormLabel>\n</template>\n"
    },
    {
      "name": "constant.ts",
      "content": "import AutoFormFieldArray from './AutoFormFieldArray.vue'\nimport AutoFormFieldBoolean from './AutoFormFieldBoolean.vue'\nimport AutoFormFieldDate from './AutoFormFieldDate.vue'\nimport AutoFormFieldEnum from './AutoFormFieldEnum.vue'\nimport AutoFormFieldFile from './AutoFormFieldFile.vue'\nimport AutoFormFieldInput from './AutoFormFieldInput.vue'\nimport AutoFormFieldNumber from './AutoFormFieldNumber.vue'\nimport AutoFormFieldObject from './AutoFormFieldObject.vue'\n\nexport const INPUT_COMPONENTS = {\n  date: AutoFormFieldDate,\n  select: AutoFormFieldEnum,\n  radio: AutoFormFieldEnum,\n  checkbox: AutoFormFieldBoolean,\n  switch: AutoFormFieldBoolean,\n  textarea: AutoFormFieldInput,\n  number: AutoFormFieldNumber,\n  string: AutoFormFieldInput,\n  file: AutoFormFieldFile,\n  array: AutoFormFieldArray,\n  object: AutoFormFieldObject,\n}\n\n/**\n * Define handlers for specific Zod types.\n * You can expand this object to support more types.\n */\nexport const DEFAULT_ZOD_HANDLERS: {\n  [key: string]: keyof typeof INPUT_COMPONENTS\n} = {\n  ZodString: 'string',\n  ZodBoolean: 'checkbox',\n  ZodDate: 'date',\n  ZodEnum: 'select',\n  ZodNativeEnum: 'select',\n  ZodNumber: 'number',\n  ZodArray: 'array',\n  ZodObject: 'object',\n}\n"
    },
    {
      "name": "dependencies.ts",
      "content": "import type * as z from 'zod'\nimport type { Ref } from 'vue'\nimport { computed, ref, watch } from 'vue'\nimport { useFieldValue, useFormValues } from 'vee-validate'\nimport { createContext } from 'radix-vue'\nimport { type Dependency, DependencyType, type EnumValues } from './interface'\nimport { getFromPath, getIndexIfArray } from './utils'\n\nexport const [injectDependencies, provideDependencies] = createContext<Ref<Dependency<z.infer<z.ZodObject<any>>>[] | undefined>>('AutoFormDependencies')\n\nexport default function useDependencies(\n  fieldName: string,\n) {\n  const form = useFormValues()\n  // parsed test[0].age => test.age\n  const currentFieldName = fieldName.replace(/\\[\\d+\\]/g, '')\n  const currentFieldValue = useFieldValue<any>(fieldName)\n\n  if (!form)\n    throw new Error('useDependencies should be used within <AutoForm>')\n\n  const dependencies = injectDependencies()\n  const isDisabled = ref(false)\n  const isHidden = ref(false)\n  const isRequired = ref(false)\n  const overrideOptions = ref<EnumValues | undefined>()\n\n  const currentFieldDependencies = computed(() => dependencies.value?.filter(\n    dependency => dependency.targetField === currentFieldName,\n  ))\n\n  function getSourceValue(dep: Dependency<any>) {\n    const source = dep.sourceField as string\n    const index = getIndexIfArray(fieldName) ?? -1\n    const [sourceLast, ...sourceInitial] = source.split('.').toReversed()\n    const [_targetLast, ...targetInitial] = (dep.targetField as string).split('.').toReversed()\n\n    if (index >= 0 && sourceInitial.join(',') === targetInitial.join(',')) {\n      const [_currentLast, ...currentInitial] = fieldName.split('.').toReversed()\n      return getFromPath(form.value, currentInitial.join('.') + sourceLast)\n    }\n\n    return getFromPath(form.value, source)\n  }\n\n  const sourceFieldValues = computed(() => currentFieldDependencies.value?.map(dep => getSourceValue(dep)))\n\n  const resetConditionState = () => {\n    isDisabled.value = false\n    isHidden.value = false\n    isRequired.value = false\n    overrideOptions.value = undefined\n  }\n\n  watch([sourceFieldValues, dependencies], () => {\n    resetConditionState()\n    currentFieldDependencies.value?.forEach((dep) => {\n      const sourceValue = getSourceValue(dep)\n      const conditionMet = dep.when(sourceValue, currentFieldValue.value)\n\n      switch (dep.type) {\n        case DependencyType.DISABLES:\n          if (conditionMet)\n            isDisabled.value = true\n\n          break\n        case DependencyType.REQUIRES:\n          if (conditionMet)\n            isRequired.value = true\n\n          break\n        case DependencyType.HIDES:\n          if (conditionMet)\n            isHidden.value = true\n\n          break\n        case DependencyType.SETS_OPTIONS:\n          if (conditionMet)\n            overrideOptions.value = dep.options\n\n          break\n      }\n    })\n  }, { immediate: true, deep: true })\n\n  return {\n    isDisabled,\n    isHidden,\n    isRequired,\n    overrideOptions,\n  }\n}\n"
    },
    {
      "name": "index.ts",
      "content": "export { getObjectFormSchema, getBaseSchema, getBaseType } from './utils'\nexport type { Config, ConfigItem, FieldProps } from './interface'\n\nexport { default as AutoForm } from './AutoForm.vue'\nexport { default as AutoFormField } from './AutoFormField.vue'\nexport { default as AutoFormLabel } from './AutoFormLabel.vue'\n\nexport { default as AutoFormFieldArray } from './AutoFormFieldArray.vue'\nexport { default as AutoFormFieldBoolean } from './AutoFormFieldBoolean.vue'\nexport { default as AutoFormFieldDate } from './AutoFormFieldDate.vue'\nexport { default as AutoFormFieldEnum } from './AutoFormFieldEnum.vue'\nexport { default as AutoFormFieldFile } from './AutoFormFieldFile.vue'\nexport { default as AutoFormFieldInput } from './AutoFormFieldInput.vue'\nexport { default as AutoFormFieldNumber } from './AutoFormFieldNumber.vue'\nexport { default as AutoFormFieldObject } from './AutoFormFieldObject.vue'\n"
    },
    {
      "name": "interface.ts",
      "content": "import type { Component, InputHTMLAttributes } from 'vue'\nimport type { ZodAny, z } from 'zod'\nimport type { INPUT_COMPONENTS } from './constant'\n\nexport interface FieldProps {\n  fieldName: string\n  label?: string\n  required?: boolean\n  config?: ConfigItem\n  disabled?: boolean\n}\n\nexport interface Shape {\n  type: string\n  default?: any\n  required?: boolean\n  options?: string[]\n  schema?: ZodAny\n}\n\nexport interface ConfigItem {\n  /** Value for the `FormLabel` */\n  label?: string\n  /** Value for the `FormDescription` */\n  description?: string\n  /** Pick which component to be rendered. */\n  component?: keyof typeof INPUT_COMPONENTS | Component\n  /** Hide `FormLabel`. */\n  hideLabel?: boolean\n  inputProps?: InputHTMLAttributes\n}\n\n// Define a type to unwrap an array\ntype UnwrapArray<T> = T extends (infer U)[] ? U : never\n\nexport type Config<SchemaType extends object> = {\n  // If SchemaType.key is an object, create a nested Config, otherwise ConfigItem\n  [Key in keyof SchemaType]?:\n  SchemaType[Key] extends any[]\n    ? UnwrapArray<Config<SchemaType[Key]>>\n    : SchemaType[Key] extends object\n      ? Config<SchemaType[Key]>\n      : ConfigItem;\n}\n\nexport enum DependencyType {\n  DISABLES,\n  REQUIRES,\n  HIDES,\n  SETS_OPTIONS,\n}\n\ninterface BaseDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> {\n  sourceField: keyof SchemaType\n  type: DependencyType\n  targetField: keyof SchemaType\n  when: (sourceFieldValue: any, targetFieldValue: any) => boolean\n}\n\nexport type ValueDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =\n  BaseDependency<SchemaType> & {\n    type:\n      | DependencyType.DISABLES\n      | DependencyType.REQUIRES\n      | DependencyType.HIDES\n  }\n\nexport type EnumValues = readonly [string, ...string[]]\n\nexport type OptionsDependency<\n  SchemaType extends z.infer<z.ZodObject<any, any>>,\n> = BaseDependency<SchemaType> & {\n  type: DependencyType.SETS_OPTIONS\n\n  // Partial array of values from sourceField that will trigger the dependency\n  options: EnumValues\n}\n\nexport type Dependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =\n  | ValueDependency<SchemaType>\n  | OptionsDependency<SchemaType>\n"
    },
    {
      "name": "utils.ts",
      "content": "import type { z } from 'zod'\n\n// TODO: This should support recursive ZodEffects but TypeScript doesn't allow circular type definitions.\nexport type ZodObjectOrWrapped =\n  | z.ZodObject<any, any>\n  | z.ZodEffects<z.ZodObject<any, any>>\n\n/**\n * Beautify a camelCase string.\n * e.g. \"myString\" -> \"My String\"\n */\nexport function beautifyObjectName(string: string) {\n  // Remove bracketed indices\n  // if numbers only return the string\n  let output = string.replace(/\\[\\d+\\]/g, '').replace(/([A-Z])/g, ' $1')\n  output = output.charAt(0).toUpperCase() + output.slice(1)\n  return output\n}\n\n/**\n * Parse string and extract the index\n * @param string\n * @returns index or undefined\n */\nexport function getIndexIfArray(string: string) {\n  const indexRegex = /\\[(\\d+)\\]/\n  // Match the index\n  const match = string.match(indexRegex)\n  // Extract the index (number)\n  const index = match ? Number.parseInt(match[1]) : undefined\n  return index\n}\n\n/**\n * Get the lowest level Zod type.\n * This will unpack optionals, refinements, etc.\n */\nexport function getBaseSchema<\n  ChildType extends z.ZodAny | z.AnyZodObject = z.ZodAny,\n>(schema: ChildType | z.ZodEffects<ChildType>): ChildType | null {\n  if (!schema)\n    return null\n  if ('innerType' in schema._def)\n    return getBaseSchema(schema._def.innerType as ChildType)\n\n  if ('schema' in schema._def)\n    return getBaseSchema(schema._def.schema as ChildType)\n\n  return schema as ChildType\n}\n\n/**\n * Get the type name of the lowest level Zod type.\n * This will unpack optionals, refinements, etc.\n */\nexport function getBaseType(schema: z.ZodAny) {\n  const baseSchema = getBaseSchema(schema)\n  return baseSchema ? baseSchema._def.typeName : ''\n}\n\n/**\n * Search for a \"ZodDefault\" in the Zod stack and return its value.\n */\nexport function getDefaultValueInZodStack(schema: z.ZodAny): any {\n  const typedSchema = schema as unknown as z.ZodDefault<\n    z.ZodNumber | z.ZodString\n  >\n\n  if (typedSchema._def.typeName === 'ZodDefault')\n    return typedSchema._def.defaultValue()\n\n  if ('innerType' in typedSchema._def) {\n    return getDefaultValueInZodStack(\n      typedSchema._def.innerType as unknown as z.ZodAny,\n    )\n  }\n  if ('schema' in typedSchema._def) {\n    return getDefaultValueInZodStack(\n      (typedSchema._def as any).schema as z.ZodAny,\n    )\n  }\n\n  return undefined\n}\n\nexport function getObjectFormSchema(\n  schema: ZodObjectOrWrapped,\n): z.ZodObject<any, any> {\n  if (schema?._def.typeName === 'ZodEffects') {\n    const typedSchema = schema as z.ZodEffects<z.ZodObject<any, any>>\n    return getObjectFormSchema(typedSchema._def.schema)\n  }\n  return schema as z.ZodObject<any, any>\n}\n\nfunction isIndex(value: unknown): value is number {\n  return Number(value) >= 0\n}\n/**\n * Constructs a path with dot paths for arrays to use brackets to be compatible with vee-validate path syntax\n */\nexport function normalizeFormPath(path: string): string {\n  const pathArr = path.split('.')\n  if (!pathArr.length)\n    return ''\n\n  let fullPath = String(pathArr[0])\n  for (let i = 1; i < pathArr.length; i++) {\n    if (isIndex(pathArr[i])) {\n      fullPath += `[${pathArr[i]}]`\n      continue\n    }\n\n    fullPath += `.${pathArr[i]}`\n  }\n\n  return fullPath\n}\n\ntype NestedRecord = Record<string, unknown> | { [k: string]: NestedRecord }\n/**\n * Checks if the path opted out of nested fields using `[fieldName]` syntax\n */\nexport function isNotNestedPath(path: string) {\n  return /^\\[.+\\]$/.test(path)\n}\nfunction isObject(obj: unknown): obj is Record<string, unknown> {\n  return obj !== null && !!obj && typeof obj === 'object' && !Array.isArray(obj)\n}\nfunction isContainerValue(value: unknown): value is Record<string, unknown> {\n  return isObject(value) || Array.isArray(value)\n}\nfunction cleanupNonNestedPath(path: string) {\n  if (isNotNestedPath(path))\n    return path.replace(/\\[|\\]/g, '')\n\n  return path\n}\n\n/**\n * Gets a nested property value from an object\n */\nexport function getFromPath<TValue = unknown>(object: NestedRecord | undefined, path: string): TValue | undefined\nexport function getFromPath<TValue = unknown, TFallback = TValue>(\n  object: NestedRecord | undefined,\n  path: string,\n  fallback?: TFallback,\n): TValue | TFallback\nexport function getFromPath<TValue = unknown, TFallback = TValue>(\n  object: NestedRecord | undefined,\n  path: string,\n  fallback?: TFallback,\n): TValue | TFallback | undefined {\n  if (!object)\n    return fallback\n\n  if (isNotNestedPath(path))\n    return object[cleanupNonNestedPath(path)] as TValue | undefined\n\n  const resolvedValue = (path || '')\n    .split(/\\.|\\[(\\d+)\\]/)\n    .filter(Boolean)\n    .reduce((acc, propKey) => {\n      if (isContainerValue(acc) && propKey in acc)\n        return acc[propKey]\n\n      return fallback\n    }, object as unknown)\n\n  return resolvedValue as TValue | undefined\n}\n"
    }
  ],
  "type": "components:ui"
}
