@bildvitta/quasar-ui-asteroid 3.20.0-beta.2 → 3.20.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 (102) hide show
  1. package/package.json +3 -3
  2. package/src/asteroid.js +8 -1
  3. package/src/components/actions/QasActions.vue +12 -2
  4. package/src/components/actions-menu/QasActionsMenu.vue +18 -5
  5. package/src/components/alert/QasAlert.vue +89 -64
  6. package/src/components/app-user/QasAppUser.vue +2 -1
  7. package/src/components/board-generator/QasBoardGenerator.vue +883 -162
  8. package/src/components/board-generator/QasBoardGenerator.yml +83 -2
  9. package/src/components/board-generator/private/PvBoardGeneratorCardsContainer.vue +25 -0
  10. package/src/components/box/QasBox.vue +16 -3
  11. package/src/components/box/QasBox.yml +10 -0
  12. package/src/components/btn/QasBtn.vue +27 -5
  13. package/src/components/btn/QasBtn.yml +10 -1
  14. package/src/components/btn-dropdown/QasBtnDropdown.vue +13 -1
  15. package/src/components/card/QasCard.vue +97 -25
  16. package/src/components/card/QasCard.yml +10 -0
  17. package/src/components/card-image/QasCardImage.vue +10 -1
  18. package/src/components/card-image/QasCardImage.yml +5 -0
  19. package/src/components/chart-view/QasChartView.vue +4 -3
  20. package/src/components/chart-view/QasChartView.yml +5 -0
  21. package/src/components/checkbox/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  22. package/src/components/copy/QasCopy.vue +6 -1
  23. package/src/components/copy/QasCopy.yml +5 -0
  24. package/src/components/date-time-input/QasDateTimeInput.vue +30 -6
  25. package/src/components/dialog/QasDialog.vue +308 -91
  26. package/src/components/dialog/QasDialog.yml +51 -23
  27. package/src/components/dialog/composables/use-cancel.js +1 -1
  28. package/src/components/dialog/composables/use-dynamic-components.js +2 -2
  29. package/src/components/dialog/composables/use-ok.js +1 -0
  30. package/src/components/dialog-router/QasDialogRouter.vue +1 -1
  31. package/src/components/drawer/QasDrawer.vue +76 -26
  32. package/src/components/drawer/QasDrawer.yml +10 -0
  33. package/src/components/expansion-item/QasExpansionItem.yml +5 -0
  34. package/src/components/filters/QasFilters.vue +2 -1
  35. package/src/components/filters/private/PvFiltersActions.vue +79 -13
  36. package/src/components/form-generator/QasFormGenerator.vue +8 -1
  37. package/src/components/form-generator/QasFormGenerator.yml +10 -0
  38. package/src/components/form-view/QasFormView.vue +20 -11
  39. package/src/components/form-view/QasFormView.yml +6 -0
  40. package/src/components/gallery/composables/use-delete.js +2 -3
  41. package/src/components/gallery/private/PvGalleryCarouselDialog.vue +8 -7
  42. package/src/components/grid-item/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  43. package/src/components/header/QasHeader.vue +66 -11
  44. package/src/components/header/QasHeader.yml +16 -1
  45. package/src/components/infinite-scroll/QasInfiniteScroll.vue +1 -1
  46. package/src/components/label/QasLabel.vue +3 -1
  47. package/src/components/layout/QasLayout.vue +16 -1
  48. package/src/components/layout/private/PvLayoutNotificationsDrawer.vue +2 -1
  49. package/src/components/layout/private/PvLayoutOverlayDrawer.vue +4 -2
  50. package/src/components/lazy-loading-components/QasLazyLoadingComponents.vue +262 -0
  51. package/src/components/lazy-loading-components/QasLazyLoadingComponents.yml +49 -0
  52. package/src/components/list-view/QasListView.vue +12 -4
  53. package/src/components/list-view/QasListView.yml +12 -0
  54. package/src/components/page-header/QasPageHeader.vue +49 -3
  55. package/src/components/page-header/QasPageHeader.yml +5 -0
  56. package/src/components/router-link/QasRouterLink.vue +72 -0
  57. package/src/components/router-link/QasRouterLink.yml +24 -0
  58. package/src/components/search-box/QasSearchBox.vue +1 -1
  59. package/src/components/select/QasSelect.vue +8 -1
  60. package/src/components/select-list-dialog/QasSelectListDialog.vue +40 -20
  61. package/src/components/select-list-dialog/QasSelectListDialog.yml +14 -2
  62. package/src/components/signature-uploader/QasSignatureUploader.vue +5 -18
  63. package/src/components/single-view/QasSingleView.vue +2 -2
  64. package/src/components/skeleton/QasSkeleton.vue +139 -0
  65. package/src/components/skeleton/QasSkeleton.yml +48 -0
  66. package/src/components/sortable/QasSortable.vue +1 -1
  67. package/src/components/stepper/QasStepper.vue +24 -2
  68. package/src/components/table-generator/QasTableGenerator.vue +186 -35
  69. package/src/components/table-generator/QasTableGenerator.yml +6 -1
  70. package/src/components/tabs-generator/QasTabsGenerator.vue +14 -3
  71. package/src/components/tabs-generator/QasTabsGenerator.yml +5 -1
  72. package/src/components/text-truncate/QasTextTruncate.vue +61 -12
  73. package/src/components/text-truncate/QasTextTruncate.yml +5 -0
  74. package/src/components/toggle-visibility/QasToggleVisibility.vue +2 -1
  75. package/src/components/tooltip/QasTooltip.vue +6 -1
  76. package/src/components/tree-generator/QasTreeGenerator.vue +4 -6
  77. package/src/components/uploader/QasUploader.vue +12 -2
  78. package/src/composables/private/use-view.js +1 -1
  79. package/src/composables/use-overlay-navigation.js +116 -10
  80. package/src/composables/use-screen.js +17 -1
  81. package/src/css/components/button.scss +82 -3
  82. package/src/css/components/item.scss +6 -0
  83. package/src/css/utils/background.scss +5 -0
  84. package/src/css/utils/border.scss +6 -0
  85. package/src/css/utils/container.scss +4 -3
  86. package/src/css/utils/text.scss +9 -0
  87. package/src/helpers/copy-to-clipboard.js +2 -1
  88. package/src/helpers/filters.js +1 -1
  89. package/src/helpers/promise-handler.js +2 -1
  90. package/src/helpers/set-scroll-gradient.js +31 -8
  91. package/src/helpers/set-scroll-on-grab.js +10 -3
  92. package/src/index.scss +1 -0
  93. package/src/mixins/search-filter.js +7 -1
  94. package/src/plugins/delete/Delete.js +7 -9
  95. package/src/plugins/delete/Delete.yml +1 -1
  96. package/src/plugins/dialog/Dialog.yml +1 -1
  97. package/src/plugins/notify-error/NotifyError.yml +1 -1
  98. package/src/plugins/notify-success/NotifySuccess.yml +1 -1
  99. package/src/plugins/screen/Screen.js +17 -1
  100. package/src/plugins/screen/Screen.yml +5 -1
  101. package/src/vue-plugin.js +5 -7
  102. package/src/plugins/index.js +0 -5
