| <template> | 
|   <nut-input type="number" :formatter="formatter" formatTrigger="onBlur" v-model="innerModelValue"> | 
|     <template #right> | 
|       <slot name="right"></slot> | 
|     </template> | 
|   </nut-input> | 
| </template> | 
|   | 
| <script setup lang="ts"> | 
| import { computed } from 'vue'; | 
|   | 
| defineOptions({ | 
|   name: 'NumberInput', | 
| }); | 
|   | 
| type Props = { | 
|   min?: number; | 
|   max?: number; | 
|   precision?: number; | 
|   modelValue?: number | string; | 
| }; | 
|   | 
| const props = withDefaults(defineProps<Props>(), { | 
|   max: Math.pow(2, 53) - 1, | 
| }); | 
|   | 
| const emit = defineEmits<{ | 
|   (e: 'update:modelValue', val: string | number): void; | 
| }>(); | 
|   | 
| const innerModelValue = computed({ | 
|   get() { | 
|     return props.modelValue + ''; | 
|   }, | 
|   set(val) { | 
|     emit('update:modelValue', val); | 
|   }, | 
| }); | 
|   | 
| function formatter(value: string): string { | 
|   const newVal = value !== '' ? Number.parseFloat(value) : ''; | 
|   if (Number.isNaN(newVal)) { | 
|     return ''; | 
|   } | 
|   if (newVal && newVal > props.max) { | 
|     return `${toPrecision(props.max)}`; | 
|   } | 
|   if (props.min !== undefined && !!`${newVal}` && (newVal as number) < props.min) { | 
|     return `${toPrecision(props.min)}`; | 
|   } | 
|   return newVal !== '' ? `${toPrecision(newVal)}` : newVal; | 
| } | 
|   | 
| function toPrecision(num: number) { | 
|   if (props.precision) { | 
|     if (props.precision === 0) return Math.round(num); | 
|     let snum = String(num); | 
|     const pointPos = snum.indexOf('.'); | 
|     if (pointPos === -1) return num; | 
|     const nums = snum.replace('.', '').split(''); | 
|     const datum = nums[pointPos + props.precision]; | 
|     if (!datum) return num; | 
|     const length = snum.length; | 
|     if (snum.charAt(length - 1) === '5') { | 
|       snum = `${snum.slice(0, Math.max(0, length - 1))}6`; | 
|     } | 
|     return Number(snum).toFixed(props.precision); | 
|   } | 
|   return String(num); | 
| } | 
| </script> |