Files
simrsx-fe/app/components/pub/my-ui/form/input-base.vue
T
Khafid Prayoga 044de2d965 refactor(form): migrate form components to use doc-entry pattern
- Replace FieldGroup/Field/Label with DE.Cell/DE.Field/DE.Label components
- Add ButtonAction component with preset styling for common form actions
- Simplify form layouts using doc-entry grid system
- Add support for disabled/readonly states in form fields
2025-11-24 12:45:03 +07:00

112 lines
2.9 KiB
Vue

<script setup lang="ts">
import type { FormErrors } from '~/types/error'
import { Input } from '~/components/pub/ui/input'
import { cn } from '~/lib/utils'
import * as DE from '~/components/pub/my-ui/doc-entry'
const props = defineProps<{
fieldName: string
placeholder: string
label?: string
errors?: FormErrors
class?: string
colSpan?: number
numericOnly?: boolean
maxLength?: number
isRequired?: boolean
isDisabled?: boolean
rightLabel?: string
bottomLabel?: string
suffixMsg?: string
iconName?: string
}>()
function handleInput(event: Event) {
const target = event.target as HTMLInputElement
let value = target.value
// Filter numeric only jika diperlukan
if (props.numericOnly) {
value = value.replace(/\D/g, '')
}
// Batasi panjang maksimal jika diperlukan
if (props.maxLength && value.length > props.maxLength) {
value = value.slice(0, props.maxLength)
}
// Update value jika ada perubahan
if (target.value !== value) {
target.value = value
// Trigger input event untuk update form
target.dispatchEvent(new Event('input', { bubbles: true }))
}
}
</script>
<template>
<DE.Cell :col-span="colSpan || 1">
<DE.Label
v-if="label"
:label-for="fieldName"
:is-required="isRequired && !isDisabled"
>
{{ label }}
</DE.Label>
<DE.Field
:id="fieldName"
:errors="errors"
>
<FormField
v-slot="{ componentField }"
:name="fieldName"
>
<FormItem>
<FormControl class="relative">
<div class="relative w-full max-w-sm items-center">
<Input
:disabled="isDisabled"
v-bind="componentField"
:placeholder="placeholder"
:maxlength="maxLength"
:class="cn('focus:border-primary focus:ring-2 focus:ring-primary focus:ring-offset-0')"
autocomplete="off"
aria-autocomplete="none"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
@input="handleInput"
/>
<span
v-if="suffixMsg"
class="absolute inset-y-0 end-0 flex items-center justify-center px-2 text-muted-foreground"
>
{{ suffixMsg }}
</span>
<Icon
v-if="iconName"
:name="iconName"
class="absolute right-2 top-1/2 -translate-y-1/2 text-gray-500 dark:text-gray-400"
/>
<p
v-show="rightLabel"
class="absolute right-3 top-0 text-gray-400"
>
{{ rightLabel }}
</p>
</div>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
<p
v-show="bottomLabel"
class="text-gray-400"
>
{{ bottomLabel }}
</p>
</DE.Cell>
</template>