@bildvitta/quasar-ui-asteroid 3.8.0-beta.0 → 3.8.0-beta.2

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.
Files changed (27) hide show
  1. package/package.json +1 -1
  2. package/src/components/dialog/QasDialog.yml +1 -1
  3. package/src/components/field/QasField.vue +1 -1
  4. package/src/components/filters/QasFilters.vue +82 -48
  5. package/src/components/filters/QasFilters.yml +51 -9
  6. package/src/components/filters/private/PvFiltersButton.vue +89 -0
  7. package/src/components/form-view/QasFormView.vue +12 -0
  8. package/src/components/gallery-card/QasGalleryCard.vue +116 -0
  9. package/src/components/gallery-card/QasGalleryCard.yml +45 -0
  10. package/src/components/grid-generator/QasGridGenerator.vue +0 -5
  11. package/src/components/label/QasLabel.vue +19 -6
  12. package/src/components/nested-fields/QasNestedFields.vue +47 -30
  13. package/src/components/pagination/QasPagination.vue +2 -2
  14. package/src/components/signature-uploader/QasSignatureUploader.vue +45 -57
  15. package/src/components/signature-uploader/QasSignatureUploader.yml +5 -9
  16. package/src/components/table-generator/QasTableGenerator.vue +39 -3
  17. package/src/components/table-generator/QasTableGenerator.yml +10 -0
  18. package/src/components/uploader/QasUploader.vue +330 -168
  19. package/src/components/uploader/QasUploader.yml +68 -12
  20. package/src/components/uploader/private/PvUploaderGalleryCard.vue +332 -0
  21. package/src/css/components/index.scss +1 -0
  22. package/src/css/components/scrollbar.scss +20 -0
  23. package/src/css/variables/index.scss +1 -0
  24. package/src/css/variables/scrollbar.scss +11 -0
  25. package/src/helpers/download-file.js +21 -0
  26. package/src/helpers/index.js +10 -9
  27. package/src/vue-plugin.js +3 -0
@@ -1,67 +1,47 @@
1
1
  <template>
2
- <q-field borderless class="qas-uploader" :error="hasErrorMessage" :error-message="errorMessage" :hint="hintValue" no-error-icon>
3
- <q-uploader ref="uploader" auto-upload bordered :class="uploaderClasses" :factory="factory" flat :max-files="maxFiles" method="PUT" :readonly="readonly" v-bind="attributes" @factory-failed="factoryFailed" @uploaded="uploaded" @uploading="updateUploading(true)">
2
+ <div class="qas-uploader">
3
+ <q-uploader ref="uploader" auto-upload class="bg-transparent" :class="uploaderClasses" v-bind="attributes" :factory="factory" flat :max-files="maxFiles" method="PUT" @factory-failed="factoryFailed" @uploaded="uploaded" @uploading="updateUploading(true)">
4
4
  <template #header="scope">
5
5
  <slot name="header" :scope="scope">
6
- <div class="flex flex-center full-width justify-between no-border no-wrap q-gutter-xs q-pa-sm text-white transparent">
7
- <q-spinner v-if="scope.isUploading" size="24px" />
6
+ <div class="flex items-center justify-between">
7
+ <div>
8
+ <qas-label v-bind="labelProps" />
8
9
 
9
- <div class="col column items-start justify-center">
10
- <div v-if="$attrs.label" class="q-uploader__title">{{ $attrs.label }}</div>
11
- <div v-if="scope.files.length" class="q-uploader__subtitle">
12
- {{ scope.uploadProgressLabel }} ({{ scope.uploadSizeLabel }})
10
+ <div v-if="errorMessage" class="q-mt-xs text-caption text-negative">
11
+ {{ errorMessage }}
13
12
  </div>
14
13
  </div>
15
14
 
