feat(form): add validation error styling to form components

Add error state handling and styling for form inputs and select components using vee-validate. Also adjust delete button alignment in person-relative form.
This commit is contained in:
Khafid Prayoga
2025-11-24 13:34:49 +07:00
parent 6c63d15b9e
commit 96a7ada059
3 changed files with 29 additions and 10 deletions
@@ -85,14 +85,17 @@ const { title = 'Kontak Pasien', isReadonly = false } = props
numeric-only
:is-disabled="isReadonly"
/>
<DE.Cell class="flex items-end justify-start">
<ButtonAction
:disabled="isReadonly"
preset="delete"
:title="`Hapus Kontak ${idx + 1}`"
icon-only
@click="remove(idx)"
/>
<DE.Cell class="flex items-start justify-start">
<DE.Field :class="idx === 0 ? 'mt-[30px]' : 'mt-0'">
<ButtonAction
v-if="idx !== 0"
:disabled="isReadonly"
preset="delete"
:title="`Hapus Kontak ${idx + 1}`"
icon-only
@click="remove(idx)"
/>
</DE.Field>
</DE.Cell>
</DE.Block>
</div>
+10 -1
View File
@@ -2,6 +2,8 @@
import type { FormErrors } from '~/types/error'
import { Input } from '~/components/pub/ui/input'
import { cn } from '~/lib/utils'
import { computed } from 'vue'
import { useFieldError } from 'vee-validate'
import * as DE from '~/components/pub/my-ui/doc-entry'
@@ -43,6 +45,10 @@ function handleInput(event: Event) {
target.dispatchEvent(new Event('input', { bubbles: true }))
}
}
// Get error state from vee-validate
const fieldError = useFieldError(() => props.fieldName)
const hasError = computed(() => !!fieldError.value)
</script>
<template>
@@ -70,7 +76,10 @@ function handleInput(event: Event) {
v-bind="componentField"
:placeholder="placeholder"
:maxlength="maxLength"
:class="cn('focus:border-primary focus:ring-2 focus:ring-primary focus:ring-offset-0')"
:class="cn(
'focus:border-primary focus:ring-2 focus:ring-primary focus:ring-offset-0',
hasError && 'border-red-500 focus:border-red-500 focus:ring-red-500'
)"
autocomplete="off"
aria-autocomplete="none"
autocorrect="off"
+8 -1
View File
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { SelectRoot } from 'radix-vue'
import { watch } from 'vue'
import { watch, computed } from 'vue'
import { useFieldError } from 'vee-validate'
import SelectContent from '~/components/pub/ui/select/SelectContent.vue'
import SelectGroup from '~/components/pub/ui/select/SelectGroup.vue'
import SelectItem from '~/components/pub/ui/select/SelectItem.vue'
@@ -29,9 +30,14 @@ const props = defineProps<{
isDisabled?: boolean
autoWidth?: boolean
autoFill?: boolean
id?: string
// otherPlacement sudah tidak digunakan, diganti dengan priority system di Item interface
}>()
// Get error state from vee-validate if id is provided
const fieldError = props.id ? useFieldError(() => props.id!) : ref(null)
const hasError = computed(() => !!fieldError.value)
const emit = defineEmits<{
'update:modelValue': [value: string]
}>()
@@ -121,6 +127,7 @@ watch(
'cursor-not-allowed bg-gray-100 opacity-50': isDisabled,
'bg-white text-black dark:bg-gray-800 dark:text-white': !isDisabled,
'w-full': !autoWidth,
'border-red-500 focus:ring-red-500': hasError,
},
props.class,
)