@a-vision-software/vue-input-components 1.4.11 → 1.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@a-vision-software/vue-input-components",
3
- "version": "1.4.11",
3
+ "version": "1.4.13",
4
4
  "description": "A collection of reusable Vue 3 input components with TypeScript support",
5
5
  "author": "A-Vision Software",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/a-vision/vue-input-components.git"
9
+ "url": "git+https://github.com/a-vision/vue-input-components.git"
10
10
  },
11
11
  "homepage": "https://a-vision.github.io/vue-input-components/",
12
12
  "keywords": [
@@ -88,4 +88,4 @@
88
88
  "publishConfig": {
89
89
  "access": "public"
90
90
  }
91
- }
91
+ }
@@ -1,18 +1,28 @@
1
1
  <template>
2
- <div class="file-upload">
3
- <div
4
- class="upload-area"
5
- :class="{ 'is-dragging': isDragging, 'has-files': files.length > 0 }"
6
- @dragenter.prevent="handleDragEnter"
7
- @dragleave.prevent="handleDragLeave"
8
- @dragover.prevent
9
- @drop.prevent="handleDrop"
10
- @click="triggerFileInput"
11
- >
12
- <input ref="fileInput" type="file" multiple class="file-input" @change="handleFileSelect" />
2
+ <div class="file-upload"
3
+ :class="{ 'label-position-top': labelPosition === 'top', 'label-position-left': labelPosition === 'left' }" :style="{
4
+ '--file-upload-width': width || 'auto',
5
+ '--file-upload-height': height || 'auto',
6
+ '--file-upload-color': error ? 'var(--ui-error-text-color)' : (color || 'var(--ui-upload-text-color, #888888)'),
7
+ '--file-upload-disabled-color': 'color-mix(in srgb, var(--file-upload-color), white 70%)',
8
+ '--file-upload-background-color': bgColor || 'var(--ui-upload-bg-color, #ffffff)',
9
+ '--file-upload-background-active-color': activeColor || 'var(--ui-upload-active-bg-color, #cccccc)',
10
+ '--file-upload-border-color': borderColor || 'var(--ui-upload-border-color, #888888)',
11
+ '--file-upload-icon-color': iconColor || 'var(--file-upload-color, #888888)',
12
+ '--file-upload-progress-color': progressColor || 'var(--ui-progress-color, #4444aa)',
13
+ '--file-upload-error-color': 'var(--ui-error-text-color, #aa0000)',
14
+ '--file-upload-success-color': 'var(--ui-success-text-color, #00aa00)',
15
+ }">
16
+ <label class="file-upload-label" v-if="label" for="fileInput">{{ label }}</label>
17
+ <div class="upload-area"
18
+ :class="{ 'is-dragging': isDragging, 'has-files': files.length > 0, 'is-disabled': disabled }">
19
+ <input ref="fileInput" type="file" :multiple="multiple" class="file-input" @change="handleFileSelect"
20
+ :accept="accept" :required="required" :disabled="disabled" :placeholder="placeholder"
21
+ @dragenter.prevent="handleDragEnter" @dragleave.prevent="handleDragLeave" @dragover.prevent
22
+ @drop.prevent="handleDrop" />
13
23
  <div class="upload-content">
14
- <font-awesome-icon :icon="['fas', icon || 'upload']" />
15
- <p v-if="files.length === 0">Drag & drop files here or click to select</p>
24
+ <font-awesome-icon v-if="icon" :icon="['fas', icon]" />
25
+ <p v-if="files.length === 0" v-text="placeholder || 'Drag & drop files here or click to select'"></p>
16
26
  <div v-else class="selected-files">
17
27
  <p>{{ files.length }} file(s) selected</p>
18
28
  <div v-for="(file, index) in files" :key="index" class="file-info">
@@ -21,42 +31,42 @@
21
31
  </div>
22
32
  </div>
23
33
  </div>
34
+ <div v-if="error" class="error-message">{{ error }}</div>
35
+ <div v-if="uploadStatus" class="status-message" :class="uploadStatus.type">
36
+ {{ uploadStatus.message }}
37
+ </div>
38
+ <div v-if="uploadProgress > 0 && uploadProgress < 100" class="progress-bar">
39
+ <div class="progress" :style="{ width: `${uploadProgress}%` }"></div>
40
+ </div>
24
41
  </div>
