@bildvitta/quasar-ui-asteroid 3.8.0-beta.1 → 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.
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="text-bold text-subtitle2" :class="labelClass">
2
+ <div class="text-subtitle2" :class="classes">
3
3
  <slot :label-with-suffix="labelWithSuffix">{{ labelWithSuffix }}</slot>
4
4
  </div>
5
5
  </template>
@@ -23,17 +23,30 @@ export default {
23
23
 
24
24
  margin: {
25
25
  default: 'sm',
26
- type: String
26
+ type: String,
27
+ validator: value => {
28
+ const marginList = ['none', 'auto', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl']
29
+
30
+ return marginList.includes(value)
31
+ }
32
+ },
33
+
34
+ color: {
35
+ type: String,
36
+ default: 'grey-9'
27
37
  }
28
38
  },
29
39
 
30
40
  computed: {
31
- labelClass () {
32
- return `q-mb-${this.margin}`
33
- },
34
-
35
41
  labelWithSuffix () {
36
42
  return addCounterSuffix(this.label, parseFloat(this.count))
43
+ },
44
+
45
+ classes () {
46
+ return [
47
+ `q-mb-${this.margin}`,
48
+ `text-${this.color}`
49
+ ]
37
50
  }
38
51
  }
39
52
  }
@@ -7,12 +7,12 @@
7
7
  <div ref="inputContent">
8
8
  <component :is="componentTag" v-bind="componentProps">
9
9
  <div v-for="(row, index) in nested" :id="`row-${index}`" :key="`row-${index}`" class="full-width">
10
- <div v-if="!row[destroyKey]" :key="index" class="col-12 q-mt-md">
10
+ <div :key="index" class="col-12 q-mt-md">
11
11
  <div>
12
- <div class="flex items-center justify-between q-py-md">
12
+ <header class="flex items-center q-py-md" :class="headerClasses">
13
13
  <qas-label v-if="!useSingleLabel" :label="getRowLabel(index)" />
14
14
  <qas-actions-menu v-if="hasBlockActions(row)" v-bind="actionsMenuProps" :list="getActionsList(index, row)" />
15
- </div>
15
+ </header>
16
16
 
17
17
  <div ref="formGenerator" class="col-12 justify-between q-col-gutter-x-md row">
18
18
  <slot :errors="transformedErrors" :fields="children" :index="index" name="fields" :update-value="updateValuesFromInput">
@@ -70,7 +70,6 @@ import QasLabel from '../label/QasLabel.vue'
70
70
  import { TransitionGroup } from 'vue'
71
71
 
72
72
  import { constructObject } from '../../helpers'
73
- import { extend } from 'quasar'
74
73
 
