@bildvitta/quasar-ui-asteroid 3.8.0-beta.1 → 3.8.0-beta.3

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
  }
@@ -6,34 +6,32 @@
6
6
 
7
7
  <div ref="inputContent">
8
8
  <component :is="componentTag" v-bind="componentProps">
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">
11
- <div>
12
- <div class="flex items-center justify-between q-py-md">
13
- <qas-label v-if="!useSingleLabel" :label="getRowLabel(index)" />
14
- <qas-actions-menu v-if="hasBlockActions(row)" v-bind="actionsMenuProps" :list="getActionsList(index, row)" />
15
- </div>
16
-
17
- <div ref="formGenerator" class="col-12 justify-between q-col-gutter-x-md row">
18
- <slot :errors="transformedErrors" :fields="children" :index="index" name="fields" :update-value="updateValuesFromInput">
19
- <qas-form-generator v-model="nested[index]" :class="formClasses" :columns="formColumns" :disable="isDisabledRow(row)" :errors="transformedErrors[index]" :fields="children" :fields-props="fieldsProps" @update:model-value="updateValuesFromInput($event, index)">
20
- <template v-for="(slot, key) in $slots" #[key]="scope">
21
- <slot v-bind="scope" :disabled="isDisabledRow(row)" :errors="transformedErrors" :index="index" :name="key" />
22
- </template>
23
- </qas-form-generator>
24
- </slot>
25
-
26
- <div v-if="hasInlineActions(row)" class="flex items-center qas-nested-fields__actions">
27
- <qas-actions-menu v-bind="actionsMenuProps" :list="getActionsList(index, row)" />
28
- </div>
9
+ <template v-for="(row, index) in nested" :key="`row-${index}`">
10
+ <div v-if="!row[destroyKey]" :id="`row-${index}`" class="full-width q-mt-md">
11
+ <header class="flex items-center q-py-md" :class="headerClasses">
12
+ <qas-label v-if="!useSingleLabel" :label="getRowLabel(index)" />
13
+ <qas-actions-menu v-if="hasBlockActions(row)" v-bind="actionsMenuProps" :list="getActionsList(index, row)" />
14
+ </header>
15
+
16
+ <div ref="formGenerator" class="col-12 justify-between q-col-gutter-x-md row">
17
+ <slot :errors="transformedErrors" :fields="children" :index="index" name="fields" :update-value="updateValuesFromInput">
18
+ <qas-form-generator v-model="nested[index]" :class="formClasses" :columns="formColumns" :disable="isDisabledRow(row)" :errors="transformedErrors[index]" :fields="children" :fields-props="fieldsProps" @update:model-value="updateValuesFromInput($event, index)">
19
+ <template v-for="(slot, key) in $slots" #[key]="scope">
20
+ <slot v-bind="scope" :disabled="isDisabledRow(row)" :errors="transformedErrors" :index="index" :name="key" />
21
+ </template>
22
+ </qas-form-generator>
23
+ </slot>
24
+
25
+ <div v-if="hasInlineActions(row)" class="flex items-center qas-nested-fields__actions">
26
+ <qas-actions-menu v-bind="actionsMenuProps" :list="getActionsList(index, row)" />
29
27
  </div>
28
+ </div>
30
29
 
31
- <div class="col-12">
32
- <slot :fields="children" :index="index" :model="nested[index]" name="custom-fields" :update-value="updateValuesFromInput" />
33
- </div>
30
+ <div class="col-12">
31
+ <slot :fields="children" :index="index" :model="nested[index]" name="custom-fields" :update-value="updateValuesFromInput" />
34
32
  </div>
35
33
  </div>
36
- </div>
34
+ </template>
37
35
  </component>
38
36
 
39
37
  <div v-if="useAdd" class="q-mt-md">
@@ -68,9 +66,9 @@ import QasFormGenerator from '../form-generator/QasFormGenerator.vue'
68
66
  import QasInput from '../input/QasInput.vue'
69
67
  import QasLabel from '../label/QasLabel.vue'
70
68
  import { TransitionGroup } from 'vue'
69
+ import { extend } from 'quasar'
71
70
 
72
71
  import { constructObject } from '../../helpers'
73
- import { extend } from 'quasar'
74
72
 
75
73
  export default {
76
74
  name: 'QasNestedFields',
@@ -290,6 +288,10 @@ export default {
290
288
 
291
289
  showAddFirstInputButton () {
292
290
  return this.useFirstInputButton && !this.nested.length
291
+ },
292
+
293
+ headerClasses () {
294
+ return this.useSingleLabel ? 'justify-end' : 'justify-between'
293
295
  }
294
296
  },
295
297
 
@@ -364,18 +366,7 @@ export default {
364
366
 
365
367
  this.$qas.logger.group('QasNestedFields - add', [payload])
366
368
 
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)
369
+ this.updateModelValue()
379
370
  },
380
371
 
381
372
  /*
@@ -393,13 +384,17 @@ export default {
393
384
 
394
385
  this.$qas.logger.group('QasNestedFields - destroy', [{ index, row }])
395
386
 
396
- return this.updateModelValue()
387
+ this.updateModelValue()
388
+ },
389
+
390
+ updateModelValue () {
391
+ this.$emit('update:modelValue', this.nested)
397
392
  },
398
393
 
399
394
  updateValuesFromInput (value, index) {
400
395
  this.nested.splice(index, 1, value)
401
396
 
402
- return this.updateModelValue(null, index)
397
+ this.updateModelValue()
403
398
  },
404
399
 
405
400
  setDefaultNestedValue () {
@@ -419,9 +414,26 @@ export default {
419
414
  })
420
415
  },
421
416
 
422
- getRowLabel (rowKey) {
417
+ async setFocus () {
418
+ await this.$nextTick()
419
+
420
+ const { formGenerator } = this.$refs
421
+ const firstElementToBeFocused = formGenerator.pop().querySelector('input, select, textarea')
422
+
423
+ return firstElementToBeFocused?.focus && firstElementToBeFocused.focus()
424
+ },
425
+
426
+ getRealRowIndex (index) {
427
+ return [...this.nested].splice(0, index).filter(item => !item[this.destroyKey]).length
428
+ },
429
+
430
+ getRowLabel (rowIndex) {
423
431
  if (this.rowLabel) {
424
- return this.useIndexLabel ? `${this.rowLabel} ${rowKey + 1}` : this.rowLabel
432
+ if (!this.useIndexLabel) return this.rowLabel
433
+
434
+ const index = this.useRemoveOnDestroy ? rowIndex : this.getRealRowIndex(rowIndex)
435
+
436
+ return `${this.rowLabel} ${index + 1}`
425
437
  }
426
438
 
427
439
  return this.fieldLabel
@@ -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`.