@@ -5,29 +5,49 @@
5
5
  </slot>
6
6
 
7
7
  <q-table v-show="hasResults" ref="table" v-bind="attributes" v-model:selected="selectedModel" class="bg-white text-grey-8">
8
- <template v-for="(_, name) in slots" #[name]="context">
9
- <slot :name="name" v-bind="context" />
8
+ <template v-if="skeleton" #header-cell="props">
9
+ <q-th :props="props">
10
+ <qas-skeleton v-bind="getThSkeletonProps()" />
11
+ </q-th>
12
+ </template>
13
+
14
+ <template v-for="(column, index) in columnsWithTooltip" :key="index" #[`header-cell-${column.name}`]="context">
15
+ <q-th :props="context">
16
+ {{ context.col.label }}
17
+
18
+ <qas-tip class="q-pl-xs" :text="column.tooltip" />
19
+ </q-th>
10
20
  </template>
11
21
 
12
22
  <!-- Necessário para sobrescrever o QCheckbox e usar o QasCheckbox. -->
13
23
  <template #header-selection="props">
14
- <div class="qas-table-generator__cancel-mouse-target" data-table-ignore-tr-hover>
24
+ <qas-skeleton v-if="skeleton" type="QasCheckbox" />
25
+
26
+ <div v-else class="qas-table-generator__cancel-mouse-target" data-table-ignore-tr-hover>
15
27
  <qas-checkbox v-model="props.selected" />
16
28
  </div>