75
74
  export default {
76
75
  name: 'QasNestedFields',
@@ -242,7 +241,7 @@ export default {
242
241
 
243
242
  data () {
244
243
  return {
245
- nested: [],
244
+ destroyKeyList: {},
246
245
  hasDestroyAlways: true
247
246
  }
248
247
  },
@@ -290,18 +289,22 @@ export default {
290
289
 
291
290
  showAddFirstInputButton () {
292
291
  return this.useFirstInputButton && !this.nested.length
292
+ },
293
+
294
+ headerClasses () {
295
+ return this.useSingleLabel ? 'justify-end' : 'justify-between'
296
+ },
297
+
298
+ nested () {
299
+ return this.modelValue.filter(item => !item[this.destroyKey])
300
+ },
301
+
302
+ hasDestroyKeyList () {
303
+ return !!Object.keys(this.destroyKeyList).length
293
304
  }
294
305
  },
295
306
 
296
307
  watch: {
297
- modelValue: {
298
- handler (value) {
299
- this.nested = extend(true, [], value)
300
- },
301
- deep: true,
302
- immediate: true
303
- },
304
-
305
308
  rowObject: {
306
309
  handler () {
307
310
  this.setDefaultNestedValue()
@@ -364,18 +367,7 @@ export default {
364
367
 
365
368
  this.$qas.logger.group('QasNestedFields - add', [payload])
366
369
 
367
- return this.updateModelValue()
368
- },
369
-
370
- setFocus () {
371
- const { formGenerator } = this.$refs
372
- const firstElementToBeFocused = formGenerator.pop().querySelector('input, select, textarea')
373
-
374
- return firstElementToBeFocused?.focus && firstElementToBeFocused.focus()
375
- },
376
-
377
- updateModelValue (value) {
378
- return this.$emit('update:modelValue', value || this.nested)
370
+ this.updateModelValue()
379
371
  },
380
372
 
381
373
  /*
@@ -387,19 +379,35 @@ export default {
387
379
  * ao invés de adicionar a flag [destroyKey]
388
380
  */
389
381
  destroy (index, row) {
390
- !row[this.identifierItemKey] || this.useRemoveOnDestroy
391
- ? this.nested.splice(index, 1)
392
- : this.nested.splice(index, 1, { [this.destroyKey]: true, ...row })
382
+ const [removedRow] = this.nested.splice(index, 1)
383
+
384
+ if (!this.useRemoveOnDestroy && row[this.identifierItemKey]) {
385
+ this.destroyKeyList[row[this.identifierItemKey]] = { row: removedRow, index }
386
+ }
393
387
 
394
388
  this.$qas.logger.group('QasNestedFields - destroy', [{ index, row }])
395
389
 
396
- return this.updateModelValue()
390
+ this.updateModelValue()
391
+ },
392
+
393
+ updateModelValue () {
394
+ const nested = [...this.nested]
395
+
396
+ if (this.hasDestroyKeyList) {
397
+ for (const key in this.destroyKeyList) {
398
+ const { row, index } = this.destroyKeyList[key]
399
+
400
+ nested.splice(index, 0, { ...row, [this.destroyKey]: true })
401
+ }
402
+ }
403
+
404
+ this.$emit('update:modelValue', nested)
397
405
  },
398
406
 
399
407
  updateValuesFromInput (value, index) {
400
408
  this.nested.splice(index, 1, value)
401
409
 
402
- return this.updateModelValue(null, index)
410
+ return this.updateModelValue()
403
411
  },
404
412
 
405
413
  setDefaultNestedValue () {
@@ -419,6 +427,15 @@ export default {
419
427
  })
420
428
  },
421
429
 
430
+ async setFocus () {
431
+ await this.$nextTick()
432
+
433
+ const { formGenerator } = this.$refs
434
+ const firstElementToBeFocused = formGenerator.pop().querySelector('input, select, textarea')
435
+
436
+ return firstElementToBeFocused?.focus && firstElementToBeFocused.focus()
437
+ },
438
+
422
439
  getRowLabel (rowKey) {
423
440
  if (this.rowLabel) {
424
441
  return this.useIndexLabel ? `${this.rowLabel} ${rowKey + 1}` : this.rowLabel
@@ -1,19 +1,6 @@
1
1
  <template>
2
2
  <div>
3
- <qas-uploader ref="uploader" v-model="model" :label="uploadLabel" v-bind="$attrs" :readonly="readonly" :use-resize="false">
4
- <template #header="{ scope }">
5
- <div class="cursor-pointer flex flex-center full-width justify-between no-border no-wrap q-gutter-xs text-white transparent" :class="headerClass" @click="openDialog">
6
- <div class="col column items-start justify-center">
7
- <div v-if="uploadLabel" class="q-uploader__title">{{ uploadLabel }}</div>
8
- </div>
9
-
10
- <qas-btn v-if="!readonly" color="white" icon="sym_r_add" :use-hover-on-white-color="false" variant="tertiary" @click="openDialog" />
11
-
12
- <qas-btn ref="forceUpload" class="hidden" @click="upload(scope)" />
13
- <qas-btn ref="buttonCleanFiles" class="hidden" @click="scope.removeUploadedFiles" />
14
- </div>
15
- </template>
16
- </qas-uploader>
3
+ <qas-uploader ref="uploader" v-model="model" :add-button-fn="openDialog" :use-resize="false" v-bind="defaultUploaderProps" />
17
4
 
18
5
  <qas-dialog v-model="isOpenedDialog" v-bind="defaultDialogProps">
19
6
  <template #header>
@@ -30,7 +17,6 @@
30
17
  </template>
31
18
 
32
19
  <script>
33
- import QasBtn from '../btn/QasBtn.vue'
34
20
  import QasDialog from '../dialog/QasDialog.vue'
35
21
  import QasUploader from '../uploader/QasUploader.vue'
36
22
  import QasSignaturePad from '../signature-pad/QasSignaturePad.vue'
@@ -41,19 +27,20 @@ export default {
41
27
  name: 'QasSignatureUploader',
42
28
 
43
29
  components: {
44
- QasBtn,
45
30
  QasDialog,
46
31
  QasUploader,
47
32
  QasSignaturePad
48
33
  },
49
34
 
35
+ inheritAttrs: false,
36
+
50
37
  props: {
51
38
  dialogProps: {
52
39
  type: Object,
53
40
  default: () => ({})
54
41
  },
55
42
 
56
- uploadLabel: {
43
+ modelValue: {
57
44
  default: '',
58
45
  type: String
59
46
  },
@@ -63,18 +50,14 @@ export default {
63
50
  type: String
64
51
  },
65
52
 
66
- modelValue: {
67
- default: '',
68
- type: String
69
- },
70
-
71
53
  type: {
72
54
  default: 'image/png',
73
55
  type: String
74
56
  },
75
57
 
76
- readonly: {
77
- type: Boolean
58
+ uploaderProps: {
59
+ type: Object,
60
+ default: () => ({})
78
61
  }
79
62
  },
80
63
 
@@ -82,27 +65,20 @@ export default {
82
65
 
83
66
  data () {
84
67
  return {
85
- isOpenedDialog: false,
68
+ base64: '',
86
69
  isEmpty: true,
87
- base64: ''
70
+ isOpenedDialog: false
88
71
  }
89
72
  },
90
73
 
91
74
  computed: {
92
- model: {
93
- get () {
94
- return this.modelValue
95
- },
96
-
97
- set (value) {
98
- this.$emit('update:modelValue', value)
75
+ defaultUploaderProps () {
76
+ return {
77
+ addButtonLabel: 'Adicionar assinatura',
78
+ ...this.uploaderProps
99
79
  }
100
80
  },
101
81
 
102
- headerClass () {
103
- return `q-pa-${this.readonly ? 'md' : 'sm'}`
104
- },
105
-
106
82
  defaultDialogProps () {
107
83
  return {
108
84
  maxWidth: '620px',
@@ -114,13 +90,14 @@ export default {
114
90
  }
115
91
  },
116
92
 
117
- signaturePadWidth () {
118
- const sizes = {
119
- [this.$qas.screen.isSmall]: { width: '100%' },
120
- [this.$qas.screen.isMedium]: { width: '570px' },
121
- [this.$qas.screen.isLarge]: { width: '350px' }
93
+ model: {
94
+ get () {
95
+ return this.modelValue
96
+ },
97
+
98
+ set (value) {
99
+ this.$emit('update:modelValue', value)
122
100
  }
123
- return sizes.true
124
101
  },
125
102
 
126
103
  signaturePadHeight () {
@@ -131,12 +108,30 @@ export default {
131
108
  }
132
109
 
133
110
  return sizes.true
111
+ },
112
+
113
+ signaturePadWidth () {
114
+ const sizes = {
115
+ [this.$qas.screen.isSmall]: { width: '100%' },
116
+ [this.$qas.screen.isMedium]: { width: '570px' },
117
+ [this.$qas.screen.isLarge]: { width: '350px' }
118
+ }
119
+
120
+ return sizes.true
121
+ },
122
+
123
+ uploaderScope () {
124
+ return this.$refs?.uploader?.uploader
134
125
  }
135
126
  },
136
127
 
137
128
  methods: {
138
129
  NotifyError,
139
130
 
131
+ closeSignature () {
132
+ this.isOpenedDialog = false
133
+ },
134
+
140
135
  openDialog () {
141
136
  if (this.readonly) return
142
137
 
@@ -144,31 +139,24 @@ export default {
144
139
  },
145
140
 
146
141
  getSignatureData () {
147
- this.$refs.buttonCleanFiles.$el.click()
148
- this.base64 = this.$refs.signaturePadModal.getSignatureData()
149
- this.$refs.forceUpload.$el.click()
150
- this.closeSignature()
151
- },
142
+ this.uploaderScope.removeUploadedFiles()
152
143
 
153
- closeSignature () {
154
- this.isOpenedDialog = false
155
- },
144
+ this.base64 = this.$refs.signaturePadModal.getSignatureData()
156
145
 
157
- removeSignature () {
158
- this.$refs.buttonCleanFiles.$el.click()
159
- this.$emit('update:modelValue')
146
+ this.upload(this.uploaderScope)
147
+ this.closeSignature()
160
148
  },
161
149
 
162
- upload (scope) {
150
+ upload () {
163
151
  try {
164
152
  const fileName = this.signatureLabel.split(' ').join('-')
165
153
  const extension = this.type.split('/').pop() || 'png'
166
154
  const blob = base64ToBlob(this.base64)
167
155
  const file = new File([blob], `${fileName}.${extension}`, { type: this.type })
168
156
 
169
- scope.addFiles([file])
157
+ this.uploaderScope.addFiles([file])
170
158
  } catch {
171
- NotifyError('Ops! Erro ao enviar sua assinatura.')
159
+ NotifyError('Falha ao carregar assinatura.')
172
160
  }
173
161
  }
174
162
  }
@@ -13,11 +13,6 @@ props:
13
13
  desc: Model do componente, retorna url da imagem upada, usando para v-model.
14
14
  type: String
15
15
 
16
- readonly:
17
- desc: Controla se o componente vai ser apenas para visualização ou pode também fazer upload.
18
- default: image/png
19
- type: String
20
-
21
16
  signature-label:
22
17
  desc: Rótulo do componente de assinatura.
23
18
  default: {}
@@ -27,10 +22,11 @@ props:
27
22
  desc: Tipo da imagem gerada.
28
23
  default: image/png
29
24
  type: String
30
-
31
- upload-label:
32
- desc: Rótulo do uploader.
33
- type: String
25
+
26
+ uploader-props:
27
+ desc: Propriedades repassadas para o QasUploader.
28
+ default: {}
29
+ type: Object
34
30
 
35
31
  events:
36
32
  '@update:model-value -> function(value)':
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <qas-box class="q-px-lg q-py-md">
3
- <q-table ref="table" class="bg-white qas-table-generator text-grey-8" :class="tableClass" v-bind="attributes">
3
+ <q-table ref="table" class="bg-white qas-table-generator text-grey-8" v-bind="attributes">
4
4
  <template v-for="(_, name) in slots" #[name]="context">
5
5
  <slot :name="name" v-bind="context" />
6
6
  </template>
@@ -65,6 +65,15 @@ export default {
65
65
 
66
66
  useExternalLink: {
67
67
  type: Boolean
68
+ },
69
+
70
+ useStickyHeader: {
71
+ type: Boolean
72
+ },
73
+
74
+ stickyHeaderTableHeight: {
75
+ default: '528px',
76
+ type: String
68
77
  }
69
78
  },
70
79
 
@@ -110,12 +119,14 @@ export default {
110
119
 
111
120
  attributes () {
112
121
  const attributes = {
122
+ class: this.tableClass,
113
123
  columns: this.columnsByFields,
114
- rows: this.resultsByFields,
115
124
  flat: true,
116
125
  hideBottom: true,
117
126
  pagination: { rowsPerPage: 0 },
118
127
  rowKey: this.rowKey,
128
+ rows: this.resultsByFields,
129
+ style: this.tableStyle,
119
130
 
120
131
  // Eventos.
121
132
  onRowClick: this.$attrs.onRowClick && this.onRowClick
@@ -196,7 +207,16 @@ export default {
196
207
  },
197
208
 
198
209
  tableClass () {
199
- return this.$qas.screen.isSmall && 'qas-table-generator--mobile'
210
+ return {
211
+ 'qas-table-generator--mobile': this.$qas.screen.isSmall,
212
+ 'qas-table-generator--sticky-header': this.useStickyHeader
213
+ }
214
+ },
215
+
216
+ tableStyle () {
217
+ return {
218
+ maxHeight: this.useStickyHeader ? this.stickyHeaderTableHeight : 'initial'
219
+ }
200
220
  },
201
221
 
202
222
  hasScrollOnGrab () {
@@ -339,5 +359,21 @@ export default {
339
359
  margin-left: 10px;
340
360
  }
341
361
  }
362
+
363
+ &--sticky-header {
364
+ .q-table thead tr {
365
+ th {
366
+ position: sticky;
367
+ z-index: 1;
368
+ }
369
+
370
+ &:first-child {
371
+ th {
372
+ background-color: white;
373
+ top: 0;
374
+ }
375
+ }
376
+ }
377
+ }
342
378
  }
343
379
  </style>
@@ -46,6 +46,16 @@ props:
46
46
  default: false
47
47
  type: Boolean
48
48
 
49
+ use-sticky-header:
50
+ desc: Usado para manter o header da tabela (thead) fixo.
51
+ default: false
52
+ type: Boolean
53
+
54
+ sticky-header-table-height:
55
+ desc: Usado para definir a altura máxima da tabela e exibir o scroll vertical quando a propriedade "use-sticky-header" é utilizada.
56
+ default: 528px
57
+ type: String
58
+
49
59
  slots:
50
60
  body:
51
61
  desc: Acesso direto dentro do `tbody`.