| <template> |
| <div class="w-full"> |
| <label v-if="label" :for="id" class="input-label mb-1.5 block"> |
| {{ label }} |
| <span v-if="required" class="text-red-500">*</span> |
| </label> |
| <div class="relative"> |
| |
| <div |
| v-if="$slots.prefix" |
| class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3.5 text-gray-400 dark:text-dark-400" |
| > |
| <slot name="prefix"></slot> |
| </div> |
| |
| <input |
| :id="id" |
| ref="inputRef" |
| :type="type" |
| :value="modelValue" |
| :disabled="disabled" |
| :required="required" |
| :placeholder="placeholderText" |
| :autocomplete="autocomplete" |
| :readonly="readonly" |
| :class="[ |
| 'input w-full transition-all duration-200', |
| $slots.prefix ? 'pl-11' : '', |
| $slots.suffix ? 'pr-11' : '', |
| error ? 'input-error ring-2 ring-red-500/20' : '', |
| disabled ? 'cursor-not-allowed bg-gray-100 opacity-60 dark:bg-dark-900' : '' |
| ]" |
| @input="onInput" |
| @change="$emit('change', ($event.target as HTMLInputElement).value)" |
| @blur="$emit('blur', $event)" |
| @focus="$emit('focus', $event)" |
| @keyup.enter="$emit('enter', $event)" |
| /> |
| |
| |
| <div |
| v-if="$slots.suffix" |
| class="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 dark:text-dark-400" |
| > |
| <slot name="suffix"></slot> |
| </div> |
| </div> |
| |
| <p v-if="error" class="input-error-text mt-1.5"> |
| {{ error }} |
| </p> |
| <p v-else-if="hint" class="input-hint mt-1.5"> |
| {{ hint }} |
| </p> |
| </div> |
| </template> |
| |
| <script setup lang="ts"> |
| import { computed, ref } from 'vue' |
| |
| interface Props { |
| modelValue: string | number | null | undefined |
| type?: string |
| label?: string |
| placeholder?: string |
| disabled?: boolean |
| required?: boolean |
| readonly?: boolean |
| error?: string |
| hint?: string |
| id?: string |
| autocomplete?: string |
| } |
| |
| const props = withDefaults(defineProps<Props>(), { |
| type: 'text', |
| disabled: false, |
| required: false, |
| readonly: false |
| }) |
| |
| const emit = defineEmits<{ |
| (e: 'update:modelValue', value: string): void |
| (e: 'change', value: string): void |
| (e: 'blur', event: FocusEvent): void |
| (e: 'focus', event: FocusEvent): void |
| (e: 'enter', event: KeyboardEvent): void |
| }>() |
| |
| const inputRef = ref<HTMLInputElement | null>(null) |
| const placeholderText = computed(() => props.placeholder || '') |
| |
| const onInput = (event: Event) => { |
| const value = (event.target as HTMLInputElement).value |
| emit('update:modelValue', value) |
| } |
| |
| |
| defineExpose({ |
| focus: () => inputRef.value?.focus(), |
| select: () => inputRef.value?.select() |
| }) |
| </script> |
| |