PaceInput.vue (1484B)
1 <template> 2 <div class="pace-input"> 3 <div> 4 Distance: 5 <decimal-input v-model="model.distanceValue" 6 :aria-label="label + ' distance value'" :min="0" :digits="2"/> 7 <select v-model="model.distanceUnit" :aria-label="label + ' distance unit'"> 8 <option v-for="key in DistanceUnits" :key="key" :value="key"> 9 {{ DistanceUnitData[key].name }} 10 </option> 11 </select> 12 </div> 13 <div> 14 Time: 15 <time-input v-model="model.time" :label="label + ' duration'"/> 16 </div> 17 </div> 18 </template> 19 20 <script setup lang="ts"> 21 import { DistanceUnits, DistanceUnitData } from '@/core/units'; 22 import type { DistanceTime } from '@/core/units'; 23 24 import DecimalInput from '@/components/DecimalInput.vue'; 25 import TimeInput from '@/components/TimeInput.vue'; 26 import useObjectModel from '@/composables/useObjectModel'; 27 28 interface Props { 29 /** 30 * The prefix for each field's aria-label (defaults to 'Input') 31 */ 32 label?: string, 33 34 /** 35 * The component value 36 */ 37 modelValue: DistanceTime, 38 }; 39 40 const props = withDefaults(defineProps<Props>(), { label: 'Input' }); 41 42 // Generate internal ref tied to modelValue prop 43 const emit = defineEmits(['update:modelValue']); 44 const model = useObjectModel<DistanceTime>(() => props.modelValue, 45 (x) => emit('update:modelValue', x)); 46 </script> 47 48 <style scoped> 49 .pace-input div + div { 50 margin-top: 5px; 51 } 52 .pace-input select { 53 margin-left: 5px; 54 } 55 </style>