1<template> 2 <div class="custom-form-file-container"> 3 <b-form-file 4 :id="id" 5 ref="fileInput" 6 v-model="file" 7 :accept="accept" 8 :disabled="disabled" 9 :state="state" 10 plain 11 @input="$emit('input', $event)" 12 > 13 </b-form-file> 14 <button 15 type="button" 16 class="add-file-btn btn mt-2" 17 :class="{ 18 disabled, 19 'btn-secondary': isSecondary, 20 'btn-primary': !isSecondary, 21 }" 22 :disabled="disabled" 23 @click="openFilePicker" 24 > 25 {{ $t('global.fileUpload.browseText') }} 26 </button> 27 <slot name="invalid"></slot> 28 <div v-if="file" class="clear-selected-file px-3 py-2 mt-2"> 29 {{ file ? file.name : '' }} 30 <b-button 31 variant="light" 32 class="px-2 ms-auto" 33 :disabled="disabled" 34 @click="file = null" 35 ><icon-close :title="$t('global.fileUpload.clearSelectedFile')" /><span 36 class="visually-hidden-focusable" 37 >{{ $t('global.fileUpload.clearSelectedFile') }}</span 38 > 39 </b-button> 40 </div> 41 </div> 42</template> 43 44<script> 45import { BFormFile } from 'bootstrap-vue-next'; 46import IconClose from '@carbon/icons-vue/es/close/20'; 47import { useI18n } from 'vue-i18n'; 48 49export default { 50 name: 'FormFile', 51 components: { BFormFile, IconClose }, 52 props: { 53 id: { 54 type: String, 55 default: '', 56 }, 57 disabled: { 58 type: Boolean, 59 default: false, 60 }, 61 accept: { 62 type: String, 63 default: '', 64 }, 65 state: { 66 type: Boolean, 67 default: true, 68 }, 69 variant: { 70 type: String, 71 default: 'secondary', 72 }, 73 }, 74 emits: ['input'], 75 data() { 76 return { 77 $t: useI18n().t, 78 file: null, 79 }; 80 }, 81 computed: { 82 isSecondary() { 83 return this.variant === 'secondary'; 84 }, 85 }, 86 methods: { 87 openFilePicker() { 88 // Access the native input element within the BFormFile component 89 const fileInput = document.getElementById(this.id); 90 if (fileInput) { 91 fileInput.click(); 92 } 93 }, 94 }, 95}; 96</script> 97 98<style lang="scss" scoped> 99// Hide the native file input but keep it accessible 100:deep(.form-control), 101:deep(input[type='file']) { 102 opacity: 0; 103 height: 0; 104 width: 0; 105 position: absolute; 106 pointer-events: none; 107} 108 109.add-file-btn { 110 &.disabled { 111 border-color: $gray-400; 112 background-color: $gray-400; 113 color: $gray-600; 114 box-shadow: none !important; 115 } 116 &:focus { 117 box-shadow: 118 inset 0 0 0 3px theme-color('primary'), 119 inset 0 0 0 5px $white; 120 } 121} 122 123.clear-selected-file { 124 display: flex; 125 align-items: center; 126 background-color: theme-color('light'); 127 word-break: break-all; 128 .btn { 129 width: 36px; 130 height: 36px; 131 display: flex; 132 align-items: center; 133 134 &:focus { 135 box-shadow: inset 0 0 0 2px theme-color('primary'); 136 } 137 } 138} 139</style> 140