yunohost-portal/components/FormField.vue

96 lines
2.1 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-08-07 16:39:06 +02:00
srHideLabel?: boolean
2023-07-25 19:19:27 +02:00
}>()
2023-08-07 17:29:04 +02:00
const { t } = useI18n()
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
)
})
2023-08-07 17:29:04 +02:00
const error = computed(() => {
const e = errorMessage.value as
| string
| undefined
| { key: string; values: Record<string, any> }
if (!e) return ''
if (typeof e === 'string') return t(e)
return t(e.key, e.values)
})
2023-07-25 19:19:27 +02:00
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-08-07 16:39:06 +02:00
<!-- eslint-disable vuejs-accessibility/label-has-for -->
<label
:id="name + '__label'"
:for="name"
class="block ms-1 mb-2"
:class="{ 'sr-only': srHideLabel }"
>
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"
>
2023-08-07 17:29:04 +02:00
{{ error }}
2023-07-25 19:19:27 +02:00
</div>
<small
v-if="description"
:id="name + '__description'"
tabindex="-1"
class="block text-gray-400 mt-1"
>
{{ description }}
</small>
</div>
</div>
</div>
</template>