@bildvitta/quasar-ui-asteroid 3.17.0-beta.2 → 3.17.0-beta.21

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 (51) hide show
  1. package/package.json +2 -2
  2. package/src/assets/sounds/nave-notification.mp3 +0 -0
  3. package/src/components/actions/QasActions.vue +1 -1
  4. package/src/components/app-menu/QasAppMenu.vue +6 -1
  5. package/src/components/avatar/QasAvatar.vue +7 -8
  6. package/src/components/board-generator/QasBoardGenerator.vue +407 -40
  7. package/src/components/board-generator/QasBoardGenerator.yml +53 -12
  8. package/src/components/btn-dropdown/QasBtnDropdown.vue +14 -1
  9. package/src/components/card/QasCard.vue +13 -4
  10. package/src/components/chart-view/QasChartView.vue +44 -20
  11. package/src/components/chart-view/QasChartView.yml +10 -0
  12. package/src/components/checkbox/QasCheckbox.vue +30 -9
  13. package/src/components/checkbox/QasCheckbox.yml +5 -0
  14. package/src/components/copy/QasCopy.vue +12 -2
  15. package/src/components/copy/QasCopy.yml +8 -0
  16. package/src/components/date-time-input/QasDateTimeInput.vue +1 -1
  17. package/src/components/dialog/QasDialog.vue +3 -3
  18. package/src/components/expansion-item/QasExpansionItem.vue +120 -34
  19. package/src/components/expansion-item/QasExpansionItem.yml +38 -5
  20. package/src/components/filters/QasFilters.vue +1 -1
  21. package/src/components/filters/private/PvFiltersButton.vue +1 -1
  22. package/src/components/form-generator/QasFormGenerator.vue +39 -27
  23. package/src/components/form-generator/QasFormGenerator.yml +3 -0
  24. package/src/components/grabbable/QasGrabbable.vue +14 -6
  25. package/src/components/grabbable/QasGrabbable.yml +4 -0
  26. package/src/components/grid-generator/QasGridGenerator.vue +67 -34
  27. package/src/components/grid-generator/QasGridGenerator.yml +15 -0
  28. package/src/components/header/QasHeader.vue +58 -12
  29. package/src/components/header/QasHeader.yml +5 -0
  30. package/src/components/infinite-scroll/QasInfiniteScroll.vue +16 -17
  31. package/src/components/infinite-scroll/QasInfiniteScroll.yml +7 -0
  32. package/src/components/list-items/QasListItems.vue +28 -4
  33. package/src/components/list-items/QasListItems.yml +10 -0
  34. package/src/components/list-view/QasListView.vue +17 -5
  35. package/src/components/list-view/QasListView.yml +9 -0
  36. package/src/components/nested-fields/QasNestedFields.vue +91 -36
  37. package/src/components/nested-fields/QasNestedFields.yml +23 -0
  38. package/src/components/radio/QasRadio.vue +24 -5
  39. package/src/components/radio/QasRadio.yml +6 -0
  40. package/src/components/select/QasSelect.vue +129 -5
  41. package/src/components/select/QasSelect.yml +11 -0
  42. package/src/components/stepper-form-view/QasStepperFormView.yml +1 -1
  43. package/src/components/table-generator/QasTableGenerator.vue +10 -1
  44. package/src/components/text-truncate/QasTextTruncate.vue +11 -4
  45. package/src/components/text-truncate/QasTextTruncate.yml +4 -0
  46. package/src/composables/private/use-generator.js +3 -9
  47. package/src/composables/use-notifications.js +14 -0
  48. package/src/css/components/field.scss +13 -6
  49. package/src/css/components/item.scss +5 -1
  50. package/src/enums/Spacing.js +33 -0
  51. package/src/helpers/set-scroll-on-grab.js +9 -1
@@ -2,24 +2,20 @@
2
2
  <div :id="fieldName" class="qas-nested-fields" :data-cy="`nested-fields-${fieldName}`">
3
3
  <component :is="containerComponent">
4
4
  <div v-if="useSingleLabel" class="text-left">
5
- <qas-label :label="fieldLabel" typography="h5" />
5
+ <qas-label :label="fieldLabel" />
6
6
  </div>
7
7
 
8
8
  <div ref="inputContent">
9
9
  <component :is="componentTag" v-bind="componentProps">
10
10
  <template v-for="(row, index) in nested" :key="`row-${index}`">
