ConfigJsonCard.vue
1 <script setup lang="ts"> 2 import { ref, computed, watch } from 'vue' 3 4 defineOptions({ 5 inheritAttrs: false 6 }) 7 8 const emit = defineEmits(['update:modelValue', 'onError', 'focus', 'blur']) 9 10 type JSONValue = string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue } 11 12 const props = defineProps({ 13 modelValue: { 14 type: Object as () => {}, 15 required: true 16 } 17 }) 18 19 const handleFocus = () => { 20 emit('focus') 21 } 22 23 const handleBlur = () => { 24 emit('blur') 25 } 26 27 const json2Str = (json: JSONValue | {}) => { 28 return JSON.stringify(json, null, 2) 29 } 30 31 const { modelValue: jsonParams } = props 32 33 const jsonString = ref(json2Str(jsonParams)) 34 35 const editableSamplingParams = computed({ 36 get: () => jsonString.value, 37 set: (value) => { 38 console.log('JSON changed: ', value) 39 jsonString.value = value 40 try { 41 const parsed = JSON.parse(value) 42 emit('update:modelValue', parsed) 43 jsonError.value = null 44 emit('onError', null) 45 } catch (e: any) { 46 jsonError.value = e.message 47 emit('onError', e.message) 48 } 49 } 50 }) 51 52 const jsonError = ref<string | null>(null) 53 54 watch( 55 () => jsonParams, 56 (newVal) => { 57 jsonString.value = json2Str(newVal) 58 }, 59 { deep: true } 60 ) 61 </script> 62 63 <template> 64 <v-card variant="text"> 65 <v-card-text> 66 <v-textarea 67 v-model="editableSamplingParams" 68 variant="solo" 69 outlined 70 auto-grow 71 v-bind="$attrs" 72 :error-messages="jsonError" 73 :hide-details="!Boolean(jsonError ?? '')" 74 @focus="handleFocus" 75 @blur="handleBlur" 76 ></v-textarea> 77 </v-card-text> 78 </v-card> 79 </template>