@bildvitta/quasar-ui-asteroid 3.15.0-beta.7 → 3.15.0-beta.9

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bildvitta/quasar-ui-asteroid",
3
3
  "description": "Asteroid",
4
- "version": "3.15.0-beta.7",
4
+ "version": "3.15.0-beta.9",
5
5
  "author": "Bild & Vitta <systemteam@bild.com.br>",
6
6
  "license": "MIT",
7
7
  "main": "dist/asteroid.cjs.min.js",
@@ -1,9 +1,9 @@
1
1
  <template>
2
- <div v-if="hasActions" class="qas-actions-menu" data-cy="actions-menu">
3
- <component :is="component.is" v-bind="component.props" variant="tertiary" @click.stop.prevent>
4
- <q-list v-if="isBtnDropdown" data-cy="actions-menu-list">
5
- <slot v-for="(item, key) in actions" :item="item" :name="key">
6
- <q-item v-bind="item.props" :key="key" clickable data-cy="actions-menu-list-item" @click="onClick(item)">
2
+ <div v-if="hasList" class="qas-actions-menu" data-cy="actions-menu">
3
+ <qas-btn-dropdown v-bind="btnDropdownProps">
4
+ <q-list data-cy="actions-menu-list">
5
+ <slot v-for="(item, key) in formattedList.dropdownList" :item="item" :name="key">
6
+ <q-item v-bind="getItemProps(item)" :key="key" clickable data-cy="actions-menu-list-item" @click="setClickHandler(item)">
7
7
  <q-item-section avatar>
8
8
  <q-icon :name="item.icon" />
9
9
  </q-item-section>
@@ -17,21 +17,35 @@
17
17
  </slot>
18
18
  </q-list>
19
19
 
20
- <q-tooltip v-if="hasTooltip" class="text-caption">
21
- {{ tooltipLabel }}
22
- </q-tooltip>
23
- </component>
20
+ <template v-for="(item, name) in tooltipLabels" :key="name" #[`bottom-${name}`]>
21
+ <q-tooltip v-if="showTooltip(item)">
22
+ {{ item.label }}
23
+ </q-tooltip>
24
+ </template>
25
+ </qas-btn-dropdown>
24
26
  </div>
25
27
  </template>
26
28
 
27
29
  <script setup>
28
- import QasBtn from '../btn/QasBtn.vue'
29
30
  import QasBtnDropdown from '../btn-dropdown/QasBtnDropdown.vue'
30
31
 
31
32
  import useScreen from '../../composables/use-screen'
32
33
 
34
+ import useDelete from './composables/use-delete'
35
+ import useTooltips from './composables/use-tooltips'
36
+ import useOptionsActions from './composables/use-options-actions'
37
+ import useSingleAction from './composables/use-single-action'
38
+ import useDoubleSplitActions from './composables/use-double-split-actions'
39
+ import useSingleSplitActions from './composables/use-single-split-actions'
40
+
41
+ import getLabel from './utils/get-label'
42
+ import setClickHandler from './utils/set-click-handler'
43
+
33
44
  import { computed, inject } from 'vue'
34
45
 
46
+ const DEFAULT_COLOR = 'grey-10'
47
+ const SPLIT_SIZE = 2
48
+
35
49
  defineOptions({ name: 'QasActionsMenu' })
36
50
 
37
51
  const qas = inject('qas')