16
- <qas-btn v-if="showAddFile" ref="buttonUpload" color="white" icon="sym_r_add" :use-hover-on-white-color="false" variant="tertiary" @click="$refs.hiddenInput.click()" />
17
-
18
- <input ref="hiddenInput" :accept="attributes.accept" class="qas-uploader__input" :multiple="isMultiple" type="file">
19
-
20
- <qas-btn ref="buttonCleanFiles" class="hidden" @click="scope.removeUploadedFiles" />
21
-
22
- <qas-btn v-if="scope.canUpload" color="white" icon="sym_r_cloud_upload" :use-hover-on-white-color="false" variant="tertiary" @click="scope.upload" />
23
-
24
- <qas-btn v-if="scope.isUploading" color="white" icon="sym_r_clear" :use-hover-on-white-color="false" variant="tertiary" @click="scope.abort" />
15
+ <div v-if="hasAddFile">
16
+ <qas-btn color="primary" icon="sym_r_add" :label="addButtonLabel" :use-label-on-small-screen="false" variant="tertiary" @click="onAddButtonClick(scope)" />
17
+ </div>
25
18
  </div>
19
+
20
+ <!-- ------------------------------------ tags hidden -------------------------------------- -->
21
+ <input ref="hiddenInput" :accept="attributes.accept" class="qas-uploader__input" :multiple="isMultiple" type="file">
22
+ <qas-btn ref="buttonCleanFiles" class="hidden" @click="scope.removeUploadedFiles" />
26
23
  </slot>
27
24
  </template>
28
25
 
29
26
  <template #list="scope">
30
- <slot name="list" :scope="scope">
31
- <div class="col-12 q-col-gutter-md row">
32
- <div v-for="(file, index) in getFilesList(scope.files, scope)" :key="index" class="row" :class="itemClass">
33
- <qas-avatar class="q-mr-sm" color="primary" icon="sym_r_attach_file" :image="file.url" rounded :text-color="getColorFileIcon(file)" />
34
-
35
- <div class="col items-center no-wrap row">
36
- <div class="column no-wrap" :class="{ col: isMultiple }">
37
- <div class="ellipsis" :class="getFileNameClass(file.isFailed)">{{ file.name }}</div>
38
- <div v-if="file.isUploaded" class="text-caption">{{ file.progressLabel }} ({{ file.sizeLabel }})</div>
39
- </div>
40
- <div class="items-center q-ml-sm row">
41
- <q-icon v-if="file.isFailed" color="negative" name="sym_r_warning" size="20px" />
42
- <qas-btn v-if="!scope.readonly" color="grey-9" icon="sym_r_delete" variant="tertiary" @click="removeItem(index, scope, file)" />
43
- </div>
44
- </div>
45
- </div>
27
+ <div v-if="hasGalleryCardSection" class="q-col-gutter-lg q-mt-sm row">
28
+ <div v-for="(file, key, index) in getFilesList(scope.files, scope)" :key="index" :class="columnClasses">
29
+ <pv-uploader-gallery-card v-bind="getUploaderGalleryCardProps({ key, scope, file, index })" />
46
30
  </div>
47
- </slot>
31
+ </div>
48
32
  </template>
49
33
  </q-uploader>
50
34
 
51
35
  <slot :context="self" name="custom-upload" />
52
-
53
- <template v-if="hasErrorMessage" #after>
54
- <q-icon color="negative" name="sym_r_error" />
55
- </template>
56
- </q-field>
36
+ </div>
57
37
  </template>
58
38
 
59
39
  <script>
60
- import QasAvatar from '../avatar/QasAvatar.vue'
40
+ import PvUploaderGalleryCard from './private/PvUploaderGalleryCard.vue'
61
41
 
62
42
  import { uid, extend } from 'quasar'
63
43
  import { NotifyError } from '../../plugins'
64
- import { getImageSize, getResizeDimensions } from '../../helpers/images'
44
+ import { getImageSize, getResizeDimensions } from '../../helpers/images.js'
65
45
 
66
46
  import Pica from 'pica'
