blob: 57eface7e919c79cbe29108b7899b923b2262ee5 [file] [log] [blame]
SurenNeware978807d2020-09-03 18:35:21 +05301<template>
2 <div class="custom-form-file-container">
jason westoverd36ac8a2025-11-03 20:58:59 -06003 <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>
SurenNeware978807d2020-09-03 18:35:21 +053028 <div v-if="file" class="clear-selected-file px-3 py-2 mt-2">
29 {{ file ? file.name : '' }}
Yoshie Muranaka2ec04fb2021-01-20 12:19:16 -080030 <b-button
31 variant="light"
jason westoverd36ac8a2025-11-03 20:58:59 -060032 class="px-2 ms-auto"
Yoshie Muranaka2ec04fb2021-01-20 12:19:16 -080033 :disabled="disabled"
34 @click="file = null"
SurenNeware6e2cb972020-12-24 20:58:16 +053035 ><icon-close :title="$t('global.fileUpload.clearSelectedFile')" /><span
jason westoverd36ac8a2025-11-03 20:58:59 -060036 class="visually-hidden-focusable"
SurenNeware6e2cb972020-12-24 20:58:16 +053037 >{{ $t('global.fileUpload.clearSelectedFile') }}</span
38 >
39 </b-button>
SurenNeware978807d2020-09-03 18:35:21 +053040 </div>
41 </div>
42</template>
43
44<script>
jason westoverd36ac8a2025-11-03 20:58:59 -060045import { BFormFile } from 'bootstrap-vue-next';
SurenNeware978807d2020-09-03 18:35:21 +053046import IconClose from '@carbon/icons-vue/es/close/20';
Surya Vde23ea22024-07-11 15:19:46 +053047import { useI18n } from 'vue-i18n';
SurenNeware978807d2020-09-03 18:35:21 +053048
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 },
Yoshie Muranaka391f9492021-02-08 10:50:53 -080069 variant: {
70 type: String,
71 default: 'secondary',
72 },
SurenNeware978807d2020-09-03 18:35:21 +053073 },
Hariharan Rangasamyc5d60f52025-10-31 12:58:56 +053074 emits: ['input'],
SurenNeware978807d2020-09-03 18:35:21 +053075 data() {
76 return {
Surya Vde23ea22024-07-11 15:19:46 +053077 $t: useI18n().t,
SurenNeware978807d2020-09-03 18:35:21 +053078 file: null,
79 };
80 },
Yoshie Muranaka391f9492021-02-08 10:50:53 -080081 computed: {
82 isSecondary() {
83 return this.variant === 'secondary';
84 },
85 },
jason westoverd36ac8a2025-11-03 20:58:59 -060086 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 },
SurenNeware978807d2020-09-03 18:35:21 +053095};
96</script>
97
98<style lang="scss" scoped>
jason westoverd36ac8a2025-11-03 20:58:59 -060099// Hide the native file input but keep it accessible
100:deep(.form-control),
101:deep(input[type='file']) {
SurenNeware978807d2020-09-03 18:35:21 +0530102 opacity: 0;
103 height: 0;
jason westoverd36ac8a2025-11-03 20:58:59 -0600104 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 {
Ed Tanous81323992024-02-27 11:26:24 -0800117 box-shadow:
118 inset 0 0 0 3px theme-color('primary'),
119 inset 0 0 0 5px $white;
SurenNeware978807d2020-09-03 18:35:21 +0530120 }
121}
122
SurenNeware978807d2020-09-03 18:35:21 +0530123.clear-selected-file {
124 display: flex;
125 align-items: center;
126 background-color: theme-color('light');
jason westoverd36ac8a2025-11-03 20:58:59 -0600127 word-break: break-all;
SurenNeware978807d2020-09-03 18:35:21 +0530128 .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>