{ "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": "\n\n\n \n \n \n \"\n :field-name=\"key.toString()\"\n :config=\"fieldConfig?.[key as keyof typeof fieldConfig] as ConfigItem\"\n >\n \n \n \n \n\n \n \n\n" }, { "name": "AutoFormField.vue", "content": "\n\n\n \n \n \n\n" }, { "name": "AutoFormFieldArray.vue", "content": "\n\n\n \n \n \n \n \n \n {{ schema?.description || beautifyObjectName(fieldName) }}\n \n \n\n \n \n \n \n\n \n \n \n \n \n \n \n \n\n \n \n Add\n \n \n\n \n \n \n \n \n\n" }, { "name": "AutoFormFieldBoolean.vue", "content": "\n\n\n \n \n \n \n \n \n \n \n \n {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n \n \n\n \n {{ config.description }}\n \n \n \n \n\n" }, { "name": "AutoFormFieldDate.vue", "content": "\n\n\n \n \n \n {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n \n \n \n \n \n \n \n \n {{ slotProps.componentField.modelValue ? df.format(slotProps.componentField.modelValue.toDate(getLocalTimeZone())) : \"Pick a date\" }}\n \n \n \n \n \n \n \n \n \n\n \n {{ config.description }}\n \n \n \n \n\n" }, { "name": "AutoFormFieldEnum.vue", "content": "\n\n\n \n \n \n {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n \n \n \n \n \n \n {{ beautifyObjectName(option) }}\n \n \n\n \n \n \n \n \n \n {{ beautifyObjectName(option) }}\n \n \n \n \n \n\n \n {{ config.description }}\n \n \n \n \n\n" }, { "name": "AutoFormFieldFile.vue", "content": "\n\n\n \n \n \n {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n \n \n \n {\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 \n {{ inputFile?.name }}\n {\n inputFile = undefined\n slotProps.componentField.onInput(undefined)\n }\"\n >\n \n \n \n \n \n \n {{ config.description }}\n \n \n \n \n\n" }, { "name": "AutoFormFieldInput.vue", "content": "\n\n\n \n \n \n {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n \n \n \n \n \n \n \n {{ config.description }}\n \n \n \n \n\n" }, { "name": "AutoFormFieldNumber.vue", "content": "\n\n\n \n \n \n {{ config?.label || beautifyObjectName(label ?? fieldName) }}\n \n \n \n \n \n \n \n {{ config.description }}\n \n \n \n \n\n" }, { "name": "AutoFormFieldObject.vue", "content": "\n\n\n \n \n \n \n \n {{ schema?.description || beautifyObjectName(fieldName) }}\n \n \n \n \n \n \n \n \n \n \n\n" }, { "name": "AutoFormLabel.vue", "content": "\n\n\n \n \n *\n \n\n" }, { "name": "constant.ts", "content": "import { AutoFormFieldArray, AutoFormFieldBoolean, AutoFormFieldDate, AutoFormFieldEnum, AutoFormFieldFile, AutoFormFieldInput, AutoFormFieldNumber, AutoFormFieldObject } from './'\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, inject, ref, watch } from 'vue'\nimport { FieldContextKey, FormContextKey } from 'vee-validate'\nimport { createContext } from 'radix-vue'\nimport { type Dependency, DependencyType, type EnumValues } from './interface'\nimport { getIndexIfArray } from './utils'\n\nexport const [injectDependencies, provideDependencies] = createContext>>[] | undefined>>('AutoFormDependencies')\n\nfunction getValueByPath>(obj: T, path: string): any {\n const keys = path.split('.')\n let value = obj\n\n for (const key of keys) {\n if (value && typeof value === 'object' && key in value)\n value = value[key]\n else\n return undefined\n }\n\n return value\n}\n\nexport default function useDependencies(\n fieldName: string,\n) {\n const form = inject(FormContextKey)\n const field = inject(FieldContextKey)\n\n const currentFieldName = fieldName.replace(/\\[\\d+\\]/g, '')\n\n if (!form)\n throw new Error('useDependencies should be used within ')\n\n const { controlledValues } = form\n const dependencies = injectDependencies()\n const isDisabled = ref(false)\n const isHidden = ref(false)\n const isRequired = ref(false)\n const overrideOptions = ref()\n\n const currentFieldValue = computed(() => field?.value.value)\n const currentFieldDependencies = computed(() => dependencies.value?.filter(\n dependency => dependency.targetField === currentFieldName,\n ))\n\n function getSourceValue(dep: Dependency) {\n const source = dep.sourceField as string\n const lastKey = source.split('.').at(-1)\n if (source.includes('.') && lastKey) {\n if (Array.isArray(field?.value.value)) {\n const index = getIndexIfArray(fieldName) ?? -1\n return field?.value.value[index][lastKey]\n }\n\n return getValueByPath(form!.values, source)\n }\n\n return controlledValues.value[source as string]\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\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 { default as AutoForm } from './AutoForm.vue'\nexport { default as AutoFormField } from './AutoFormField.vue'\nexport { getObjectFormSchema, getBaseSchema, getBaseType } from './utils'\nexport type { Config, ConfigItem } from './interface'\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 { InputHTMLAttributes, SelectHTMLAttributes } 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\n /** Hide `FormLabel`. */\n hideLabel?: boolean\n inputProps?: InputHTMLAttributes\n enumProps?: SelectHTMLAttributes & { options?: any[] }\n}\n\n// Define a type to unwrap an array\ntype UnwrapArray = T extends (infer U)[] ? U : never\n\nexport type Config = {\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>\n : SchemaType[Key] extends object\n ? Config\n : ConfigItem;\n}\n\nexport enum DependencyType {\n DISABLES,\n REQUIRES,\n HIDES,\n SETS_OPTIONS,\n}\n\ninterface BaseDependency>> {\n sourceField: keyof SchemaType\n type: DependencyType\n targetField: keyof SchemaType\n when: (sourceFieldValue: any, targetFieldValue: any) => boolean\n}\n\nexport type ValueDependency>> =\n BaseDependency & {\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>,\n> = BaseDependency & {\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>> =\n | ValueDependency\n | OptionsDependency\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\n | z.ZodEffects>\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 | 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 {\n if (schema?._def.typeName === 'ZodEffects') {\n const typedSchema = schema as z.ZodEffects>\n return getObjectFormSchema(typedSchema._def.schema)\n }\n return schema as z.ZodObject\n}\n" } ], "type": "components:ui" }
{{ inputFile?.name }}