17
29
  </template>
18
30
 
19
31
  <!-- Necessário para sobrescrever o QCheckbox e usar o QasCheckbox. -->
20
32
  <template #body-selection="props">
21
- <div class="qas-table-generator__cancel-mouse-target" data-table-ignore-tr-hover>
33
+ <qas-skeleton v-if="skeleton" type="QasCheckbox" />
34
+
35
+ <div v-else class="qas-table-generator__cancel-mouse-target" data-table-ignore-tr-hover>
22
36
  <qas-checkbox v-model="props.selected" />
23
37
  </div>
24
38
  </template>
25
39
 
40
+ <template v-for="(_, name) in slots" #[name]="context">
41
+ <slot :name="name" v-bind="context" />
42
+ </template>
43
+
26
44
  <template v-for="(fieldName, index) in bodyCellNameSlots" :key="index" #[`body-cell-${fieldName}`]="context">
27
45
  <q-td :class="getTdClasses(context.row)">
28
- <component :is="tdChildComponent" class="qas-table-generator__td-item" v-bind="getTdChildComponentProps(context.row)">
46
+ <qas-skeleton v-if="skeleton" v-bind="getTgSkeletonProps(fieldName, context.row)" />
47
+
48
+ <component :is="tdChildComponent(context.row)" v-else class="qas-table-generator__td-item" v-bind="getTdChildComponentProps(context.row)">
29
49
  <slot :name="`body-cell-${fieldName}`" v-bind="context || {}">
30
- <pv-table-generator-td v-if="getFieldsProps(context.row, context.rowIndex)[fieldName]" :component-data="getFieldsProps(context.row, context.rowIndex)[fieldName]" :label="fields[fieldName]?.label" :name="fieldName" :row="context.row" />
50
+ <pv-table-generator-td v-if="getFieldsProps(context.row, context.rowIndex)[fieldName]" :component-data="getFieldsProps(context.row, context.rowIndex)[fieldName]" :label="normalizedFields[fieldName]?.label" :name="fieldName" :row="context.row" />
31
51
 
32
52
  <template v-else>
33
53
  {{ context.row?.[fieldName] }}
@@ -36,14 +56,6 @@
36
56
  </component>
37
57
  </q-td>
38
58
  </template>
39
-
40
- <template v-for="(column, index) in columnsWithTooltip" :key="index" #[`header-cell-${column.name}`]="context">
41
- <q-th :props="context">
42
- {{ context.col.label }}
43
-
44
- <qas-tip class="q-pl-xs" :text="column.tooltip" />
45
- </q-th>
46
- </template>
47
59
  </q-table>
48
60
 
49
61
  <qas-empty-result-text v-if="!hasResults" />
@@ -57,6 +69,7 @@ import QasCheckbox from '../checkbox/QasCheckbox.vue'
57
69
  import QasEmptyResultText from '../empty-result-text/QasEmptyResultText.vue'
58
70
  import QasHeader from '../header/QasHeader.vue'
59
71
  import QasTip from '../tip/QasTip.vue'
72
+ import QasSkeleton from '../skeleton/QasSkeleton.vue'
60
73
 
61
74
  import { isEmpty, humanize, setScrollOnGrab, setScrollGradient } from '../../helpers'
62
75
 
@@ -71,16 +84,26 @@ export default {
71
84
  QasEmptyResultText,
72
85
  QasHeader,
73
86
  QasCheckbox,
74
- QasTip
87
+ QasTip,
88
+ QasSkeleton
75
89
  },
76
90
 
77
91
  provide () {
78
92
  return {
93
+ isTableGenerator: true,
94
+
79
95
  /**
80
96
  * @see QasBtn.vue - Injetando os valores padrões para o QasBtn.
81
97
  */
82
98
  btnPropsDefaults: {
83
99
  size: 'sm'
100
+ },
101
+
102
+ /**
103
+ * @see QasTextTruncate.vue - Injetando os valores padrões para o QasTextTruncate.
104
+ */
105
+ textTruncatePropsDefaults: {
106
+ typography: 'body2'
84
107
  }
85
108
  }
86
109
  },
@@ -142,6 +165,10 @@ export default {
142
165
  type: Array
143
166
  },
144
167
 