25
- <div v-if="error" class="error-message">{{ error }}</div>
26
- <div v-if="uploadProgress > 0 && uploadProgress < 100" class="progress-bar">
27
- <div class="progress" :style="{ width: `${uploadProgress}%` }"></div>
28
- </div>
29
- <div v-if="uploadStatus" class="status-message" :class="uploadStatus.type">
30
- {{ uploadStatus.message }}
31
- </div>
32
- <button v-if="files.length > 0 && !uploadUrl" class="upload-button" @click="handleStartUpload">
42
+ <button v-if="files.length > 0 && !uploadUrl && !disabled && showUploadButton" class="upload-button"
43
+ @click="handleStartUpload">
33
44
  Upload Files
34
45
  </button>
35
46
  </div>
36
47
  </template>
37
48
 
38
49
  <script setup lang="ts">
39
- import { ref, watch } from 'vue'
40
-
41
- const props = defineProps<{
42
- icon?: string
43
- uploadUrl?: string
44
- }>()
50
+ import { ref, watch, onMounted } from 'vue'
51
+ import type { FileUploadProps, FileUploadEmits, UploadStatus, UploadCallbackResponse } from '@/types/fileupload'
45
52
 
46
- const emit = defineEmits<{
47
- (e: 'upload-complete', files: File[]): void
48
- (e: 'upload-error', error: string): void
49
- (e: 'files-selected', files: File[]): void
50
- (e: 'start-upload', files: File[]): void
51
- }>()
53
+ const props = defineProps<FileUploadProps>()
54
+ const emit = defineEmits<FileUploadEmits>()
52
55
 
53
- const MAX_FILE_SIZE = 20 * 1024 * 1024 // 20MB in bytes
54
56
  const fileInput = ref<HTMLInputElement | null>(null)
55
57
  const files = ref<File[]>([])
56
58
  const isDragging = ref(false)
59
+ const startUpload = ref(props.doUpload)
57
60
  const uploadProgress = ref(0)
58
61
  const error = ref('')
59
- const uploadStatus = ref<{ type: 'success' | 'error'; message: string } | null>(null)
62
+ const uploadStatus = ref<UploadStatus>({
63
+ type: 'pending',
64
+ message: '',
65
+ })
66
+
67
+ onMounted(() => {
68
+ startUpload.value = props.doUpload;
69
+ })
60
70
 
