yunohost-portal/components/FormField.vue

78 lines
1.7 KiB
Vue
Raw Normal View History

2023-07-25 19:19:27 +02:00
<script setup lang="ts">
import { useField } from 'vee-validate'
import { formGroupExtras } from '@/composables/form'
const props = defineProps<{
name: string
label: string
icon?: string
description?: string
2023-07-26 04:08:17 +02:00
row?: boolean
2023-07-25 19:19:27 +02:00
}>()
const { errorMessage } = useField(() => props.name)
const invalid = computed(() => !!errorMessage.value)
const describedBy = computed(() => {
return (
[
props.description ? props.name + '__description' : null,
invalid.value ? props.name + '__feedback_invalid' : null,
]
.filter((x) => x)
.join(' ') || undefined
)
})
provide(formGroupExtras, {
describedBy,
invalid,
})
</script>
<template>
<div>
<div
role="group"
:aria-invalid="invalid"
2023-07-26 04:08:17 +02:00
:class="{ 'is-invalid': invalid, 'flex-col': !row }"
2023-07-25 19:19:27 +02:00
class="flex"
>
<slot name="label">
2023-07-26 04:08:17 +02:00
<label :id="name + '__label'" :for="name" class="block ml-1 mb-2">
2023-07-25 19:19:27 +02:00
<Icon
v-if="icon"
:name="icon"
size="2em"
aria-hidden="true"
class="m-2"
/>
<span :class="{ 'sr-only': !!icon }">{{ label }}</span>
</label>
</slot>
<div>
<slot name="default" />
<div
v-show="invalid"
:id="name + '__feedback_invalid'"
tabindex="-1"
aria-live="assertive"
aria-atomic="true"
class="text-error mt-1"
>
{{ errorMessage }}
</div>
<small
v-if="description"
:id="name + '__description'"
tabindex="-1"
class="block text-gray-400 mt-1"
>
{{ description }}
</small>
</div>
</div>
</div>
</template>