@@ -42,6 +56,10 @@ const props = defineProps({
42
56
  type: Object
43
57
  },
44
58
 
59
+ disable: {
60
+ type: Boolean
61
+ },
62
+
45
63
  deleteLabel: {
46
64
  default: 'Excluir',
47
65
  type: String
@@ -57,11 +75,6 @@ const props = defineProps({
57
75
  type: Object
58
76
  },
59
77
 
60
- dropdownIcon: {
61
- default: 'sym_r_more_vert',
62
- type: String
63
- },
64
-
65
78
  list: {
66
79
  default: () => ({}),
67
80
  type: Object
@@ -83,8 +96,33 @@ const props = defineProps({
83
96
  })
84
97
 
85
98
  const screen = useScreen()
86
- const { deleteBtnProps, hasDelete } = useDelete()
87
99
 
100
+ const { deleteBtnProps, hasDelete } = useDelete({ color: DEFAULT_COLOR, props, qas })
101
+
102
+ const hasSplitName = computed(() => !!props.splitName)
103
+ const hasList = computed(() => !!Object.keys(fullList.value).length)
104
+
105
+ /**
106
+ * Tamanho total da lista, considerando ação de deletar caso exista.
107
+ */
108
+ const listSize = computed(() => Object.keys(fullList.value).length)
109
+
110
+ /**
111
+ * Só existe split caso tenha a propriedade "splitName" e o tamanho da lista seja
112
+ * maior que o tamanho permitido no SPLIT_SIZE (no caso 2).
113
+ */
114
+ const hasSplit = computed(() => hasSplitName.value && listSize.value > SPLIT_SIZE)
115
+
116
+ /**
117
+ * Quando existe apenas i item na lista, neste caso é mostrado o botão direto,
118
+ * mesmo que não tenha a propriedade "splitName".
119
+ */
120
+ const isSingle = computed(() => Object.keys(fullList.value).length === 1)
121
+
122
+ /**
123
+ * Lista englobando as que vem por propriedade "list" mergeadas com a do
124
+ * delete, caso exista.
125
+ */
88
126
  const fullList = computed(() => {
89
127
  return {
90
128
  ...props.list,
@@ -92,123 +130,103 @@ const fullList = computed(() => {
92
130
  }
93
131
  })
94
132
 
95
- const hasSplit = computed(() => !!props.splitName)
96
-
97
- // --------------------------------- actions -----------------------------------
98
- const actions = computed(() => {
99
- const list = { ...fullList.value }
133
+ /**
134
+ * chave do primaria do objeto, é considerado sendo a splitName caso exista no
135
+ * objeto, porém pode acontecer deste item deixar de existir por algum motivo
136
+ * então consideramos a chave primaria sendo o primeiro item da computada fullList.
137
+ */
138
+ const primaryKey = computed(() => {
139
+ return props.splitName in fullList.value ? props.splitName : Object.keys(fullList.value)?.[0]
140
+ })
100
141
 
101
- if (hasSplit.value && list[props.splitName] && isBtnDropdown.value) {
102
- screen.isSmall
103
- ? Object.assign(list, { [props.splitName]: list[props.splitName] })
104
- : delete list[props.splitName]
142
+ const btnDropdownProps = computed(() => {
143
+ return {
144
+ buttonsPropsList: formattedList.value.buttonsList,
145
+ disable: props.disable,
146
+ useSplit: hasSplit.value
105
147
  }
106
-
107
- return list
108
148
  })
109
149
 
110
- const hasActions = computed(() => !!Object.keys(actions.value).length)
111
- const firstItemKey = computed(() => Object.keys(actions.value)?.[0])
150
+ const primaryButtonProps = computed(() => {
151
+ const buttonProps = fullList.value[primaryKey.value] || {}
112
152
 
113
- // -------------------------------- tooltip ------------------------------------
114
- const tooltipLabel = computed(() => actions.value[firstItemKey.value]?.label)
115
- const hasTooltip = computed(() => {
116
- return !isBtnDropdown.value && !props.useLabel && props.useTooltip
117
- })
153
+ return {
154
+ /**
155
+ * Caso seja "isSingle" e tenha a opção de deletar, significa que único botão
156
+ * que existe é o de deletar, então a cor precisa ser "DEFAULT_COLOR", em todos
157
+ * os outros cenários, é primary.
158
+ */
159
+ color: isSingle.value && hasDelete.value ? DEFAULT_COLOR : 'primary',
118
160
 
119
- // --------------------------------- button ------------------------------------
120
- const defaultButtonProps = computed(() => {
121
- const { label, variant, ...buttonProps } = props.buttonProps
161
+ ...buttonProps,
122
162
 
123
- return {
124
- useHoverOnWhiteColor: true,
125
- useLabelOnSmallScreen: false,
126
- ...buttonProps
163
+ label: getLabel({ useLabel: props.useLabel, label: buttonProps.label }),
164
+ onClick: () => setClickHandler(buttonProps)
127
165
  }
128
166
  })
129
167
 
130
- const btnDropdownProps = computed(() => {
131
- const { icon, label } = fullList.value[props.splitName] || {}
168
+ const formattedList = computed(() => {
169
+ const buttonsPropsList = { ...fullList.value }
132
170
 
133
- const {
134
- icon: defaultIcon,
135
- ...defaultBtnProps
136
- } = defaultButtonProps.value
171
+ /**
172
+ * dropdownList: lista que ficará no menu dropdown.
173
+ * buttonsList: lista de botões que ficará **fora** do menu dropdown.
174
+ */
175
+ const payload = { dropdownList: {}, buttonsList: {} }
137
176
 
138
- return {
139
- buttonProps: {
140
- ...(props.useLabel && { label: hasSplit.value ? label : 'Opções' }),
141
- ...defaultBtnProps,
142
- icon: icon || defaultIcon
143
- },
177
+ if ((!hasSplitName.value || screen.isSmall) && !isSingle.value) {
178
+ const { buttonsList } = useOptionsActions({ color: DEFAULT_COLOR, props })
144
179
 
145
- dropdownIcon: props.dropdownIcon,
146
- useSplit: hasSplit.value,
180
+ payload.buttonsList = buttonsList.value
181
+ payload.dropdownList = buttonsPropsList
147
182
 
148
- onClick: () => onClick(fullList.value[props.splitName])
183
+ return payload
149
184
  }
150
- })
151
185
 
152
- const btnProps = computed(() => {
153
- const { color, icon } = actions.value[firstItemKey.value] || {}
154
- const { color: defaultColor, ...defaultBtnProps } = defaultButtonProps.value
186
+ if (isSingle.value) {
187
+ const { buttonsList } = useSingleAction({ primaryButtonProps, primaryKey })
155
188
 
156
- return {
157
- color: color || defaultColor,
158
- icon,
159
- label: props.useLabel ? tooltipLabel.value : '',
160
- onClick,
161
- ...defaultBtnProps
162
- }
163
- })
189
+ payload.buttonsList = buttonsList.value
164
190
 
165
- const isBtnDropdown = computed(() => Object.keys(fullList.value || {}).length > 1)
191
+ return payload
192
+ }
166
193
 
167
- // -------------------------------- component ----------------------------------
168
- const component = computed(() => {
169
- const is = isBtnDropdown.value ? QasBtnDropdown : QasBtn
194
+ if (listSize.value === SPLIT_SIZE) {
195
+ const { buttonsList } = useDoubleSplitActions({
196
+ buttonsPropsList,
197
+ color: DEFAULT_COLOR,
198
+ primaryButtonProps,
199
+ primaryKey,
200
+ props
201
+ })
170
202
 
171
- return {
172
- is,
173
- props: {
174
- ...(isBtnDropdown.value ? btnDropdownProps.value : btnProps.value),
175
- ...(hasDelete.value && props.deleteProps)
176
- }
203
+ payload.buttonsList = buttonsList.value
177
204
  }
178
- })
179
205
 
180
- // --------------------------------- methods -----------------------------------
181
- function onClick (item = {}) {
182
- if (!isBtnDropdown.value) {
183
- item = actions.value[firstItemKey.value]
184
- }
206
+ if (listSize.value > SPLIT_SIZE) {
207
+ const { list } = useSingleSplitActions({
208
+ buttonsPropsList,
209
+ primaryButtonProps,
210
+ primaryKey,
211
+ props
212
+ })
185
213
 
186
- if (typeof item.handler === 'function') {
187
- const { handler, ...filtered } = item
188
- item.handler(filtered)
214
+ payload.buttonsList = list.value.buttonsList
215
+ payload.dropdownList = list.value.dropdownList
189
216
  }
190
- }
191
217
 
192
- // ------------------------------- composables ---------------------------------
193
- function useDelete () {
194
- const hasDelete = computed(() => !!Object.keys(props.deleteProps).length)
195
-
196
- const deleteBtnProps = computed(() => {
197
- return {
198
- ...(hasDelete.value && {
199
- delete: {
200
- color: 'grey-10',
201
- icon: props.deleteIcon,
202
- label: props.deleteLabel,
203
- handler: () => qas.delete(props.deleteProps)
204
- }
205
- })
206
- }
207
- })
218
+ return payload
219
+ })
220
+
221
+ const { showTooltip, tooltipLabels } = useTooltips({ formattedList, fullList, props })
222
+
223
+ // functions
224
+ function getItemProps (item) {
225
+ const { disable, props: itemProps } = item
208
226
 
209
227
  return {
210
- deleteBtnProps,
211
- hasDelete
228
+ disable,
229
+ ...itemProps
212
230
  }
213
231
  }
214
232
  </script>
@@ -5,10 +5,14 @@ meta:
5
5
 
6
6
  props:
7
7
  button-props:
8
- desc: Propriedades repassadas para o "QasBtn" caso esteja em modo de botão (apenas um item na prop "list"), caso esteja em modo de dropdown (mais de 1 item na prop "list") é enviado para a propriedade buttonProps do "QasBtnDropdown".
8
+ desc: Propriedades que são usadas no modo "Opções", que é quando não é usado a propriedade "splitName" ou esteja no mobile;
9
9
  default: {}
10
10
  type: Object
11
- examples: ["{ color: 'white', icon: 'sym_r_person', useLabelOnSmallScreen: false }"]
11
+
12
+ disable:
13
+ desc: Desabilita o componente como um todo.
14
+ default: false
15
+ type: Boolean
12
16
 
13
17
  delete-icon:
14
18
  desc: Ícone do botão de deletar.
@@ -0,0 +1,30 @@
1
+ import { computed } from 'vue'
2
+
3
+ /**
4
+ * @param {{
5
+ * color: string,
6
+ * props: { deleteIcon: string, deleteLabel: string, deleteProps: object },
7
+ * qas: { delete: function(object) }
8
+ * }}
9
+ */
10
+ export default function useDelete ({ color, props, qas }) {
11
+ const hasDelete = computed(() => !!Object.keys(props.deleteProps).length)
12
+
13
+ const deleteBtnProps = computed(() => {
14
+ return {
15
+ ...(hasDelete.value && {
16
+ delete: {
17
+ color,
18
+ icon: props.deleteIcon,
19
+ label: props.deleteLabel,
20
+ handler: () => qas.delete(props.deleteProps)
21
+ }
22
+ })
23
+ }
24
+ })
25
+
26
+ return {
27
+ deleteBtnProps,
28
+ hasDelete
29
+ }
30
+ }
@@ -0,0 +1,42 @@
1
+ import setClickHandler from '../utils/set-click-handler'
2
+ import getLabel from '../utils/get-label'
3
+
4
+ import { computed } from 'vue'
5
+
6
+ /**
7
+ * Cenário onde ficará um botão ao lado do outro "Ação primaria | Ação secundaria".
8
+ *
9
+ * @param {{
10
+ * color: string,
11
+ * props: { useLabel: boolean },
12
+ * primaryKey: import('vue').ComputedRef<string>,
13
+ * buttonsPropsList: import('vue').ComputedRef<object>
14
+ * primaryButtonProps: import('vue').ComputedRef<primaryButtonProps>
15
+ * }} config
16
+ */
17
+ export default function useDoubleSplitActions (config = {}) {
18
+ const { color, props, primaryKey, buttonsPropsList, primaryButtonProps } = config
19
+
20
+ const buttonsList = computed(() => {
21
+ const secondaryKey = Object.keys(buttonsPropsList).find(key => key !== primaryKey.value)
22
+ const secondaryButton = buttonsPropsList[secondaryKey]
23
+
24
+ return {
25
+ [primaryKey.value]: {
26
+ ...primaryButtonProps.value,
27
+ label: getLabel({ useLabel: props.useLabel, label: primaryButtonProps.value.label })
28
+ },
29
+
30
+ [secondaryKey]: {
31
+ ...secondaryButton,
32
+ color,
33
+ label: getLabel({ useLabel: props.useLabel, label: secondaryButton.label }),
34
+ onClick: () => setClickHandler(secondaryButton)
35
+ }
36
+ }
37
+ })
38
+
39
+ return {
40
+ buttonsList
41
+ }
42
+ }
@@ -0,0 +1,28 @@
1
+ import getLabel from '../utils/get-label'
2
+
3
+ import { computed } from 'vue'
4
+
5
+ /**
6
+ * Cenário onde não é utilizado com split e tenha mais de 1 item na lista,
7
+ * neste caso, ele se torna o botão de "opções" onde será usado em casos como
8
+ * dentro de cards, etc.
9
+ *
10
+ * @param {{ color: string, props: { buttonProps: object, useLabel: boolean } }}
11
+ */
12
+ export default function useOptionsActions ({ props, color }) {
13
+ const buttonsList = computed(() => {
14
+ return {
15
+ options: {
16
+ color,
17
+ iconRight: 'sym_r_more_vert',
18
+ useLabelOnSmallScreen: false,
19
+ ...props.buttonProps,
20
+ label: getLabel({ useLabel: props.useLabel, label: 'Opções' }) // label não pode ser sobrescrita.
21
+ }
22
+ }
23
+ })
24
+
25
+ return {
26
+ buttonsList
27
+ }
28
+ }
@@ -0,0 +1,17 @@
1
+ import { computed } from 'vue'
2
+
3
+ /**
4
+ * Cenário para quando existir apenas 1 item na lista.
5
+ *
6
+ * @param {{
7
+ * primaryKey: import('vue').ComputedRef<string>,
8
+ * primaryButtonProps: import('vue').ComputedRef<primaryButtonProps>
9
+ * }}
10
+ */
11
+ export default function useSingleAction ({ primaryKey, primaryButtonProps }) {
12
+ const buttonsList = computed(() => ({ [primaryKey.value]: { ...primaryButtonProps.value } }))
13
+
14
+ return {
15
+ buttonsList
16
+ }
17
+ }
@@ -0,0 +1,35 @@
1
+ import { computed } from 'vue'
2
+
3
+ import getLabel from '../utils/get-label'
4
+
5
+ /**
6
+ * Cenário onde vai ter mais de 2 itens na lista, então precisa ficar
7
+ * o botão primário fora do dropdown e o restante dentro do dropdown.
8
+ *
9
+ * @param {{
10
+ * props: { useLabel: boolean },
11
+ * primaryKey: import('vue').ComputedRef<string>,
12
+ * buttonsPropsList: import('vue').ComputedRef<object>
13
+ * primaryButtonProps: import('vue').ComputedRef<primaryButtonProps>
14
+ * }} config
15
+ */
16
+ export default function useSingleSplitActions ({ buttonsPropsList, props, primaryKey, primaryButtonProps }) {
17
+ delete buttonsPropsList[primaryKey.value]
18
+
19
+ const list = computed(() => {
20
+ return {
21
+ buttonsList: {
22
+ [primaryKey.value]: {
23
+ ...primaryButtonProps.value,
24
+ label: getLabel({ useLabel: props.useLabel, label: primaryButtonProps.value.label })
25
+ }
26
+ },
27
+
28
+ dropdownList: buttonsPropsList
29
+ }
30
+ })
31
+
32
+ return {
33
+ list
34
+ }
35
+ }
@@ -0,0 +1,43 @@
1
+ import { computed } from 'vue'
2
+
3
+ /**
4
+ * Composable responsável pelo tooltip
5
+ *
6
+ * @param {{
7
+ * props: { useTooltip: boolean, useLabel: boolean },
8
+ * formattedList: import('vue').ComputedRef<object>
9
+ * fullList: import('vue').ComputedRef<object>
10
+ * }}
11
+ */
12
+ export default function useTooltip ({ props, formattedList, fullList }) {
13
+ const hasTooltip = computed(() => !props.useLabel && props.useTooltip)
14
+
15
+ /**
16
+ * Precisa existir um tooltip para item de "formattedList.value.buttonsList",
17
+ * então é preciso fazer um tratamento, uma vez que dentro de "formattedList.value.buttonsList"
18
+ * não existe mais "labels", então recuperamos elas de "fullList".
19
+ */
20
+ const tooltipLabels = computed(() => {
21
+ if (!hasTooltip.value) return {}
22
+
23
+ const formattedProps = {}
24
+
25
+ for (const key in formattedList.value.buttonsList) {
26
+ formattedProps[key] = {
27
+ label: fullList.value[key]?.label
28
+ }
29
+ }
30
+
31
+ return formattedProps
32
+ })
33
+
34
+ function showTooltip ({ label }) {
35
+ return hasTooltip.value && label
36
+ }
37
+
38
+ return {
39
+ tooltipLabels,
40
+
41
+ showTooltip
42
+ }
43
+ }
@@ -0,0 +1,3 @@
1
+ export default function getLabel ({ useLabel, label }) {
2
+ return useLabel ? label : ''
3
+ }
@@ -0,0 +1,6 @@
1
+ export default function setClickHandler (item = {}) {
2
+ if (typeof item.handler === 'function') {
3
+ const { handler, ...filtered } = item
4
+ item.handler(filtered)
5
+ }
6
+ }
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="qas-app-menu">
3
- <q-drawer v-model="model" :behavior="behavior" class="shadow-2" :mini="isMiniMode" :mini-width="88" show-if-above :width="drawerWidth" @mouseenter="onMouseEvent" @mouseleave="onMouseEvent">
3
+ <q-drawer :key="reRenderCount" v-model="model" :behavior="behavior" class="shadow-2" :mini="isMiniMode" :mini-width="88" show-if-above :width="drawerWidth" @mouseenter="onMouseEvent" @mouseleave="onMouseEvent">
4
4
  <div class="column full-height justify-between no-wrap">
5
5
  <div class="full-width">
6
6
  <!-- Brand -->
@@ -93,7 +93,7 @@ import useAppUser from './composables/use-app-user'
93
93
  import useDevelopmentBadge from './composables/use-development-badge'
94
94
  import { useScreen } from '../../composables'
95
95
 
96
- import { ref, computed } from 'vue'
96
+ import { ref, computed, watch } from 'vue'
97
97
  import { useRouter } from 'vue-router'
98
98
 
99
99
  defineOptions({
@@ -155,6 +155,7 @@ const rootRoute = router.hasRoute('Root') ? { name: 'Root' } : { path: '/' }
155
155
 
156
156
  const hasOpenedMenu = ref(false)
157
157
  const isMini = ref(screen.isLarge)
158
+ const reRenderCount = ref(0)
158
159
 
159
160
  const composableParams = {
160
161
  props,
@@ -194,6 +195,24 @@ const classes = computed(() => {
194
195
  }
195
196
  })
196
197
 
198
+ /**
199
+ * @desc Recurso tecnológico temporário (ou definitivo), este bug ocorre por conta
200
+ * da atualização do vue para a versão `v3.4+`, onde tiveram mudanças referentes a
201
+ * reatividade, existem issues abertas no Quasar, porém sem expectativas
202
+ * de que um dia será resolvido por parte deles.
203
+ *
204
+ * @see {@link https://github.com/quasarframework/quasar/issues/16651}
205
+ */
206
+ watch(() => behavior.value, value => {
207
+ /**
208
+ * @desc quando o comportamento passa a ser desktop novamente é porque aconteceu um
209
+ * resize na pagina, então é necessário renderizar o componente QDrawer novamente.
210
+ */
211
+ if (value === 'desktop') {
212
+ reRenderCount.value += 1
213
+ }
214
+ })
215
+
197
216
  // métodos
198
217
  function closeDrawer () {
199
218
  emit('update:modelValue', false)
@@ -72,9 +72,11 @@
72
72
  import QasAvatar from '../avatar/QasAvatar.vue'
73
73
 
74
74
  import useNotifications from '../../composables/use-notifications'
75
+ import useQueryCache from '../../composables/use-query-cache'
75
76
  import { NotifySuccess, NotifyError } from '../../plugins'
76
77
 
77
78
  import { ref, computed, watch, inject } from 'vue'
79
+ import { useRouter } from 'vue-router'
78
80
 
79
81
  defineOptions({ name: 'QasAppUser' })
80
82
 
@@ -111,8 +113,12 @@ const emit = defineEmits(['sign-out', 'toggle-notifications'])
111
113
  // vindo direto do boot api.js
112
114
  const axios = inject('axios')
113
115
 
116
+ const router = useRouter()
117
+
114
118
  const { isNotificationsEnabled, unreadNotificationsCount } = useNotifications()
115
119
 
120
+ const { reset } = useQueryCache()
121
+
116
122
  const companiesModel = ref('')
117
123
  const loading = ref(false)
118
124
 
@@ -198,9 +204,17 @@ async function setCompanies (value) {
198
204
  NotifyError('Falha ao alterar vínculo.')
199
205
  } finally {
200
206
  loading.value = false
207
+
208
+ clearCachedFilters()
201
209
  }
202
210
  }
203
211
 
212
+ function clearCachedFilters () {
213
+ reset()
214
+
215
+ router.push({ query: {} })
216
+ }
217
+
204
218
  function onMenuHide () {
205
219
  if (!companiesModel.value) {
206
220
  companiesModel.value = props.companyProps.modelValue
@@ -1,21 +1,25 @@
1
1
  <template>
2
2
  <div class="qas-btn-dropdown" :class="classes.parent">
3
- <div v-if="hasLeftButton" :class="classes.leftSide">
4
- <slot name="left-button">
5
- <qas-btn variant="tertiary" v-bind="defaultButtonProps" @click="onClick">
6
- <q-menu v-if="hasMenuOnLeftSide" v-model="isMenuOpened" anchor="bottom right" auto-close self="top right" @update:model-value="onUpdateMenuValue">
7
- <div :class="classes.menuContent">
8
- <slot />
9
- </div>
10
- </q-menu>
11
- </qas-btn>
12
- </slot>
3
+ <div v-if="hasButtons" class="flex">
4
+ <div v-for="(buttonProps, key, index) in props.buttonsPropsList" :key="key">
5
+ <div class="flex">
6
+ <qas-btn :disable="props.disable" v-bind="buttonProps" variant="tertiary" @click="onClick">
7
+ <q-menu v-if="hasMenuOnLeftSide" v-model="isMenuOpened" anchor="bottom right" auto-close self="top right" @update:model-value="onUpdateMenuValue">
8
+ <div :class="classes.menuContent">
9
+ <slot />
10
+ </div>
11
+ </q-menu>
12
+ </qas-btn>
13
+
14
+ <slot :name="`bottom-${key}`" />
15
+
16
+ <q-separator v-if="hasSeparator(index)" class="q-mx-sm qas-btn-dropdown__separator self-center" dark vertical />
17
+ </div>
18
+ </div>
13
19
  </div>
14
20
 
15
- <q-separator v-if="hasSeparator" class="q-mr-sm qas-btn-dropdown__separator self-center" dark vertical />
16
-
17
21
  <div v-if="props.useSplit">
18
- <qas-btn color="grey-10" :icon="props.dropdownIcon" variant="tertiary">
22
+ <qas-btn color="grey-10" :disable="disable" :icon="props.dropdownIcon" variant="tertiary">
19
23
  <q-menu v-if="hasDefaultSlot" anchor="bottom right" auto-close self="top right">
20
24
  <div :class="classes.menuContent">
21
25
  <slot />
@@ -37,7 +41,7 @@ defineOptions({
37
41
  })
38
42
 
39
43
  const props = defineProps({
40
- buttonProps: {
44
+ buttonsPropsList: {
41
45
  default: () => ({}),
42
46
  type: Object
43
47
  },
@@ -47,7 +51,11 @@ const props = defineProps({
47
51
  type: String
48
52
  },
49
53
 
50
- useSplit: {
54
+ disable: {
55
+ type: Boolean
56
+ },
57
+
58
+ menu: {
51
59
  type: Boolean
52
60
  },
53
61
 
@@ -55,8 +63,13 @@ const props = defineProps({
55
63
  type: Boolean
56
64
  },
57
65
 
58
- menu: {
66
+ useSplit: {
59
67
  type: Boolean
68
+ },
69
+
70
+ useTooltip: {
71
+ type: Boolean,
72
+ default: true
60
73
  }
61
74
  })
62
75
 
@@ -67,47 +80,24 @@ const screen = useScreen()
67
80
 
68
81
  const isMenuOpened = ref(false)
69
82
 
70
- const defaultButtonProps = computed(() => {
71
- const {
72
- icon,
73
- iconRight,
74
- color,
75
- ...defaultProps
76
- } = props.buttonProps
77
-
78
- const defaultIconRight = iconRight || props.dropdownIcon
79
-
80
- return {
81
- useLabelOnSmallScreen: false,
82
-
83
- ...defaultProps,
84
-
85
- color: color || (!props.useSplit ? 'grey-10' : 'primary'),
86
- ...(!props.useSplit && { iconRight: defaultIconRight }),
87
- ...(props.useSplit && { icon })
88
- }
89
- })
90
-
91
83
  const classes = computed(() => {
92
84
  return {
93
85
  parent: {
94
86
  'flex inline items-center': props.useSplit
95
87
  },
96
88
 
97
- leftSide: {
98
- 'q-mr-sm': props.useSplit
99
- },
100
-
101
89
  menuContent: {
102
90
  'q-pa-md': props.useMenuPadding
103
91
  }
104
92
  }
105
93
  })
106
94
 
95
+ const buttonsPropsListSize = computed(() => Object.keys(props.buttonsPropsList).length)
96
+ const isSingleButton = computed(() => buttonsPropsListSize.value === 1)
97
+
98
+ const hasButtons = computed(() => !screen.isSmall || !props.useSplit)
107
99
  const hasDefaultSlot = computed(() => !!slots.default)
108
- const hasLeftButton = computed(() => !screen.isSmall || !props.useSplit)
109
- const hasMenuOnLeftSide = computed(() => hasDefaultSlot.value && !props.useSplit)
110
- const hasSeparator = computed(() => !screen.isSmall && props.useSplit)
100
+ const hasMenuOnLeftSide = computed(() => hasDefaultSlot.value && !props.useSplit && isSingleButton.value)
111
101
 
112
102
  watch(() => props.menu, value => {
113
103
  isMenuOpened.value = value
@@ -120,6 +110,14 @@ function onUpdateMenuValue (value) {
120
110
  function onClick (event) {
121
111
  emit('click', event)
122
112
  }
113
+
114
+ function isLast (index) {
115
+ return index + 1 === buttonsPropsListSize.value
116
+ }
117
+
118
+ function hasSeparator (index) {
119
+ return props.useSplit || !isLast(index)
120
+ }
123
121
  </script>
124
122
 
125
123
  <style lang="scss">
@@ -4,11 +4,16 @@ meta:
4
4
  desc: Componente semelhante ao QBtnDropdown porém utilizando o QasBtn e QSeparator para aplicar estilos padrões do Design System.
5
5
 
6
6
  props:
7
- button-props:
8
- desc: Propriedades repassadas para o QasBtn.
9
- default: {}
10
- type: Object
11
- examples: ["{ color: 'white', icon: 'sym_r_person' }"]
7
+ buttons-props-list:
8
+ desc: Lista de propriedades repassadas para os botões.
9
+ default: []
10
+ type: Array
11
+ examples: ["[{ color: 'white', icon: 'sym_r_person' }]"]
12
+
13
+ disable:
14
+ desc: Desabilita o componente como um todo.
15
+ default: false
16
+ type: Boolean
12
17
 
13
18
  dropdown-icon:
14
19
  desc: Ícone a direita do dropdown.
@@ -33,10 +38,9 @@ props:
33
38
 
34
39
  slots:
35
40
  default:
36
- desc: Slot para passar o conteúdo do dropdown (menu)
37
-
38
- left-button:
39
- desc: Slot para substituir o botão a esquerda.
41
+ desc: Slot para passar o conteúdo do dropdown (menu).
42
+ bottom-[buttons-props-list-key]:
43
+ desc: Slot unitário para acessar abaixo de cada botão (normalmente utilizado para tooltip).
40
44
 
41
45
  events:
42
46
  '@click -> function (event)':
@@ -489,7 +489,7 @@ export default {
489
489
  if (file.isFailed) return
490
490
 
491
491
  if (!this.isMultiple) {
492
- return this.$emit('update:modelValue')
492
+ return this.$emit('update:modelValue', this.useObjectModel ? {} : '')
493
493
  }
494
494
 
495
495
  const clonedValue = extend(true, [], this.modelValue)
@@ -605,6 +605,14 @@ export default {
605
605
  this.$emit('update:modelValue', this.isMultiple ? [...this.modelValue, model] : model || '')
606
606
 
607
607
  this.updateUploading(false)
608
+ },
609
+
610
+ reset () {
611
+ this.$refs.uploader.reset()
612
+
613
+ const emptyModel = this.isMultiple ? [] : this.useObjectModel ? {} : ''
614
+
615
+ this.$emit('update:modelValue', emptyModel)
608
616
  }
609
617
  }
610
618
  }
@@ -186,3 +186,7 @@ events:
186
186
  value:
187
187
  desc: Retorna se está ou não fazendo um upload.
188
188
  type: Boolean
189
+
190
+ methods:
191
+ 'reset: () => void':
192
+ desc: Reseta o campo do uploader.
@@ -1,7 +1,7 @@
1
1
  import { SessionStorage } from 'quasar'
2
2
  import { filterObject } from '../helpers'
3
3
 
4
- const cachedFilters = SessionStorage.getItem('cachedFilters') || {}
4
+ let cachedFilters = SessionStorage.getItem('cachedFilters') || {}
5
5
 
6
6
  function updateSessionStorage () {
7
7
  SessionStorage.set('cachedFilters', cachedFilters)
@@ -41,6 +41,12 @@ export default function () {
41
41
  updateSessionStorage()
42
42
  }
43
43
 
44
+ function reset () {
45
+ cachedFilters = {}
46
+
47
+ updateSessionStorage()
48
+ }
49
+
44
50
  return {
45
51
  addOne,
46
52
  addMany,
@@ -48,6 +54,7 @@ export default function () {
48
54
  findAll,
49
55
  clearOne,
50
56
  clearAll,
51
- cachedFilters
57
+ cachedFilters,
58
+ reset
52
59
  }
53
60
  }