61
71
  const formatFileSize = (bytes: number): string => {
62
72
  if (bytes === 0) return '0 Bytes'
@@ -67,8 +77,8 @@ const formatFileSize = (bytes: number): string => {
67
77
  }
68
78
 
69
79
  const validateFileSize = (file: File): boolean => {
70
- if (file.size > MAX_FILE_SIZE) {
71
- error.value = `File "${file.name}" exceeds the maximum size of 20MB`
80
+ if (props.maxSize && file.size > props.maxSize) {
81
+ error.value = `File "${file.name}" exceeds the maximum size of ${props.maxSize}MB`
72
82
  return false
73
83
  }
74
84
  return true
@@ -93,10 +103,6 @@ const handleDrop = (e: DragEvent) => {
93
103
  }
94
104
  }
95
105
 
96
- const triggerFileInput = () => {
97
- fileInput.value?.click()
98
- }
99
-
100
106
  const handleFileSelect = (e: Event) => {
101
107
  error.value = ''
102
108
  const input = e.target as HTMLInputElement
@@ -109,7 +115,7 @@ const handleFileSelect = (e: Event) => {
109
115
  input.value = ''
110
116
  }
111
117
 
112
- const uploadFiles = async () => {
118
+ const uploadFiles = () => {
113
119
  if (!props.uploadUrl) {
114
120
  error.value = 'No upload URL provided'
115
121
  return
@@ -123,13 +129,45 @@ const uploadFiles = async () => {
123
129
  const formData = new FormData()
124
130
  files.value.forEach((file) => {
125
131
  formData.append('files', file)
126
- })
132
+ });
133
+
134
+ if (props.uploadCallback) {
135
+ props.uploadCallback(formData)
136
+ .then((response: UploadCallbackResponse) => {
137
+ const { formData, headers } = response;
138
+ doUploadFiles(formData, headers)
139
+ })
140
+ .catch((err) => {
141
+ const errorMessage = err instanceof Error ? err.message : 'Upload failed'
142
+ error.value = errorMessage
143
+ uploadStatus.value = {
144
+ type: 'error',
145
+ message: errorMessage,
146
+ }
147
+ emit('upload-complete', files.value)
148
+ emit('upload-error', uploadStatus.value)
149
+ });
150
+ } else {
151
+ doUploadFiles(formData, {})
152
+ }
153
+ }
127
154
 
155
+ const doUploadFiles = (formData: FormData, headers: Record<string, string>) => {
128
156
  try {
129
157
  const xhr = new XMLHttpRequest()
158
+ console.log('doUploadFiles:', formData, headers)
159
+
130
160
  xhr.upload.addEventListener('progress', (e) => {
131
161
  if (e.lengthComputable) {
132
162
  uploadProgress.value = (e.loaded / e.total) * 100
163
+ emit('upload-progress', uploadProgress.value)
164
+
165
+ if (uploadProgress.value >= 100) {
166
+ uploadStatus.value = {
167
+ type: 'processing',
168
+ message: 'Please wait...',
169
+ }
170
+ }
133
171
  }
134
172
  })
135
173
 
@@ -140,8 +178,10 @@ const uploadFiles = async () => {
140
178
  message: 'Upload completed successfully',
141
179
  }
142
180
  emit('upload-complete', files.value)
181
+ emit('upload-success', uploadStatus.value)
143
182
  files.value = []
144
183
  uploadProgress.value = 0
184
+ startUpload.value = false;
145
185
  } else {
146
186
  throw new Error(`Upload failed with status ${xhr.status}`)
147
187
  }
@@ -151,7 +191,12 @@ const uploadFiles = async () => {
151
191
  throw new Error('Upload failed')
152
192
  })
153
193
 
154
- xhr.open('POST', props.uploadUrl)
194
+ xhr.open('POST', props.uploadUrl || '')
195
+
196
+ Object.entries(headers).forEach(([key, value]) => {
197
+ xhr.setRequestHeader(key, value)
198
+ })
199
+
155
200
  xhr.send(formData)
156
201
  } catch (err) {
157
202
  const errorMessage = err instanceof Error ? err.message : 'Upload failed'
@@ -160,67 +205,105 @@ const uploadFiles = async () => {
160
205
  type: 'error',
161
206
  message: errorMessage,
162
207
  }
163
- emit('upload-error', errorMessage)
208
+ emit('upload-complete', files.value)
209
+ emit('upload-error', uploadStatus.value)
164
210
  }
165
211
  }
166
212
 
167
213
  const handleStartUpload = () => {
168
- emit('start-upload', files.value)
214
+ emit('upload-started', files.value)
169
215
  }
170
216
 
171
217
  // Watch for changes in files and automatically upload when files are selected
172
218
  watch(files, (newFiles) => {
173
219
  if (newFiles.length > 0) {
174
- if (props.uploadUrl) {
220
+ if (props.uploadUrl && props.doUpload) {
175
221
  uploadFiles()
176
222
  } else {
177
223
  emit('files-selected', newFiles)
178
224
  }
179
225
  }
180
226
  })
227
+
228
+ watch(() => props.doUpload, (newDoUpload) => {
229
+ if (files.value && newDoUpload) {
230
+ startUpload.value = newDoUpload;
231
+ } else {
232
+ emit('files-selected', files.value)
233
+ startUpload.value = false;
234
+ }
235
+ })
236
+
237
+ watch(() => startUpload.value, (newStartUpload) => {
238
+ if (newStartUpload) {
239
+ uploadFiles()
240
+ }
241
+ })
181
242
  </script>
182
243
 
183
244
  <style scoped>
184
245
  .file-upload {
185
- width: 100%;
186
- max-width: 600px;
246
+ width: var(--file-upload-width);
247
+ height: var(--file-upload-height);
187
248
  margin: 0 auto;
249
+
250
+ &.label-position-left {
251
+ display: grid;
252
+ grid-template-columns: 10em calc(100% - 10em);
253
+ gap: 1rem;
254
+ }
255
+
188
256
  }
189
257
 
190
258
  .upload-area {
191
- border: 2px dashed var(--upload-border-color);
259
+ position: relative;
260
+ border: 2px dashed var(--file-upload-border-color);
192
261
  border-radius: 0.75rem;
193
262
  padding: 2rem;
194
263
  text-align: center;
195
264
  cursor: pointer;
196
265
  transition: all 0.3s ease;
197
- background-color: var(--upload-bg-color);
266
+ background-color: var(--file-upload-background-color);
198
267
  }
199
268
 
200
269
  .upload-area.is-dragging {
201
- border-color: var(--upload-dragging-border-color);
202
- background-color: var(--upload-dragging-bg-color);
270
+ background-color: var(--file-upload-background-active-color);
203
271
  }
204
272
 
205
273
  .upload-area.has-files {
206
- border-color: var(--upload-has-files-border-color);
207
- background-color: var(--upload-has-files-bg-color);
274
+ background-color: var(--file-upload-background-active-color);
275
+ }
276
+
277
+ .upload-area.is-disabled {
278
+ color: var(--file-upload-disabled-color);
279
+ border-color: var(--file-upload-disabled-color);
280
+ cursor: not-allowed;
208
281
  }
209
282
 
210
283
  .file-input {
211
- display: none;
284
+ position: absolute;
285
+ top: 0;
286
+ left: 0;
287
+ right: 0;
288
+ bottom: 0;
289
+ opacity: 0;
290
+ }
291
+
292
+ .upload-area.is-disabled .file-input {
293
+ cursor: not-allowed;
212
294
  }
213
295
 
214
296
  .upload-content {
215
- display: flex;
216
- flex-direction: column;
217
- align-items: center;
297
+ display: grid;
298
+ grid-template-rows: 1fr 1fr;
299
+ text-align: center;
218
300
  gap: 1rem;
219
301
  }
220
302
 
221
303
  .upload-content :deep(svg) {
222
304
  font-size: 2rem;
223
- color: var(--upload-icon-color);
305
+ color: var(--file-upload-icon-color);
306
+ margin: 0 auto;
224
307
  }
225
308
 
226
309
  .selected-files {
@@ -229,7 +312,7 @@ watch(files, (newFiles) => {
229
312
  max-height: 200px;
230
313
  overflow-y: auto;
231
314
  font-size: 0.75rem;
232
- color: var(--upload-text-color);
315
+ color: var(--file-upload-color);
233
316
  }
234
317
 
235
318
  .file-info {
@@ -255,23 +338,51 @@ watch(files, (newFiles) => {
255
338
  flex-shrink: 0;
256
339
  }
257
340
 
341
+ /*
342
+ .label-position-left {
343
+ line-height: 2em;
344
+
345
+ .upload-area {
346
+ padding: 0;
347
+ }
348
+
349
+ .upload-content {
350
+ padding: 0;
351
+ grid-template-rows: 1fr;
352
+ grid-template-columns: 3em auto;
353
+ }
354
+ }
355
+
356
+ .label-position-left .upload-content :deep(svg) {
357
+ font-size: 1.25em;
358
+ margin-top: 0.25em;
359
+ }
360
+ */
361
+
258
362
  .error-message {
259
- color: var(--error-text-color);
363
+ color: var(--file-upload-error-color);
260
364
  margin-top: 1rem;
261
365
  font-size: 0.875rem;
366
+ position: absolute;
367
+ bottom: 0;
368
+ left: 0;
369
+ right: 0;
262
370
  }
263
371
 
264
372
  .progress-bar {
265
373
  height: 0.5rem;
266
- background-color: var(--progress-bg-color);
267
374
  border-radius: 0.25rem;
268
375
  margin-top: 1rem;
269
376
  overflow: hidden;
377
+ position: absolute;
378
+ bottom: 0;
379
+ left: 0;
380
+ right: 0;
270
381
  }
271
382
 
272
383
  .progress {
273
384
  height: 100%;
274
- background-color: var(--progress-color);
385
+ background-color: var(--file-upload-progress-color);
275
386
  transition: width 0.3s ease;
276
387
  }
277
388
 
@@ -280,22 +391,24 @@ watch(files, (newFiles) => {
280
391
  padding: 0.5rem;
281
392
  border-radius: 0.25rem;
282
393
  font-size: 0.875rem;
394
+ position: absolute;
395
+ bottom: 0;
396
+ left: 0;
397
+ right: 0;
283
398
  }
284
399
 
285
400
  .status-message.success {
286
- background-color: var(--success-bg-color);
287
- color: var(--success-text-color);
401
+ color: var(--file-upload-success-color);
288
402
  }
289
403
 
290
404
  .status-message.error {
291
- background-color: var(--error-bg-color);
292
- color: var(--error-text-color);
405
+ color: var(--file-upload-error-color);
293
406
  }
294
407
 
295
408
  .upload-button {
296
409
  margin-top: 1rem;
297
410
  padding: 0.5rem 1rem;
298
- background-color: var(--primary-color);
411
+ background-color: var(--file-upload-color);
299
412
  color: white;
300
413
  border: none;
301
414
  border-radius: 0.25rem;
@@ -305,6 +418,6 @@ watch(files, (newFiles) => {
305
418
  }
306
419
 
307
420
  .upload-button:hover {
308
- background-color: var(--primary-color-light);
421
+ background-color: var(--file-upload-color-light);
309
422
  }
310
423
  </style>
@@ -1,26 +1,45 @@
1
- export interface FileUploadProps {
2
- modelValue: File[]
3
- label?: string
4
- placeholder?: string
5
- error?: string
6
- disabled?: boolean
7
- required?: boolean
8
- multiple?: boolean
9
- accept?: string
10
- maxSize?: number
11
- uploadUrl?: string
1
+ interface FileUploadProps {
2
+ width?: string // Width of the upload area.
3
+ height?: string // Height of the upload area.
4
+ label?: string // Label text displayed above the upload area.
5
+ labelPosition?: 'top' | 'left' // Position of the label.
6
+ icon?: string // Icon to display.
7
+ placeholder?: string // Placeholder text displayed when no files are selected.
8
+ error?: string // Error message to display when the upload fails.
9
+ disabled?: boolean // Whether to disable the upload.
10
+ required?: boolean // Whether to require the upload.
11
+ multiple?: boolean // Whether to allow multiple files to be selected.
12
+ accept?: string // File types to accept.
13
+ maxSize?: number // Maximum file size in MB.
14
+ uploadUrl?: string // URL to upload the files to.
15
+ showUploadButton?: boolean // Whether to show the upload button.
16
+ doUpload?: boolean // Whether to automatically upload files when selected. Also setting it from 'false' to 'true' will trigger the upload.
17
+ iconColor?: string // Icon color.
18
+ color?: string // Text color.
19
+ bgColor?: string // Background color.
20
+ borderColor?: string // Border color.
21
+ progressColor?: string // Progress color.
22
+ activeColor?: string // Active color.
23
+ uploadCallback?: (formData: FormData) => Promise<UploadCallbackResponse> // Callback function to handle the upload.
12
24
  }
13
25
 
14
- export interface FileUploadEmits {
15
- (e: 'update:modelValue', files: File[]): void
16
- (e: 'files-selected', files: File[]): void
17
- (e: 'start-upload', files: File[]): void
18
- (e: 'upload-progress', progress: number): void
19
- (e: 'upload-success', response: any): void
20
- (e: 'upload-error', error: Error): void
26
+ interface UploadCallbackResponse {
27
+ formData: FormData
28
+ headers: Record<string, string>
21
29
  }
22
30
 
23
- export interface FileUploadComponent {
24
- focus: () => void
25
- blur: () => void
31
+ interface UploadStatus {
32
+ type: 'pending' | 'success' | 'error' | 'processing'
33
+ message: string
26
34
  }
35
+
36
+ interface FileUploadEmits {
37
+ (e: 'files-selected', files: File[]): void // Emitted when files are selected.
38
+ (e: 'upload-started', files: File[]): void // Emitted when the upload starts.
39
+ (e: 'upload-complete', files: File[]): void // Emitted when the upload completes.
40
+ (e: 'upload-progress', progress: number): void // Emitted when the upload progresses.
41
+ (e: 'upload-success', status: UploadStatus): void // Emitted when the upload succeeds.
42
+ (e: 'upload-error', status: UploadStatus): void // Emitted when the upload fails.
43
+ }
44
+
45
+ export type { FileUploadProps, FileUploadEmits, UploadStatus, UploadCallbackResponse }
@@ -10,30 +10,27 @@
10
10
  <div class="file-upload-grid">
11
11
  <div class="upload-section">
12
12
  <h2>Basic Upload</h2>
13
- <FileUpload
14
- icon="upload"
15
- upload-url="https://httpbin.org/post"
16
- @upload-complete="handleUploadComplete"
17
- @upload-error="handleUploadError"
18
- />
19
- <div
20
- v-if="uploadStatus.basic && uploadStatus.basic.message"
21
- :class="['status-message', uploadStatus.basic.type]"
22
- >
13
+ <FileUpload label="Upload a file" placeholder="Select one or more files" label-position="left" width="100%"
14
+ error="File upload failed" :disabled="false" :required="true" :multiple="true" icon="upload"
15
+ upload-url="https://httpbin.org/post" @upload-complete="handleUploadComplete"
16
+ @upload-error="handleUploadError" :do-upload="true" />
17
+ <div v-if="uploadStatus.basic && uploadStatus.basic.message && false"
18
+ :class="['status-message', uploadStatus.basic.type]">
23
19
  {{ uploadStatus.basic.message }}
24
20
  </div>
25
21
  </div>
26
22
  <div class="upload-section">
27
- <h2>Image Upload</h2>
28
- <FileUpload
29
- icon="image"
30
- @files-selected="handleFilesSelected"
31
- @start-upload="handleStartUpload"
32
- />
23
+ <h2>Multiple Image Upload (<span @click="imageDisabled = !imageDisabled"
24
+ v-text="imageDisabled ? 'disabled' : 'enabled'"></span>)</h2>
25
+ <FileUpload icon="image" accept="image/*" @start-upload="handleStartUpload" :disabled="imageDisabled"
26
+ upload-url="https://httpbin.org/post" :multiple="true" :do-upload="uploadImages"
27
+ @upload-complete="showImagesUpload = false" :upload-callback="handleUploadCallback"
28
+ @files-selected="showImagesUpload = true" />
29
+ <button @click="uploadImages = true" v-if="showImagesUpload">Upload Images</button>
33
30
  </div>
34
31
  <div class="upload-section">
35
32
  <h2>Document Upload</h2>
36
- <FileUpload icon="file" />
33
+ <FileUpload icon="file" accept="application/pdf" :show-upload-button="true" />
37
34
  </div>
38
35
  </div>
39
36
  </div>
@@ -42,16 +39,32 @@
42
39
  <script setup lang="ts">
43
40
  import { ref } from 'vue'
44
41
  import FileUpload from '@/components/FileUpload.vue'
42
+ import type { UploadStatus, UploadCallbackResponse } from '@/types/fileupload'
45
43
 
46
- interface UploadStatus {
47
- type: 'success' | 'error'
48
- message: string
49
- }
44
+ const imageDisabled = ref(true);
45
+ const uploadImages = ref(false);
46
+ const showImagesUpload = ref(false);
47
+ const imageUploadData = ref({ tag: 'test', type: 'image', name: 'test' });
50
48
 
51
49
  const uploadStatus = ref<Record<string, UploadStatus>>({
52
50
  basic: { type: 'success', message: '' },
53
51
  })
54
52
 
53
+ const handleUploadCallback = (formData: FormData): Promise<UploadCallbackResponse> => {
54
+ return new Promise((resolve) => {
55
+ // Add imageUploadData to formData
56
+ Object.entries(imageUploadData.value).forEach(([key, value]) => {
57
+ formData.append(key, value)
58
+ })
59
+ resolve({
60
+ formData,
61
+ headers: {
62
+ 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIqInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvqG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ',
63
+ },
64
+ });
65
+ })
66
+ }
67
+
55
68
  const handleUploadComplete = (files: File[]) => {
56
69
  uploadStatus.value.basic = {
57
70
  type: 'success',
@@ -63,10 +76,10 @@ const handleUploadComplete = (files: File[]) => {
63
76
  }, 3000)
64
77
  }
65
78
 
66
- const handleUploadError = (error: string) => {
79
+ const handleUploadError = (status: UploadStatus) => {
67
80
  uploadStatus.value.basic = {
68
- type: 'error',
69
- message: error,
81
+ type: status.type,
82
+ message: status.message,
70
83
  }
71
84
  // Clear status after 3 seconds
72
85
  setTimeout(() => {
@@ -74,10 +87,6 @@ const handleUploadError = (error: string) => {
74
87
  }, 3000)
75
88
  }
76
89
 
77
- const handleFilesSelected = (files: File[]) => {
78
- console.log('Files selected:', files)
79
- }
80
-
81
90
  const handleStartUpload = (files: File[]) => {
82
91
  console.log('Start upload:', files)
83
92
  }