@bildvitta/quasar-ui-asteroid 3.18.0-beta.3 → 3.18.0-beta.4
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 +1 -1
- package/src/components/actions-menu/QasActionsMenu.vue +32 -7
- package/src/components/btn/QasBtn.vue +37 -8
- package/src/components/btn-dropdown/QasBtnDropdown.vue +7 -2
- package/src/components/btn-dropdown/QasBtnDropdown.yml +5 -0
- package/src/components/header/QasHeader.vue +11 -2
- package/src/components/table-generator/QasTableGenerator.vue +22 -43
- package/src/components/table-generator/_components/PvTableGeneratorTd.vue +13 -1
- package/src/css/components/button.scss +4 -2
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
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">
|
|
3
|
+
<qas-btn-dropdown v-bind="btnDropdownProps" v-model:menu="menuModel">
|
|
4
|
+
<q-list v-if="hasDropdownLength" data-cy="actions-menu-list">
|
|
5
5
|
<slot v-for="(item, key) in formattedList.dropdownList" :item="item" :name="key">
|
|
6
6
|
<q-item v-bind="getItemProps(item)" :key="key" active-class="primary" clickable data-cy="actions-menu-list-item" @click="setClickHandler(item)">
|
|
7
7
|
<q-item-section avatar>
|
|
8
|
-
<q-
|
|
8
|
+
<q-spinner v-if="item.loading" size="sm" />
|
|
9
|
+
<q-icon v-else :name="item.icon" />
|
|
9
10
|
</q-item-section>
|
|
10
11
|
|
|
11
12
|
<q-item-section>
|
|
@@ -41,7 +42,7 @@ import useSingleSplitActions from './composables/use-single-split-actions'
|
|
|
41
42
|
import getLabel from './utils/get-label'
|
|
42
43
|
import setClickHandler from './utils/set-click-handler'
|
|
43
44
|
|
|
44
|
-
import { computed, inject } from 'vue'
|
|
45
|
+
import { computed, inject, ref, watch } from 'vue'
|
|
45
46
|
|
|
46
47
|
const DEFAULT_COLOR = 'grey-10'
|
|
47
48
|
const SPLIT_SIZE = 2
|
|
@@ -95,10 +96,15 @@ const props = defineProps({
|
|
|
95
96
|
}
|
|
96
97
|
})
|
|
97
98
|
|
|
99
|
+
// refs
|
|
100
|
+
const menuModel = ref(false)
|
|
101
|
+
|
|
102
|
+
// composables
|
|
98
103
|
const screen = useScreen()
|
|
99
104
|
|
|
100
105
|
const { deleteBtnProps, hasDelete } = useDelete({ color: DEFAULT_COLOR, props, qas })
|
|
101
106
|
|
|
107
|
+
// computeds
|
|
102
108
|
const hasSplitName = computed(() => !!props.splitName)
|
|
103
109
|
const hasList = computed(() => !!Object.keys(fullList.value).length)
|
|
104
110
|
|
|
@@ -157,11 +163,22 @@ const defaultButtonPropsList = computed(() => {
|
|
|
157
163
|
return normalizedButtonPropsList
|
|
158
164
|
})
|
|
159
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Procura se alguma ação está com "loading: true", para o dropdown não fechar
|
|
168
|
+
* automaticamente após clicar em alguma ação.
|
|
169
|
+
*/
|
|
170
|
+
const hasActiveLoading = computed(() => {
|
|
171
|
+
return Object.values(formattedList.value.dropdownList)?.some(action => action.loading)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
const hasDropdownLength = computed(() => !!Object.keys(formattedList.value.dropdownList).length)
|
|
175
|
+
|
|
160
176
|
const btnDropdownProps = computed(() => {
|
|
161
177
|
return {
|
|
162
178
|
buttonsPropsList: defaultButtonPropsList.value,
|
|
163
179
|
disable: props.disable,
|
|
164
|
-
useSplit: hasSplit.value
|
|
180
|
+
useSplit: hasSplit.value,
|
|
181
|
+
useAutoClose: !hasActiveLoading.value
|
|
165
182
|
}
|
|
166
183
|
})
|
|
167
184
|
|
|
@@ -238,14 +255,22 @@ const formattedList = computed(() => {
|
|
|
238
255
|
|
|
239
256
|
const { showTooltip, tooltipLabels } = useTooltips({ formattedList, fullList, props })
|
|
240
257
|
|
|
258
|
+
watch(() => hasActiveLoading.value, handleMenuModel)
|
|
241
259
|
// functions
|
|
242
260
|
function getItemProps (item) {
|
|
243
|
-
const { disable, props: itemProps, to } = item
|
|
261
|
+
const { disable, loading, props: itemProps, to } = item
|
|
244
262
|
|
|
245
263
|
return {
|
|
246
|
-
disable,
|
|
264
|
+
disable: disable || loading, // ficará desabilitado se for passado a prop "disable" ou o "loading" seja true.
|
|
247
265
|
to,
|
|
248
266
|
...itemProps
|
|
249
267
|
}
|
|
250
268
|
}
|
|
269
|
+
|
|
270
|
+
function handleMenuModel (newValue, oldValue) {
|
|
271
|
+
// Fecha o menu após o estado de loading do item passar de true para false
|
|
272
|
+
if (oldValue && !newValue) {
|
|
273
|
+
menuModel.value = false
|
|
274
|
+
}
|
|
275
|
+
}
|
|
251
276
|
</script>
|
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<!-- "data-table-ignore-tr-hover" é para desabilitar o hover do tr no QasTableGenerator -->
|
|
3
3
|
<q-btn ref="button" class="qas-btn" data-table-ignore-tr-hover v-bind="attributes">
|
|
4
|
-
<slot />
|
|
5
|
-
|
|
6
4
|
<template v-for="(_, name) in nonDefaultSlots" #[name]="context">
|
|
7
5
|
<slot :name="name" v-bind="context || {}" />
|
|
8
6
|
</template>
|
|
7
|
+
|
|
8
|
+
<div class="items-center justify-center no-wrap row text-center" :class="containerClasses">
|
|
9
|
+
<q-spinner v-if="hasLeftSpinner" :class="iconClasses" size="sm" />
|
|
10
|
+
|
|
11
|
+
<q-icon v-if="hasIcon" :class="iconClasses" :name="props.icon" />
|
|
12
|
+
|
|
13
|
+
<div v-if="showLabel" :class="labelClasses">
|
|
14
|
+
{{ props.label }}
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<q-spinner v-if="hasRightSpinner" :class="iconRightClasses" size="sm" />
|
|
18
|
+
|
|
19
|
+
<q-icon v-if="hasIconRight" :class="iconRightClasses" :name="props.iconRight" />
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<slot />
|
|
9
23
|
</q-btn>
|
|
10
24
|
</template>
|
|
11
25
|
|
|
@@ -46,6 +60,10 @@ const props = defineProps({
|
|
|
46
60
|
type: String
|
|
47
61
|
},
|
|
48
62
|
|
|
63
|
+
loading: {
|
|
64
|
+
type: Boolean
|
|
65
|
+
},
|
|
66
|
+
|
|
49
67
|
variant: {
|
|
50
68
|
default: 'tertiary',
|
|
51
69
|
type: String,
|
|
@@ -84,6 +102,18 @@ const hasIconOnly = computed(() => {
|
|
|
84
102
|
)
|
|
85
103
|
})
|
|
86
104
|
|
|
105
|
+
const hasLeftSpinner = computed(() => props.loading && !props.iconRight)
|
|
106
|
+
const hasRightSpinner = computed(() => props.loading && props.iconRight)
|
|
107
|
+
|
|
108
|
+
const hasIconRight = computed(() => props.iconRight && !props.loading)
|
|
109
|
+
const hasIcon = computed(() => props.icon && !props.loading)
|
|
110
|
+
|
|
111
|
+
const labelClasses = computed(() => ({ ellipsis: props.useEllipsis }))
|
|
112
|
+
const containerClasses = computed(() => ({ 'full-width': props.useEllipsis }))
|
|
113
|
+
|
|
114
|
+
const iconClasses = computed(() => ({ 'on-left': !hasIconOnly.value }))
|
|
115
|
+
const iconRightClasses = computed(() => ({ 'on-right': !hasIconOnly.value }))
|
|
116
|
+
|
|
87
117
|
const classes = computed(() => {
|
|
88
118
|
return {
|
|
89
119
|
'qas-btn--primary': isPrimary.value,
|
|
@@ -104,17 +134,20 @@ const classes = computed(() => {
|
|
|
104
134
|
'qas-btn--no-hover-on-white': !props.useHoverOnWhiteColor,
|
|
105
135
|
|
|
106
136
|
// ellipsis
|
|
107
|
-
'
|
|
137
|
+
'full-width': props.useEllipsis
|
|
108
138
|
}
|
|
109
139
|
})
|
|
110
140
|
|
|
111
141
|
const attributes = computed(() => {
|
|
112
142
|
const {
|
|
143
|
+
class: externalClass,
|
|
113
144
|
dense,
|
|
145
|
+
disable,
|
|
114
146
|
fab,
|
|
115
147
|
fabMini,
|
|
116
148
|
flat,
|
|
117
149
|
glossy,
|
|
150
|
+
loading,
|
|
118
151
|
noWrap,
|
|
119
152
|
outline,
|
|
120
153
|
padding,
|
|
@@ -127,16 +160,12 @@ const attributes = computed(() => {
|
|
|
127
160
|
stretch,
|
|
128
161
|
textColor,
|
|
129
162
|
unelevated,
|
|
130
|
-
class: externalClass,
|
|
131
163
|
...attributesPayload
|
|
132
164
|
} = attrs
|
|
133
165
|
|
|
134
166
|
return {
|
|
135
|
-
...(showLabel.value && { label: props.label }),
|
|
136
|
-
|
|
137
167
|
...attributesPayload,
|
|
138
|
-
|
|
139
|
-
iconRight: props.iconRight,
|
|
168
|
+
disable: disable || props.loading,
|
|
140
169
|
class: [classes.value, externalClass]
|
|
141
170
|
}
|
|
142
171
|
})
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<div v-for="(buttonProps, key, index) in props.buttonsPropsList" :key="key">
|
|
5
5
|
<div class="flex no-wrap">
|
|
6
6
|
<qas-btn :disable="props.disable" v-bind="buttonProps" no-wrap variant="tertiary" @click="onClick">
|
|
7
|
-
<q-menu v-if="hasMenuOnLeftSide" v-model="isMenuOpened" anchor="bottom right" auto-close class="qas-menu" self="top right" @update:model-value="onUpdateMenuValue">
|
|
7
|
+
<q-menu v-if="hasMenuOnLeftSide" v-model="isMenuOpened" anchor="bottom right" :auto-close="props.useAutoClose" class="qas-menu" self="top right" @update:model-value="onUpdateMenuValue">
|
|
8
8
|
<div :class="classes.menuContent">
|
|
9
9
|
<slot />
|
|
10
10
|
</div>
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
<div v-if="props.useSplit">
|
|
22
22
|
<qas-btn v-bind="splittedButtonProps">
|
|
23
|
-
<q-menu v-if="hasDefaultSlot" anchor="bottom right" auto-close class="qas-menu" self="top right">
|
|
23
|
+
<q-menu v-if="hasDefaultSlot" v-model="isMenuOpened" anchor="bottom right" :auto-close="props.useAutoClose" class="qas-menu" self="top right" @update:model-value="onUpdateMenuValue">
|
|
24
24
|
<div :class="classes.menuContent">
|
|
25
25
|
<slot />
|
|
26
26
|
</div>
|
|
@@ -70,6 +70,11 @@ const props = defineProps({
|
|
|
70
70
|
useTooltip: {
|
|
71
71
|
type: Boolean,
|
|
72
72
|
default: true
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
useAutoClose: {
|
|
76
|
+
type: Boolean,
|
|
77
|
+
default: true
|
|
73
78
|
}
|
|
74
79
|
})
|
|
75
80
|
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
</div>
|
|
21
21
|
</div>
|
|
22
22
|
|
|
23
|
-
<div class="items-start no-wrap q-col-gutter-sm row" :class="descriptionSectionClasses">
|
|
23
|
+
<div v-if="hasDescriptionOrOnlyActionsSection" class="items-start no-wrap q-col-gutter-sm row" :class="descriptionSectionClasses">
|
|
24
24
|
<div v-if="hasDescriptionSection" class="text-body1 text-grey-8">
|
|
25
25
|
<slot name="description">
|
|
26
26
|
{{ props.description }}
|
|
@@ -147,6 +147,15 @@ const hasLabel = computed(() => !!Object.keys(props.labelProps).length)
|
|
|
147
147
|
const hasDefaultButton = computed(() => !!Object.keys(props.buttonProps).length)
|
|
148
148
|
const hasDefaultFilters = computed(() => !!Object.keys(props.filtersProps).length)
|
|
149
149
|
const hasDefaultActionsMenu = computed(() => !!Object.keys(props.actionsMenuProps).length)
|
|
150
|
-
const hasDescriptionSection = computed(() => props.description || slots.description)
|
|
150
|
+
const hasDescriptionSection = computed(() => !!props.description || !!slots.description)
|
|
151
151
|
const hasLabelSection = computed(() => hasLabel.value || slots.label || hasBadges.value)
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Só exibo a seção de descrição com a seção de ações ao lado quando:
|
|
155
|
+
* - Tenha descrição;
|
|
156
|
+
* - OU não tenha seção da label E tenha componente de ações.
|
|
157
|
+
*/
|
|
158
|
+
const hasDescriptionOrOnlyActionsSection = computed(() => {
|
|
159
|
+
return hasDescriptionSection.value || (!hasLabelSection.value && hasActionsComponent.value)
|
|
160
|
+
})
|
|
152
161
|
</script>
|
|
@@ -9,16 +9,6 @@
|
|
|
9
9
|
<slot :name="name" v-bind="context" />
|
|
10
10
|
</template>
|
|
11
11
|
|
|
12
|
-
<template #header-cell="context">
|
|
13
|
-
<q-th v-if="context.col.label" :class="[context.col.headerClasses, context.col.__thClass]">
|
|
14
|
-
<qas-btn v-if="context.col.sortable" color="grey-10" icon-right="sym_r_swap_vert" :label="context.col.label" @click="$refs.table.sort(context.col)" />
|
|
15
|
-
|
|
16
|
-
<span v-else>
|
|
17
|
-
{{ context.col.label }}
|
|
18
|
-
</span>
|
|
19
|
-
</q-th>
|
|
20
|
-
</template>
|
|
21
|
-
|
|
22
12
|
<template v-for="(fieldName, index) in bodyCellNameSlots" :key="index" #[`body-cell-${fieldName}`]="context">
|
|
23
13
|
<q-td :class="getTdClasses(context.row)">
|
|
24
14
|
<component :is="tdChildComponent" class="qas-table-generator__td-item" v-bind="getTdChildComponentProps(context.row)">
|
|
@@ -193,8 +183,6 @@ export default {
|
|
|
193
183
|
},
|
|
194
184
|
|
|
195
185
|
columnsByFields () {
|
|
196
|
-
const hasMultipleResults = this.rowsPerPage > 1
|
|
197
|
-
|
|
198
186
|
if (!this.hasFields) {
|
|
199
187
|
return this.normalizedColumns.filter(column => column instanceof Object)
|
|
200
188
|
}
|
|
@@ -202,17 +190,13 @@ export default {
|
|
|
202
190
|
const columns = []
|
|
203
191
|
|
|
204
192
|
function columnByField (field) {
|
|
205
|
-
const { label, name
|
|
193
|
+
const { label, name } = field
|
|
206
194
|
|
|
207
195
|
columns.push({
|
|
208
196
|
align: 'left',
|
|
209
197
|
field: name,
|
|
210
198
|
label,
|
|
211
|
-
name
|
|
212
|
-
headerClasses: 'text-grey-10',
|
|
213
|
-
sortable: sortable ?? hasMultipleResults,
|
|
214
|
-
sort,
|
|
215
|
-
rawSort
|
|
199
|
+
name
|
|
216
200
|
})
|
|
217
201
|
}
|
|
218
202
|
|
|
@@ -504,6 +488,8 @@ export default {
|
|
|
504
488
|
padding-bottom: var(--qas-spacing-sm);
|
|
505
489
|
padding-left: 0;
|
|
506
490
|
padding-top: var(--qas-spacing-sm);
|
|
491
|
+
position: relative;
|
|
492
|
+
z-index: 0;
|
|
507
493
|
|
|
508
494
|
&:not(:last-child) {
|
|
509
495
|
padding-right: var(--qas-spacing-md);
|
|
@@ -514,40 +500,33 @@ export default {
|
|
|
514
500
|
}
|
|
515
501
|
|
|
516
502
|
&::before {
|
|
517
|
-
|
|
503
|
+
position: absolute;
|
|
504
|
+
content: '';
|
|
505
|
+
top: 0;
|
|
506
|
+
left: 0;
|
|
507
|
+
z-index: -1;
|
|
508
|
+
background-color: transparent;
|
|
518
509
|
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
&__middle {
|
|
522
|
-
padding-left: var(--qas-spacing-md);
|
|
523
|
-
padding-right: var(--qas-spacing-md);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
tr {
|
|
527
|
-
position: relative;
|
|
528
510
|
|
|
529
|
-
|
|
530
|
-
background-color: transparent;
|
|
531
|
-
bottom: 0;
|
|
532
|
-
content: '';
|
|
511
|
+
&:first-child::before {
|
|
533
512
|
left: calc(var(--qas-spacing-md) * -1);
|
|
534
|
-
|
|
535
|
-
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
&:last-child::before {
|
|
536
516
|
right: calc(var(--qas-spacing-md) * -1);
|
|
537
|
-
top: 0;
|
|
538
|
-
transition: background-color var(--qas-generic-transition);
|
|
539
517
|
}
|
|
540
518
|
}
|
|
541
519
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
}
|
|
520
|
+
tr:hover td::before {
|
|
521
|
+
background-color: var(--qas-background-color);
|
|
522
|
+
}
|
|
546
523
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
524
|
+
&__middle {
|
|
525
|
+
padding-left: var(--qas-spacing-md);
|
|
526
|
+
padding-right: var(--qas-spacing-md);
|
|
527
|
+
}
|
|
550
528
|
|
|
529
|
+
tbody tr {
|
|
551
530
|
/*
|
|
552
531
|
A regra só é aplicada se nenhum elemento filho com o atributo "data-table-ignore-tr-hover"
|
|
553
532
|
estiver também em estado de hover, impedindo que estilos conflitantes sejam aplicados.
|
|
@@ -83,11 +83,23 @@ const component = computed(() => {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
// Os componentes abaixo precisam adicionar o stopPropagation e preventDefault no click para nao chamar o rowClick ou rowRouteFn
|
|
87
|
+
const hasPreventEvent = ['QasActionsMenu', 'QasBtn'].includes(props.componentData.component)
|
|
88
|
+
|
|
86
89
|
return {
|
|
87
90
|
is: defineAsyncComponent(componentPaths[props.componentData.component].component),
|
|
88
91
|
props: {
|
|
89
92
|
...componentPaths[props.componentData.component].props,
|
|
90
|
-
...props.componentData.props
|
|
93
|
+
...props.componentData.props,
|
|
94
|
+
|
|
95
|
+
...(hasPreventEvent && {
|
|
96
|
+
onClick: event => {
|
|
97
|
+
event.stopPropagation()
|
|
98
|
+
event.preventDefault()
|
|
99
|
+
|
|
100
|
+
props.componentData.props?.onClick?.(event)
|
|
101
|
+
}
|
|
102
|
+
})
|
|
91
103
|
}
|
|
92
104
|
}
|
|
93
105
|
})
|
|
@@ -101,11 +101,13 @@
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
.q-icon.on-left
|
|
104
|
+
.q-icon.on-left,
|
|
105
|
+
.q-spinner.on-left {
|
|
105
106
|
margin-right: var(--qas-spacing-xs);
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
.q-icon.on-right
|
|
109
|
+
.q-icon.on-right,
|
|
110
|
+
.q-spinner.on-right {
|
|
109
111
|
margin-left: var(--qas-spacing-xs);
|
|
110
112
|
}
|
|
111
113
|
|