11
11
  <div v-if="!row[destroyKey]" :id="`row-${index}`" class="full-width qas-nested-fields__field-item" data-cy="nested-fields-item">
12
- <header v-if="hasHeader" class="flex items-center q-pb-md" :class="headerClasses">
13
- <qas-label v-if="!useSingleLabel" :label="getRowLabel(index)" margin="none" typography="h5" />
14
-
15
- <qas-actions-menu v-if="hasBlockActions(row)" v-bind="getActionsMenuProps(index, row)" :use-label="false" />
16
- </header>
12
+ <qas-header v-if="hasHeader({ row })" class="flex" v-bind="getHeaderProps({ index, row })" />
17
13
 
18
14
  <slot :errors="transformedErrors" :fields="getFields(index, row)" :index="index" :model="nested[index]" name="before-fields" :update-value="updateValuesFromInput" />
19
15
 
20
- <div ref="formGenerator" class="col-12 justify-between q-col-gutter-x-md row">
16
+ <div ref="formGenerator" :class="formGeneratorParentClasses">
21
17
  <slot :errors="transformedErrors" :fields="getFields(index, row)" :index="index" name="fields" :update-value="updateValuesFromInput">
22
- <qas-form-generator v-model="nested[index]" class="col" :columns="formColumns" :disable="isDisabledRow(row)" :errors="transformedErrors[index]" :fields="getFields(index, row)" :fields-props="getFieldsProps(index, row)" :gutter="formGutter" @update:model-value="updateValuesFromInput($event, index)">
18
+ <qas-form-generator v-model="nested[index]" class="col" :columns="formColumns" :common-columns="formCommonColumns" :disable="isDisabledRow(row)" :errors="transformedErrors[index]" :fields="getFields(index, row)" :fields-props="getFieldsProps(index, row)" :gutter="formGutter" @update:model-value="updateValuesFromInput($event, index)">
23
19
  <template v-for="(slot, key) in $slots" #[key]="scope">
24
20
  <slot v-bind="scope" :disabled="isDisabledRow(row)" :errors="transformedErrors" :index="index" :name="key" />
25
21
  </template>
@@ -27,7 +23,7 @@
27
23
  </slot>
28
24
 
29
25
  <div v-if="hasInlineActions(row)" class="flex items-center qas-nested-fields__actions">
30
- <qas-actions-menu v-bind="getActionsMenuProps(index, row)" :use-label="false" />
26
+ <qas-actions-menu v-bind="getInlineActionsMenuProps(index, row)" :use-label="false" />
31
27
  </div>
32
28
  </div>
33
29
 
@@ -36,7 +32,7 @@
36
32
  </template>
37
33
  </component>
38
34
 
39
- <div v-if="useAdd">
35
+ <div v-if="useAdd" :class="addButtonClass">
40
36
  <slot :add="add" name="add-input">
41
37
  <div v-if="showAddFirstInputButton" class="text-left">
42
38
  <qas-btn class="q-px-sm" color="primary" data-cy="nested-fields-add-btn" :label="addFirstInputLabel" variant="tertiary" @click="add()" />
@@ -70,7 +66,7 @@ import QasInput from '../input/QasInput.vue'
70
66
  import QasLabel from '../label/QasLabel.vue'
71
67
 
72
68
  import { constructObject } from '../../helpers'
73
- import { Spacing } from '../../enums/Spacing'
69
+ import { Spacing, SpacingWithNumber } from '../../enums/Spacing'
74
70
 
75
71
  import { TransitionGroup } from 'vue'
76
72
  import debug from 'debug'
@@ -167,12 +163,22 @@ export default {
167
163
  default: () => []
168
164
  },
169
165
 
166
+ formCommonColumns: {
167
+ type: [Object, String],
168
+ default: () => ({})
169
+ },
170
+
170
171
  formGutter: {
171
- default: Spacing.Lg,
172
+ default: Spacing.Md,
172
173
  type: [String, Boolean],
173
174
  validator: value => typeof value === 'boolean' || Object.values(Spacing).includes(value)
174
175
  },
175
176
 
