Files
gamegroup_fe/src/components/common/Input/Input.vue

89 lines
1.8 KiB
Vue
Raw Normal View History

<template>
<div class="g-input-wrapper">
<input
v-model="inputValue"
:type="type"
:placeholder="placeholder"
:disabled="disabled"
:class="inputClass"
@focus="handleFocus"
@blur="handleBlur"
/>
<button v-if="clearable && inputValue" @click="handleClear" class="clear-btn">×</button>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
interface Props {
modelValue: string | number
type?: 'text' | 'password' | 'email' | 'tel'
placeholder?: string
disabled?: boolean
clearable?: boolean
}
const props = withDefaults(defineProps<Props>(), {
type: 'text',
clearable: false
})
const emit = defineEmits<{
'update:modelValue': [value: string]
focus: [event: FocusEvent]
blur: [event: FocusEvent]
}>()
const inputValue = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val)
})
const focused = ref(false)
const inputClass = computed(() => [
'g-input',
{
'is-focused': focused.value,
'is-disabled': props.disabled
}
])
const handleFocus = (e: FocusEvent) => {
focused.value = true
emit('focus', e)
}
const handleBlur = (e: FocusEvent) => {
focused.value = false
emit('blur', e)
}
const handleClear = () => {
inputValue.value = ''
}
</script>
<style scoped lang="scss">
.g-input-wrapper {
@apply relative;
}
.g-input {
@apply w-full px-4 py-2.5 rounded-lg border-2 border-gray-200 transition-all duration-200;
&:focus {
@apply border-primary-500 outline-none shadow-md;
}
&.is-disabled {
@apply bg-gray-100 cursor-not-allowed;
}
}
.clear-btn {
@apply absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 text-xl;
}
</style>