@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
@@ -4,10 +4,10 @@ meta:
4
4
  desc: Componente de dialog.
5
5
 
6
6
  props:
7
- actions-props:
8
- desc: Props repassadas para o "QasActions".
9
- default: {}
10
- type: Object
7
+ badges:
8
+ desc: Badges que aparecem no canto superior direito do dialog.
9
+ type: [Array, Object]
10
+ default: []
11
11
 
12
12
  cancel:
13
13
  desc: Props para o botão de cancelar, pode ser objeto com as propriedades ou um boolean, caso for "false", remove o botão de cancelar.
@@ -15,19 +15,13 @@ props:
15
15
  type: [Object, Boolean]
16
16
  examples: ["{ label: 'Meu botão de cancelar', onClick: () => alert('fui clicado!') }"]
17
17
 
18
- card:
19
- desc: Objeto contendo as informações para serem exibidas dentro do dialog como "title" e "description".
20
- default: {}
21
- type: Object
22
- examples: ["{ title: 'Meu título', description: 'Minha descrição' }"]
23
-
24
- max-width:
25
- desc: Tamanho máximo do dialog.
26
- type: String
18
+ description:
19
+ desc: Descrição do dialog, pode ser uma string, um componente ou uma string com HTML (passando a prop useHtmlDescription).
20
+ type: [String, Object]
27
21
 
28
- min-width:
29
- desc: Tamanho mínimo do dialog.
30
- type: String
22
+ disable-close-button:
23
+ desc: Define se o botão de fechar no canto superior direito estará desabilitado.
24
+ type: Boolean
31
25
 
32
26
  model-value:
33
27
  desc: Model do componente, abre ou fecha o dialog.
@@ -42,33 +36,60 @@ props:
42
36
  type: [Object, Boolean]
43
37
  examples: ["{ label: 'Meu botão de confirmar', onClick: () => alert('fui clicado!') }"]
44
38
 
45
- persistent:
46
- desc: Define se o dialog vai fechar ou não após clicar fora do dialog.
39
+ size:
40
+ desc: Tamanho do dialog.
41
+ type: String
42
+ default: 'md'
43
+ options: ['xs', 'sm', 'md', 'lg', 'xl']
44
+
45
+ use-auto-close-on-cancel:
46
+ desc: Define se o dialog vai fechar automaticamente ao clicar no botão de cancelar.
47
+ type: Boolean
48
+ default: true
49
+
50
+ use-auto-close-on-ok:
51
+ desc: Define se o dialog vai fechar automaticamente ao clicar no botão de confirmar (ok).
52
+ type: Boolean
47
53
  default: true
54
+
55
+ use-close-button:
56
+ desc: Define se o dialog vai ter um botão de fechar no canto superior direito.
48
57
  type: Boolean
49
58
 
50
59
  use-form:
51
60
  desc: Define se a tag onde fica a descrição no dialog vai ser um "<q-form />" ou "<div />".
52
61
  type: Boolean
53
62
 
54
- use-full-max-width:
55
- desc: propriedade para utilizar `100% do maxWidth`.
63
+ use-html-description:
64
+ desc: Define se a descrição aceita HTML (utilize com cuidado para evitar XSS).
56
65
  type: Boolean
57
66
 
58
67
  use-validation-all-at-once:
59
68
  desc: Valida todos os campos de uma única vez, ao invés de ser um por vez (que é o padrão).
60
69
  type: Boolean
61
70
 
62
- slots:
63
- actions:
64
- desc: Slot para ações (botões por exemplo).
71
+ tertiary:
72
+ desc: Props para o botão terciário
73
+ type: Object
74
+ default: {}
65
75
 
76
+ title:
77
+ desc: Título do dialog.
78
+ type: String
79
+ required: true
80
+
81
+ slots:
66
82
  description:
67
83
  desc: Slot para descrição.
68
84
 
69
85
  header:
70
86
  desc: Slot para o título.
71
87
 
