running-tools

A collection of tools for runners and their coaches
git clone https://git.ashermorgan.net/running-tools/
Log | Files | Refs | README

IntegerInput.vue (1749B)


      1 <template>
      2   <input ref="inputElement" type="number" step="1" required @blur="onblur" v-model="stringValue">
      3 </template>
      4 
      5 <script setup lang="ts">
      6 import { ref, watch } from 'vue';
      7 
      8 /**
      9  * The component value
     10  */
     11 const model = defineModel({
     12   type: Number,
     13   default: 0,
     14 });
     15 
     16 const props = defineProps({
     17   /**
     18    * The number of digits to show before the decimal point
     19    */
     20   padding: {
     21     type: Number,
     22     default: 0,
     23     validator(value: number) {
     24       return value >= 0;
     25     },
     26   },
     27 });
     28 
     29 /**
     30  * The internal integer value
     31  */
     32 const internalValue = ref(model.value);
     33 
     34 /**
     35  * The raw string value (empty if input is currently invalid)
     36  */
     37 const stringValue = ref(format(model.value));
     38 
     39 /**
     40  * The input element
     41  */
     42 const inputElement = ref();
     43 
     44 /**
     45  * Update the internal value when the component value changes
     46  */
     47 watch(model, (newValue) => {
     48   if (Math.abs(newValue - internalValue.value) > 0.00001) {
     49     internalValue.value = newValue;
     50     stringValue.value = format(internalValue.value);
     51   }
     52 });
     53 
     54 /**
     55  * Update the internal value when the raw string value changes
     56  */
     57 watch(stringValue, (newValue) => {
     58   if (inputElement.value.validity.valid) {
     59     internalValue.value = Number(newValue);
     60     model.value = internalValue.value;
     61   }
     62 });
     63 
     64 /**
     65  * Reformat display value if not invalid
     66  */
     67 function onblur() {
     68   if (inputElement.value.validity.valid) {
     69     stringValue.value = format(internalValue.value);
     70   }
     71 }
     72 
     73 /**
     74  * Format an integer as a string
     75  * @param {number} value The integer
     76  * @returns {string} The formated string
     77  */
     78 function format(value: number): string {
     79   return value.toString().padStart(props.padding, '0');
     80 }
     81 </script>
     82 
     83 <style scoped>
     84 input {
     85   width: 3em;  /* can fit 999 comfortably */
     86   text-align: center;
     87 }
     88 </style>