@bildvitta/quasar-ui-asteroid 3.9.0 → 3.10.0-beta.1

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.
@@ -16,9 +16,7 @@
16
16
 
17
17
  <div v-else-if="!mx_isFetching">
18
18
  <slot name="empty-results">
19
- <div class="q-my-lg text-body1 text-grey-7">
20
- Não há itens para serem exibidos.
21
- </div>
19
+ <qas-empty-result-text />
22
20
  </slot>
23
21
  </div>
24
22
 
@@ -1,13 +1,9 @@
1
1
  <template>
2
- <qas-box>
3
- <qas-input v-bind="attributes" ref="search" v-model="mx_search">
4
- <template #prepend>
5
- <q-icon color="grey-8" name="sym_r_search" />
6
- </template>
7
- </qas-input>
8
-
9
- <div ref="scrollContainer" class="overflow-auto q-mt-xs relative-position" :style="containerStyle">
10
- <component :is="component.is" v-bind="component.props">
2
+ <div>
3
+ <qas-search-input v-bind="attributes" v-model="mx_search" />
4
+
5
+ <div ref="scrollContainer" class="overflow-auto q-mt-md relative-position" :style="containerStyle">
6
+ <component :is="component.is" v-bind="component.props" class="q-mr-sm">
11
7
  <slot v-if="mx_hasFilteredOptions" />
12
8
  </component>
13
9
 
@@ -18,17 +14,14 @@
18
14
  </slot>
19
15
 
20
16
  <slot v-if="showEmptyResult" name="empty-result">
21
- <div class="absolute-center text-center">
22
- <q-icon class="q-mb-sm text-center" color="primary" name="sym_r_search" size="38px" />
23
- <div>{{ emptyResultText }}</div>
24
- </div>
17
+ <qas-empty-result-text class="q-mt-md" />
25
18
  </slot>
26
19
 
27
20
  <q-inner-loading :showing="showInnerLoading">
28
21
  <q-spinner color="grey" size="3em" />
29
22
  </q-inner-loading>
30
23
  </div>
31
- </qas-box>
24
+ </div>
32
25
  </template>
33
26
 
34
27
  <script>
@@ -54,11 +47,6 @@ export default {
54
47
  type: String
55
48
  },
56
49
 
