{
  "name": "auto-form",
  "dependencies": [
    "vee-validate",
    "@vee-validate/zod",
    "zod"
  ],
  "registryDependencies": [],
  "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 '@ui/registry/css/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\n    if (!Array.isArray(options) && typeof options === 'object') {\n      options = Object.values(options);\n    }\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\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\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  } 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\n      name=\"customAutoForm\"\n      :fields=\"fields\"\n    >\n      <template\n        v-for=\"(shape, key) of shapes\"\n        :key=\"key\"\n      >\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  }\n\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 '@ui/registry/css/ui/accordion';\nimport { Button } from '@ui/registry/css/ui/button';\nimport { Separator } from '@ui/registry/css/ui/separator';\nimport { FormItem, FormMessage } from '@ui/registry/css/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\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\n    v-slot=\"{ fields, remove, push }\"\n    as=\"section\"\n    :name=\"fieldName\"\n  >\n    <slot v-bind=\"props\">\n      <Accordion\n        type=\"multiple\"\n        class=\"w-full\"\n        collapsible\n        :disabled=\"disabled\"\n        as-child\n      >\n        <FormItem>\n          <AccordionItem\n            :value=\"fieldName\"\n            class=\"border-none\"\n          >\n            <AccordionTrigger>\n              <AutoFormLabel\n                class=\"text-base\"\n                :required=\"required\"\n              >\n                {{ schema?.description || beautifyObjectName(fieldName) }}\n              </AutoFormLabel>\n            </AccordionTrigger>\n\n            <AccordionContent>\n              <template\n                v-for=\"(field, index) of fields\"\n                :key=\"field.key\"\n              >\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\n                  class=\"mr-2\"\n                  :size=\"16\"\n                />\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 '@ui/registry/css/ui/form';\nimport { Switch } from '@ui/registry/css/ui/switch';\nimport { Checkbox } from '@ui/registry/css/ui/checkbox';\n\nconst props = defineProps<FieldProps>();\n\nconst booleanComponent = computed(() => props.config?.component === 'switch' ? Switch : Checkbox);\n</script>\n\n<template>\n  <FormField\n    v-slot=\"slotProps\"\n    :name=\"fieldName\"\n  >\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\n          v-if=\"!config?.hideLabel\"\n          :required=\"required\"\n        >\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 '@ui/registry/css/ui/form';\nimport { Calendar } from '@ui/registry/css/ui/calendar';\nimport { Button } from '@ui/registry/css/ui/button';\nimport { Popover, PopoverContent, PopoverTrigger } from '@ui/registry/css/ui/popover';\nimport { cn } from '@ui/utils';\n\ndefineProps<FieldProps>();\n\nconst df = new DateFormatter('en-US', {\n  dateStyle: 'long',\n});\n</script>\n\n<template>\n  <FormField\n    v-slot=\"slotProps\"\n    :name=\"fieldName\"\n  >\n    <FormItem>\n      <AutoFormLabel\n        v-if=\"!config?.hideLabel\"\n        :required=\"required\"\n      >\n        {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n      </AutoFormLabel>\n      <FormControl>\n        <slot v-bind=\"slotProps\">\n          <div>\n            <Popover>\n              <PopoverTrigger\n                as-child\n                :disabled=\"disabled\"\n              >\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\n                    class=\"mr-2 h-4 w-4\"\n                    :size=\"16\"\n                  />\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\n                  initial-focus\n                  v-bind=\"slotProps.componentField\"\n                />\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 '@ui/registry/css/ui/form';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@ui/registry/css/ui/select';\nimport { Label } from '@ui/registry/css/ui/label';\nimport { RadioGroup, RadioGroupItem } from '@ui/registry/css/ui/radio-group';\n\ndefineProps<FieldProps & {\n  options?: string[];\n}>();\n</script>\n\n<template>\n  <FormField\n    v-slot=\"slotProps\"\n    :name=\"fieldName\"\n  >\n    <FormItem>\n      <AutoFormLabel\n        v-if=\"!config?.hideLabel\"\n        :required=\"required\"\n      >\n        {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n      </AutoFormLabel>\n      <FormControl>\n        <slot v-bind=\"slotProps\">\n          <RadioGroup\n            v-if=\"config?.component === 'radio'\"\n            :disabled=\"disabled\"\n            :orientation=\"'vertical'\"\n            v-bind=\"{ ...slotProps.componentField }\"\n          >\n            <div\n              v-for=\"(option, index) in options\"\n              :key=\"option\"\n              class=\"mb-2 flex items-center gap-3 space-y-0\"\n            >\n              <RadioGroupItem\n                :id=\"`${option}-${index}`\"\n                :value=\"option\"\n              />\n              <Label :for=\"`${option}-${index}`\">{{ beautifyObjectName(option) }}</Label>\n            </div>\n          </RadioGroup>\n\n          <Select\n            v-else\n            :disabled=\"disabled\"\n            v-bind=\"{ ...slotProps.componentField }\"\n          >\n            <SelectTrigger class=\"w-full\">\n              <SelectValue :placeholder=\"config?.inputProps?.placeholder\" />\n            </SelectTrigger>\n            <SelectContent>\n              <SelectItem\n                v-for=\"option in options\"\n                :key=\"option\"\n                :value=\"option\"\n              >\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 '@ui/registry/css/ui/form';\nimport { Input } from '@ui/registry/css/ui/input';\nimport { Button } from '@ui/registry/css/ui/button';\n\ndefineProps<FieldProps>();\n\nconst inputFile = ref<File>();\n\nasync function parseFileAsString(file: File | undefined): Promise<string> {\n  return new Promise((resolve, reject) => {\n    if (file) {\n      const reader = new FileReader();\n\n      reader.onloadend = () => {\n        resolve(reader.result as string);\n      };\n\n      reader.onerror = (err) => {\n        reject(err);\n      };\n\n      reader.readAsDataURL(file);\n    }\n  });\n}\n</script>\n\n<template>\n  <FormField\n    v-slot=\"slotProps\"\n    :name=\"fieldName\"\n  >\n    <FormItem v-bind=\"$attrs\">\n      <AutoFormLabel\n        v-if=\"!config?.hideLabel\"\n        :required=\"required\"\n      >\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\n            v-else\n            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          >\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 '@ui/registry/css/ui/form';\nimport { Input } from '@ui/registry/css/ui/input';\nimport { Textarea } from '@ui/registry/css/ui/textarea';\n\nconst props = defineProps<FieldProps>();\nconst inputComponent = computed(() => props.config?.component === 'textarea' ? Textarea : Input);\n</script>\n\n<template>\n  <FormField\n    v-slot=\"slotProps\"\n    :name=\"fieldName\"\n  >\n    <FormItem v-bind=\"$attrs\">\n      <AutoFormLabel\n        v-if=\"!config?.hideLabel\"\n        :required=\"required\"\n      >\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 '@ui/registry/css/ui/form';\nimport { Input } from '@ui/registry/css/ui/input';\n\ndefineOptions({\n  inheritAttrs: false,\n});\n\ndefineProps<FieldProps>();\n</script>\n\n<template>\n  <FormField\n    v-slot=\"slotProps\"\n    :name=\"fieldName\"\n  >\n    <FormItem>\n      <AutoFormLabel\n        v-if=\"!config?.hideLabel\"\n        :required=\"required\"\n      >\n        {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n      </AutoFormLabel>\n      <FormControl>\n        <slot v-bind=\"slotProps\">\n          <Input\n            type=\"number\"\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": "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 '@ui/registry/css/ui/accordion';\nimport { FormItem } from '@ui/registry/css/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  }\n\n  const shape = getBaseSchema(props.schema)?.shape;\n\n  if (!shape) {\n    return;\n  }\n\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\n    if (!Array.isArray(options) && typeof options === 'object') {\n      options = Object.values(options);\n    }\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\n        type=\"single\"\n        as-child\n        class=\"w-full\"\n        collapsible\n        :disabled=\"disabled\"\n      >\n        <FormItem>\n          <AccordionItem\n            :value=\"fieldName\"\n            class=\"border-none\"\n          >\n            <AccordionTrigger>\n              <AutoFormLabel\n                class=\"text-base\"\n                :required=\"required\"\n              >\n                {{ schema?.description || beautifyObjectName(fieldName) }}\n              </AutoFormLabel>\n            </AccordionTrigger>\n            <AccordionContent class=\"p-1 space-y-5\">\n              <template\n                v-for=\"(shape, key) in shapes\"\n                :key=\"key\"\n              >\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 '@ui/registry/css/ui/form';\n\ndefineProps<{\n  required?: boolean;\n}>();\n</script>\n\n<template>\n  <FormLabel>\n    <slot />\n    <span\n      v-if=\"required\"\n      class=\"text-destructive\"\n    > *</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  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\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 [_, ...targetInitial] = (dep.targetField as string).split('.').toReversed();\n\n    if (index >= 0 && sourceInitial.join(',') === targetInitial.join(',')) {\n      const [_, ...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\n          break;\n        case DependencyType.REQUIRES:\n          if (conditionMet) {\n            isRequired.value = true;\n          }\n\n          break;\n        case DependencyType.HIDES:\n          if (conditionMet) {\n            isHidden.value = true;\n          }\n\n          break;\n        case DependencyType.SETS_OPTIONS:\n          if (conditionMet) {\n            overrideOptions.value = dep.options;\n          }\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\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  const match = string.match(indexRegex);\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  }\n\n  if ('innerType' in schema._def) {\n    return getBaseSchema(schema._def.innerType as ChildType);\n  }\n\n  if ('schema' in schema._def) {\n    return getBaseSchema(schema._def.schema as ChildType);\n  }\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\n  if ('innerType' in typedSchema._def) {\n    return getDefaultValueInZodStack(\n      typedSchema._def.innerType as unknown as z.ZodAny,\n    );\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\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/**\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\n  if (!pathArr.length) {\n    return '';\n  }\n\n  let fullPath = String(pathArr[0]);\n\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/**\n * Checks if the path opted out of nested fields using `[fieldName]` syntax\n */\nexport function isNotNestedPath(path: string) {\n  return /^\\[.+\\]$/.test(path);\n}\n\nfunction isObject(obj: unknown): obj is Record<string, unknown> {\n  return obj !== null && !!obj && typeof obj === 'object' && !Array.isArray(obj);\n}\n\nfunction isContainerValue(value: unknown): value is Record<string, unknown> {\n  return isObject(value) || Array.isArray(value);\n}\n\nfunction cleanupNonNestedPath(path: string) {\n  if (isNotNestedPath(path)) {\n    return path.replace(/\\[|\\]/g, '');\n  }\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;\n\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\n  if (isNotNestedPath(path)) {\n    return object[cleanupNonNestedPath(path)] as TValue | undefined;\n  }\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\n      return fallback;\n    }, object as unknown);\n\n  return resolvedValue as TValue | undefined;\n}\n"
    }
  ],
  "type": "components:ui"
}