88
+ provide:
89
+ is-dialog:
90
+ desc: Identificador booleano que indica quando um componente está dentro do contexto de um QasDialog.
91
+ type: Boolean
92
+
72
93
  events:
73
94
  '@update:model-value -> function (value)':
74
95
  desc: Dispara toda vez que o model é atualizado, também utilizado para v-model.
@@ -99,6 +120,10 @@ selectors:
99
120
  desc: Seletor do botão de cancelar do componente.
100
121
  examples: ['data-cy="dialog-cancel-btn"']
101
122
 
123
+ dialog-tertiary-btn:
124
+ desc: Seletor do botão terciário do componente.
125
+ examples: ['data-cy="dialog-tertiary-btn"']
126
+
102
127
  dialog-close-btn:
103
128
  desc: Seletor do botão de fechar do componente.
104
129
  examples: ['data-cy="dialog-close-btn"']
@@ -111,6 +136,9 @@ selectors:
111
136
  desc: Seletor do botão de confirmar do componente.
112
137
  examples: ['data-cy="dialog-ok-btn"']
113
138
 
139
+ title:
140
+ desc: Slot para inserir conteúdo adicional ao lado do título do card do dialog.
141
+
114
142
  dialog-title:
115
143
  desc: Seletor do título do componente.
116
144
  examples: ['data-cy="dialog-title"']