177
+ headerProps: {
178
+ type: Function,
179
+ default: () => {}
180
+ },
181
+
176
182
  identifierItemKey: {
177
183
  type: String,
178
184
  default: 'uuid'
@@ -296,15 +302,14 @@ export default {
296
302
  return this.useFirstInputButton && !this.nested.length
297
303
  },
298
304
 
299
- hasHeader () {
300
- return (this.useSingleLabel && !this.useInlineActions) || !this.useSingleLabel
301
- },
302
-
303
- headerClasses () {
305
+ addButtonClass () {
304
306
  return {
305
- 'justify-end': this.useSingleLabel,
306
- 'justify-between': !this.useSingleLabel
307
+ 'q-mt-md': !!this.nested.length
307
308
  }
309
+ },
310
+
311
+ formGeneratorParentClasses () {
312
+ return this.useInlineActions ? 'col-12 justify-between q-col-gutter-x-md row' : 'full-width'
308
313
  }
309
314
  },
310
315
 
@@ -333,8 +338,8 @@ export default {
333
338
  },
334
339
 
335
340
  methods: {
336
- getActionsMenuProps (index, row) {
337
- if (typeof this.actionsMenuProps === 'function') {
341
+ getInlineActionsMenuProps (index, row) {
342
+ if (typeof this.actionsMenuProps === 'function' && this.useInlineActions) {
338
343
  return this.actionsMenuProps({
339
344
  index,
340
345
  row,
@@ -344,7 +349,7 @@ export default {
344
349
 
345
350
  return {
346
351
  ...this.actionsMenuProps,
347
- list: this.getActionsMenuList(index, row)
352
+ list: this.getActionsMenuList(index, row, this.actionsMenuProps?.list)
348
353
  }
349
354
  },
350
355
 
@@ -368,11 +373,11 @@ export default {
368
373
  return list
369
374
  },
370
375
 
371
- getActionsMenuList (index, row) {
376
+ getActionsMenuList (index, row, defaultList = {}) {
372
377
  const list = this.getDefaultActionsMenuList(index, row)
373
378
 
374
- for (const key in this.actionsMenuProps.list) {
375
- const { handler, ...content } = this.actionsMenuProps.list[key] || {}
379
+ for (const key in defaultList) {
380
+ const { handler, ...content } = defaultList[key] || {}
376
381
 
377
382
  list[key] = {
378
383
  handler: payload => handler?.({ payload, row, index }),
@@ -456,14 +461,32 @@ export default {
456
461
 
457
462
  setScroll () {
458
463
  const elements = this.$refs.inputContent.children
464
+
465
+ // elemento de ação, e não das linhas (rows) de inputs
459
466
  const element = elements[elements.length - 1]
467
+
468
+ // ultima linha (rows) de inputs
469
+ const rowsElement = elements[0]?.children
470
+
471
+ // pegamos a posição do elemento de ação
460
472
  const { top } = element.getBoundingClientRect()
461
- const pageOffset = window.pageYOffset
462
473
 
463
- window.scrollTo({
464
- behavior: 'smooth',
465
- top: pageOffset + top
466
- })
474
+ // pegamos a altura da ultima linha (rows) de inputs
475
+ const lastRowHeight = rowsElement?.[rowsElement.length - 1]?.clientHeight
476
+
477
+ // pegamos a posição da página
478
+ const pageOffset = window.scrollY
479
+
480
+ // 56 é a altura do header no mobile
481
+ const safeScrollSize = this.$qas.screen.isSmall ? 56 + SpacingWithNumber.Lg : SpacingWithNumber.Lg
482
+
483
+ /**
484
+ * É necessário descontar a altura da última linha (rows) de inputs para que o scroll
485
+ * fique no final da última linha (rows) de inputs.
486
+ */
487
+ const scrollTop = pageOffset + top - (lastRowHeight + safeScrollSize)
488
+
489
+ window.scrollTo({ behavior: 'smooth', top: scrollTop })
467
490
  },
468
491
 
469
492
  async setFocus () {
@@ -507,6 +530,41 @@ export default {
507
530
 
508
531
  hasInlineActions (row) {
509
532
  return this.useInlineActions && !this.isDisabledRow(row)
533
+ },
534
+
535
+ hasHeader ({ row }) {
536
+ return this.hasBlockActions(row) || !this.useSingleLabel
537
+ },
538
+
539
+ getHeaderProps ({ index, row }) {
540
+ const hasLabel = !this.useSingleLabel
541
+ const hasActions = this.hasBlockActions(row)
542
+
543
+ const { labelProps, actionsMenuProps, ...payload } = this.headerProps?.({ index, row }) || {}
544
+
545
+ return {
546
+ ...payload,
547
+
548
+ spacing: 'sm',
549
+
550
+ ...(hasActions && {
551
+ actionsMenuProps: {
552
+ useLabel: false,
553
+
554
+ ...actionsMenuProps,
555
+
556
+ list: this.getActionsMenuList(index, row, actionsMenuProps?.list)
557
+ }
558
+ }),
559
+
560
+ ...(hasLabel && {
561
+ labelProps: {
562
+ typography: 'h5',
563
+ label: this.getRowLabel(index),
564
+ ...labelProps
565
+ }
566
+ })
567
+ }
510
568
  }
511
569
  }
512
570
  }
@@ -514,16 +572,13 @@ export default {
514
572
 
515
573
  <style lang="scss">
516
574
  .qas-nested-fields {
575
+ // mesmo tamanho do input
517
576
  &__actions {
518
- height: 56px;
519
- }
520
-
521
- &__field-item {
522
- margin-bottom: var(--qas-spacing-md);
577
+ height: 40px;
523
578
  }
524
579
 
525
580
  &__field-item + &__field-item {
526
- margin-top: var(--qas-spacing-xl);
581
+ margin-top: var(--qas-spacing-lg);
527
582
  }
528
583
  }
529
584
  </style>
@@ -74,12 +74,34 @@ props:
74
74
  type: [Array, String, Object]
75
75
  examples: ["[{ sm: 6, md: 12 }]", "{ name: { sm: 6, md: 12 } }", "12"]
76
76
 
77
+ form-common-columns:
78
+ desc: Colunas do grid comuns.
79
+ default: {}
80
+ type: [String, Object]
81
+ examples: ["{ col: 12, sm: 6}" , "12"]
82
+
77
83
  form-gutter:
78
84
  desc: Espaçamento entre colunas do formulário.
79
85
  default: lg
80
86
  type: [String, Boolean]
81
87
  examples: [xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, false]
82
88
 
89
+ header-props:
90
+ desc: Propriedades do header do nested por linha por callback.
91
+ default: () => {}
92
+ type: Function
93
+ params:
94
+ context:
95
+ desc: Payload da linha (row) -> index/row.
96
+ type: Object
97
+ params:
98
+ index:
99
+ desc: Índice da linha.
100
+ type: Number
101
+ row:
102
+ desc: Valores contendo na linha atual.
103
+ type: Object
104
+
83
105
  identifier-item-key:
84
106
  desc: Define um identificador para o item. O identificador será utilizado para validar exclusão do item, por exemplo.
85
107
  default: uuid
@@ -251,6 +273,7 @@ slots:
251
273
  type: Function
252
274
  examples: ["updateValue({ name: 'novo valor' }, 2)"]
253
275
 
276
+
254
277
  events:
255
278
  '@update:model-value -> function (value)':
256
279
  desc: Dispara toda vez que o model é atualizado, também utilizado para v-model.
@@ -1,5 +1,11 @@
1
1
  <template>
2
- <component :is="component.is" v-bind="component.props" />
2
+ <div>
3
+ <div v-if="canShowOptionGroupLabel" class="q-mb-sm text-body1">
4
+ {{ props.label }}
5
+ </div>
6
+
7
+ <component :is="component.is" v-bind="component.props" />
8
+ </div>
3
9
  </template>
4
10
 
5
11
  <script setup>
@@ -10,8 +16,20 @@ defineOptions({
10
16
  inheritAttrs: false
11
17
  })
12
18
 
19
+ const props = defineProps({
20
+ label: {
21
+ default: '',
22
+ type: String
23
+ }
24
+ })
25
+
13
26
  const attrs = useAttrs()
14
27
 
28
+ const isOptionGroup = computed(() => !!attrs.options?.length)
29
+
30
+ // Só mostra a label caso for q-option-group e tenha label vindo nas props
31
+ const canShowOptionGroupLabel = computed(() => isOptionGroup.value && !!props.label)
32
+
15
33
  /**
16
34
  * - quando é um grupo de opções, o componente é 'QOptionGroup', caso contrário,
17
35
  * é 'QRadio'.
@@ -19,16 +37,17 @@ const attrs = useAttrs()
19
37
  * - todos os casos é usado o dense.
20
38
  */
21
39
  const component = computed(() => {
22
- const isOptionGroup = !!attrs.options?.length
23
-
24
40
  const { inline = true, ...payloadProps } = attrs
25
41
 
26
42
  return {
27
- is: isOptionGroup ? 'q-option-group' : 'q-radio',
43
+ is: isOptionGroup.value ? 'q-option-group' : 'q-radio',
44
+
28
45
  props: {
29
46
  ...payloadProps,
30
47
 
31
- ...(isOptionGroup && {
48
+ label: props.label,
49
+
50
+ ...(isOptionGroup.value && {
32
51
  inline,
33
52
  class: {
34
53
  'q-gutter-x-md': inline,
@@ -1,5 +1,11 @@
1
1
  type: component
2
2
 
3
+ props:
4
+ label:
5
+ desc: Label utilizada em casos de ser q-option-group.
6
+ default: ''
7
+ type: String
8
+
3
9
  meta:
4
10
  desc: Componente wrapper do QRadio.
5
11
 
@@ -1,7 +1,7 @@
1
1
  <template>
2
- <q-select v-model="model" v-bind="attributes" class="qas-select" :class="componentClasses" no-error-icon :outlined="false">
3
- <template v-if="isSearchable" #prepend>
4
- <q-icon name="sym_r_search" />
2
+ <q-select v-model="model" v-bind="attributes" class="qas-select" :class="componentClasses" no-error-icon>
3
+ <template v-if="hasIcon" #prepend>
4
+ <q-icon :name="defaultIcon" />
5
5
  </template>
6
6
 
7
7
  <template #no-option>
@@ -30,6 +30,34 @@
30
30
  </qas-badge>
31
31
  </template>
32
32
 
33
+ <template v-if="useCustomOptions" #option="scope">
34
+ <q-item v-bind="scope.itemProps" class="qas-select__option">
35
+ <q-item-section>
36
+ <div class="items-center q-gutter-x-sm row">
37
+ <q-item-label>
38
+ {{ scope.opt.label }}
39
+ </q-item-label>
40
+
41
+ <div v-for="(badge, index) in getFilteredBadgeList(scope.opt)" :key="index">
42
+ <qas-badge v-if="hasBadge(badge)" v-bind="getBadgeProps(badge)" />
43
+ </div>
44
+ </div>
45
+
46
+ <div v-if="scope.opt.caption">
47
+ <div class="items-center q-col-gutter-x-sm row">
48
+ <q-item-label v-for="(caption, index) in getCaptionArray(scope.opt.caption)" :key="index" caption class="items-center q-mt-xs row">
49
+ <div>
50
+ {{ caption }}
51
+ </div>
52
+
53
+ <q-separator v-if="hasSeparator({ caption: getCaptionArray(scope.opt.caption), index })" class="q-ml-sm" vertical />
54
+ </q-item-label>
55
+ </div>
56
+ </div>
57
+ </q-item-section>
58
+ </q-item>
59
+ </template>
60
+
33
61
  <template v-for="(_, name) in $slots" #[name]="context">
34
62
  <slot :name="name" v-bind="context || {}" />
35
63
  </template>
@@ -49,12 +77,27 @@ export default {
49
77
 
50
78
  mixins: [searchFilterMixin],
51
79
 
80
+ inject: {
81
+ isBox: { default: false },
82
+ isDialog: { default: false }
83
+ },
84
+
52
85
  props: {
86
+ badgeProps: {
87
+ default: () => ({}),
88
+ type: Object
89
+ },
90
+
53
91
  fuseOptions: {
54
92
  default: () => ({}),
55
93
  type: Object
56
94
  },
57
95
 
96
+ icon: {
97
+ type: String,
98
+ default: ''
99
+ },
100
+
58
101
  label: {
59
102
  type: String,
60
103
  default: ''
@@ -83,6 +126,10 @@ export default {
83
126
  type: Boolean
84
127
  },
85
128
 
129
+ useCustomOptions: {
130
+ type: Boolean
131
+ },
132
+
86
133
  useFetchOptionsOnCreate: {
87
134
  default: true,
88
135
  type: Boolean
@@ -95,6 +142,10 @@ export default {
95
142
  useSearch: {
96
143
  type: Boolean,
97
144
  default: undefined
145
+ },
146
+
147
+ useFilterMode: {
148
+ type: Boolean
98
149
  }
99
150
  },
100
151
 
@@ -113,7 +164,7 @@ export default {
113
164
  clearable: this.isSearchable,
114
165
  emitValue: true,
115
166
  mapOptions: true,
116
- outlined: true,
167
+ outlined: this.useFilterMode,
117
168
  dense: true,
118
169
  dropdownIcon: 'sym_r_expand_more',
119
170
  clearIcon: 'sym_r_close',
@@ -151,6 +202,10 @@ export default {
151
202
  return this.hasFuse || this.useLazyLoading
152
203
  },
153
204
 
205
+ isBordered () {
206
+ return (this.isBox || this.isDialog) && this.useFilterMode
207
+ },
208
+
154
209
  hasError () {
155
210
  return this.mx_hasFetchError || this.$attrs.error
156
211
  },
@@ -198,7 +253,13 @@ export default {
198
253
  // redesign
199
254
  componentClasses () {
200
255
  return {
201
- 'qas-select--has-icon': this.isSearchable || this.hasAppend,
256
+ ...(this.useFilterMode && {
257
+ 'qas-select--filter rounded-borders': true,
258
+ 'shadow-2': !this.isBordered,
259
+ bordered: this.isBordered
260
+ }),
261
+
262
+ 'qas-select--has-icon': this.hasAppend || this.hasIcon,
202
263
  'qas-select--closed': !this.isPopupContentOpen,
203
264
  'qas-select--loading': this.hasLoading
204
265
  }
@@ -214,6 +275,14 @@ export default {
214
275
 
215
276
  hasAppend () {
216
277
  return !!this.$slots.append
278
+ },
279
+
280
+ defaultIcon () {
281
+ return this.icon || 'sym_r_search'
282
+ },
283
+
284
+ hasIcon () {
285
+ return this.isSearchable || !!this.icon
217
286
  }
218
287
  },
219
288
 
@@ -328,6 +397,51 @@ export default {
328
397
  : this.options[0]
329
398
 
330
399
  this.$emit('update:modelValue', modelValue)
400
+ },
401
+
402
+ getFilteredBadgeList (payload = {}) {
403
+ const { label, value, disable, caption, ...rest } = payload
404
+
405
+ const badgeList = []
406
+
407
+ /**
408
+ * Exemplo de estrutura percorrida:
409
+ *
410
+ * @example
411
+ * {
412
+ * isTester: true,
413
+ * isOwner: false
414
+ * }
415
+ */
416
+ for (const [key, val] of Object.entries(rest)) {
417
+ if (key in this.badgeProps) {
418
+ badgeList.push({ [key]: val })
419
+ }
420
+ }
421
+
422
+ return badgeList
423
+ },
424
+
425
+ getBadgeProps (badge) {
426
+ const model = Object.keys(badge)[0]
427
+
428
+ const isFunction = typeof this.badgeProps[model] === 'function'
429
+
430
+ return isFunction ? this.badgeProps[model](badge[model]).props : this.badgeProps[model]
431
+ },
432
+
433
+ hasBadge (badge) {
434
+ const model = Object.keys(badge)[0]
435
+
436
+ return badge[model] || this.badgeProps[model](badge[model]).show
437
+ },
438
+
439
+ getCaptionArray (caption) {
440
+ return Array.isArray(caption) ? caption : [caption]
441
+ },
442
+
443
+ hasSeparator ({ caption, index }) {
444
+ return index !== caption.length - 1
331
445
  }
332
446
  }
333
447
  }
@@ -347,12 +461,22 @@ export default {
347
461
  }
348
462
  }
349
463
 
464
+ &--filter {
465
+ .q-field__control:before {
466
+ border: 0;
467
+ }
468
+ }
469
+
350
470
  &__menu {
351
471
  .q-item {
352
472
  font-weight: 400 !important;
353
473
  }
354
474
  }
355
475
 
476
+ &__option:hover .q-item__label--caption {
477
+ color: var(--q-primary);
478
+ }
479
+
356
480
  &--closed {
357
481
  .q-field__native span {
358
482
  white-space: nowrap;
@@ -7,6 +7,12 @@ meta:
7
7
  desc: Componente para select que implementa o "QSelect" repassando propriedades, slots e eventos.
8
8
 
9
9
  props:
10
+ badge-list:
11
+ desc: Configuração das badges no qual cada key é um callback com o valor booleano retornado pelo back.
12
+ default: {}
13
+ examples: ["{ isTester: () => { return { color: 'grey-8', label: 'Tester', textColor: 'white' }} }"]
14
+ type: Object
15
+
10
16
  entity:
11
17
  desc: Entidade enviada para a action "fetchFieldOptions" (usar somente quando "useLazyLoading" estiver habilitada).
12
18
  default: ''
@@ -29,6 +35,11 @@ props:
29
35
  keys: [label, value]
30
36
  threshold: 0.4
31
37
 
38
+ icon:
39
+ desc: Ícone da esquerda.
40
+ type: String
41
+ default: ''
42
+
32
43
  label:
33
44
  desc: Label do componente.
34
45
  type: String
@@ -17,7 +17,7 @@ props:
17
17
  desc: Propriedades que serão repassadas para o QasStepper.
18
18
  type: Object
19
19
 
20
- inject:
20
+ provide:
21
21
  stepper-model:
22
22
  desc: Model do stepper caso precise recuperar o step atual para alguma lógica. Possui reatividade, portanto para acessar é necessário do ".value"
23
23
  type: Number
@@ -4,7 +4,7 @@
4
4
  <qas-header v-if="hasHeaderProps" v-bind="headerProps" />
5
5
  </slot>
6
6
 
7
- <q-table ref="table" class="bg-white qas-table-generator text-grey-8" v-bind="attributes">
7
+ <q-table v-show="hasResults" ref="table" class="bg-white qas-table-generator text-grey-8" v-bind="attributes">
8
8
  <template v-for="(_, name) in slots" #[name]="context">
9
9
  <slot :name="name" v-bind="context" />
10
10
  </template>
@@ -19,6 +19,8 @@
19
19
  </q-td>
20
20
  </template>
21
21
  </q-table>
22
+
23
+ <qas-empty-result-text v-if="!hasResults" />
22
24
  </component>
23
25
  </template>
24
26
 
@@ -130,8 +132,15 @@ export default {
130
132
  return !!this.$slots['body-cell']
131
133
  },
132
134
 
135
+ hasResults () {
136
+ return !!this.resultsByFields.length
137
+ },
138
+
133
139
  attributes () {
134
140
  const attributes = {
141
+ tableClass: {
142
+ 'overflow-hidden-y': !this.useStickyHeader
143
+ },
135
144
  class: this.tableClass,
136
145
  columns: this.columnsByFields,
137
146
  flat: true,
@@ -2,7 +2,7 @@
2
2
  <div ref="parent" :class="classes">
3
3
  <div class="no-wrap row text-no-wrap">
4
4
  <div ref="truncate" class="ellipsis">
5
- <slot>{{ displayText }}</slot>
5
+ <slot>{{ formattedText }}</slot>
6
6
  </div>
7
7
 
8
8
  <qas-btn v-if="hasButton" class="q-ml-sm" :label="buttonLabel" @click.stop.prevent="toggle" />
@@ -87,6 +87,11 @@ const props = defineProps({
87
87
 
88
88
  useObjectList: {
89
89
  type: Boolean
90
+ },
91
+
92
+ emptyText: {
93
+ type: String,
94
+ default: '-'
90
95
  }
91
96
  })
92
97
 
@@ -119,6 +124,8 @@ useMutationObserver({ truncate, callbackFn: truncateText })
119
124
 
120
125
  const classes = computed(() => [`text-${props.color}`, `text-${props.typography}`])
121
126
 
127
+ const formattedText = computed(() => props.list.length || props.text ? displayText.value : props.emptyText)
128
+
122
129
  // composable functions
123
130
  function useDialog ({ props, textContent }) {
124
131
  // reactive vars
@@ -141,7 +148,7 @@ function useDialog ({ props, textContent }) {
141
148
  }
142
149
  })
143
150
 
144
- // methods
151
+ // functions
145
152
  function toggle () {
146
153
  show.value = !show.value
147
154
  }
@@ -163,7 +170,7 @@ function useMutationObserver ({ truncate, callbackFn = () => {} }) {
163
170
  onMounted(() => observeContentChange())
164
171
  onUnmounted(() => observer.value.disconnect())
165
172
 
166
- // methods
173
+ // functions
167
174
  function observeContentChange () {
168
175
  const config = { childList: true, subtree: true, characterData: true }
169
176
 
@@ -190,7 +197,7 @@ function useTruncate ({ parent, props }) {
190
197
  // computed
191
198
  const isTruncated = computed(() => textWidth.value > maxPossibleWidth.value)
192
199
 
193
- // methods
200
+ // functions
194
201
  function truncateText () {
195
202
  parent.value.style.maxWidth = '100%'
196
203
  textWidth.value = truncate.value.clientWidth