65 lines
2.4 KiB
Vue
65 lines
2.4 KiB
Vue
<script setup lang="ts">
|
|
import { isNumeric } from '@/lib/utils';
|
|
import { component as VueNumber } from '@coders-tm/vue-number-format'
|
|
import { computed } from 'vue'
|
|
|
|
const props = defineProps<{
|
|
modelValue: number | string
|
|
decimal?: string
|
|
separator?: string
|
|
precision?: number
|
|
minimumFractionDigits?: number
|
|
maximumFractionDigits?: number
|
|
prefix?: string
|
|
suffix?: string
|
|
}>()
|
|
const emit = defineEmits<{ (e: 'update:modelValue', value: number): void }>()
|
|
|
|
const value = computed<number>({
|
|
get() {
|
|
if (typeof props.modelValue === 'string') {
|
|
const parsedValue = parseFloat(props.modelValue.replace(',', '.'))
|
|
return isNaN(parsedValue) ? 0 : parsedValue
|
|
}
|
|
return (props.modelValue as number) || 0
|
|
},
|
|
set(val: any) {
|
|
const newVal = parseFloat(String(val));
|
|
const current = typeof props.modelValue === 'string'
|
|
? parseFloat(props.modelValue.replace(',', '.'))
|
|
: (props.modelValue as number) || 0;
|
|
|
|
if (isNaN(newVal) && isNaN(current)) return;
|
|
if (newVal === current) return;
|
|
|
|
emit('update:modelValue', newVal);
|
|
}
|
|
})
|
|
|
|
const number = {
|
|
decimal: props.decimal || ',',
|
|
separator: props.separator || '.',
|
|
prefix: props.prefix || '',
|
|
suffix: props.suffix || '',
|
|
precision: props.precision || 2,
|
|
minimumFractionDigits: isNumeric(props.minimumFractionDigits) ? props.minimumFractionDigits : 2,
|
|
maximumFractionDigits: isNumeric(props.maximumFractionDigits) ? props.maximumFractionDigits : 2,
|
|
masked: false,
|
|
} as {
|
|
decimal: string
|
|
separator: string
|
|
prefix: string
|
|
suffix: string
|
|
precision: number
|
|
minimumFractionDigits: number
|
|
maximumFractionDigits: number
|
|
masked: boolean
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex items-center gap-2">
|
|
<vue-number class="file:text-foreground border-input flex min-w-4 rounded-lg transition-[color,box-shadow] outline-none disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive tabular-nums h-6 py-0 px-1 m-0 bg-transparent border-none dark:bg-transparent hover:border
|
|
dark:hover:border placeholder:text-muted-foreground/30 shadow-none w-full text-right" v-model="value" v-bind="number" />
|
|
</div>
|
|
</template> |