@@ -15,7 +15,7 @@ export default function useCancel (config = {}) {
15
15
  const defaultCancel = computed(() => {
16
16
  return {
17
17
  label: 'Cancelar',
18
- outline: true,
18
+ 'data-cy': 'dialog-cancel-btn',
19
19
 
20
20
  ...props.cancel,
21
21
 
@@ -35,12 +35,12 @@ export default function useDynamicComponents (config = {}) {
35
35
  })
36
36
 
37
37
  const hasRenderFunction = computed(() => {
38
- const description = props.card.description
38
+ const description = props.description
39
39
 
40
40
  return typeof description === 'object' && description !== null && !Array.isArray(description)
41
41
  })
42
42
 
43
- const descriptionComponent = computed(() => hasRenderFunction.value ? props.card.description : 'div')
43
+ const descriptionComponent = computed(() => hasRenderFunction.value ? props.description : 'div')
44
44
 
45
45
  // métodos
46
46
  function submitHandler () {
@@ -18,6 +18,7 @@ export default function useOk (config = {}) {
18
18
  return {
19
19
  label: 'Ok',
20
20
  type: (props.ok?.type || props.useForm) ? 'submit' : 'button',
21
+ 'data-cy': 'dialog-ok-btn',
21
22
 
22
23
  ...attrs,
23
24
 
@@ -9,7 +9,7 @@
9
9
  </template>
10
10
 
11
11
  <script setup>
12
- import { NotifyError } from '../../plugins'
12
+ import NotifyError from '../../plugins/notify-error/NotifyError.js'
13
13
 
14
14
  import { Loading, extend } from 'quasar'
15
15
  import { ref, markRaw } from 'vue'
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <qas-dialog class="qas-drawer" v-bind="attributes" @update:model-value="onUpdateModelValue">
2
+ <qas-dialog v-model="model" class="qas-drawer" :class="containerDialogClasses" v-bind="attributes">
3
3
  <template #header>
4
4
  <slot name="header">
5
5
  <div class="items-center justify-between row">
@@ -11,18 +11,18 @@
11
11
  </slot>
12
12
  </span>
13
13
 
14
- <qas-btn v-close-popup class="z-max" color="grey-10" data-cy="drawer-close-btn" icon="sym_r_close" variant="tertiary" @click="emit('update:modelValue', false)" />
14
+ <qas-btn class="z-max" color="grey-10" data-cy="drawer-close-btn" icon="sym_r_close" variant="tertiary" @click="close" />
15
15
  </div>
16
16
  </slot>
17
17
  </template>
18
18
 
19
19
  <template #description>
20
- <div>
21
- <div class="relative-position" data-cy="drawer-default">
20
+ <div class="relative-position">
21
+ <div data-cy="drawer-default">
22
22
  <slot />
23
23
  </div>
24
24
 
25
- <div v-if="props.loading" class="qas-drawer__loading" :style="loadingStyle">
25
+ <div v-if="props.loading" class="qas-drawer__loading">
26
26
  <div class="full-height relative-position">
27
27
  <q-inner-loading :showing="props.loading">
28
28
  <q-spinner color="grey" size="2em" />
@@ -40,7 +40,7 @@ import QasBtn from '../btn/QasBtn.vue'
40
40
 
41
41
  import useScreen from '../../composables/use-screen.js'
42
42
 
43
- import { computed, useAttrs } from 'vue'
43
+ import { computed, inject, provide } from 'vue'
44
44
 
45
45
  defineOptions({
46
46
  name: 'QasDrawer',
@@ -53,9 +53,8 @@ const props = defineProps({
53
53
  default: () => ({})
54
54
  },
55
55
 
56
- maxWidth: {
57
- type: String,
58
- default: '60%'
56
+ persistent: {
57
+ type: Boolean
59
58
  },
60
59
 
61
60
  position: {
@@ -71,43 +70,57 @@ const props = defineProps({
71
70
 
72
71
  loading: {
73
72
  type: Boolean
73
+ },
74
+
75
+ size: {
76
+ type: String,
77
+ default: 'sm',
78
+ validator: value => !value || ['sm', 'md', 'lg', 'xl'].includes(value)
74
79
  }
75
80
  })
76
81
 
77
- const emit = defineEmits(['update:modelValue'])
82
+ // globals
83
+ const isOverlay = inject('isOverlay', false)
84
+
85
+ provide('drawerProps', computed(() => ({ persistent: props.persistent })))
78
86
 
79
- const attrs = useAttrs()
87
+ // emits
88
+ const model = defineModel({ type: Boolean })
89
+
90
+ // composables
80
91
  const screen = useScreen()
81
92
 
82
93
  // computed
83
- const normalizedMaxWidth = computed(() => screen.isSmall ? '95%' : props.maxWidth)
84
-
85
- const loadingStyle = computed(() => {
86
- return {
87
- right: `calc(100% - ${normalizedMaxWidth.value})`
88
- }
94
+ const containerDialogClasses = computed(() => {
95
+ // tratamento para mobile, onde sempre pegará 95% da tela.
96
+ if (screen.isSmall) return 'qas-drawer--mobile'
97
+
98
+ /**
99
+ * no caso de ter passado a prop lg ou xl, mas o tamanho da tela ser médio,
100
+ * o drawer irá se comportar como md, pegando 512px de largura, caso contrário, teria o problema
101
+ * do drawer acabar pegando 100% da página, tendo o comportamento errado.
102
+ */
103
+ if (screen.isMedium && (props.size === 'lg' || props.size === 'xl')) return 'qas-drawer--md'
104
+
105
+ return isOverlay ? 'qas-drawer--overlay' : `qas-drawer--${props.size}`
89
106
  })
90
107
 
91
108
  const attributes = computed(() => {
92
- const { modelValue } = attrs
93
-
94
109
  return {
95
- persistent: false,
96
- modelValue,
97
-
98
110
  ...props.dialogProps,
99
111
 
112
+ title: props.title,
100
113
  cancel: false,
101
- maxWidth: normalizedMaxWidth.value,
102
114
  maximized: true,
103
115
  ok: false,
104
116
  position: props.position,
105
- useFullMaxWidth: true
117
+ persistent: props.persistent
106
118
  }
107
119
  })
108
120
 
109
- function onUpdateModelValue (value) {
110
- emit('update:modelValue', value)
121
+ // functions
122
+ function close () {
123
+ model.value = false
111
124
  }
112
125
  </script>
113
126
 
@@ -118,6 +131,43 @@ function onUpdateModelValue (value) {
118
131
  left: 0;
119
132
  position: absolute;
120
133
  top: 0;
134
+ width: 100%;
135
+ }
136
+
137
+ &--mobile {
138
+ .qas-dialog__container {
139
+ max-width: 95% !important;
140
+ }
141
+ }
142
+
143
+ &--overlay {
144
+ .qas-dialog__container {
145
+ max-width: 90% !important;
146
+ }
147
+ }
148
+
149
+ &--sm {
150
+ .qas-dialog__container {
151
+ max-width: 368px !important;
152
+ }
153
+ }
154
+
155
+ &--md {
156
+ .qas-dialog__container {
157
+ max-width: 512px !important;
158
+ }
159
+ }
160
+
161
+ &--lg {
162
+ .qas-dialog__container {
163
+ max-width: 656px !important;
164
+ }
165
+ }
166
+
167
+ &--xl {
168
+ .qas-dialog__container {
169
+ max-width: 960px !important;
170
+ }
121
171
  }
122
172
  }
123
173
  </style>
@@ -20,6 +20,11 @@ props:
20
20
  examples: [v-model="value"]
21
21
  model: true
22
22
 
23
+ persistent:
24
+ desc: Define se o drawer pode ser fechado clicando fora dele ou pressionando a tecla ESC.
25
+ default: false
26
+ type: Boolean
27
+
23
28
  position:
24
29
  desc: 'Posição do drawer, sendo possível apenas 2 opções: [left, right].'
25
30
  default: left
@@ -29,6 +34,11 @@ props:
29
34
  desc: Titulo do drawer.
30
35
  type: String
31
36
 
37
+ size:
38
+ desc: Tamanho do drawer.
39
+ default: sm
40
+ type: String
41
+
32
42
  slots:
33
43
  header:
34
44
  desc: Slot para conteúdo do cabeçalho.
@@ -62,6 +62,11 @@ slots:
62
62
  content:
63
63
  desc: Slot para substituir o conteúdo principal do card.
64
64
 
65
+ provide:
66
+ is-expansion-item:
67
+ desc: Identificador booleano que indica quando um componente está dentro do contexto de um QasExpansionItem.
68
+ type: Boolean
69
+
65
70
  events:
66
71
  '@update:model-value -> function(value)':
67
72
  desc: Dispara quando o model-value altera, também usado para v-model.
@@ -249,13 +249,14 @@ export default {
249
249
  orderByOptions: this.orderByOptions,
250
250
  useOrderBy: this.hasOrderByOptions,
251
251
  useFilterButton: this.useFilterButton,
252
+ isFetchingFilters: this.isFetching,
252
253
 
253
254
  filtersButtonProps: {
254
255
  color: this.filterButtonColor,
255
256
  error: this.hasFetchError,
256
257
  fields: this.fields,
257
258
  fieldsProps: this.formattedFieldsProps,
258
- loading: this.isFetching
259
+ skeleton: this.isFetching
259
260
  },
260
261
 
261
262
  /**
@@ -2,7 +2,7 @@
2
2
  <qas-btn-dropdown v-bind="btnDropdownProps">
3
3
  <!-- Seção do botão de filtrar -->
4
4
  <template v-if="props.useFilterButton" #btn-content-filtersButton>
5
- <q-menu ref="filtersButtonMenu" anchor="center right" class="full-width" max-width="270px" no-refocus self="top right" @hide="emit('hide-filters-menu')">
5
+ <q-menu ref="filtersButtonMenu" anchor="center right" class="full-width pv-filter-actions" max-width="300px" no-refocus self="top right" @before-hide="onMenuHide" @before-show="onMenuShow" @hide="emit('hide-filters-menu')">
6
6
  <div v-if="props.filtersButtonProps.loading" class="q-pa-xl text-center">
7
7
  <q-spinner color="grey" size="2em" />
8
8
  </div>
@@ -11,20 +11,24 @@
11
11
  <q-icon color="negative" name="sym_r_warning" size="2em" />
12
12
  </div>
13
13
 
14
- <q-form v-else class="q-gutter-y-md q-pa-md" @submit.prevent="emit('filter')">
15
- <div v-for="(field, index) in props.filtersButtonProps.fields" :key="index">
16
- <qas-field v-model="filtersButtonModel[field.name]" :data-cy="`filters-${field.name}-field`" :field="field" v-bind="props.filtersButtonProps.fieldsProps[field.name]" />
14
+ <q-form v-else class="pv-filter-actions__form" @submit.prevent="emit('filter')">
15
+ <div ref="content" class="pv-filter-actions__fields-content q-gutter-y-md q-pt-md q-px-md">
16
+ <div v-for="(field, index) in props.filtersButtonProps.fields" :key="index">
17
+ <qas-field v-model="filtersButtonModel[field.name]" :data-cy="`filters-${field.name}-field`" :field="field" v-bind="props.filtersButtonProps.fieldsProps[field.name]" />
18
+ </div>
17
19
  </div>
18
20
 
19
- <qas-actions gutter="sm" use-equal-width>
20
- <template #primary>
21
- <qas-btn class="full-width" data-cy="filters-submit-btn" label="Filtrar" size="sm" type="submit" variant="primary" />
22
- </template>
21
+ <div class="pv-filter-actions__actions q-pa-md q-pb-md q-px-md">
22
+ <qas-actions gutter="sm" spacing-top="none" use-equal-width>
23
+ <template #primary>
24
+ <qas-btn class="full-width" data-cy="filters-submit-btn" label="Filtrar" size="sm" type="submit" variant="primary" />
25
+ </template>
23
26
 
24
- <template #secondary>
25
- <qas-btn class="full-width" data-cy="filters-clear-btn" label="Limpar" size="sm" variant="secondary" @click="emit('clear-filters')" />
26
- </template>
27
- </qas-actions>
27
+ <template #secondary>
28
+ <qas-btn class="full-width" data-cy="filters-clear-btn" label="Limpar" size="sm" variant="secondary" @click="emit('clear-filters')" />
29
+ </template>
30
+ </qas-actions>
31
+ </div>
28
32
  </q-form>
29
33
  </q-menu>
30
34
  </template>
@@ -52,8 +56,10 @@ import QasBtn from '../../btn/QasBtn.vue'
52
56
  import QasBtnDropdown from '../../btn-dropdown/QasBtnDropdown.vue'
53
57
  import QasField from '../../field/QasField.vue'
54
58
 
59
+ import { setScrollGradient } from '../../../helpers'
60
+
55
61
  import { useRoute } from 'vue-router'
56
- import { computed, ref } from 'vue'
62
+ import { computed, ref, nextTick } from 'vue'
57
63
 
58
64
  defineOptions({ name: 'PvFiltersActions' })
59
65
 
@@ -74,6 +80,10 @@ const props = defineProps({
74
80
 
75
81
  useOrderBy: {
76
82
  type: Boolean
83
+ },
84
+
85
+ isFetchingFilters: {
86
+ type: Boolean
77
87
  }
78
88
  })
79
89
 
@@ -88,10 +98,19 @@ defineExpose({ hideFiltersMenu })
88
98
 
89
99
  // template refs
90
100
  const filtersButtonMenu = ref(null)
101
+ const content = ref(null)
91
102
 
92
103
  // composables
93
104
  const route = useRoute()
94
105
 
106
+ const { initializeScrollGradient, removeScrollGradient } = setScrollGradient({
107
+ styles: {
108
+ gradientLevel: 2
109
+ },
110
+
111
+ orientation: 'y'
112
+ })
113
+
95
114
  // computeds
96
115
  const btnDropdownProps = computed(() => {
97
116
  return {
@@ -99,6 +118,7 @@ const btnDropdownProps = computed(() => {
99
118
  ...(props.useFilterButton && {
100
119
  filtersButton: {
101
120
  label: 'Filtrar',
121
+ skeleton: props.isFetchingFilters,
102
122
  useLabelOnSmallScreen: false,
103
123
  icon: 'sym_r_filter_alt',
104
124
  'data-cy': 'filters-btn' // manter compatibilidade
@@ -130,4 +150,50 @@ function isActive (value) {
130
150
  function hideFiltersMenu () {
131
151
  filtersButtonMenu.value?.hide()
132
152
  }
153
+
154
+ /**
155
+ * Precisa usar nextTick com o evento `before-show` ou invés de `show` para evitar um delay na renderização
156
+ * do gradiente, dessa forma o gradiente é aplicado imediatamente após o menu ser exibido.
157
+ */
158
+ async function onMenuShow () {
159
+ await nextTick()
160
+
161
+ if (content.value) {
162
+ initializeScrollGradient(content.value)
163
+ }
164
+ }
165
+
166
+ function onMenuHide () {
167
+ if (content.value) {
168
+ removeScrollGradient(content.value)
169
+ }
170
+ }
133
171
  </script>
172
+
173
+ <style lang="scss">
174
+ .pv-filter-actions {
175
+ &.q-menu {
176
+ display: flex;
177
+ flex-direction: column;
178
+ max-height: 600px;
179
+ overflow: hidden;
180
+ }
181
+
182
+ &__form {
183
+ display: flex;
184
+ flex-direction: column;
185
+ overflow: hidden;
186
+ }
187
+
188
+ &__fields-content {
189
+ flex: 1 1 auto;
190
+ min-height: 0;
191
+ overflow-y: auto;
192
+ }
193
+
194
+ &__actions {
195
+ flex: 0 0 auto;
196
+ width: 100%;
197
+ }
198
+ }
199
+ </style>
@@ -1,7 +1,9 @@
1
1
  <template>
2
2
  <div :class="fieldsetClasses">
3
3
  <div v-for="(fieldsetItem, fieldsetItemKey) in normalizedFields" :key="fieldsetItemKey" :class="getFieldSetColumnClass(fieldsetItem.column)">
4
- <component :is="containerComponent.is" v-bind="containerComponent.props">
4
+ <qas-skeleton v-if="props.skeleton" height="200px" />
5
+
6
+ <component :is="containerComponent.is" v-else v-bind="containerComponent.props">
5
7
  <slot v-if="fieldsetItem.__hasFieldset" :name="`legend-${fieldsetItemKey}`">
6
8
  <qas-header v-if="fieldsetItem.__hasHeader" v-bind="getHeaderProps({ values: fieldsetItem })" />
7
9
  </slot>
@@ -63,6 +65,7 @@ import QasBox from '../box/QasBox.vue'
63
65
  import QasBtn from '../btn/QasBtn.vue'
64
66
  import QasField from '../field/QasField.vue'
65
67
  import QasHeader from '../header/QasHeader.vue'
68
+ import QasSkeleton from '../skeleton/QasSkeleton.vue'
66
69
 
67
70
  import { gutterValidator } from '../../helpers/private/gutter-validator'
68
71
  import useGenerator, { baseProps } from '../../composables/private/use-generator'
@@ -116,6 +119,10 @@ const props = defineProps({
116
119
  type: Array
117
120
  },
118
121
 
122
+ skeleton: {
123
+ type: Boolean
124
+ },
125
+
119
126
  useBox: {
120
127
  type: Boolean
121
128
  }
@@ -72,6 +72,11 @@ props:
72
72
  default: []
73
73
  type: Array
74
74
 
75
+ skeleton:
76
+ desc: Exibe um esqueleto de carregamento no lugar do conteúdo.
77
+ default: false
78
+ type: Boolean
79
+
75
80
  use-box:
76
81
  desc: Contra QasBox dentro do form-generator e fieldset.
77
82
  default: false
@@ -115,6 +120,11 @@ slots:
115
120
  'legend-bottom[nome-da-chave-do-fieldset]-[nome-da-chave-do-subset]':
116
121
  desc: Acessa o slot da seção abaixo do conteúdo do form de um subset específico.
117
122
 
123
+ provide:
124
+ is-form-generator:
125
+ desc: Identificador booleano que indica quando um componente está dentro do contexto de um QasFormGenerator.
126
+ type: Boolean
127
+
118
128
  events:
119
129
  '@update:model-value -> function(value)':
120
130
  desc: Dispara quando o model-value altera, também usado para v-model.