bilhej/frontend/src/components/PlateInput.vue

106 lines
2.3 KiB
Vue

<script setup lang="ts">
import { ref, computed, watch } from 'vue'
const plate = defineModel<string>({ required: true })
const emit = defineEmits<{
(e: 'lookup', plate: string): void
}>()
const touched = ref(false)
const lastEmitted = ref('')
const SWEDISH_PLATE_REGEX = /^[A-Z]{3}(\d{3}|\d{2}[A-Z])$/
const isValid = computed(() => SWEDISH_PLATE_REGEX.test(plate.value ?? ''))
const showError = computed(
() => touched.value && !isValid.value && (plate.value?.length ?? 0) > 0,
)
function handleInput(event: Event) {
const target = event.target as HTMLInputElement
const rawValue = target.value
const transformed = rawValue.toUpperCase().replace(/[^A-Z0-9]/g, '')
plate.value = transformed
touched.value = true
}
watch(isValid, (valid) => {
if (valid && plate.value && plate.value !== lastEmitted.value) {
lastEmitted.value = plate.value
emit('lookup', plate.value)
}
})
</script>
<template>
<div class="plate-input">
<label for="plate" class="plate-input__label">Registreringsnummer</label>
<input
id="plate"
type="text"
inputmode="text"
autocomplete="off"
spellcheck="false"
:value="plate"
class="plate-input__field"
:class="{ 'plate-input__field--error': showError }"
placeholder="ABC 123"
maxlength="7"
@input="handleInput"
/>
<p v-if="showError" class="plate-input__error">
Ange ett giltigt registreringsnummer
</p>
</div>
</template>
<style scoped>
.plate-input {
display: flex;
flex-direction: column;
gap: 0.5rem;
width: 100%;
}
.plate-input__label {
font-size: 0.875rem;
font-weight: 500;
color: #4a5568;
}
.plate-input__field {
width: 100%;
padding: 0.875rem 1rem;
font-size: 1.5rem;
font-family: monospace;
letter-spacing: 0.15em;
text-transform: uppercase;
border: 2px solid #cbd5e0;
border-radius: 0.5rem;
outline: none;
transition: border-color 0.15s ease;
box-sizing: border-box;
}
.plate-input__field:focus {
border-color: #4299e1;
box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.25);
}
.plate-input__field--error {
border-color: #e53e3e;
}
.plate-input__field--error:focus {
border-color: #e53e3e;
box-shadow: 0 0 0 3px rgba(229, 62, 62, 0.25);
}
.plate-input__error {
margin: 0;
font-size: 0.8125rem;
color: #e53e3e;
}
</style>