xref: /openbmc/webui-vue/src/components/Global/FormFile.vue (revision d36ac8a8be8636ddd0e64ce005d507b21bcdeb00)
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