57
- emptyResultText: {
58
- default: 'Não há resultados disponíveis.',
59
- type: String
60
- },
61
-
62
50
  fuseOptions: {
63
51
  default: () => ({}),
64
52
  type: Object
@@ -110,12 +98,10 @@ export default {
110
98
  computed: {
111
99
  attributes () {
112
100
  return {
113
- clearable: true,
101
+ ref: 'search',
114
102
  disable: this.isDisabled,
115
- debounce: this.useLazyLoading ? 1200 : 0,
116
- outlined: true,
103
+ useDebounce: this.useLazyLoading,
117
104
  placeholder: this.placeholder,
118
- hideBottomSpace: true,
119
105
  error: this.mx_hasFetchError,
120
106
  loading: this.mx_isFetching
121
107
  }
@@ -195,7 +181,7 @@ export default {
195
181
  await this.mx_filterOptionsByStore(value)
196
182
 
197
183
  this.$refs.infiniteScrollRef.resume()
198
- this.$refs.search.focus()
184
+ this.$refs.search.input.focus()
199
185
 
200
186
  return
201
187
  }
@@ -222,12 +208,7 @@ export default {
222
208
  },
223
209
 
224
210
  created () {
225
- if (this.useLazyLoading) return
226
-
227
- this.mx_filteredOptions = this.list
228
- this.fuse = new Fuse(this.list, this.defaultFuseOptions)
229
-
230
- this.setListWatcher()
211
+ this.setSearchMethod()
231
212
  },
232
213
 
233
214
  methods: {
@@ -239,7 +220,9 @@ export default {
239
220
  // Se tiver erro no primeiro fetch, retorna o "done" na proxima.
240
221
  if (((this.mx_hasFetchError && !this.mx_hasFilteredOptions) || this.hasNoOptionsOnFirstFetch)) return done()
241
222
 
242
- if (!this.mx_hasFilteredOptions && !this.mx_search) {
223
+ const canMakeFirstFetch = this.mx_fetchCount === 0 && this.mx_hasFilteredOptions
224
+
225
+ if ((!this.mx_hasFilteredOptions || canMakeFirstFetch) && !this.mx_search) {
243
226
  await this.mx_setFetchOptions()
244
227
  return done()
245
228
  }
@@ -258,6 +241,23 @@ export default {
258
241
 
259
242
  this.filterOptionsByFuse(this.mx_search)
260
243
  }, { deep: true })
244
+ },
245
+
246
+ setSearchMethod () {
247
+ this.useLazyLoading ? this.setLazyLoading() : this.setFuse()
248
+ },
249
+
250
+ setFuse () {
251
+ const list = [...this.list]
252
+
253
+ this.mx_filteredOptions = list
254
+ this.fuse = new Fuse(list, this.defaultFuseOptions)
255
+
256
+ this.setListWatcher()
257
+ },
258
+
259
+ setLazyLoading () {
260
+ this.mx_setCachedOptions('list')
261
261
  }
262
262
  }
263
263
  }
@@ -9,11 +9,6 @@ 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
12
  entity:
18
13
  desc: Entidade enviada para a action "fetchFieldOptions" (usar somente quando "useLazyLoading" estiver habilitada).
19
14
  default: ''
@@ -0,0 +1,122 @@
1
+ <template>
2
+ <div class="qas-filter-input">
3
+ <qas-input ref="input" v-model="model" class="bg-white q-px-sm rounded-borders-sm shadow-2" v-bind="$attrs" data-cy="search-input" :debounce="debounce" dense hide-bottom-space input-class="ellipsis text-grey-8" :outlined="false" type="search">
4
+ <template #prepend>
5
+ <q-icon v-if="useSearchOnType" color="grey-8" name="sym_r_search" />
6
+ <qas-btn v-else color="grey-9" icon="sym_r_search" variant="tertiary" @click="$emit('filter')" />
7
+ </template>
8
+
9
+ <template #append>
10
+ <qas-btn v-if="hasSearch" color="grey-9" icon="sym_r_clear" variant="tertiary" @click="clear" />
11
+
12
+ <slot name="after-clear" />
13
+ </template>
14
+ </qas-input>
15
+ </div>
16
+ </template>
17
+
18
+ <script>
19
+ export default {
20
+ name: 'QasSearchInput',
21
+
22
+ inheritAttrs: false,
23
+
24
+ props: {
25
+ modelValue: {
26
+ default: '',
27
+ type: String
28
+ },
29
+
30
+ useDebounce: {
31
+ default: true,
32
+ type: Boolean
33
+ },
34
+
35
+ useSearchOnType: {
36
+ default: true,
37
+ type: Boolean
38
+ }
39
+ },
40
+
41
+ emits: [
42
+ 'clear',
43
+ 'filter',
44
+ 'update:modelValue'
45
+ ],
46
+
47
+ computed: {
48
+ debounce () {
49
+ return this.useDebounce ? '1200' : ''
50
+ },
51
+
52
+ hasSearch () {
53
+ return !!this.model.length
54
+ },
55
+
56
+ input () {
57
+ return this.$refs.input
58
+ },
59
+
60
+ model: {
61
+ get () {
62
+ return this.modelValue
63
+ },
64
+
65
+ set (value) {
66
+ this.$emit('update:modelValue', value)
67
+ }
68
+ }
69
+ },
70
+
71
+ methods: {
72
+ clear () {
73
+ this.$emit('clear', this.modelValue)
74
+ this.$emit('update:modelValue', '')
75
+ }
76
+ }
77
+ }
78
+ </script>
79
+
80
+ <style lang="scss">
81
+ .qas-filter-input {
82
+ position: relative;
83
+
84
+ .q-field {
85
+ &::before {
86
+ border: 2px solid transparent;
87
+ border-radius: var(--qas-generic-border-radius);
88
+ bottom: 0;
89
+ content: '';
90
+ left: 0;
91
+ pointer-events: none;
92
+ position: absolute;
93
+ right: 0;
94
+ top: 0;
95
+ transition: border-color var(--qas-generic-transition);
96
+ }
97
+
98
+ &--dense .q-field__prepend {
99
+ padding-right: var(--qas-spacing-xs);
100
+ }
101
+
102
+ &--dense .q-field__append {
103
+ padding-left: var(--qas-spacing-sm);
104
+ }
105
+
106
+ &--focused::before {
107
+ border-color: var(--q-primary);
108
+ color: var(--q-primary);
109
+ }
110
+
111
+ &__control::after,
112
+ &__control::before {
113
+ display: none !important;
114
+ }
115
+
116
+ &__native {
117
+ padding-bottom: var(--qas-spacing-sm);
118
+ padding-top: var(--qas-spacing-sm);
119
+ }
120
+ }
121
+ }
122
+ </style>
@@ -0,0 +1,43 @@
1
+ type: component
2
+
3
+ meta:
4
+ desc: Componente de input para pesquisa / filtros.
5
+
6
+ props:
7
+ model-value:
8
+ desc: Model do componente, utilizado para v-model.
9
+ default: ''
10
+ type: String
11
+ model: true
12
+
13
+ use-debounce:
14
+ desc: Controla debounce.
15
+ default: true
16
+ type: Boolean
17
+
18
+ use-search-on-type:
19
+ desc: Controla se vai habilitar o botão de pesquisa ao clicar.
20
+ default: true
21
+ type: Boolean
22
+
23
+ slots:
24
+ after-clear:
25
+ desc: Slot para acessar área após o botão de limpar pesquisa.
26
+
27
+ events:
28
+ '@update:clear -> function(oldValue)':
29
+ desc: Dispara quando é clicado no botão de limpar pesquisa.
30
+ params:
31
+ oldValue:
32
+ desc: Valor do model antes de ser limpo.
33
+ type: String
34
+
35
+ '@update:filter -> function()':
36
+ desc: Dispara quando a prop "useSearchOnType" for "false" e é clicado no botão de pesquisar.
37
+
38
+ '@update:model-value -> function(value)':
39
+ desc: Dispara quando o model-value altera, também usado para v-model.
40
+ params:
41
+ value:
42
+ desc: Novo valor do model.
43
+ type: String
@@ -43,11 +43,6 @@ export default {
43
43
  type: Object
44
44
  },
45
45
 
46
- labelKey: {
47
- default: '',
48
- type: String
49
- },
50
-
51
46
  modelValue: {
52
47
  default: () => [],
53
48
  type: [Array, Object, String, Number, Boolean]
@@ -63,9 +58,9 @@ export default {
63
58
  type: Array
64
59
  },
65
60
 
66
- valueKey: {
67
- default: '',
68
- type: String
61
+ useFetchOptionsOnCreate: {
62
+ default: true,
63
+ type: Boolean
69
64
  },
70
65
 
71
66
  useSearch: {
@@ -114,10 +109,6 @@ export default {
114
109
  return this.hasFuse || this.useLazyLoading
115
110
  },
116
111
 
117
- defaultOptions () {
118
- return this.mx_handleOptions(this.options)
119
- },
120
-
121
112
  hasError () {
122
113
  return this.mx_hasFetchError || this.$attrs.error
123
114
  },
@@ -153,7 +144,7 @@ export default {
153
144
 
154
145
  watch: {
155
146
  defaultFuseOptions () {
156
- this.setFuse()
147
+ if (this.hasFuse) this.setFuse()
157
148
  },
158
149
 
159
150
  options: {
@@ -162,7 +153,7 @@ export default {
162
153
 
163
154
  if (this.fuse || this.hasFuse) this.setFuse()
164
155
 
165
- this.mx_filteredOptions = this.defaultOptions
156
+ this.mx_filteredOptions = this.options
166
157
  },
167
158
 
168
159
  immediate: true
@@ -170,15 +161,12 @@ export default {
170
161
  },
171
162
 
172
163
  created () {
173
- this.setFuse()
174
- this.useLazyLoading && this.mx_setFetchOptions('')
164
+ this.setSearchMethod()
175
165
  },
176
166
 
177
167
  methods: {
178
168
  setFuse () {
179
- if (this.hasFuse) {
180
- this.fuse = new Fuse(this.defaultOptions, this.defaultFuseOptions)
181
- }
169
+ this.fuse = new Fuse(this.options, this.defaultFuseOptions)
182
170
  },
183
171
 
184
172
  async onFilter (value, update) {
@@ -195,13 +183,25 @@ export default {
195
183
 
196
184
  filterOptionsByFuse (value) {
197
185
  if (value === '') {
198
- this.mx_filteredOptions = this.defaultOptions
186
+ this.mx_filteredOptions = this.options
199
187
  return
200
188
  }
201
189
 
202
190
  const results = this.fuse.search(value)
203
191
 
204
192
  this.mx_filteredOptions = this.mx_getNormalizedFuseResults(results)
193
+ },
194
+
195
+ setLazyLoading () {
196
+ this.mx_setCachedOptions('options')
197
+
198
+ if (this.useFetchOptionsOnCreate) this.mx_setFetchOptions('')
199
+ },
200
+
201
+ setSearchMethod () {
202
+ if (this.useLazyLoading) return this.setLazyLoading()
203
+
204
+ if (this.hasFuse) this.setFuse()
205
205
  }
206
206
  }
207
207
  }
@@ -71,6 +71,11 @@ props:
71
71
  type: String
72
72
  examples: [value-key="uuid"]
73
73
 
74
+ use-fetch-options-on-create:
75
+ desc: Controla se o componente vai fazer um fetch das opções assim que o mesmo é criado (caso tenha lazy loading ativado).
76
+ default: true
77
+ type: Boolean
78
+
74
79
  use-search:
75
80
  desc: Controla se vai ou não ter campo de busca no select.
76
81
  default: undefined
@@ -1,18 +1,20 @@
1
1
  <template>
2
- <qas-search-box v-model:results="results" class="q-pa-md" :fuse-options="fuseOptions" :list="sortedList">
2
+ <qas-search-box v-model:results="results" v-bind="defaultSearchBoxProps" :list="sortedList">
3
3
  <template #default>
4
4
  <q-list separator>
5
- <q-item v-for="result in results" :key="result.value">
5
+ <q-item v-for="result in results" :key="result.value" class="q-px-none">
6
6
  <slot v-bind="slotData" :item="result" name="item">
7
7
  <slot name="item-section" :result="result">
8
- <q-item-section class="items-start text-bold">
9
- <div :class="labelClass" @click="onClickLabel({ item: result, index })">{{ result.label }}</div>
8
+ <q-item-section>
9
+ <div :class="labelClass" @click="onClickLabel({ item: result, index })">
10
+ {{ result.label }}
11
+ </div>
10
12
  </q-item-section>
11
13
  </slot>
12
14
 
13
15
  <q-item-section avatar>
14
16
  <slot :item="result" name="item-action" v-bind="slotData">
15
- <qas-btn v-bind="getButtonProps(result)" @click="handleClick(result)" />
17
+ <qas-btn :disable="readonly" :use-label-on-small-screen="false" v-bind="getButtonProps(result)" @click="handleClick(result)" />
16
18
  </slot>
17
19
  </q-item-section>
18
20
  </slot>
@@ -36,19 +38,21 @@ export default {
36
38
  QasSearchBox
37
39
  },
38
40
 
41
+ inheritAttrs: false,
42
+
39
43
  props: {
40
- deleteOnly: {
41
- type: Boolean
44
+ addLabel: {
45
+ type: String,
46
+ default: 'Adicionar'
42
47
  },
43
48
 
44
- fuseOptions: {
45
- default: () => ({ keys: ['label'] }),
46
- type: Object
49
+ deleteLabel: {
50
+ type: String,
51
+ default: 'Excluir'
47
52
  },
48
53
 
49
- list: {
50
- default: () => [],
51
- type: Array
54
+ deleteOnly: {
55
+ type: Boolean
52
56
  },
53
57
 
54
58
  modelValue: {
@@ -56,6 +60,15 @@ export default {
56
60
  default: () => []
57
61
  },
58
62
 
63
+ readonly: {
64
+ type: Boolean
65
+ },
66
+
67
+ searchBoxProps: {
68
+ type: Object,
69
+ default: () => ({})
70
+ },
71
+
59
72
  useClickableLabel: {
60
73
  type: Boolean
61
74
  }
@@ -77,10 +90,26 @@ export default {
77
90
  },
78
91
 
79
92
  computed: {
93
+ defaultSearchBoxProps () {
94
+ return {
95
+ fuseOptions: { keys: ['label'] },
96
+
97
+ ...this.searchBoxProps
98
+ }
99
+ },
100
+
101
+ hasLazyLoading () {
102
+ return this.defaultSearchBoxProps.useLazyLoading
103
+ },
104
+
80
105
  labelClass () {
81
106
  return this.useClickableLabel && 'cursor-pointer'
82
107
  },
83
108
 
109
+ list () {
110
+ return this.defaultSearchBoxProps.list || []
111
+ },
112
+
84
113
  slotData () {
85
114
  return {
86
115
  add: this.add,
@@ -94,9 +123,9 @@ export default {
94
123
  watch: {
95
124
  list: {
96
125
  handler (value) {
97
- if (!this.sortedList.length) {
98
- this.sortedList = value
99
- }
126
+ if (!this.hasLazyLoading) return this.sortList()
127
+
128
+ this.sortedList = [...value]
100
129
  },
101
130
 
102
131
  immediate: true
@@ -113,7 +142,7 @@ export default {
113
142
  },
114
143
 
115
144
  created () {
116
- this.handleList()
145
+ if (!this.hasLazyLoading) this.handleList()
117
146
  },
118
147
 
119
148
  methods: {
@@ -128,9 +157,10 @@ export default {
128
157
  const isSelected = this.values.includes(value)
129
158
 
130
159
  return {
160
+ label: isSelected ? this.deleteLabel : this.addLabel,
131
161
  variant: 'tertiary',
132
162
  color: isSelected ? 'grey-9' : 'primary',
133
- icon: isSelected ? 'sym_r_remove' : 'sym_r_add'
163
+ icon: isSelected ? 'sym_r_delete' : 'sym_r_add'
134
164
  }
135
165
  },
136
166
 
@@ -7,20 +7,20 @@ meta:
7
7
  desc: Componente para selecionar dentro de uma lista com pesquisa utilizando o `QasSearchBox`.
8
8
 
9
9
  props:
10
+ add-label:
11
+ desc: Label do botão de adicionar.
12
+ default: Adicionar
13
+ type: String
14
+
15
+ delete-label:
16
+ desc: Label do botão de deletar.
17
+ default: Excluir
18
+ type: String
19
+
10
20
  delete-only:
11
21
  desc: Caso o "modelValue" tenha valor, ele remove tudo na lista que não esteja dentro do modelValue.
12
22
  type: Boolean
13
23
 
14
- fuse-options:
15
- desc: Propriedade que será repassada para o "QasSearchBox".
16
- default: "{ keys: ['label'] }"
17
- type: Object
18
-
19
- list:
20
- desc: Lista que será feita a seleção e pesquisa.
21
- default: []
22
- type: Array
23
-
24
24
  model-value:
25
25
  desc: Model do componente, que será controlado tudo que foi selecionado.
26
26
  default: []
@@ -28,6 +28,16 @@ props:
28
28
  examples: [v-model="value"]
29
29
  model: true
30
30
 
31
+ readonly:
32
+ desc: Habilita modo visualização.
33
+ default: false
34
+ type: Boolean
35
+
36
+ search-box-props:
37
+ desc: Repassa props para o componente "QasSearchBox"
38
+ default: {}
39
+ type: Object
40
+
31
41
  use-clickable-label:
32
42
  desc: Habilita "cursor-pointer" no label e evento "click-label".
33
43
  type: Boolean
@@ -8,10 +8,7 @@
8
8
  <slot />
9
9
  </template>
10
10
 
11
- <div v-else-if="!mx_isFetching" class="q-my-xl text-center">
12
- <q-icon class="q-mb-sm text-center" color="grey-7" name="sym_r_search" size="38px" />
13
- <div class="text-grey-7">Nenhum item encontrado.</div>
14
- </div>
11
+ <qas-empty-result-text v-else-if="!mx_isFetching" class="q-my-xl" />
15
12
 
16
13
  <footer v-if="mx_hasFooterSlot">
17
14
  <slot name="footer" />