168
+ skeleton: {
169
+ type: Boolean
170
+ },
171
+
145
172
  useBox: {
146
173
  type: Boolean,
147
174
  default: true
@@ -190,10 +217,49 @@ export default {
190
217
  },
191
218
 
192
219
  computed: {
193
- tdChildComponent () {
194
- if (this.useExternalLink) return 'a'
220
+ normalizedFields () {
221
+ if (this.skeleton) {
222
+ const fields = {}
223
+
224
+ this.normalizedColumns.forEach(column => {
225
+ const columnName = column?.name || column
226
+
227
+ fields[columnName] = {
228
+ name: columnName,
229
+ label: columnName.charAt(0).toUpperCase() + columnName.slice(1),
230
+ type: 'text'
231
+ }
232
+ })
233
+
234
+ return fields
235
+ }
236
+
237
+ return this.fields
238
+ },
239
+
240
+ /**
241
+ * Caso esteja em skeleton, retorna uma lista de resultados vazios com a mesma estrutura das colunas.
242
+ * Isso é necessário para que o QasTableGenerator renderize as linhas de skeleton corretamente.
243
+ * Cada resultado terá chaves correspondentes aos nomes das colunas, todas com valores vazios.
244
+ */
245
+ normalizedResults () {
246
+ if (this.skeleton) {
247
+ return Array.from({ length: 24 }).map(() => {
248
+ const result = {}
249
+
250
+ this.normalizedColumns.forEach(column => {
251
+ const columnName = column?.name || column
195
252
 
196
- return this.rowRouteFn ? 'router-link' : 'span'
253
+ result[columnName] = ''
254
+ })
255
+
256
+ result.default = result
257
+
258
+ return result
259
+ })
260
+ }
261
+
262
+ return this.results
197
263
  },
198
264
 
199
265
  bodyCellNameSlots () {
@@ -201,7 +267,7 @@ export default {
201
267
 
202
268
  return this.normalizedColumns.length
203
269
  ? this.normalizedColumns.map(column => typeof column === 'object' ? column.name : column)
204
- : Object.keys(this.fields)
270
+ : Object.keys(this.normalizedFields)
205
271
  },
206
272
 
207
273
  slots () {
@@ -273,8 +339,8 @@ export default {
273
339
 
274
340
  // Automatic columns.
275
341
  if (!this.normalizedColumns.length) {
276
- for (const index in this.fields) {
277
- columnByField(this.fields[index])
342
+ for (const index in this.normalizedFields) {
343
+ columnByField(this.normalizedFields[index])
278
344
  }
279
345
 
280
346
  return columns
@@ -284,9 +350,9 @@ export default {
284
350
  this.normalizedColumns.forEach(column => {
285
351
  if (column instanceof Object) {
286
352
  // repassa as props e mergeia com as do field
287
- columnByField({ ...column, ...this.fields[column.name] })
288
- } else if (this.fields[column]) {
289
- columnByField(this.fields[column])
353
+ columnByField({ ...column, ...this.normalizedFields[column.name] })
354
+ } else if (this.normalizedFields[column]) {
355
+ columnByField(this.normalizedFields[column])
290
356
  }
291
357
  })
292
358
 
@@ -305,17 +371,23 @@ export default {
305
371
  },
306
372
 
307
373
  columnsWithTooltip () {
374
+ // quando estiver em skeleton, não precisa processar as colunas com tooltip
375
+ if (this.skeleton) return []
376
+
308
377
  return this.normalizedColumns.filter(column => column.tooltip)
309
378
  },
310
379
 
311
380
  hasFields () {
312
- return Object.keys(this.fields).length
381
+ return Object.keys(this.normalizedFields).length
313
382
  },
314
383
 
315
384
  resultsByFields () {
316
- if (!Object.keys(this.fields).length) return []
385
+ if (!Object.keys(this.normalizedFields).length) return []
317
386
 
318
- const results = extend(true, [], this.results)
387
+ // Validação necessária para evitar processamento sem necessidade quando estiver em skeleton.
388
+ if (this.skeleton) return this.normalizedResults
389
+
390
+ const results = extend(true, [], this.normalizedResults)
319
391
 
320
392
  const mappedResults = results.map((result, index) => {
321
393
  for (const key in result) {
@@ -323,10 +395,10 @@ export default {
323
395
  continue
324
396
  }
325
397
 
326
- const humanizedResult = humanize(this.fields[key], result[key])
398
+ const humanizedResult = humanize(this.normalizedFields[key], result[key])
327
399
  const formattedResult = isEmpty({ value: humanizedResult }) ? this.emptyResultText : humanizedResult
328
400
 
329
- result.default = this.results[index]
401
+ result.default = this.normalizedResults[index]
330
402
  result[key] = formattedResult
331
403
  }
332
404
 
@@ -337,7 +409,7 @@ export default {
337
409
  },
338
410
 
339
411
  rowsPerPage () {
340
- return this.results.length
412
+ return this.normalizedResults.length
341
413
  },
342
414
 
343
415
  tableClasses () {
@@ -498,18 +570,28 @@ export default {
498
570
  this.resizeObserver.unobserve(this.elementToObserve)
499
571
  },
500
572
 
501
- getTdClasses (row) {
573
+ /**
574
+ * Valida se o valor retornado para a row é um route.
575
+ *
576
+ * @param {Object} row - Objeto referente ao row da tabela.
577
+ *
578
+ * @returns {boolean}
579
+ */
580
+ hasRowRoute (row) {
502
581
  const routePayload = this.rowRouteFn?.(row)
503
582
  const isRoutePayloadObject = typeof routePayload === 'object'
504
- const hasRoutePayload = isRoutePayloadObject ? !!Object.keys(routePayload).length : !!routePayload
505
583
 
584
+ return isRoutePayloadObject ? !!Object.keys(routePayload).length : !!routePayload
585
+ },
586
+
587
+ getTdClasses (row) {
506
588
  return {
507
- 'qas-table-generator__td--has-action': this.hasRowClick || hasRoutePayload
589
+ 'qas-table-generator__td--has-action': this.hasRowRoute(row)
508
590
  }
509
591
  },
510
592
 
511
593
  getTdChildComponentProps (row) {
512
- if (!this.rowRouteFn) return
594
+ if (!this.hasRowRoute(row) || this.skeleton) return
513
595
 
514
596
  return {
515
597
  class: [
@@ -527,9 +609,17 @@ export default {
527
609
  },
528
610
 
529
611
  onRowClick () {
612
+ if (this.skeleton) return
613
+
530
614
  this.$attrs.onRowClick(...arguments)
531
615
  },
532
616
 
617
+ tdChildComponent (row) {
618
+ if (this.useExternalLink) return 'a'
619
+
620
+ return this.hasRowRoute(row) ? 'router-link' : 'span'
621
+ },
622
+
533
623
  getFieldsProps (row, index) {
534
624
  const isFieldsPropsFunction = typeof this.fieldsProps === 'function'
535
625
 
@@ -547,6 +637,62 @@ export default {
547
637
  }
548
638
  })
549
639
  }
640
+ },
641
+
642
+ /**
643
+ * Retorna propriedades para o componente QasSkeleton usado nas células do QasTableGenerator
644
+ *
645
+ * @param {string} column - nome da coluna
646
+ * @param {Object} row - dados da linha
647
+ */
648
+ getTgSkeletonProps (column, row) {
649
+ const normalizedFieldsProps = typeof this.fieldsProps === 'function'
650
+ ? this.fieldsProps(row)
651
+ : this.fieldsProps || {}
652
+
653
+ const columnFieldProps = normalizedFieldsProps[column]
654
+
655
+ const min = 100
656
+ const max = 160
657
+
658
+ // Gera uma largura aleatória entre min e max entre 100 e 160 pixels
659
+ const width = Math.floor(Math.random() * (max - min + 1)) + min
660
+
661
+ const isActions = column === 'actions'
662
+
663
+ // Define o tipo do skeleton baseado na configuração da coluna
664
+ const type = (
665
+ (isActions ? 'QasActionsMenu' : undefined) ||
666
+ columnFieldProps?.component ||
667
+ (this.useMultiline ? undefined : 'text')
668
+ )
669
+
670
+ return {
671
+ type,
672
+
673
+ // se for multiline e não for actions, define a altura do skeleton
674
+ height: this.useMultiline && !isActions ? '68px' : undefined,
675
+
676
+ // Define a largura do skeleton
677
+ width: columnFieldProps?.component || isActions ? undefined : `${width + 20}px`
678
+ }
679
+ },
680
+
681
+ /**
682
+ * Retorna propriedades para o componente QasSkeleton usado nos cabeçalhos do QasTableGenerator
683
+ */
684
+ getThSkeletonProps () {
685
+ const min = 60
686
+ const max = 120
687
+
688
+ // Gera uma largura aleatória entre min e max entre 60 e 120 pixels
689
+ const width = Math.floor(Math.random() * (max - min + 1)) + min
690
+
691
+ return {
692
+ type: 'text',
693
+ useContrast: true,
694
+ width: `${width}px`
695
+ }
550
696
  }
551
697
  }
552
698
  }
@@ -577,10 +723,11 @@ export default {
577
723
  }
578
724
  }
579
725
 
726
+ line-height: 100% !important;
580
727
  padding-bottom: var(--qas-spacing-sm);;
581
728
  padding-left: 0;
582
- padding-top: 0;
583
729
  padding-right: var(--qas-spacing-md);
730
+ padding-top: 0;
584
731
  }
585
732
 
586
733
  td,
@@ -601,6 +748,10 @@ export default {
601
748
  z-index: 0;
602
749
  padding-right: var(--qas-spacing-md);
603
750
 
751
+ * {
752
+ line-height: 100% !important;
753
+ }
754
+
604
755
  &::before {
605
756
  position: absolute;
606
757
  content: '';
@@ -70,7 +70,7 @@ props:
70
70
  row-route-fn:
71
71
  desc: Usado quando há a necessidade de alteração de rota ao clicar em um item da tabela(a linha passa ser um <a> habilitando a opção de abrir em uma nova aba).
72
72
  type: Function
73
- examples: ["(row) => ({ path: 'table-generator', params: { id: row.uuid } })"]
73
+ examples: ["row => ({ path: 'table-generator', params: { id: row.uuid } })", "row => undefined", "row => {}"]
74
74
 
75
75
  selected:
76
76
  desc: Usado como model das linhas selecionadas.
@@ -79,6 +79,11 @@ props:
79
79
  model: true
80
80
  examples: ["['uuid1', 'uuid2']"]
81
81
 
82
+ skeleton:
83
+ desc: Exibe um esqueleto de carregamento no lugar do conteúdo.
84
+ default: false
85
+ type: Boolean
86
+
82
87
  use-box:
83
88
  desc: Controla se o componente vai usar QasBox ou div.
84
89
  default: true
@@ -6,10 +6,16 @@
6
6
  <slot :item="tab" :name="`tab-after-${tab.value}`">
7
7
  <q-icon v-if="tab.icon" :name="tab.icon" size="sm" />
8
8
 
9
- <qas-status v-if="tab.status" :color="tab.status" />
9
+ <div v-if="tab.status">
10
+ <qas-status :color="tab.status" />
11
+ </div>
12
+
13
+ <div class="flex items-center no-wrap q-ml-xs">
14
+ <span>
15
+ {{ getFormattedLabel(tab) }}
16
+ </span>
10
17
 
11
- <div class="q-ml-xs">
12
- {{ getFormattedLabel(tab) }}
18
+ <qas-skeleton v-if="props.skeleton && !tab.counter" class="q-ml-sm" height="22px" type="text" width="25px" />
13
19
  </div>
14
20
  </slot>
15
21
  </component>
@@ -20,6 +26,7 @@
20
26
 
21
27
  <script setup>
22
28
  import QasStatus from '../status/QasStatus.vue'
29
+ import QasSkeleton from '../skeleton/QasSkeleton.vue'
23
30
 
24
31
  import { decimal } from '../../helpers'
25
32
 
@@ -35,6 +42,10 @@ const props = defineProps({
35
42
  type: Object
36
43
  },
37
44
 
45
+ skeleton: {
46
+ type: Boolean
47
+ },
48
+
38
49
  modelValue: {
39
50
  default: '',
40
51
  type: [String, Number]
@@ -13,7 +13,6 @@ props:
13
13
  type: Object
14
14
  examples: ["{ all: 24 }"]
15
15
 
16
-
17
16
  querySlug:
18
17
  desc: Nome da query string para alterar o model via URL, toda vez que a tab for alterada a query será atualizada e vice-versa.
19
18
  type: String
@@ -25,6 +24,11 @@ props:
25
24
  type: [String, Number]
26
25
  model: true
27
26
 
27
+ skeleton:
28
+ desc: Exibe um esqueleto de carregamento no lugar do conteúdo.
29
+ default: false
30
+ type: Boolean
31
+
28
32
  tabs:
29
33
  desc: Objeto ou Array contendo todas as tabs a serem geradas.
30
34
  default: {}
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div ref="parent" :class="classes">
3
- <div class="no-wrap row text-no-wrap">
3
+ <div class="items-center no-wrap row text-no-wrap">
4
4
  <!-- "data-table-hover" habilita o hover no texto dentro do QasTableGenerator -->
5
5
  <div ref="truncate" class="ellipsis" data-table-hover>
6
6
  <slot>
@@ -19,8 +19,8 @@
19
19
  <qas-btn v-if="hasButton" class="q-ml-xs" :label="buttonLabel" @click.stop.prevent="toggle" />
20
20
  </div>
21
21
 
22
- <qas-dialog v-model="show" v-bind="defaultProps" aria-label="Diálogo de texto completo" max-width="500px" role="dialog" use-full-max-width>
23
- <template v-if="isCounterMode" #description>
22
+ <qas-dialog v-model="show" v-bind="defaultProps" aria-label="Diálogo de texto completo" role="dialog" size="md">
23
+ <template v-if="showDescriptionSlot" #description>
24
24
  <component :is="dialogComponent.is" v-bind="dialogComponent.props" v-model:results="searchModel">
25
25
  <q-list separator>
26
26
  <q-item v-for="(item, index) in dialogComponent.list" :key="index" class="q-px-none">
@@ -51,6 +51,8 @@ import {
51
51
  onMounted,
52
52
  onUnmounted,
53
53
  ref,
54
+ inject,
55
+ isRef,
54
56
  watch
55
57
  } from 'vue'
56
58
 
@@ -100,7 +102,7 @@ const props = defineProps({
100
102
 
101
103
  typography: {
102
104
  type: String,
103
- default: 'body1'
105
+ default: undefined
104
106
  },
105
107
 
106
108
  list: {
@@ -108,6 +110,10 @@ const props = defineProps({
108
110
  default: () => []
109
111
  },
110
112
 
113
+ useAlwaysSeeMore: {
114
+ type: Boolean
115
+ },
116
+
111
117
  useBadge: {
112
118
  type: Boolean
113
119
  },
@@ -121,6 +127,9 @@ const props = defineProps({
121
127
  }
122
128
  })
123
129
 
130
+ // globals
131
+ const injectedDefaults = inject('textTruncatePropsDefaults', {}) // Inject reativo ou não reativo com fallback vazio
132
+
124
133
  // template refs
125
134
  const truncate = ref(null)
126
135
  const parent = ref(null)
@@ -142,6 +151,7 @@ const {
142
151
  const {
143
152
  defaultProps,
144
153
  dialogComponent,
154
+ hasDialogDescription,
145
155
  show,
146
156
  searchModel,
147
157
  toggle
@@ -158,30 +168,65 @@ const {
158
168
  useMutationObserver({ truncate, callbackFn: truncateText })
159
169
 
160
170
  // computeds
161
- const classes = computed(() => [`text-${props.color}`, `text-${props.typography}`])
171
+ /**
172
+ * Seta os valores padrões, dando prioridade:
173
+ * 1. Props
174
+ * 2. Injetado (pode ser reativo ou não reativo)
175
+ * 3. Caso esteja dentro do QasBox, seta o size para 'sm' se for primary ou secondary.
176
+ * 4. Hardcoded (tertiary, md, primary)
177
+ */
178
+ const textTruncatePropsDefaults = computed(() => {
179
+ const defaultProps = isRef(injectedDefaults) ? injectedDefaults.value : injectedDefaults
180
+
181
+ return {
182
+ typography: 'body1',
183
+ ...defaultProps
184
+ }
185
+ })
186
+
187
+ const defaultTypography = computed(() => props.typography || textTruncatePropsDefaults.value.typography)
188
+
189
+ const classes = computed(() => [`text-${props.color}`, `text-${defaultTypography.value}`])
162
190
 
163
191
  const formattedText = computed(() => props.list.length || props.text ? displayText.value : props.emptyText)
164
192
 
193
+ /**
194
+ * Se estiver em modo contador (list prop preenchida) e não houver descrição
195
+ * personalizada no diálogo, então mostra o slot de descrição.
196
+ */
197
+ const showDescriptionSlot = computed(() => isCounterMode.value && !hasDialogDescription?.value)
198
+
165
199
  // composable functions
166
200
  function useDialog ({ props, textContent }) {
167
201
  // reactive vars
168
202
  const show = ref(false)
169
203
  const searchModel = ref([])
170
204
 
171
- // computed
172
- const description = computed(() => props.text || textContent.value)
205
+ // computeds
206
+ const hasDialogDescription = computed(() => !!props.dialogProps?.description)
207
+
208
+ const description = computed(() => {
209
+ // Se dialogProps.description estiver setado, usa ele
210
+ if (hasDialogDescription.value) {
211
+ return props.dialogProps.description
212
+ }
213
+
214
+ // Senão, usa o comportamento padrão
215
+ return props.text || textContent.value
216
+ })
173
217
 
174
218
  const defaultProps = computed(() => {
175
219
  return {
176
220
  cancel: false,
177
221
  ok: false,
178
222
 
223
+ useFullMaxWidth: true,
224
+ maxWidth: '500px',
225
+
179
226
  ...props.dialogProps,
180
227
 
181
- card: {
182
- title: props.dialogTitle,
183
- description: description.value
184
- }
228
+ title: props.dialogTitle,
229
+ description: description.value
185
230
  }
186
231
  })
187
232
 
@@ -218,6 +263,7 @@ function useDialog ({ props, textContent }) {
218
263
  return {
219
264
  defaultProps,
220
265
  dialogComponent,
266
+ hasDialogDescription,
221
267
 
222
268
  show,
223
269
  searchModel,
@@ -298,6 +344,9 @@ function useTemplate () {
298
344
  const isCounterMode = computed(() => !!props.list.length)
299
345
 
300
346
  const hasButton = computed(() => {
347
+ // Caso a propriedade useAlwaysSeeMore esteja ativa, sempre exibe o botão
348
+ if (props.useAlwaysSeeMore) return true
349
+
301
350
  return isCounterMode.value ? normalizedList.value.length > props.maxVisibleItem : isTruncated.value
302
351
  })
303
352
 
@@ -306,7 +355,7 @@ function useTemplate () {
306
355
  })
307
356
 
308
357
  const buttonLabel = computed(() => {
309
- return isCounterMode.value ? counterLabel.value : props.seeMoreLabel
358
+ return isCounterMode.value && !props.useAlwaysSeeMore ? counterLabel.value : props.seeMoreLabel
310
359
  })
311
360
 
312
361
  return {
@@ -51,6 +51,11 @@ props:
51
51
  default: []
52
52
  type: Array
53
53
 
54
+ useAlwaysSeeMore:
55
+ desc: Sempre exibe o botão "ver mais", mesmo que o texto não esteja truncado.
56
+ default: false
57
+ type: Boolean
58
+
54
59
  use-badge:
55
60
  desc: Habilita badges para cada item da lista.
56
61
  default: false
@@ -1,5 +1,6 @@
1
1
  <template>
2
- <div class="qas-toggle-visibility">
2
+ <!-- "data-no-grab" para prevenir o click drag -->
3
+ <div class="qas-toggle-visibility" data-no-grab>
3
4
  <!-- "data-table-ignore-tr-hover" é para desabilitar o hover do tr no QasTableGenerator -->
4
5
  <div :aria-expanded="isVisible" aria-label="Alternar visibilidade do conteúdo" class="cursor-pointer items-center no-wrap qas-toggle-visibility__container row" data-table-ignore-tr-hover role="button" :style @click.prevent.stop="toggleVisibility">
5
6
  <div class="ellipsis qas-toggle-visibility__content">
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <q-tooltip v-bind="tooltipProps" class="bg-grey-10 text-caption">
2
+ <q-tooltip v-if="!isDragging" v-bind="tooltipProps" class="bg-grey-10 text-caption">
3
3
  <qas-breakline :text="props.text" />
4
4
  </q-tooltip>
5
5
  </template>
@@ -7,6 +7,8 @@
7
7
  <script setup>
8
8
  import QasBreakline from '../breakline/QasBreakline.vue'
9
9
 
10
+ import { inject, ref } from 'vue'
11
+
10
12
  defineOptions({ name: 'QasTooltip' })
11
13
 
12
14
  const props = defineProps({
@@ -16,6 +18,9 @@ const props = defineProps({
16
18
  }
17
19
  })
18
20
 
21
+ // injects
22
+ const isDragging = inject('isDragging', ref(false))
23
+
19
24
  // consts
20
25
  const tooltipProps = {
21
26
  anchor: 'center right',