67
47
 
@@ -69,12 +49,22 @@ export default {
69
49
  name: 'QasUploader',
70
50
 
71
51
  components: {
72
- QasAvatar
52
+ PvUploaderGalleryCard
73
53
  },
74
54
 
75
55
  inheritAttrs: false,
76
56
 
77
57
  props: {
58
+ addButtonFn: {
59
+ type: Function,
60
+ default: undefined
61
+ },
62
+
63
+ addButtonLabel: {
64
+ default: 'Adicionar',
65
+ type: String
66
+ },
67
+
78
68
  acceptResizeTypes: {
79
69
  default: () => [
80
70
  'image/jpeg',
@@ -87,19 +77,53 @@ export default {
87
77
  type: Array
88
78
  },
89
79
 
80
+ columns: {
81
+ type: Object,
82
+ default: () => ({})
83
+ },
84
+
85
+ dialogProps: {
86
+ type: Object,
87
+ default: () => ({})
88
+ },
89
+
90
90
  entity: {
91
91
  required: true,
92
92
  type: String
93
93
  },
94
94
 
95
+ error: {
96
+ type: Boolean
97
+ },
98
+
95
99
  errorMessage: {
96
100
  default: '',
97
101
  type: String
98
102
  },
99
103
 
100
- hint: {
101
- default: '',
102
- type: String
104
+ fields: {
105
+ default: () => ({}),
106
+ type: Object
107
+ },
108
+
109
+ formGeneratorProps: {
110
+ default: () => ({}),
111
+ type: Object
112
+ },
113
+
114
+ galleryCardProps: {
115
+ type: Object,
116
+ default: () => ({})
117
+ },
118
+
119
+ gridGeneratorProps: {
120
+ default: () => ({}),
121
+ type: Object
122
+ },
123
+
124
+ label: {
125
+ type: String,
126
+ default: ''
103
127
  },
104
128
 
105
129
  maxFiles: {
@@ -107,35 +131,40 @@ export default {
107
131
  type: Number
108
132
  },
109
133
 
134
+ modelValue: {
135
+ default: '',
136
+ type: [String, Array, Object]
137
+ },
138
+
110
139
  picaResizeOptions: {
111
140
  default: () => ({}),
112
141
  type: Object
113
142
  },
114
143
 
144
+ readonly: {
145
+ type: Boolean
146
+ },
147
+
115
148
  sizeLimit: {
116
149
  default: 1280,
117
150
  type: Number
118
151
  },
119
152
 
120
- useResize: {
121
- default: true,
153
+ uploading: {
122
154
  type: Boolean
123
155
  },
124
156
 
125
- readonly: {
157
+ useDownload: {
158
+ default: true,
126
159
  type: Boolean
127
160
  },
128
161
 
129
- modelValue: {
130
- default: '',
131
- type: [Array, String]
132
- },
133
-
134
- uploading: {
162
+ useObjectModel: {
135
163
  type: Boolean
136
164
  },
137
165
 
138
- useObjectModel: {
166
+ useResize: {
167
+ default: true,
139
168
  type: Boolean
140
169
  }
141
170
  },
@@ -144,66 +173,130 @@ export default {
144
173
 
145
174
  data () {
146
175
  return {
147
- isFetching: false,
148
- isUploading: false,
176
+ hasError: false,
149
177
  hiddenInputElement: null,
178
+ savedFiles: {},
150
179
  uploader: null
151
180
  }
152
181
  },
153
182
 
154
183
  computed: {
155
- self () {
156
- return this
184
+ attributes () {
185
+ return this.$attrs
157
186
  },
158
187
 
159
- uploaderClasses () {
160
- return this.hasCustomUpload ? 'hidden' : 'fit'
188
+ columnClasses () {
189
+ const irregularClasses = ['col']
190
+ const columns = this.defaultColumns
191
+
192
+ const classes = []
193
+
194
+ const profiles = {
195
+ col: 'col',
196
+ xs: 'col-xs',
197
+ sm: 'col-sm',
198
+ md: 'col-md',
199
+ lg: 'col-lg',
200
+ xl: 'col-xl'
201
+ }
202
+
203
+ for (const key in columns) {
204
+ const column = columns[key]
205
+
206
+ if (irregularClasses.includes(column)) {
207
+ classes.push(profiles[key])
208
+ continue
209
+ }
210
+
211
+ classes.push(`${profiles[key]}-${column}`)
212
+ }
213
+
214
+ return classes
161
215
  },
162
216
 
163
- showAddFile () {
164
- if (this.readonly) return
217
+ defaultColumns () {
218
+ return {
219
+ ...(this.isMultiple ? { col: 12, sm: 6, md: 4, lg: 3 } : { col: 12, sm: 6 }),
220
+ ...this.columns
221
+ }
222
+ },
223
+
224
+ defaultPicaResizeOptions () {
225
+ return {
226
+ unsharpAmount: 160,
227
+ unsharpRadius: 0.6,
228
+ unsharpThreshold: 1,
229
+ ...this.picaResizeOptions
230
+ }
231
+ },
165
232
 
166
- return this.maxFiles ? this.modelValue.length < this.maxFiles : true
233
+ defaultUploaderGalleryCardProps () {
234
+ const {
235
+ fields,
236
+ formGeneratorProps,
237
+ galleryCardProps,
238
+ gridGeneratorProps,
239
+ useDownload,
240
+ useObjectModel,
241
+ dialogProps
242
+ } = this.$props
243
+
244
+ return {
245
+ dialogProps,
246
+ fields,
247
+ formGeneratorProps,
248
+ galleryCardProps,
249
+ gridGeneratorProps,
250
+ useDownload,
251
+ useObjectModel,
252
+
253
+ useMultiple: this.isMultiple
254
+ }
167
255
  },
168
256
 
169
- isMultiple () {
170
- return this.$attrs.multiple || this.$attrs.multiple === ''
257
+ hasAddFile () {
258
+ if (this.readonly) return
259
+
260
+ const modelLength = this.useObjectModel
261
+ ? Object.keys(this.modelValue).length
262
+ : this.modelValue?.length
263
+
264
+ return this.maxFiles && this.isMultiple ? modelLength < this.maxFiles : true
171
265
  },
172
266
 
173
267
  hasCustomUpload () {
174
268
  return this.$slots['custom-upload']
175
269
  },
176
270
 
177
- itemClass () {
178
- return this.isMultiple ? 'col-12 col-md-3 col-sm-4' : 'col-12'
179
- },
180
-
181
- hintValue () {
182
- return this.hint || undefined
271
+ hasGalleryCardSection () {
272
+ return (
273
+ (this.useObjectModel ? !!Object.keys(this.modelValue).length : !!this.modelValue?.length) || this.hasError
274
+ )
183
275
  },
184
276
 
185
277
  hasHeaderSlot () {
186
278
  return this.$slots.header
187
279
  },
188
280
 
189
- hasErrorMessage () {
190
- return !!this.errorMessage.length
281
+ isMultiple () {
282
+ return this.$attrs.multiple || this.$attrs.multiple === ''
191
283
  },
192
284
 
193
- attributes () {
285
+ labelProps () {
194
286
  return {
195
- ...this.$attrs,
196
- ...this.$props
287
+ label: this.label,
288
+ margin: 'none',
289
+
290
+ ...(this.error && { color: 'negative' })
197
291
  }
198
292
  },
199
293
 
200
- defaultPicaResizeOptions () {
201
- return {
202
- unsharpAmount: 160,
203
- unsharpRadius: 0.6,
204
- unsharpThreshold: 1,
205
- ...this.picaResizeOptions
206
- }
294
+ self () {
295
+ return this
296
+ },
297
+
298
+ uploaderClasses () {
299
+ return this.hasCustomUpload ? 'hidden' : 'fit'
207
300
  }
208
301
  },
209
302
 
@@ -212,20 +305,46 @@ export default {
212
305
  this.uploader = this.$refs.uploader
213
306
 
214
307
  this.hiddenInputElement?.addEventListener?.('change', this.addFiles)
308
+
309
+ if (this.useObjectModel) {
310
+ window.addEventListener('submit-success', this.handleSubmitSuccess)
311
+ }
215
312
  },
216
313
 
217
314
  unmounted () {
218
315
  this.hiddenInputElement?.removeEventListener?.('change', this.addFiles)
316
+
317
+ if (this.useObjectModel) {
318
+ window.removeEventListener('submit-success', this.handleSubmitSuccess)
319
+ }
219
320
  },
220
321
 
221
322
  methods: {
323
+ async addFiles () {
324
+ const filesList = Array.from(this.hiddenInputElement.files)
325
+ const processedFiles = []
326
+
327
+ this.$refs.hiddenInput.value = ''
328
+
329
+ filesList.forEach(file => processedFiles.push(this.resizeImage(file)))
330
+
331
+ this.uploader.addFiles(await Promise.all(processedFiles))
332
+ },
333
+
334
+ dispatchUpload () {
335
+ this.$refs.buttonCleanFiles.$el.click()
336
+ this.hiddenInputElement.click()
337
+ },
338
+
222
339
  async factory ([file]) {
223
340
  if (!this.isMultiple && !this.hasHeaderSlot) {
224
341
  this.$refs.buttonCleanFiles.$el.click()
225
342
  }
226
343
 
227
344
  const name = `${uid()}.${file.name.split('.').pop()}`
228
- const { endpoint } = await this.fetchCredentials(name)
345
+ const { endpoint } = await this.fetchCredentials(name) || {}
346
+
347
+ if (!endpoint) return
229
348
 
230
349
  return {
231
350
  headers: [
@@ -238,80 +357,22 @@ export default {
238
357
  },
239
358
 
240
359
  factoryFailed () {
241
- this.updateUploading(false)
242
- NotifyError('Ops! Erro ao enviar o arquivo.')
243
- },
244
-
245
- dispatchUpload () {
246
- this.$refs.buttonCleanFiles.$el.click()
247
- this.hiddenInputElement.click()
248
- },
249
-
250
- uploaded (response) {
251
- const fullPath = response.xhr.responseURL.split('?').shift()
252
-
253
- const objectValue = {
254
- format: response.files[0].type,
255
- url: fullPath,
256
- name: response.files[0].name
257
- }
258
-
259
- const model = this.useObjectModel ? objectValue : fullPath
260
-
261
- this.$emit('update:modelValue', this.isMultiple ? [...this.modelValue, model] : model || '')
360
+ this.hasError = true
262
361
 
263
362
  this.updateUploading(false)
264
363
 
265
- this.$qas.logger.group('QasUploader - uploaded', [this.modelValue])
364
+ NotifyError('Falha ao carregar arquivo.')
266
365
  },
267
366
 
268
367
  async fetchCredentials (filename) {
269
- this.isFetching = true
270
-
271
368
  try {
272
369
  const { data } = await this.$axios.post('/upload-credentials/', {
273
370
  entity: this.entity,
274
371
  filename
275
372
  })
276
373
 
277
- this.$qas.logger.group(
278
- 'QasUploader - fetchCredentials -> resposta de /upload-credentials/',
279
- [data]
280
- )
281
-
282
374
  return data
283
- } finally {
284
- this.isFetching = false
285
- }
286
- },
287
-
288
- removeItem (index, scope, file) {
289
- if (file.isUploaded) {
290
- scope.removeFile(scope.files[file.indexToDelete])
291
- }
292
-
293
- if (file.isFailed) return
294
-
295
- if (!this.isMultiple) {
296
- return this.$emit('update:modelValue')
297
- }
298
-
299
- const clonedValue = extend(true, [], this.modelValue)
300
- const numberIndex = this.modelValue.findIndex(file => {
301
- if (this.useObjectModel) {
302
- return file.uuid === index || file.url.includes(index)
303
- }
304
-
305
- return this.getFileName(file) === index
306
- })
307
-
308
- clonedValue.splice(numberIndex, 1)
309
-
310
- this.$emit('update:modelValue', clonedValue)
311
- },
312
-
313
- getFileName (value) {
314
- return value.split('/').pop()
375
+ } catch {}
315
376
  },
316
377
 
317
378
  getFilesList (uploadedFiles) {
@@ -320,8 +381,6 @@ export default {
320
381
  isUploaded: true,
321
382
  url: file.xhr ? file.xhr.responseURL.split('?').shift() : '',
322
383
  name: file.name,
323
- progressLabel: file.__progressLabel,
324
- sizeLabel: file.__sizeLabel,
325
384
  indexToDelete,
326
385
  isFailed: this.isFailed(file)
327
386
  }
@@ -332,7 +391,6 @@ export default {
332
391
  : (this.modelValue ? [this.modelValue] : [])
333
392
 
334
393
  const mergedList = [...pathsList, ...uploadedFiles]
335
-
336
394
  const files = {}
337
395
 
338
396
  mergedList.forEach(file => {
@@ -358,31 +416,72 @@ export default {
358
416
  }
359
417
  })
360
418
 
361
- this.$qas.logger.group('QasUploader - getFilesList', [files])
362
-
363
419
  return files
364
420
  },
365
421
 
366
- getFileNameClass (isFailed) {
367
- return isFailed ? 'text-negative' : 'text-grey-9'
422
+ getFileName (value) {
423
+ return value.split('/').pop()
424
+ },
425
+
426
+ getModelValue (index) {
427
+ if (!this.useObjectModel) return {}
428
+
429
+ return this.isMultiple ? this.modelValue[index] || {} : this.modelValue
430
+ },
431
+
432
+ getUploaderGalleryCardProps ({ index, key, file, scope }) {
433
+ const modelValue = this.getModelValue(index)
434
+
435
+ return {
436
+ ...this.defaultUploaderGalleryCardProps,
437
+
438
+ currentModelValue: modelValue,
439
+ file,
440
+ fileKey: key,
441
+ savedFiles: this.savedFiles,
442
+
443
+ // eventos
444
+ onRemove: () => this.removeFile(key, scope, file),
445
+ onUpdateModel: value => this.updateModelValue({ index, payload: value })
446
+ }
447
+ },
448
+
449
+ handleSubmitSuccess ({ detail: { entity } }) {
450
+ if (entity === this.entity) this.setSavedFiles()
368
451
  },
369
452
 
370
453
  isFailed (file) {
371
454
  return file.__status === 'failed'
372
455
  },
373
456
 
374
- getColorFileIcon (file) {
375
- return this.isFailed(file) ? 'negative' : 'white'
457
+ onAddButtonClick (scope) {
458
+ return this.addButtonFn ? this.addButtonFn(scope) : this.$refs.hiddenInput.click()
376
459
  },
377
460
 
378
- async addFiles () {
379
- const filesList = Array.from(this.hiddenInputElement.files)
380
- const processedFiles = []
461
+ removeFile (key, scope, file) {
462
+ if (file.isUploaded) {
463
+ scope.removeFile(scope.files[file.indexToDelete])
464
+ }
381
465
 
382
- this.$refs.hiddenInput.value = ''
466
+ if (file.isFailed) return
383
467
 
384
- filesList.forEach(file => processedFiles.push(this.resizeImage(file)))
385
- this.uploader.addFiles(await Promise.all(processedFiles))
468
+ if (!this.isMultiple) {
469
+ return this.$emit('update:modelValue')
470
+ }
471
+
472
+ const clonedValue = extend(true, [], this.modelValue)
473
+
474
+ const numberIndex = this.modelValue.findIndex(file => {
475
+ if (this.useObjectModel) {
476
+ return file.uuid === key || file.url.includes(key)
477
+ }
478
+
479
+ return this.getFileName(file) === key
480
+ })
481
+
482
+ clonedValue.splice(numberIndex, 1)
483
+
484
+ this.$emit('update:modelValue', clonedValue)
386
485
  },
387
486
 
388
487
  // Função para redimensionar imagens
@@ -400,12 +499,8 @@ export default {
400
499
  // Retorna largura e altura da original da imagem
401
500
  const { width, height } = await getImageSize(image)
402
501
 
502
+ // Tamanho da imagem menor que o tamanho limite, sendo assim, não faz o resize
403
503
  if (width <= this.sizeLimit) {
404
- this.$qas.logger.info(`
405
- QasUploader - resizeImage -> Tamanho da imagem menor que o tamanho limite,
406
- sendo assim, não faz o resize
407
- `)
408
-
409
504
  return file
410
505
  }
411
506
 
@@ -427,8 +522,6 @@ export default {
427
522
 
428
523
  const newFile = new File([blob], file.name, { type })
429
524
 
430
- this.$qas.logger.group('QasUploader - resizeImage -> nova imagem', [newFile])
431
-
432
525
  return newFile
433
526
  } catch {
434
527
  // Caso não consiga redimensionar retorna o arquivo original
@@ -436,8 +529,59 @@ export default {
436
529
  }
437
530
  },
438
531
 
532
+ setSavedFiles () {
533
+ if (this.isMultiple) {
534
+ this.modelValue.forEach(model => {
535
+ const fileName = this.getFileName(model.url)
536
+
537
+ this.savedFiles[fileName] = true
538
+ })
539
+
540
+ return
541
+ }
542
+
543
+ const fileName = this.getFileName(this.modelValue.url)
544
+
545
+ this.savedFiles[fileName] = true
546
+ },
547
+
548
+ updateModelValue ({ index, payload = {} }) {
549
+ if (!this.useObjectModel) return
550
+
551
+ if (this.isMultiple) {
552
+ const modelValue = [...this.modelValue]
553
+ const value = modelValue[index]
554
+
555
+ modelValue[index] = { ...value, ...payload }
556
+
557
+ this.$emit('update:modelValue', modelValue)
558
+
559
+ return
560
+ }
561
+
562
+ this.$emit('update:modelValue', { ...this.modelValue, ...payload })
563
+ },
564
+
439
565
  updateUploading (uploading) {
440
566
  this.$emit('update:uploading', uploading)
567
+ },
568
+
569
+ uploaded (response) {
570
+ this.hasError = false
571
+
572
+ const fullPath = response.xhr.responseURL.split('?').shift()
573
+
574
+ const objectValue = {
575
+ format: response.files[0].type,
576
+ url: fullPath,
577
+ name: response.files[0].name
578
+ }
579
+
580
+ const model = this.useObjectModel ? objectValue : fullPath
581
+
582
+ this.$emit('update:modelValue', this.isMultiple ? [...this.modelValue, model] : model || '')
583
+
584
+ this.updateUploading(false)
441
585
  }
442
586
  }
443
587
  }
@@ -448,5 +592,23 @@ export default {
448
592
  &__input {
449
593
  display: none;
450
594
  }
595
+
596
+ .q-uploader {
597
+ max-height: 100%;
598
+
599
+ &__header {
600
+ background-color: transparent;
601
+ color: $grey-9;
602
+ }
603
+
604
+ &__list {
605
+ min-height: 0;
606
+ padding: 0;
607
+
608
+ &.scroll {
609
+ overflow: unset;
610
+ }
611
+ }
612
+ }
451
613
  }
452
614
  </style>