@bildvitta/quasar-ui-asteroid 3.0.0-beta.7 → 3.0.0
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/dist/api/QasAppBar.json +0 -4
- package/dist/api/QasBtn.json +2 -1
- package/dist/api/QasCard.json +13 -9
- package/dist/api/QasDateTimeInput.json +12 -12
- package/dist/api/QasDialog.json +6 -2
- package/dist/api/QasFilters.json +4 -4
- package/dist/api/QasFormGenerator.json +33 -2
- package/dist/api/QasFormView.json +43 -15
- package/dist/api/QasGridGenerator.json +5 -4
- package/dist/api/QasInput.json +1 -1
- package/dist/api/QasListItems.json +18 -17
- package/dist/api/QasListView.json +21 -7
- package/dist/api/QasNestedFields.json +13 -3
- package/dist/api/QasNumericInput.json +10 -10
- package/dist/api/QasPasswordInput.json +1 -1
- package/dist/api/QasSearchBox.json +85 -3
- package/dist/api/QasSelect.json +81 -14
- package/dist/api/QasSelectList.json +16 -14
- package/dist/api/QasSignaturePad.json +1 -1
- package/dist/api/QasSingleView.json +13 -4
- package/dist/api/QasTabsGenerator.json +5 -2
- package/dist/api/QasUploader.json +5 -0
- package/dist/asteroid.cjs.css +1 -1
- package/dist/asteroid.cjs.js +1522 -706
- package/dist/asteroid.cjs.min.js +2 -2
- package/dist/asteroid.esm.css +1 -1
- package/dist/asteroid.esm.js +1525 -709
- package/dist/asteroid.esm.min.js +2 -2
- package/dist/asteroid.umd.css +1 -1
- package/dist/asteroid.umd.js +1525 -710
- package/dist/asteroid.umd.min.js +2 -2
- package/dist/vetur/asteroid-attributes.json +176 -100
- package/dist/vetur/asteroid-tags.json +60 -41
- package/package.json +1 -1
- package/src/components/actions-menu/QasActionsMenu.vue +2 -8
- package/src/components/app-bar/QasAppBar.vue +16 -12
- package/src/components/app-bar/QasAppBar.yml +0 -4
- package/src/components/avatar/QasAvatar.vue +0 -4
- package/src/components/btn/QasBtn.vue +5 -8
- package/src/components/btn/QasBtn.yml +2 -1
- package/src/components/card/QasCard.vue +18 -9
- package/src/components/card/QasCard.yml +13 -9
- package/src/components/date-time-input/QasDateTimeInput.vue +39 -41
- package/src/components/date-time-input/QasDateTimeInput.yml +11 -12
- package/src/components/delete/QasDelete.vue +15 -1
- package/src/components/dialog/QasDialog.vue +26 -3
- package/src/components/dialog/QasDialog.yml +6 -3
- package/src/components/dialog-router/QasDialogRouter.vue +1 -1
- package/src/components/field/QasField.vue +15 -14
- package/src/components/filters/QasFilters.vue +27 -10
- package/src/components/filters/QasFilters.yml +4 -4
- package/src/components/form-generator/QasFormGenerator.vue +87 -12
- package/src/components/form-generator/QasFormGenerator.yml +16 -2
- package/src/components/form-view/QasFormView.vue +138 -56
- package/src/components/form-view/QasFormView.yml +39 -15
- package/src/components/grid-generator/QasGridGenerator.vue +23 -7
- package/src/components/grid-generator/QasGridGenerator.yml +5 -4
- package/src/components/input/QasInput.vue +37 -21
- package/src/components/input/QasInput.yml +1 -1
- package/src/components/layout/QasLayout.vue +4 -0
- package/src/components/list-items/QasListItems.vue +15 -23
- package/src/components/list-items/QasListItems.yml +14 -15
- package/src/components/list-view/QasListView.vue +45 -24
- package/src/components/list-view/QasListView.yml +19 -7
- package/src/components/map/QasMap.vue +5 -5
- package/src/components/nested-fields/QasNestedFields.vue +29 -21
- package/src/components/nested-fields/QasNestedFields.yml +9 -3
- package/src/components/numeric-input/QasNumericInput.vue +14 -14
- package/src/components/numeric-input/QasNumericInput.yml +10 -10
- package/src/components/page-header/QasPageHeader.vue +14 -11
- package/src/components/password-input/QasPasswordInput.vue +17 -16
- package/src/components/password-input/QasPasswordInput.yml +1 -1
- package/src/components/profile/QasProfile.vue +1 -1
- package/src/components/search-box/QasSearchBox.vue +138 -42
- package/src/components/search-box/QasSearchBox.yml +69 -2
- package/src/components/select/QasSelect.vue +63 -53
- package/src/components/select/QasSelect.yml +64 -13
- package/src/components/select-list/QasSelectList.vue +11 -27
- package/src/components/select-list/QasSelectList.yml +13 -14
- package/src/components/signature-pad/QasSignaturePad.yml +1 -1
- package/src/components/signature-uploader/QasSignatureUploader.vue +7 -5
- package/src/components/single-view/QasSingleView.vue +22 -6
- package/src/components/single-view/QasSingleView.yml +11 -4
- package/src/components/table-generator/QasTableGenerator.vue +13 -2
- package/src/components/tabs-generator/QasTabsGenerator.vue +2 -2
- package/src/components/tabs-generator/QasTabsGenerator.yml +2 -2
- package/src/components/text-truncate/QasTextTruncate.vue +1 -1
- package/src/components/uploader/QasUploader.vue +62 -15
- package/src/components/uploader/QasUploader.yml +5 -0
- package/src/helpers/camelize-fields-name.js +15 -0
- package/src/helpers/filters.js +2 -0
- package/src/helpers/get-normalized-options.js +20 -0
- package/src/helpers/handle-process.js +13 -0
- package/src/helpers/index.js +3 -0
- package/src/mixins/generator.js +10 -2
- package/src/mixins/index.js +2 -0
- package/src/mixins/search-filter.js +227 -0
- package/src/mixins/view.js +35 -13
- package/src/pages/Forbidden.vue +3 -1
- package/src/pages/NotFound.vue +3 -1
- package/src/pages/ServerError.vue +3 -1
- package/src/pages/Unauthorized.vue +28 -0
- package/src/plugins/index.js +4 -2
- package/src/plugins/logger/Logger.js +44 -0
- package/src/plugins/logger/Logger.yml +9 -0
- package/src/vue-plugin.js +6 -3
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
</qas-input>
|
|
16
|
-
</div>
|
|
2
|
+
<qas-input v-model="model" :bottom-slots="false" v-bind="$attrs" :type="type" use-remove-error-on-type>
|
|
3
|
+
<template #append>
|
|
4
|
+
<q-icon class="cursor-pointer" :color="iconColor" :name="icon" @click="toggle" />
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<template v-for="(_, name) in $slots" #[name]="context">
|
|
8
|
+
<slot :name="name" v-bind="context || {}" />
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<template v-if="useStrengthChecker" #hint>
|
|
12
|
+
<qas-password-strength-checker v-bind="strengthCheckerProps" :password="model" />
|
|
13
|
+
</template>
|
|
14
|
+
</qas-input>
|
|
17
15
|
</template>
|
|
18
16
|
|
|
19
17
|
<script>
|
|
@@ -29,8 +27,11 @@ export default {
|
|
|
29
27
|
|
|
30
28
|
mixins: [passwordMixin],
|
|
31
29
|
|
|
30
|
+
inheritAttrs: false,
|
|
31
|
+
|
|
32
32
|
props: {
|
|
33
|
-
|
|
33
|
+
useStrengthChecker: {
|
|
34
|
+
default: true,
|
|
34
35
|
type: Boolean
|
|
35
36
|
},
|
|
36
37
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
</div>
|
|
14
14
|
</div>
|
|
15
15
|
<slot name="grid">
|
|
16
|
-
<qas-grid-generator class="col-lg-7 col-xs-12 items-center" :columns="columns" :fields="filterObject(fields, list)"
|
|
16
|
+
<qas-grid-generator class="col-lg-7 col-xs-12 items-center" :columns="columns" :fields="filterObject(fields, list)" :result="result" :use-empty-result="false">
|
|
17
17
|
<template v-for="(_, name) in $slots" #[name]="context">
|
|
18
18
|
<slot :name="name" v-bind="context || {}" />
|
|
19
19
|
</template>
|
|
@@ -1,42 +1,64 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<qas-box>
|
|
3
|
-
<
|
|
3
|
+
<qas-input v-bind="attributes" ref="search" v-model="mx_search">
|
|
4
4
|
<template #append>
|
|
5
5
|
<q-icon color="primary" name="o_search" />
|
|
6
6
|
</template>
|
|
7
|
-
</
|
|
7
|
+
</qas-input>
|
|
8
8
|
|
|
9
|
-
<div class="overflow-auto q-mt-xs relative-position" :style="
|
|
10
|
-
<
|
|
9
|
+
<div ref="scrollContainer" class="overflow-auto q-mt-xs relative-position" :style="containerStyle">
|
|
10
|
+
<component :is="component.is" v-bind="component.props">
|
|
11
|
+
<slot v-if="mx_hasFilteredOptions" />
|
|
12
|
+
</component>
|
|
11
13
|
|
|
12
|
-
<slot v-
|
|
14
|
+
<slot v-if="showSpinnerDots" name="loading">
|
|
15
|
+
<div class="flex justify-center q-pb-sm">
|
|
16
|
+
<q-spinner-dots color="primary" size="20px" />
|
|
17
|
+
</div>
|
|
18
|
+
</slot>
|
|
19
|
+
|
|
20
|
+
<slot v-if="showEmptyResult" name="empty-result">
|
|
13
21
|
<div class="absolute-center text-center">
|
|
14
22
|
<q-icon class="q-mb-sm text-center" color="primary" name="o_search" size="38px" />
|
|
15
|
-
<div>
|
|
23
|
+
<div>{{ emptyResultText }}</div>
|
|
16
24
|
</div>
|
|
17
25
|
</slot>
|
|
26
|
+
|
|
27
|
+
<q-inner-loading :showing="showInnerLoading">
|
|
28
|
+
<q-spinner color="grey" size="3em" />
|
|
29
|
+
</q-inner-loading>
|
|
18
30
|
</div>
|
|
19
31
|
</qas-box>
|
|
20
32
|
</template>
|
|
21
33
|
|
|
22
34
|
<script>
|
|
35
|
+
import { QInfiniteScroll } from 'quasar'
|
|
23
36
|
import Fuse from 'fuse.js'
|
|
24
37
|
|
|
25
38
|
import QasBox from '../box/QasBox.vue'
|
|
39
|
+
import { searchFilterMixin } from '../../mixins'
|
|
26
40
|
|
|
27
41
|
export default {
|
|
28
42
|
name: 'QasSearchBox',
|
|
29
43
|
|
|
30
44
|
components: {
|
|
31
|
-
QasBox
|
|
45
|
+
QasBox,
|
|
46
|
+
QInfiniteScroll
|
|
32
47
|
},
|
|
33
48
|
|
|
49
|
+
mixins: [searchFilterMixin],
|
|
50
|
+
|
|
34
51
|
props: {
|
|
35
52
|
emptyListHeight: {
|
|
36
53
|
default: '100px',
|
|
37
54
|
type: String
|
|
38
55
|
},
|
|
39
56
|
|
|
57
|
+
emptyResultText: {
|
|
58
|
+
default: 'Não há resultados disponíveis.',
|
|
59
|
+
type: String
|
|
60
|
+
},
|
|
61
|
+
|
|
40
62
|
fuseOptions: {
|
|
41
63
|
default: () => ({}),
|
|
42
64
|
type: Object
|
|
@@ -81,88 +103,162 @@ export default {
|
|
|
81
103
|
|
|
82
104
|
data () {
|
|
83
105
|
return {
|
|
84
|
-
fuse: null
|
|
85
|
-
searchResults: this.list,
|
|
86
|
-
search: ''
|
|
106
|
+
fuse: null
|
|
87
107
|
}
|
|
88
108
|
},
|
|
89
109
|
|
|
90
110
|
computed: {
|
|
91
|
-
|
|
92
|
-
return {
|
|
111
|
+
attributes () {
|
|
112
|
+
return {
|
|
113
|
+
clearable: true,
|
|
114
|
+
disable: this.isDisabled,
|
|
115
|
+
debounce: this.useLazyLoading ? 500 : 0,
|
|
116
|
+
outlined: true,
|
|
117
|
+
placeholder: this.placeholder,
|
|
118
|
+
hideBottomSpace: true,
|
|
119
|
+
error: this.mx_hasFetchError,
|
|
120
|
+
loading: this.mx_isFetching
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
containerStyle () {
|
|
125
|
+
return { height: this.containerHeight }
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
hasNoOptionsOnFirstFetch () {
|
|
129
|
+
return this.mx_fetchCount === 1 && !this.mx_hasFilteredOptions
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
containerHeight () {
|
|
133
|
+
const hasEmptyList = (!this.list.length && !this.useLazyLoading) || this.hasNoOptionsOnFirstFetch
|
|
134
|
+
|
|
135
|
+
return hasEmptyList ? this.emptyListHeight : this.height
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
component () {
|
|
139
|
+
const infiniteScrollProps = {
|
|
140
|
+
offset: 100,
|
|
141
|
+
scrollTarget: this.$refs.scrollContainer,
|
|
142
|
+
ref: 'infiniteScrollRef'
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
is: this.useLazyLoading ? 'q-infinite-scroll' : 'div',
|
|
147
|
+
props: {
|
|
148
|
+
...(this.useLazyLoading && infiniteScrollProps),
|
|
149
|
+
...(this.useLazyLoading && { onLoad: this.onInfiniteScroll })
|
|
150
|
+
}
|
|
151
|
+
}
|
|
93
152
|
},
|
|
94
153
|
|
|
95
154
|
defaultFuseOptions () {
|
|
96
155
|
return {
|
|
97
|
-
distance: 100,
|
|
98
|
-
location: 0,
|
|
99
|
-
maxPatternLength: 32,
|
|
100
|
-
minMatchCharLength: 1,
|
|
101
|
-
shouldSort: true,
|
|
102
156
|
threshold: 0.1,
|
|
103
|
-
|
|
157
|
+
ignoreLocation: true,
|
|
104
158
|
|
|
105
159
|
...this.fuseOptions
|
|
106
160
|
}
|
|
107
161
|
},
|
|
108
162
|
|
|
109
|
-
|
|
110
|
-
return
|
|
163
|
+
isDisabled () {
|
|
164
|
+
return (!this.useLazyLoading && !this.list.length) || this.mx_isFetching || this.hasNoOptionsOnFirstFetch
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
showEmptyResult () {
|
|
168
|
+
return this.useEmptySlot && !this.mx_hasFilteredOptions && !this.mx_isFetching
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
showSpinnerDots () {
|
|
172
|
+
return this.mx_hasFilteredOptions && this.mx_isFetching
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
showInnerLoading () {
|
|
176
|
+
return !this.mx_hasFilteredOptions && this.mx_isFetching
|
|
111
177
|
}
|
|
112
178
|
},
|
|
113
179
|
|
|
114
180
|
watch: {
|
|
115
181
|
defaultFuseOptions (value) {
|
|
182
|
+
if (this.useLazyLoading) return
|
|
183
|
+
|
|
116
184
|
this.fuse.options = { ...this.fuse.options, ...value }
|
|
117
185
|
},
|
|
118
186
|
|
|
119
|
-
|
|
187
|
+
mx_hasFilteredOptions (value) {
|
|
120
188
|
!value && this.$emit('empty-result')
|
|
121
189
|
},
|
|
122
190
|
|
|
123
|
-
|
|
124
|
-
handler (value) {
|
|
125
|
-
this
|
|
191
|
+
mx_search: {
|
|
192
|
+
async handler (value) {
|
|
193
|
+
this.$emit('update:modelValue', value)
|
|
126
194
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
195
|
+
if (this.useLazyLoading) {
|
|
196
|
+
await this.mx_filterOptionsByStore(value)
|
|
197
|
+
|
|
198
|
+
this.$refs.infiniteScrollRef.resume()
|
|
199
|
+
this.$refs.search.focus()
|
|
200
|
+
|
|
201
|
+
return
|
|
202
|
+
}
|
|
130
203
|
|
|
131
|
-
|
|
204
|
+
this.filterOptionsByFuse(value)
|
|
205
|
+
}
|
|
132
206
|
},
|
|
133
207
|
|
|
134
|
-
|
|
208
|
+
modelValue: {
|
|
135
209
|
handler (value) {
|
|
136
|
-
this.
|
|
137
|
-
this.$emit('update:modelValue', value)
|
|
210
|
+
this.mx_search = value
|
|
138
211
|
},
|
|
139
212
|
|
|
140
213
|
immediate: true
|
|
141
214
|
},
|
|
142
215
|
|
|
143
|
-
|
|
144
|
-
handler (
|
|
145
|
-
this
|
|
216
|
+
mx_filteredOptions: {
|
|
217
|
+
handler (options) {
|
|
218
|
+
this.$emit('update:results', options)
|
|
146
219
|
},
|
|
220
|
+
|
|
147
221
|
immediate: true
|
|
148
222
|
}
|
|
149
223
|
},
|
|
150
224
|
|
|
151
225
|
created () {
|
|
152
|
-
this.
|
|
226
|
+
if (this.useLazyLoading) return
|
|
227
|
+
|
|
228
|
+
this.mx_filteredOptions = this.list
|
|
153
229
|
this.fuse = new Fuse(this.list, this.defaultFuseOptions)
|
|
154
|
-
|
|
230
|
+
|
|
231
|
+
this.setListWatcher()
|
|
155
232
|
},
|
|
156
233
|
|
|
157
234
|
methods: {
|
|
158
|
-
|
|
159
|
-
this.
|
|
160
|
-
? this.fuse.search(value)
|
|
161
|
-
: this.list
|
|
235
|
+
filterOptionsByFuse (value) {
|
|
236
|
+
this.mx_filteredOptions = value ? this.mx_getNormalizedFuseResults(this.fuse.search(value)) : this.list
|
|
162
237
|
},
|
|
163
238
|
|
|
164
|
-
|
|
165
|
-
|
|
239
|
+
async onInfiniteScroll (_, done) {
|
|
240
|
+
// Se tiver erro no primeiro fetch, retorna o "done" na proxima.
|
|
241
|
+
if (((this.mx_hasFetchError && !this.mx_hasFilteredOptions) || this.hasNoOptionsOnFirstFetch)) return done()
|
|
242
|
+
|
|
243
|
+
if (!this.mx_hasFilteredOptions && !this.mx_search) {
|
|
244
|
+
await this.mx_setFetchOptions()
|
|
245
|
+
return done()
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (this.mx_canFetchOptions()) {
|
|
249
|
+
await this.mx_loadMoreOptions()
|
|
250
|
+
return done()
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
done(true)
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
setListWatcher () {
|
|
257
|
+
this.$watch('list', value => {
|
|
258
|
+
this.fuse = new Fuse(value, this.defaultFuseOptions)
|
|
259
|
+
|
|
260
|
+
this.filterOptionsByFuse(this.mx_search)
|
|
261
|
+
}, { deep: true })
|
|
166
262
|
}
|
|
167
263
|
}
|
|
168
264
|
}
|
|
@@ -9,20 +9,50 @@ props:
|
|
|
9
9
|
default: 100px
|
|
10
10
|
type: String
|
|
11
11
|
|
|
12
|
+
empty-result-text:
|
|
13
|
+
desc: Define o texto dentro do box quando a lista está vazia.
|
|
14
|
+
default: Não há resultados disponíveis.
|
|
15
|
+
type: String
|
|
16
|
+
|
|
17
|
+
entity:
|
|
18
|
+
desc: Entidade enviada para a action "fetchFieldOptions" (usar somente quando "useLazyLoading" estiver habilitada).
|
|
19
|
+
default: ''
|
|
20
|
+
type: String
|
|
21
|
+
examples: [users]
|
|
22
|
+
|
|
23
|
+
fetching:
|
|
24
|
+
desc: Usado para saber quando o componente está fazendo fetching (usar somente quando "useLazyLoading" estiver habilitada).
|
|
25
|
+
default: false
|
|
26
|
+
type: Boolean
|
|
27
|
+
model: true
|
|
28
|
+
examples: [v-model:fetching="isFetching"]
|
|
29
|
+
|
|
12
30
|
fuse-options:
|
|
13
31
|
desc: Opções do Fuse.js (https://fusejs.io/api/options.html).
|
|
14
|
-
default: "{ distance: 100, location: 0, maxPatternLength: 32, minMatchCharLength: 1, shouldSort: true, threshold: 0.1, tokenize: true }"
|
|
15
32
|
debugger: true
|
|
16
33
|
type: Object
|
|
17
34
|
examples: ["{ keys: ['label'] }"]
|
|
35
|
+
default:
|
|
36
|
+
ignoreLocation: true
|
|
37
|
+
threshold: 0.1
|
|
18
38
|
|
|
19
39
|
height:
|
|
20
40
|
desc: Define altura do box quando a lista não está vazia.
|
|
21
41
|
default: 300px
|
|
22
42
|
type: String
|
|
23
43
|
|
|
44
|
+
lazy-loading-props:
|
|
45
|
+
desc: Propriedades para o lazy loading (usar somente quando "useLazyLoading" estiver habilitada).
|
|
46
|
+
type: Object
|
|
47
|
+
debugger: true
|
|
48
|
+
default:
|
|
49
|
+
decamelizeFieldName: true
|
|
50
|
+
url: ''
|
|
51
|
+
params:
|
|
52
|
+
limit: 48
|
|
53
|
+
|
|
24
54
|
list:
|
|
25
|
-
desc: Lista onde ocorrerá a busca
|
|
55
|
+
desc: Lista onde ocorrerá a busca sendo array de objetos (usar somente quando "useLazyLoading" **NÃO** estiver habilitada).
|
|
26
56
|
default: []
|
|
27
57
|
type: String
|
|
28
58
|
|
|
@@ -32,6 +62,11 @@ props:
|
|
|
32
62
|
examples: [v-model="search"]
|
|
33
63
|
model: true
|
|
34
64
|
|
|
65
|
+
name:
|
|
66
|
+
desc: Nome do campo a ser enviado para a action "fetchFieldOptions" (usar somente quando "useLazyLoading" estiver habilitada).
|
|
67
|
+
type: String
|
|
68
|
+
examples: [cities]
|
|
69
|
+
|
|
35
70
|
placeholder:
|
|
36
71
|
desc: Placeholder do campo de pesquisa.
|
|
37
72
|
default: Pesquisar
|
|
@@ -49,6 +84,11 @@ props:
|
|
|
49
84
|
default: true
|
|
50
85
|
type: Boolean
|
|
51
86
|
|
|
87
|
+
use-lazy-loading:
|
|
88
|
+
desc: Controla a busca pela store "fetchFieldOptions".
|
|
89
|
+
default: false
|
|
90
|
+
type: Boolean
|
|
91
|
+
|
|
52
92
|
slots:
|
|
53
93
|
default:
|
|
54
94
|
desc: Acesso ao conteúdo principal, só existe caso a busca retorne algum resultado.
|
|
@@ -56,6 +96,9 @@ slots:
|
|
|
56
96
|
empty-result:
|
|
57
97
|
desc: Acesso ao conteúdo quando a busca não retorne resultado e a prop "useEmptySlot" seja "true".
|
|
58
98
|
|
|
99
|
+
loading:
|
|
100
|
+
desc: Acesso ao conteúdo do loading que contém o "<q-spinner-dots />"..
|
|
101
|
+
|
|
59
102
|
events:
|
|
60
103
|
'@empty-result -> function ()':
|
|
61
104
|
desc: Dispara toda vez que a pesquisa não retorna resultado.
|
|
@@ -74,3 +117,27 @@ events:
|
|
|
74
117
|
desc: Novo valor do v-model:results
|
|
75
118
|
default: []
|
|
76
119
|
type: Array
|
|
120
|
+
|
|
121
|
+
'@update:fetching -> function (value)':
|
|
122
|
+
desc: Dispara toda vez que o campo de busca faz o fetch do lazy loading
|
|
123
|
+
params:
|
|
124
|
+
value:
|
|
125
|
+
desc: Novo valor do v-model:fetching
|
|
126
|
+
default: false
|
|
127
|
+
type: Boolean
|
|
128
|
+
|
|
129
|
+
'@fetch-options-success -> function (value)':
|
|
130
|
+
desc: Dispara toda vez que o campo de busca faz o fetch do lazy loading com sucesso.
|
|
131
|
+
params:
|
|
132
|
+
value:
|
|
133
|
+
desc: Valor retornado pela action "fetchFieldOptions"
|
|
134
|
+
default: {}
|
|
135
|
+
type: Object
|
|
136
|
+
|
|
137
|
+
'@fetch-options-error -> function (value)':
|
|
138
|
+
desc: Dispara toda vez que o campo de busca faz o fetch do lazy loading e cai em uma exceção.
|
|
139
|
+
params:
|
|
140
|
+
value:
|
|
141
|
+
desc: Valor retornado pela action "fetchFieldOptions"
|
|
142
|
+
default: {}
|
|
143
|
+
type: Object
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<q-select v-model="model" v-bind="attributes"
|
|
2
|
+
<q-select v-model="model" v-bind="attributes">
|
|
3
3
|
<template #append>
|
|
4
4
|
<slot name="append">
|
|
5
|
-
<q-icon v-if="
|
|
5
|
+
<q-icon v-if="isSearchable" name="o_search" />
|
|
6
6
|
</slot>
|
|
7
7
|
</template>
|
|
8
8
|
|
|
9
9
|
<template #no-option>
|
|
10
|
-
<slot name="no-option">
|
|
10
|
+
<slot v-if="!mx_isFetching" name="no-option">
|
|
11
11
|
<q-item>
|
|
12
12
|
<q-item-section class="text-grey">
|
|
13
13
|
{{ noOptionLabel }}
|
|
@@ -16,6 +16,14 @@
|
|
|
16
16
|
</slot>
|
|
17
17
|
</template>
|
|
18
18
|
|
|
19
|
+
<template #after-options>
|
|
20
|
+
<slot v-if="mx_isFetching" name="after-options">
|
|
21
|
+
<div class="flex justify-center q-pb-sm">
|
|
22
|
+
<q-spinner-dots color="primary" size="20px" />
|
|
23
|
+
</div>
|
|
24
|
+
</slot>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
19
27
|
<template v-for="(_, name) in $slots" #[name]="context">
|
|
20
28
|
<slot :name="name" v-bind="context || {}" />
|
|
21
29
|
</template>
|
|
@@ -23,11 +31,14 @@
|
|
|
23
31
|
</template>
|
|
24
32
|
|
|
25
33
|
<script>
|
|
34
|
+
import { searchFilterMixin } from '../../mixins'
|
|
26
35
|
import Fuse from 'fuse.js'
|
|
27
36
|
|
|
28
37
|
export default {
|
|
29
38
|
name: 'QasSelect',
|
|
30
39
|
|
|
40
|
+
mixins: [searchFilterMixin],
|
|
41
|
+
|
|
31
42
|
props: {
|
|
32
43
|
fuseOptions: {
|
|
33
44
|
default: () => ({}),
|
|
@@ -41,7 +52,7 @@ export default {
|
|
|
41
52
|
|
|
42
53
|
modelValue: {
|
|
43
54
|
default: () => [],
|
|
44
|
-
type: [Array, Object, String, Number]
|
|
55
|
+
type: [Array, Object, String, Number, Boolean]
|
|
45
56
|
},
|
|
46
57
|
|
|
47
58
|
noOptionLabel: {
|
|
@@ -54,13 +65,13 @@ export default {
|
|
|
54
65
|
type: Array
|
|
55
66
|
},
|
|
56
67
|
|
|
57
|
-
searchable: {
|
|
58
|
-
type: Boolean
|
|
59
|
-
},
|
|
60
|
-
|
|
61
68
|
valueKey: {
|
|
62
69
|
default: '',
|
|
63
70
|
type: String
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
useSearch: {
|
|
74
|
+
type: Boolean
|
|
64
75
|
}
|
|
65
76
|
},
|
|
66
77
|
|
|
@@ -68,7 +79,6 @@ export default {
|
|
|
68
79
|
|
|
69
80
|
data () {
|
|
70
81
|
return {
|
|
71
|
-
filteredOptions: [],
|
|
72
82
|
fuse: null
|
|
73
83
|
}
|
|
74
84
|
},
|
|
@@ -76,40 +86,45 @@ export default {
|
|
|
76
86
|
computed: {
|
|
77
87
|
attributes () {
|
|
78
88
|
return {
|
|
79
|
-
clearable: this.
|
|
89
|
+
clearable: this.isSearchable,
|
|
80
90
|
emitValue: true,
|
|
81
91
|
mapOptions: true,
|
|
82
92
|
outlined: true,
|
|
83
|
-
|
|
84
93
|
...this.$attrs,
|
|
85
94
|
|
|
86
|
-
options: this.
|
|
87
|
-
useInput: this.
|
|
95
|
+
options: this.mx_filteredOptions,
|
|
96
|
+
useInput: this.isSearchable,
|
|
97
|
+
error: this.hasError,
|
|
98
|
+
loading: this.hasLoading,
|
|
99
|
+
...(this.useLazyLoading && { onVirtualScroll: this.mx_onVirtualScroll }),
|
|
100
|
+
...(this.isSearchable && { onFilter: this.onFilter })
|
|
88
101
|
}
|
|
89
102
|
},
|
|
90
103
|
|
|
91
104
|
defaultFuseOptions () {
|
|
92
105
|
return {
|
|
93
|
-
|
|
94
|
-
includeScore: true,
|
|
106
|
+
ignoreLocation: true,
|
|
95
107
|
keys: ['label', 'value'],
|
|
96
|
-
location: 0,
|
|
97
|
-
maxPatternLength: 32,
|
|
98
|
-
minMatchCharLength: 1,
|
|
99
|
-
shouldSort: true,
|
|
100
108
|
threshold: 0.1,
|
|
101
|
-
tokenize: true,
|
|
102
109
|
|
|
103
110
|
...this.fuseOptions
|
|
104
111
|
}
|
|
105
112
|
},
|
|
106
113
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
isSearchable () {
|
|
115
|
+
return this.useSearch || this.useLazyLoading
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
defaultOptions () {
|
|
119
|
+
return this.mx_handleOptions(this.options)
|
|
120
|
+
},
|
|
111
121
|
|
|
112
|
-
|
|
122
|
+
hasError () {
|
|
123
|
+
return this.mx_hasFetchError || this.$attrs.error
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
hasLoading () {
|
|
127
|
+
return this.mx_isFetching || this.$attrs.loading
|
|
113
128
|
},
|
|
114
129
|
|
|
115
130
|
model: {
|
|
@@ -130,11 +145,11 @@ export default {
|
|
|
130
145
|
|
|
131
146
|
options: {
|
|
132
147
|
handler () {
|
|
133
|
-
if (this.
|
|
134
|
-
|
|
135
|
-
|
|
148
|
+
if (this.useLazyLoading && this.mx_hasFilteredOptions) return
|
|
149
|
+
|
|
150
|
+
if (this.fuse) this.setFuse()
|
|
136
151
|
|
|
137
|
-
this.
|
|
152
|
+
this.mx_filteredOptions = this.defaultOptions
|
|
138
153
|
},
|
|
139
154
|
|
|
140
155
|
immediate: true
|
|
@@ -143,42 +158,37 @@ export default {
|
|
|
143
158
|
|
|
144
159
|
created () {
|
|
145
160
|
this.setFuse()
|
|
161
|
+
this.useLazyLoading && this.mx_setFetchOptions('')
|
|
146
162
|
},
|
|
147
163
|
|
|
148
164
|
methods: {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (value === '') {
|
|
154
|
-
this.filteredOptions = this.formattedResult
|
|
155
|
-
} else {
|
|
156
|
-
const results = this.fuse.search(value)
|
|
157
|
-
this.filteredOptions = results.map(item => item.item)
|
|
158
|
-
}
|
|
159
|
-
})
|
|
165
|
+
setFuse () {
|
|
166
|
+
if (this.useSearch) {
|
|
167
|
+
this.fuse = new Fuse(this.defaultOptions, this.defaultFuseOptions)
|
|
168
|
+
}
|
|
160
169
|
},
|
|
161
170
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
value: this.valueKey
|
|
171
|
+
async onFilter (value, update) {
|
|
172
|
+
if (this.useLazyLoading && value !== this.mx_search) {
|
|
173
|
+
await this.mx_filterOptionsByStore(value)
|
|
166
174
|
}
|
|
167
175
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
item[newKey] = item[mapKeys[newKey]]
|
|
171
|
-
delete item[mapKeys[newKey]]
|
|
172
|
-
}
|
|
176
|
+
if (!this.useLazyLoading && this.useSearch) {
|
|
177
|
+
this.filterOptionsByFuse(value)
|
|
173
178
|
}
|
|
174
179
|
|
|
175
|
-
|
|
180
|
+
update()
|
|
176
181
|
},
|
|
177
182
|
|
|
178
|
-
|
|
179
|
-
if (
|
|
180
|
-
this.
|
|
183
|
+
filterOptionsByFuse (value) {
|
|
184
|
+
if (value === '') {
|
|
185
|
+
this.mx_filteredOptions = this.defaultOptions
|
|
186
|
+
return
|
|
181
187
|
}
|
|
188
|
+
|
|
189
|
+
const results = this.fuse.search(value)
|
|
190
|
+
|
|
191
|
+
this.mx_filteredOptions = this.mx_getNormalizedFuseResults(results)
|
|
182
192
|
}
|
|
183
193
|
}
|
|
184
194
|
}
|