@bildvitta/quasar-ui-asteroid 3.17.0-beta.0 → 3.17.0-beta.2
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/dialog/QasDialog.vue +3 -1
- package/src/components/form-generator/QasFormGenerator.vue +53 -14
- package/src/components/header/QasHeader.vue +3 -3
- package/src/components/search-input/QasSearchInput.vue +21 -2
- package/src/components/select/QasSelect.vue +25 -0
- package/src/components/select/QasSelect.yml +4 -0
- package/src/components/select-list-dialog/QasSelectListDialog.vue +14 -7
- package/src/components/table-generator/QasTableGenerator.vue +28 -0
- package/src/components/table-generator/QasTableGenerator.yml +9 -0
- package/src/css/utils/border.scss +5 -0
package/package.json
CHANGED
|
@@ -45,7 +45,7 @@ import useDynamicComponents from './composables/use-dynamic-components'
|
|
|
45
45
|
import useOk from './composables/use-ok'
|
|
46
46
|
import { useScreen } from '../../composables'
|
|
47
47
|
|
|
48
|
-
import { computed, ref, useAttrs, useSlots } from 'vue'
|
|
48
|
+
import { computed, ref, useAttrs, useSlots, provide } from 'vue'
|
|
49
49
|
import { useDialogPluginComponent } from 'quasar'
|
|
50
50
|
|
|
51
51
|
defineOptions({ name: 'QasDialog' })
|
|
@@ -120,6 +120,8 @@ const emit = defineEmits([
|
|
|
120
120
|
...useDialogPluginComponent.emits
|
|
121
121
|
])
|
|
122
122
|
|
|
123
|
+
provide('isDialog', true)
|
|
124
|
+
|
|
123
125
|
const attrs = useAttrs()
|
|
124
126
|
const screen = useScreen()
|
|
125
127
|
const slots = useSlots()
|
|
@@ -2,20 +2,22 @@
|
|
|
2
2
|
<div :class="fieldsetClasses">
|
|
3
3
|
<div v-for="(fieldsetItem, fieldsetItemKey) in normalizedFields" :key="fieldsetItemKey" :class="getFieldSetColumnClass(fieldsetItem.column)">
|
|
4
4
|
<component :is="containerComponent.is" v-bind="containerComponent.props">
|
|
5
|
-
<slot v-if="fieldsetItem
|
|
6
|
-
<qas-
|
|
7
|
-
|
|
8
|
-
<div v-if="fieldsetItem.description" class="q-mb-md text-body1 text-grey-8">{{ fieldsetItem.description }}</div>
|
|
5
|
+
<slot v-if="hasFieldsetItem(fieldsetItem)" :name="`legend-${fieldsetItemKey}`">
|
|
6
|
+
<qas-header v-bind="getHeaderProps(fieldsetItem)" />
|
|
9
7
|
</slot>
|
|
10
8
|
|
|
11
9
|
<div>
|
|
12
10
|
<slot :fields="fieldsetItem.fields?.visible" :name="`legend-section-${fieldsetItemKey}`">
|
|
13
|
-
<div :class="
|
|
14
|
-
<div
|
|
15
|
-
<
|
|
16
|
-
<
|
|
17
|
-
|
|
11
|
+
<div class="items-end justify-end" :class="getRowContainerClasses(fieldsetItem)">
|
|
12
|
+
<div :class="fieldContainerClasses">
|
|
13
|
+
<div v-for="(field, key) in fieldsetItem.fields.visible" :key="key" :class="getFieldClass({ index: key, fields: normalizedFields })">
|
|
14
|
+
<slot :field="field" :name="`field-${field.name}`">
|
|
15
|
+
<qas-field :disable="isFieldDisabled(field)" v-bind="props.fieldsProps[field.name]" :error="props.errors[key]" :field="field" :model-value="props.modelValue[field.name]" @update:model-value="updateModelValue({ key: field.name, value: $event })" />
|
|
16
|
+
</slot>
|
|
17
|
+
</div>
|
|
18
18
|
</div>
|
|
19
|
+
|
|
20
|
+
<qas-btn v-if="hasButtonProps(fieldsetItem)" class="md:q-mt-none q-ml-md q-mt-md" v-bind="fieldsetItem.buttonProps" />
|
|
19
21
|
</div>
|
|
20
22
|
|
|
21
23
|
<div v-for="(field, key) in fieldsetItem.fields.hidden" :key="key">
|
|
@@ -34,6 +36,7 @@
|
|
|
34
36
|
import { gutterValidator } from '../../helpers/private/gutter-validator'
|
|
35
37
|
import useGenerator, { baseProps } from '../../composables/private/use-generator'
|
|
36
38
|
import { Spacing } from '../../enums/Spacing'
|
|
39
|
+
import { useScreen } from '../../composables'
|
|
37
40
|
import { computed, provide, inject } from 'vue'
|
|
38
41
|
|
|
39
42
|
defineOptions({ name: 'QasFormGenerator' })
|
|
@@ -94,7 +97,9 @@ provide('isFormGenerator', true)
|
|
|
94
97
|
// composables
|
|
95
98
|
const { classes, getFieldClass, getFieldSetColumnClass } = useGenerator({ props })
|
|
96
99
|
|
|
97
|
-
const { fieldsetClasses, hasFieldset } = useFieldset({ props })
|
|
100
|
+
const { fieldsetClasses, hasFieldset, hasFieldsetItem } = useFieldset({ props })
|
|
101
|
+
|
|
102
|
+
const screen = useScreen()
|
|
98
103
|
|
|
99
104
|
// constants
|
|
100
105
|
const hasNestedFormGenerator = inject('isFormGenerator', false)
|
|
@@ -162,7 +167,9 @@ const normalizedFields = computed(() => {
|
|
|
162
167
|
label: fieldsetItem.label,
|
|
163
168
|
description: fieldsetItem.description,
|
|
164
169
|
column: fieldsetItem.column,
|
|
165
|
-
|
|
170
|
+
buttonProps: fieldsetItem.buttonProps,
|
|
171
|
+
fields: { hidden: {}, visible: {} },
|
|
172
|
+
headerProps: fieldsetItem.headerProps
|
|
166
173
|
}
|
|
167
174
|
|
|
168
175
|
fieldsetItem.fields.forEach(fieldName => {
|
|
@@ -181,13 +188,31 @@ const normalizedFields = computed(() => {
|
|
|
181
188
|
return fields
|
|
182
189
|
})
|
|
183
190
|
|
|
191
|
+
const fieldContainerClasses = computed(() => {
|
|
192
|
+
return [
|
|
193
|
+
...classes.value,
|
|
194
|
+
{
|
|
195
|
+
col: !screen.isSmall
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
})
|
|
199
|
+
|
|
184
200
|
// methods
|
|
185
201
|
function getFieldType ({ type }) {
|
|
186
202
|
return type === 'hidden' ? 'hidden' : 'visible'
|
|
187
203
|
}
|
|
188
204
|
|
|
189
|
-
function
|
|
190
|
-
return
|
|
205
|
+
function getHeaderProps (fieldsetItem) {
|
|
206
|
+
return {
|
|
207
|
+
description: fieldsetItem.description,
|
|
208
|
+
|
|
209
|
+
labelProps: {
|
|
210
|
+
...fieldsetItem.headerProps?.labelProps,
|
|
211
|
+
...(fieldsetItem.label && { label: fieldsetItem.label })
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
...fieldsetItem.headerProps
|
|
215
|
+
}
|
|
191
216
|
}
|
|
192
217
|
|
|
193
218
|
function isFieldDisabled ({ disable }) {
|
|
@@ -201,6 +226,14 @@ function updateModelValue ({ key, value }) {
|
|
|
201
226
|
emit('update:modelValue', models)
|
|
202
227
|
}
|
|
203
228
|
|
|
229
|
+
function hasButtonProps ({ buttonProps = {} }) {
|
|
230
|
+
return !!Object.keys(buttonProps).length
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function getRowContainerClasses (item) {
|
|
234
|
+
return { row: hasButtonProps(item) }
|
|
235
|
+
}
|
|
236
|
+
|
|
204
237
|
// composables
|
|
205
238
|
function useFieldset ({ props }) {
|
|
206
239
|
const fieldsetClasses = computed(() => {
|
|
@@ -215,9 +248,15 @@ function useFieldset ({ props }) {
|
|
|
215
248
|
|
|
216
249
|
const hasFieldset = computed(() => !!Object.keys(props.fieldset).length)
|
|
217
250
|
|
|
251
|
+
function hasFieldsetItem (fieldset = {}) {
|
|
252
|
+
return !!Object.keys(fieldset).length
|
|
253
|
+
}
|
|
254
|
+
|
|
218
255
|
return {
|
|
219
256
|
fieldsetClasses,
|
|
220
|
-
hasFieldset
|
|
257
|
+
hasFieldset,
|
|
258
|
+
|
|
259
|
+
hasFieldsetItem
|
|
221
260
|
}
|
|
222
261
|
}
|
|
223
262
|
</script>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<div v-if="hasLabelSection" class="items-center justify-between no-wrap row" :class="labelSectionClasses">
|
|
4
4
|
<div class="items-center q-col-gutter-sm row">
|
|
5
5
|
<slot name="label">
|
|
6
|
-
<qas-label v-bind="defaultLabelProps" />
|
|
6
|
+
<qas-label v-if="hasLabel" v-bind="defaultLabelProps" />
|
|
7
7
|
</slot>
|
|
8
8
|
|
|
9
9
|
<div v-if="hasBadges" class="col-auto items-center q-col-gutter-sm row">
|
|
@@ -73,7 +73,7 @@ const props = defineProps({
|
|
|
73
73
|
},
|
|
74
74
|
|
|
75
75
|
spacing: {
|
|
76
|
-
default: Spacing.
|
|
76
|
+
default: Spacing.Md,
|
|
77
77
|
type: String,
|
|
78
78
|
validator: gutterValidator
|
|
79
79
|
}
|
|
@@ -102,5 +102,5 @@ const hasLabel = computed(() => !!Object.keys(props.labelProps).length)
|
|
|
102
102
|
const hasDefaultButton = computed(() => !!Object.keys(props.buttonProps).length)
|
|
103
103
|
const hasDefaultActionsMenu = computed(() => !!Object.keys(props.actionsMenuProps).length)
|
|
104
104
|
const hasDescriptionSection = computed(() => props.description || slots.description)
|
|
105
|
-
const hasLabelSection = computed(() => hasLabel.value || slots.label)
|
|
105
|
+
const hasLabelSection = computed(() => hasLabel.value || slots.label || hasBadges.value)
|
|
106
106
|
</script>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<component :is="component" class="qas-search-input" :class="containerClasses" :use-spacing="false">
|
|
3
3
|
<qas-input ref="input" v-model="model" class="qas-search-input__input" v-bind="$attrs" data-cy="search-input" :debounce="debounce" dense hide-bottom-space input-class="ellipsis text-grey-8" inputmode="search" outlined type="search">
|
|
4
4
|
<template #prepend>
|
|
5
5
|
<q-icon v-if="useSearchOnType" color="grey-8" name="sym_r_search" />
|
|
@@ -13,13 +13,18 @@
|
|
|
13
13
|
<slot name="after-clear" />
|
|
14
14
|
</template>
|
|
15
15
|
</qas-input>
|
|
16
|
-
</
|
|
16
|
+
</component>
|
|
17
17
|
</template>
|
|
18
18
|
|
|
19
19
|
<script>
|
|
20
20
|
export default {
|
|
21
21
|
name: 'QasSearchInput',
|
|
22
22
|
|
|
23
|
+
inject: {
|
|
24
|
+
isBox: { default: false },
|
|
25
|
+
isDialog: { default: false }
|
|
26
|
+
},
|
|
27
|
+
|
|
23
28
|
inheritAttrs: false,
|
|
24
29
|
|
|
25
30
|
props: {
|
|
@@ -46,6 +51,20 @@ export default {
|
|
|
46
51
|
],
|
|
47
52
|
|
|
48
53
|
computed: {
|
|
54
|
+
component () {
|
|
55
|
+
return this.isBoxOrDialog ? 'div' : 'qas-box'
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
containerClasses () {
|
|
59
|
+
return {
|
|
60
|
+
bordered: this.isBoxOrDialog
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
isBoxOrDialog () {
|
|
65
|
+
return this.isBox || this.isDialog
|
|
66
|
+
},
|
|
67
|
+
|
|
49
68
|
debounce () {
|
|
50
69
|
return this.useDebounce ? '1200' : ''
|
|
51
70
|
},
|
|
@@ -79,6 +79,10 @@ export default {
|
|
|
79
79
|
type: Boolean
|
|
80
80
|
},
|
|
81
81
|
|
|
82
|
+
useAutoSelect: {
|
|
83
|
+
type: Boolean
|
|
84
|
+
},
|
|
85
|
+
|
|
82
86
|
useFetchOptionsOnCreate: {
|
|
83
87
|
default: true,
|
|
84
88
|
type: Boolean
|
|
@@ -187,6 +191,10 @@ export default {
|
|
|
187
191
|
return getRequiredLabel({ label: this.label, required: this.required })
|
|
188
192
|
},
|
|
189
193
|
|
|
194
|
+
canSetDefaultOption () {
|
|
195
|
+
return (this.required || this.useAutoSelect) && this.options.length === 1 && !this.modelValue
|
|
196
|
+
},
|
|
197
|
+
|
|
190
198
|
// redesign
|
|
191
199
|
componentClasses () {
|
|
192
200
|
return {
|
|
@@ -220,15 +228,24 @@ export default {
|
|
|
220
228
|
this.togglePopupContentClass(value)
|
|
221
229
|
},
|
|
222
230
|
|
|
231
|
+
required () {
|
|
232
|
+
if (!this.canSetDefaultOption) return
|
|
233
|
+
|
|
234
|
+
this.setDefaultOption()
|
|
235
|
+
},
|
|
236
|
+
|
|
223
237
|
options: {
|
|
224
238
|
handler () {
|
|
225
239
|
if (this.useLazyLoading && this.mx_hasFilteredOptions) return
|
|
226
240
|
|
|
227
241
|
if (this.fuse || this.hasFuse) this.setFuse()
|
|
228
242
|
|
|
243
|
+
if (this.canSetDefaultOption) this.setDefaultOption()
|
|
244
|
+
|
|
229
245
|
this.mx_filteredOptions = [...this.options]
|
|
230
246
|
},
|
|
231
247
|
|
|
248
|
+
deep: true,
|
|
232
249
|
immediate: true
|
|
233
250
|
}
|
|
234
251
|
},
|
|
@@ -303,6 +320,14 @@ export default {
|
|
|
303
320
|
if (popupContentElement) {
|
|
304
321
|
popupContentElement.classList.toggle('qas-select__is-fetching', force)
|
|
305
322
|
}
|
|
323
|
+
},
|
|
324
|
+
|
|
325
|
+
setDefaultOption () {
|
|
326
|
+
const modelValue = this.attributes.emitValue
|
|
327
|
+
? this.options[0].value
|
|
328
|
+
: this.options[0]
|
|
329
|
+
|
|
330
|
+
this.$emit('update:modelValue', modelValue)
|
|
306
331
|
}
|
|
307
332
|
}
|
|
308
333
|
}
|
|
@@ -81,6 +81,10 @@ props:
|
|
|
81
81
|
type: String
|
|
82
82
|
examples: [value-key="uuid"]
|
|
83
83
|
|
|
84
|
+
use-auto-select:
|
|
85
|
+
desc: Controla se o select vai auto preencher em casos de ter uma única opção e não for required.
|
|
86
|
+
type: Boolean
|
|
87
|
+
|
|
84
88
|
use-fetch-options-on-create:
|
|
85
89
|
desc: Controla se o componente vai fazer um fetch das opções assim que o mesmo é criado (caso tenha lazy loading ativado).
|
|
86
90
|
default: true
|
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
{{ props.description }}
|
|
17
17
|
</div>
|
|
18
18
|
|
|
19
|
-
<
|
|
20
|
-
|
|
19
|
+
<component
|
|
20
|
+
:is="containerListComponent"
|
|
21
|
+
v-if="canShowContainerList"
|
|
21
22
|
class="q-mt-md relative-position"
|
|
22
23
|
>
|
|
23
24
|
<span class="text-grey-10 text-subtitle1">
|
|
@@ -42,7 +43,7 @@
|
|
|
42
43
|
size="2em"
|
|
43
44
|
/>
|
|
44
45
|
</q-inner-loading>
|
|
45
|
-
</
|
|
46
|
+
</component>
|
|
46
47
|
|
|
47
48
|
<span
|
|
48
49
|
v-if="hasError"
|
|
@@ -76,7 +77,7 @@
|
|
|
76
77
|
</template>
|
|
77
78
|
|
|
78
79
|
<script setup>
|
|
79
|
-
import { computed, ref, watch, useSlots } from 'vue'
|
|
80
|
+
import { computed, ref, watch, useSlots, inject } from 'vue'
|
|
80
81
|
|
|
81
82
|
defineOptions({ name: 'QasSelectListDialog' })
|
|
82
83
|
|
|
@@ -143,8 +144,11 @@ const emit = defineEmits(['add', 'remove', 'update:modelValue'])
|
|
|
143
144
|
|
|
144
145
|
const slots = useSlots()
|
|
145
146
|
|
|
147
|
+
const isBox = inject('isBox', false)
|
|
148
|
+
|
|
146
149
|
const hasError = computed(() => Array.isArray(props.error) ? !!props.error.length : !!props.error)
|
|
147
150
|
const errorMessage = computed(() => Array.isArray(props.error) ? props.error.join(' ') : props.error)
|
|
151
|
+
const containerListComponent = computed(() => isBox ? 'div' : 'qas-box')
|
|
148
152
|
|
|
149
153
|
const {
|
|
150
154
|
listModel,
|
|
@@ -160,7 +164,7 @@ const {
|
|
|
160
164
|
const {
|
|
161
165
|
selectedOptions,
|
|
162
166
|
|
|
163
|
-
|
|
167
|
+
canShowContainerList,
|
|
164
168
|
|
|
165
169
|
add,
|
|
166
170
|
removeAll,
|
|
@@ -224,7 +228,10 @@ function useList () {
|
|
|
224
228
|
filteredOptions.value = [...options]
|
|
225
229
|
})
|
|
226
230
|
|
|
227
|
-
|
|
231
|
+
/**
|
|
232
|
+
* Valida se tenho opções ou se está carregando para mostrar o container da listagem.
|
|
233
|
+
*/
|
|
234
|
+
const canShowContainerList = computed(() => hasFilteredOptions.value || props.loading)
|
|
228
235
|
const hasFilteredOptions = computed(() => model.value.length)
|
|
229
236
|
|
|
230
237
|
/*
|
|
@@ -282,7 +289,7 @@ function useList () {
|
|
|
282
289
|
filteredOptions,
|
|
283
290
|
selectedOptions,
|
|
284
291
|
|
|
285
|
-
|
|
292
|
+
canShowContainerList,
|
|
286
293
|
hasFilteredOptions,
|
|
287
294
|
|
|
288
295
|
add,
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<component :is="parentComponent.is">
|
|
3
|
+
<slot name="parent-header">
|
|
4
|
+
<qas-header v-if="hasHeaderProps" v-bind="headerProps" />
|
|
5
|
+
</slot>
|
|
6
|
+
|
|
3
7
|
<q-table ref="table" class="bg-white qas-table-generator text-grey-8" v-bind="attributes">
|
|
4
8
|
<template v-for="(_, name) in slots" #[name]="context">
|
|
5
9
|
<slot :name="name" v-bind="context" />
|
|
@@ -41,6 +45,11 @@ export default {
|
|
|
41
45
|
type: [Array, Object]
|
|
42
46
|
},
|
|
43
47
|
|
|
48
|
+
headerProps: {
|
|
49
|
+
default: () => ({}),
|
|
50
|
+
type: Object
|
|
51
|
+
},
|
|
52
|
+
|
|
44
53
|
results: {
|
|
45
54
|
default: () => [],
|
|
46
55
|
required: true,
|
|
@@ -228,6 +237,10 @@ export default {
|
|
|
228
237
|
return {
|
|
229
238
|
is: this.useBox ? 'qas-box' : 'div'
|
|
230
239
|
}
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
hasHeaderProps () {
|
|
243
|
+
return !!Object.keys(this.headerProps).length
|
|
231
244
|
}
|
|
232
245
|
},
|
|
233
246
|
|
|
@@ -320,8 +333,15 @@ export default {
|
|
|
320
333
|
<style lang="scss">
|
|
321
334
|
.qas-table-generator {
|
|
322
335
|
.q-table {
|
|
336
|
+
thead tr {
|
|
337
|
+
height: 24px;
|
|
338
|
+
}
|
|
339
|
+
|
|
323
340
|
th {
|
|
324
341
|
@include set-typography($subtitle1);
|
|
342
|
+
|
|
343
|
+
border: 0 !important;
|
|
344
|
+
padding: 0 calc(var(--qas-spacing-lg) / 2);
|
|
325
345
|
}
|
|
326
346
|
|
|
327
347
|
td,
|
|
@@ -334,6 +354,10 @@ export default {
|
|
|
334
354
|
td {
|
|
335
355
|
@include set-typography($body1);
|
|
336
356
|
|
|
357
|
+
height: 40px;
|
|
358
|
+
padding-left: calc(var(--qas-spacing-lg) / 2);
|
|
359
|
+
padding-right: calc(var(--qas-spacing-lg) / 2);
|
|
360
|
+
|
|
337
361
|
&:before {
|
|
338
362
|
transition: background-color var(--qas-generic-transition);
|
|
339
363
|
}
|
|
@@ -345,6 +369,10 @@ export default {
|
|
|
345
369
|
background-color: var(--qas-background-color);
|
|
346
370
|
}
|
|
347
371
|
}
|
|
372
|
+
|
|
373
|
+
&:last-child td {
|
|
374
|
+
padding-bottom: 0;
|
|
375
|
+
}
|
|
348
376
|
}
|
|
349
377
|
|
|
350
378
|
thead tr:hover {
|
|
@@ -20,6 +20,12 @@ props:
|
|
|
20
20
|
type: Object
|
|
21
21
|
examples: ["{ email: { name: 'email', type: 'email', label: 'E-mail' } }"]
|
|
22
22
|
|
|
23
|
+
header-props:
|
|
24
|
+
desc: Propriedades repassadas para o componente `QasHeader`.
|
|
25
|
+
default: {}
|
|
26
|
+
type: Object
|
|
27
|
+
examples: ["{ description: 'Descrição', labelProps: { label: 'Titulo do header'} }"]
|
|
28
|
+
|
|
23
29
|
results:
|
|
24
30
|
desc: Lista com resultados para serem mostrados na tabela.
|
|
25
31
|
default: {}
|
|
@@ -70,6 +76,9 @@ slots:
|
|
|
70
76
|
default: {}
|
|
71
77
|
type: Object
|
|
72
78
|
|
|
79
|
+
parent-header:
|
|
80
|
+
desc: 'Acesso ao slot do header dentro container'
|
|
81
|
+
|
|
73
82
|
events:
|
|
74
83
|
'@row-click -> function(event, row, index)':
|
|
75
84
|
desc: Dispara ao clicar em uma linha. Não funciona usando slots personalizados (body, row e item).
|