66 lines
1.4 KiB
Vue
66 lines
1.4 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { extractNumericString, formatNumber } from '@/utils/format'
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
modelValue?: number | null
|
|
placeholder?: string
|
|
disabled?: boolean
|
|
id?: string
|
|
inputClass?: string
|
|
allowEmpty?: boolean
|
|
}>(),
|
|
{
|
|
modelValue: null,
|
|
placeholder: '',
|
|
disabled: false,
|
|
inputClass: 'admin-input',
|
|
allowEmpty: true,
|
|
},
|
|
)
|
|
|
|
const emit = defineEmits<{
|
|
'update:modelValue': [value: number | null]
|
|
}>()
|
|
|
|
const displayValue = computed(() => {
|
|
if (props.modelValue == null || !Number.isFinite(props.modelValue)) return ''
|
|
return formatNumber(props.modelValue)
|
|
})
|
|
|
|
function onInput(event: Event) {
|
|
const input = event.target as HTMLInputElement
|
|
const numeric = extractNumericString(input.value)
|
|
if (!numeric) {
|
|
emit('update:modelValue', props.allowEmpty ? null : 0)
|
|
input.value = ''
|
|
return
|
|
}
|
|
const next = Number(numeric)
|
|
emit('update:modelValue', next)
|
|
input.value = formatNumber(next)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<input
|
|
:id="id"
|
|
type="text"
|
|
inputmode="numeric"
|
|
dir="ltr"
|
|
class="admin-currency-input"
|
|
:class="inputClass"
|
|
:value="displayValue"
|
|
:placeholder="placeholder"
|
|
:disabled="disabled"
|
|
@input="onInput"
|
|
/>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.admin-currency-input {
|
|
text-align: right;
|
|
}
|
|
</style>
|