refactor: change name to fieldName to allow easier slotProps binding
This commit is contained in:
parent
0cd3371e4a
commit
9162c7464c
|
|
@ -9,29 +9,77 @@ import { toast } from '@/lib/registry/new-york/ui/toast'
|
||||||
import type { Config } from '@/lib/registry/new-york/ui/auto-form'
|
import type { Config } from '@/lib/registry/new-york/ui/auto-form'
|
||||||
import { AutoForm, AutoFormField } from '@/lib/registry/new-york/ui/auto-form'
|
import { AutoForm, AutoFormField } from '@/lib/registry/new-york/ui/auto-form'
|
||||||
|
|
||||||
|
enum Sports {
|
||||||
|
Football = 'Football/Soccer',
|
||||||
|
Basketball = 'Basketball',
|
||||||
|
Baseball = 'Baseball',
|
||||||
|
Hockey = 'Hockey (Ice)',
|
||||||
|
None = 'I don\'t like sports',
|
||||||
|
}
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
age: z.number().default(20),
|
username: z
|
||||||
parentsAllowed: z.boolean().optional(),
|
.string({
|
||||||
vegetarian: z.boolean().default(true),
|
required_error: 'Username is required.',
|
||||||
mealOptions: z.enum(['Pasta', 'Salad', 'Beef Wellington']).optional(),
|
})
|
||||||
invitedGuests: z
|
.min(2, {
|
||||||
.array(
|
message: 'Username must be at least 2 characters.',
|
||||||
z.object({
|
}),
|
||||||
name: z.string(),
|
|
||||||
age: z.coerce.number(),
|
|
||||||
}),
|
|
||||||
).default([{ name: '123', age: 0 }]),
|
|
||||||
|
|
||||||
subObject: z.object({
|
password: z
|
||||||
subField: z.string().optional().default('Sub Field'),
|
.string({
|
||||||
numberField: z.number().optional().default(10),
|
required_error: 'Password is required.',
|
||||||
|
})
|
||||||
|
.min(8, {
|
||||||
|
message: 'Password must be at least 8 characters.',
|
||||||
|
}),
|
||||||
|
|
||||||
subSubObject: z
|
favouriteNumber: z.coerce
|
||||||
.object({
|
.number({
|
||||||
subSubField: z.string().default('Sub Sub Field'),
|
invalid_type_error: 'Favourite number must be a number.',
|
||||||
})
|
})
|
||||||
.describe('Sub Sub Object Description'),
|
.min(1, {
|
||||||
}),
|
message: 'Favourite number must be at least 1.',
|
||||||
|
})
|
||||||
|
.max(10, {
|
||||||
|
message: 'Favourite number must be at most 10.',
|
||||||
|
})
|
||||||
|
.default(1)
|
||||||
|
.optional(),
|
||||||
|
|
||||||
|
acceptTerms: z
|
||||||
|
.boolean()
|
||||||
|
.refine(value => value, {
|
||||||
|
message: 'You must accept the terms and conditions.',
|
||||||
|
path: ['acceptTerms'],
|
||||||
|
}),
|
||||||
|
|
||||||
|
sendMeMails: z.boolean().optional(),
|
||||||
|
|
||||||
|
birthday: z.coerce.date().optional(),
|
||||||
|
|
||||||
|
color: z.enum(['red', 'green', 'blue']).optional(),
|
||||||
|
|
||||||
|
// Another enum example
|
||||||
|
marshmallows: z
|
||||||
|
.enum(['not many', 'a few', 'a lot', 'too many']),
|
||||||
|
|
||||||
|
// Native enum example
|
||||||
|
sports: z.nativeEnum(Sports).describe('What is your favourite sport?'),
|
||||||
|
|
||||||
|
bio: z
|
||||||
|
.string()
|
||||||
|
.min(10, {
|
||||||
|
message: 'Bio must be at least 10 characters.',
|
||||||
|
})
|
||||||
|
.max(160, {
|
||||||
|
message: 'Bio must not be longer than 30 characters.',
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
|
||||||
|
customParent: z.string().optional(),
|
||||||
|
|
||||||
|
file: z.string().optional(),
|
||||||
})
|
})
|
||||||
|
|
||||||
function onSubmit(values: Record<string, any>) {
|
function onSubmit(values: Record<string, any>) {
|
||||||
|
|
@ -47,55 +95,56 @@ function onSubmit(values: Record<string, any>) {
|
||||||
class="w-2/3 space-y-6"
|
class="w-2/3 space-y-6"
|
||||||
:schema="schema"
|
:schema="schema"
|
||||||
:field-config="{
|
:field-config="{
|
||||||
age: {
|
password: {
|
||||||
description:
|
label: 'Your secure password',
|
||||||
'Setting this below 18 will require parents consent.',
|
inputProps: {
|
||||||
|
type: 'password',
|
||||||
|
placeholder: '••••••••',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
parentsAllowed: {
|
favouriteNumber: {
|
||||||
label: 'Did your parents allow you to register?',
|
description: 'Your favourite number between 1 and 10.',
|
||||||
},
|
},
|
||||||
vegetarian: {
|
acceptTerms: {
|
||||||
label: 'Are you a vegetarian?',
|
label: 'Accept terms and conditions.',
|
||||||
description:
|
inputProps: {
|
||||||
'Setting this to true will remove non-vegetarian food options.',
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mealOptions: {
|
|
||||||
|
birthday: {
|
||||||
|
description: 'We need your birthday to send you a gift.',
|
||||||
|
},
|
||||||
|
|
||||||
|
sendMeMails: {
|
||||||
|
component: 'switch',
|
||||||
|
},
|
||||||
|
|
||||||
|
bio: {
|
||||||
|
component: 'textarea',
|
||||||
|
},
|
||||||
|
|
||||||
|
marshmallows: {
|
||||||
|
label: 'How many marshmallows fit in your mouth?',
|
||||||
component: 'radio',
|
component: 'radio',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
file: {
|
||||||
|
label: 'Text file',
|
||||||
|
component: 'file',
|
||||||
|
},
|
||||||
}"
|
}"
|
||||||
:dependencies="[
|
|
||||||
{
|
|
||||||
// 'age' hides 'parentsAllowed' when the age is 18 or older
|
|
||||||
sourceField: 'age',
|
|
||||||
type: DependencyType.HIDES,
|
|
||||||
targetField: 'parentsAllowed',
|
|
||||||
when: (age) => age >= 18,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// 'vegetarian' checkbox hides the 'Beef Wellington' option from 'mealOptions'
|
|
||||||
// if its not already selected
|
|
||||||
sourceField: 'vegetarian',
|
|
||||||
type: DependencyType.SETS_OPTIONS,
|
|
||||||
targetField: 'mealOptions',
|
|
||||||
when: (vegetarian, mealOption) =>
|
|
||||||
vegetarian && mealOption !== 'Beef Wellington',
|
|
||||||
options: ['Pasta', 'Salad'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sourceField: 'age',
|
|
||||||
type: DependencyType.HIDES,
|
|
||||||
targetField: 'invitedGuests.age' as any,
|
|
||||||
when: (age) => age >= 18,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sourceField: 'age' as any,
|
|
||||||
type: DependencyType.HIDES,
|
|
||||||
targetField: 'subObject.subSubObject' as any,
|
|
||||||
when: (age) => age >= 18,
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
@submit="onSubmit"
|
@submit="onSubmit"
|
||||||
>
|
>
|
||||||
|
<template #acceptTerms="slotProps">
|
||||||
|
<AutoFormField v-bind="slotProps" />
|
||||||
|
<div class="!mt-2 text-sm">
|
||||||
|
I agree to the <button class="text-primary underline">
|
||||||
|
terms and conditions
|
||||||
|
</button>.
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<Button type="submit">
|
<Button type="submit">
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -72,11 +72,12 @@ const formComponentProps = computed(() => {
|
||||||
<slot
|
<slot
|
||||||
:shape="shape"
|
:shape="shape"
|
||||||
:name="key.toString() as keyof z.infer<T>"
|
:name="key.toString() as keyof z.infer<T>"
|
||||||
|
:field-name="key.toString()"
|
||||||
:config="fieldConfig?.[key as keyof typeof fieldConfig] as ConfigItem"
|
:config="fieldConfig?.[key as keyof typeof fieldConfig] as ConfigItem"
|
||||||
>
|
>
|
||||||
<AutoFormField
|
<AutoFormField
|
||||||
:config="fieldConfig?.[key as keyof typeof fieldConfig] as ConfigItem"
|
:config="fieldConfig?.[key as keyof typeof fieldConfig] as ConfigItem"
|
||||||
:name="key.toString()"
|
:field-name="key.toString()"
|
||||||
:shape="shape"
|
:shape="shape"
|
||||||
/>
|
/>
|
||||||
</slot>
|
</slot>
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { DEFAULT_ZOD_HANDLERS, INPUT_COMPONENTS } from './constant'
|
||||||
import useDependencies from './dependencies'
|
import useDependencies from './dependencies'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
name: string
|
fieldName: string
|
||||||
shape: Shape
|
shape: Shape
|
||||||
label?: string
|
label?: string
|
||||||
config?: ConfigItem | Config<U>
|
config?: ConfigItem | Config<U>
|
||||||
|
|
@ -22,14 +22,14 @@ const delegatedProps = computed(() => {
|
||||||
return undefined
|
return undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
const { isDisabled, isHidden, isRequired, overrideOptions } = useDependencies(props.name)
|
const { isDisabled, isHidden, isRequired, overrideOptions } = useDependencies(props.fieldName)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<component
|
<component
|
||||||
:is="isValidConfig(config) ? INPUT_COMPONENTS[config.component!] : INPUT_COMPONENTS[DEFAULT_ZOD_HANDLERS[shape.type]] "
|
:is="isValidConfig(config) ? INPUT_COMPONENTS[config.component!] : INPUT_COMPONENTS[DEFAULT_ZOD_HANDLERS[shape.type]] "
|
||||||
v-if="!isHidden"
|
v-if="!isHidden"
|
||||||
:name="name"
|
:field-name="fieldName"
|
||||||
:label="label"
|
:label="label"
|
||||||
:required="isRequired || shape.required"
|
:required="isRequired || shape.required"
|
||||||
:options="overrideOptions || shape.options"
|
:options="overrideOptions || shape.options"
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,14 @@ import { Separator } from '@/lib/registry/new-york/ui/separator'
|
||||||
import { FormMessage } from '@/lib/registry/new-york/ui/form'
|
import { FormMessage } from '@/lib/registry/new-york/ui/form'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
name: string
|
fieldName: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
config?: Config<T>
|
config?: Config<T>
|
||||||
schema?: z.ZodArray<T>
|
schema?: z.ZodArray<T>
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const fieldContext = useField(props.name)
|
const fieldContext = useField(props.fieldName)
|
||||||
|
|
||||||
function isZodArray(
|
function isZodArray(
|
||||||
item: z.ZodArray<any> | z.ZodDefault<any>,
|
item: z.ZodArray<any> | z.ZodDefault<any>,
|
||||||
|
|
@ -56,13 +56,13 @@ provide(FieldContextKey, fieldContext)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FieldArray v-slot="{ fields, remove, push }" as="section" :name="name">
|
<FieldArray v-slot="{ fields, remove, push }" as="section" :name="fieldName">
|
||||||
<slot v-bind="props">
|
<slot v-bind="props">
|
||||||
<Accordion type="multiple" class="w-full" collapsible :disabled="disabled">
|
<Accordion type="multiple" class="w-full" collapsible :disabled="disabled">
|
||||||
<AccordionItem :value="name" class="border-none">
|
<AccordionItem :value="fieldName" class="border-none">
|
||||||
<AccordionTrigger>
|
<AccordionTrigger>
|
||||||
<AutoFormLabel class="text-base" :required="required">
|
<AutoFormLabel class="text-base" :required="required">
|
||||||
{{ schema?.description || beautifyObjectName(name) }}
|
{{ schema?.description || beautifyObjectName(fieldName) }}
|
||||||
</AutoFormLabel>
|
</AutoFormLabel>
|
||||||
</AccordionTrigger>
|
</AccordionTrigger>
|
||||||
|
|
||||||
|
|
@ -70,8 +70,8 @@ provide(FieldContextKey, fieldContext)
|
||||||
<template v-for="(field, index) of fields" :key="field.key">
|
<template v-for="(field, index) of fields" :key="field.key">
|
||||||
<div class="mb-4 p-[1px]">
|
<div class="mb-4 p-[1px]">
|
||||||
<AutoFormField
|
<AutoFormField
|
||||||
:name="`${name}[${index}]`"
|
:field-name="`${fieldName}[${index}]`"
|
||||||
:label="name"
|
:label="fieldName"
|
||||||
:shape="itemShape!"
|
:shape="itemShape!"
|
||||||
:config="config as ConfigItem"
|
:config="config as ConfigItem"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { beautifyObjectName } from '../utils'
|
import { beautifyObjectName } from '../utils'
|
||||||
import type { ConfigItem, FieldProps } from '../interface'
|
import type { FieldProps } from '../interface'
|
||||||
import AutoFormLabel from '../AutoFormLabel.vue'
|
import AutoFormLabel from '../AutoFormLabel.vue'
|
||||||
import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/lib/registry/new-york/ui/form'
|
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form'
|
||||||
import { Switch } from '@/lib/registry/new-york/ui/switch'
|
import { Switch } from '@/lib/registry/new-york/ui/switch'
|
||||||
import { Checkbox } from '@/lib/registry/new-york/ui/checkbox'
|
import { Checkbox } from '@/lib/registry/new-york/ui/checkbox'
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ const booleanComponent = computed(() => props.config?.component === 'switch' ? S
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FormField v-slot="slotProps" :name="name">
|
<FormField v-slot="slotProps" :name="fieldName">
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<div class="space-y-0 mb-3 flex items-center gap-3">
|
<div class="space-y-0 mb-3 flex items-center gap-3">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
|
|
@ -28,7 +28,7 @@ const booleanComponent = computed(() => props.config?.component === 'switch' ? S
|
||||||
</slot>
|
</slot>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<AutoFormLabel v-if="!config?.hideLabel" :required="required">
|
<AutoFormLabel v-if="!config?.hideLabel" :required="required">
|
||||||
{{ config?.label || beautifyObjectName(label ?? name) }}
|
{{ config?.label || beautifyObjectName(label ?? fieldName) }}
|
||||||
</AutoFormLabel>
|
</AutoFormLabel>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ import { DateFormatter, getLocalTimeZone } from '@internationalized/date'
|
||||||
import { CalendarIcon } from '@radix-icons/vue'
|
import { CalendarIcon } from '@radix-icons/vue'
|
||||||
import { beautifyObjectName } from '../utils'
|
import { beautifyObjectName } from '../utils'
|
||||||
import AutoFormLabel from '../AutoFormLabel.vue'
|
import AutoFormLabel from '../AutoFormLabel.vue'
|
||||||
import type { ConfigItem, FieldProps } from '../interface'
|
import type { FieldProps } from '../interface'
|
||||||
import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/lib/registry/new-york/ui/form'
|
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form'
|
||||||
|
|
||||||
import { Calendar } from '@/lib/registry/new-york/ui/calendar'
|
import { Calendar } from '@/lib/registry/new-york/ui/calendar'
|
||||||
import { Button } from '@/lib/registry/new-york/ui/button'
|
import { Button } from '@/lib/registry/new-york/ui/button'
|
||||||
|
|
@ -19,10 +19,10 @@ const df = new DateFormatter('en-US', {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FormField v-slot="slotProps" :name="name">
|
<FormField v-slot="slotProps" :name="fieldName">
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<AutoFormLabel v-if="!config?.hideLabel" :required="required">
|
<AutoFormLabel v-if="!config?.hideLabel" :required="required">
|
||||||
{{ config?.label || beautifyObjectName(label ?? name) }}
|
{{ config?.label || beautifyObjectName(label ?? fieldName) }}
|
||||||
</AutoFormLabel>
|
</AutoFormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<slot v-bind="slotProps">
|
<slot v-bind="slotProps">
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { computed } from 'vue'
|
||||||
import { beautifyObjectName } from '../utils'
|
import { beautifyObjectName } from '../utils'
|
||||||
import type { FieldProps } from '../interface'
|
import type { FieldProps } from '../interface'
|
||||||
import AutoFormLabel from '../AutoFormLabel.vue'
|
import AutoFormLabel from '../AutoFormLabel.vue'
|
||||||
import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/lib/registry/new-york/ui/form'
|
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form'
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/lib/registry/new-york/ui/select'
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/lib/registry/new-york/ui/select'
|
||||||
import { Label } from '@/lib/registry/new-york/ui/label'
|
import { Label } from '@/lib/registry/new-york/ui/label'
|
||||||
import { RadioGroup, RadioGroupItem } from '@/lib/registry/new-york/ui/radio-group'
|
import { RadioGroup, RadioGroupItem } from '@/lib/registry/new-york/ui/radio-group'
|
||||||
|
|
@ -16,10 +16,10 @@ const computedOptions = computed(() => props.config?.enumProps?.options || props
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FormField v-slot="slotProps" :name="name">
|
<FormField v-slot="slotProps" :name="fieldName">
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<AutoFormLabel v-if="!config?.hideLabel" :required="required">
|
<AutoFormLabel v-if="!config?.hideLabel" :required="required">
|
||||||
{{ config?.label || beautifyObjectName(label ?? name) }}
|
{{ config?.label || beautifyObjectName(label ?? fieldName) }}
|
||||||
</AutoFormLabel>
|
</AutoFormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<slot v-bind="slotProps">
|
<slot v-bind="slotProps">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { beautifyObjectName } from '../utils'
|
import { beautifyObjectName } from '../utils'
|
||||||
import type { ConfigItem, FieldProps } from '../interface'
|
import type { FieldProps } from '../interface'
|
||||||
import AutoFormLabel from '../AutoFormLabel.vue'
|
import AutoFormLabel from '../AutoFormLabel.vue'
|
||||||
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form'
|
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form'
|
||||||
import { Input } from '@/lib/registry/new-york/ui/input'
|
import { Input } from '@/lib/registry/new-york/ui/input'
|
||||||
|
|
@ -24,10 +24,10 @@ async function parseFileAsString(file: File | undefined): Promise<string> {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FormField v-slot="slotProps" :name="name">
|
<FormField v-slot="slotProps" :name="fieldName">
|
||||||
<FormItem v-bind="$attrs">
|
<FormItem v-bind="$attrs">
|
||||||
<AutoFormLabel v-if="!config?.hideLabel" :required="required">
|
<AutoFormLabel v-if="!config?.hideLabel" :required="required">
|
||||||
{{ config?.label || beautifyObjectName(label ?? name) }}
|
{{ config?.label || beautifyObjectName(label ?? fieldName) }}
|
||||||
</AutoFormLabel>
|
</AutoFormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<slot v-bind="slotProps">
|
<slot v-bind="slotProps">
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { beautifyObjectName } from '../utils'
|
import { beautifyObjectName } from '../utils'
|
||||||
import type { Config, ConfigItem, FieldProps } from '../interface'
|
import type { FieldProps } from '../interface'
|
||||||
import AutoFormLabel from '../AutoFormLabel.vue'
|
import AutoFormLabel from '../AutoFormLabel.vue'
|
||||||
import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/lib/registry/new-york/ui/form'
|
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form'
|
||||||
import { Input } from '@/lib/registry/new-york/ui/input'
|
import { Input } from '@/lib/registry/new-york/ui/input'
|
||||||
import { Textarea } from '@/lib/registry/new-york/ui/textarea'
|
import { Textarea } from '@/lib/registry/new-york/ui/textarea'
|
||||||
|
|
||||||
|
|
@ -12,10 +12,10 @@ const inputComponent = computed(() => props.config?.component === 'textarea' ? T
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FormField v-slot="slotProps" :name="name">
|
<FormField v-slot="slotProps" :name="fieldName">
|
||||||
<FormItem v-bind="$attrs">
|
<FormItem v-bind="$attrs">
|
||||||
<AutoFormLabel v-if="!config?.hideLabel" :required="required">
|
<AutoFormLabel v-if="!config?.hideLabel" :required="required">
|
||||||
{{ config?.label || beautifyObjectName(label ?? name) }}
|
{{ config?.label || beautifyObjectName(label ?? fieldName) }}
|
||||||
</AutoFormLabel>
|
</AutoFormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<slot v-bind="slotProps">
|
<slot v-bind="slotProps">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { beautifyObjectName } from '../utils'
|
import { beautifyObjectName } from '../utils'
|
||||||
import type { Config, ConfigItem, FieldProps } from '../interface'
|
import type { FieldProps } from '../interface'
|
||||||
import AutoFormLabel from '../AutoFormLabel.vue'
|
import AutoFormLabel from '../AutoFormLabel.vue'
|
||||||
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form'
|
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form'
|
||||||
import { Input } from '@/lib/registry/new-york/ui/input'
|
import { Input } from '@/lib/registry/new-york/ui/input'
|
||||||
|
|
@ -13,10 +13,10 @@ defineProps<FieldProps>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FormField v-slot="slotProps" :name="name">
|
<FormField v-slot="slotProps" :name="fieldName">
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<AutoFormLabel v-if="!config?.hideLabel" :required="required">
|
<AutoFormLabel v-if="!config?.hideLabel" :required="required">
|
||||||
{{ config?.label || beautifyObjectName(label ?? name) }}
|
{{ config?.label || beautifyObjectName(label ?? fieldName) }}
|
||||||
</AutoFormLabel>
|
</AutoFormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<slot v-bind="slotProps">
|
<slot v-bind="slotProps">
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import AutoFormField from '../AutoFormField.vue'
|
||||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/lib/registry/new-york/ui/accordion'
|
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/lib/registry/new-york/ui/accordion'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
name: string
|
fieldName: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
config?: Config<T>
|
config?: Config<T>
|
||||||
schema?: ZodObject<T>
|
schema?: ZodObject<T>
|
||||||
|
|
@ -45,15 +45,15 @@ const shapes = computed(() => {
|
||||||
<section>
|
<section>
|
||||||
<slot v-bind="props">
|
<slot v-bind="props">
|
||||||
<Accordion type="multiple" class="w-full" collapsible :disabled="disabled">
|
<Accordion type="multiple" class="w-full" collapsible :disabled="disabled">
|
||||||
<AccordionItem :value="name" class="border-none">
|
<AccordionItem :value="fieldName" class="border-none">
|
||||||
<AccordionTrigger class="text-base">
|
<AccordionTrigger class="text-base">
|
||||||
{{ schema?.description || beautifyObjectName(name) }}
|
{{ schema?.description || beautifyObjectName(fieldName) }}
|
||||||
</AccordionTrigger>
|
</AccordionTrigger>
|
||||||
<AccordionContent class="p-[1px] space-y-5">
|
<AccordionContent class="p-[1px] space-y-5">
|
||||||
<template v-for="(shape, key) in shapes" :key="key">
|
<template v-for="(shape, key) in shapes" :key="key">
|
||||||
<AutoFormField
|
<AutoFormField
|
||||||
:config="config?.[key as keyof typeof config] as ConfigItem"
|
:config="config?.[key as keyof typeof config] as ConfigItem"
|
||||||
:name="`${name}.${key.toString()}`"
|
:field-name="`${fieldName}.${key.toString()}`"
|
||||||
:label="key.toString()"
|
:label="key.toString()"
|
||||||
:shape="shape"
|
:shape="shape"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import type { ZodAny, z } from 'zod'
|
||||||
import type { INPUT_COMPONENTS } from './constant'
|
import type { INPUT_COMPONENTS } from './constant'
|
||||||
|
|
||||||
export interface FieldProps {
|
export interface FieldProps {
|
||||||
name: string
|
fieldName: string
|
||||||
label?: string
|
label?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
config?: ConfigItem
|
config?: ConfigItem
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user