@tagplus/components 4.7.12 → 5.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.
Files changed (88) hide show
  1. package/dist/tp.common.js +2 -1
  2. package/dist/tp.common.js.LICENSE.txt +9 -0
  3. package/dist/tp.common.js.map +1 -1
  4. package/dist/tp.common.lang-en-js.js +2 -0
  5. package/dist/tp.common.lang-en-js.js.map +1 -0
  6. package/dist/tp.css +11 -167
  7. package/dist/tp.umd.js +2 -1
  8. package/dist/tp.umd.js.LICENSE.txt +9 -0
  9. package/dist/tp.umd.js.map +1 -1
  10. package/dist/tp.umd.lang-en-js.js +2 -0
  11. package/dist/tp.umd.lang-en-js.js.map +1 -0
  12. package/dist/tp.umd.min.js +2 -1
  13. package/dist/tp.umd.min.js.LICENSE.txt +9 -0
  14. package/dist/tp.umd.min.js.map +1 -1
  15. package/dist/tp.umd.min.lang-en-js.js +2 -0
  16. package/dist/tp.umd.min.lang-en-js.js.map +1 -0
  17. package/package.json +51 -50
  18. package/src/assets/scss/_fonts.scss +24 -23
  19. package/src/assets/scss/_helpers.scss +4 -0
  20. package/src/assets/scss/_mixins.scss +2 -2
  21. package/src/assets/scss/_overrides.scss +5 -52
  22. package/src/assets/scss/_resass.scss +21 -12
  23. package/src/assets/scss/_variables.scss +0 -1
  24. package/src/assets/scss/index.scss +1 -4
  25. package/src/components/Autosuggest/Autosuggest.vue +340 -767
  26. package/src/components/Autosuggest/Multisuggest.vue +22 -0
  27. package/src/components/Autosuggest/autosuggest-props.js +210 -0
  28. package/src/components/Autosuggest/autosuggest-style.scss +127 -0
  29. package/src/components/Autosuggest/core.js +63 -0
  30. package/src/components/Autosuggest/index.js +2 -0
  31. package/src/components/Autosuggest/multisuggest-props.js +9 -0
  32. package/src/components/Autosuggest/option.vue +136 -0
  33. package/src/components/Autosuggest/select-dropdown.vue +64 -0
  34. package/src/components/Autosuggest/useOption.js +120 -0
  35. package/src/components/Autosuggest/useSelect.js +1133 -0
  36. package/src/components/AutosuggestTest.vue +56 -0
  37. package/src/components/CardExemplo.vue +49 -0
  38. package/src/components/CodeSample.vue +78 -0
  39. package/src/components/Inline/Inline.vue +24 -32
  40. package/src/components/InputNumber/InputNumber.vue +329 -378
  41. package/src/components/InputNumber/input-number.js +135 -0
  42. package/src/components/Loader/Loader.vue +42 -53
  43. package/src/components/Loader/animations.scss +13 -0
  44. package/src/components/Money/Money.vue +11 -20
  45. package/src/components/Multisuggest/index.js +2 -3
  46. package/src/components/MultisuggestTest.vue +56 -0
  47. package/src/components/OptionsList/OptionsList.vue +7 -6
  48. package/src/components/OptionsListItem/OptionsListItem.vue +46 -42
  49. package/src/components/Percent/Percent.vue +8 -14
  50. package/src/components/Skeleton/Skeleton.vue +16 -11
  51. package/src/components/Step/Step.vue +42 -35
  52. package/src/components/Steps/Steps.vue +4 -7
  53. package/src/components/TesteToCurrency.vue +171 -0
  54. package/src/components/Tip/Tip.vue +45 -30
  55. package/src/components/ValueSelector.vue +60 -0
  56. package/src/components/autosuggestMixin.js +301 -0
  57. package/src/components/index.js +4 -1
  58. package/src/locale/i18n.js +114 -0
  59. package/src/locale/lang/en.js +3 -2
  60. package/src/locale/lang/pt-br.js +3 -2
  61. package/src/main.js +9 -14
  62. package/src/mixins/floatFormatter.js +12 -16
  63. package/src/plugins/currency.js +100 -0
  64. package/src/utils/browser.js +6 -0
  65. package/src/utils/constants.js +3 -0
  66. package/src/utils/error.js +22 -0
  67. package/src/utils/filters.js +1 -14
  68. package/src/utils/helpers.js +41 -0
  69. package/src/utils/i18n.js +2 -0
  70. package/src/utils/icon.js +35 -0
  71. package/src/utils/index.js +20 -0
  72. package/src/utils/objects.js +17 -0
  73. package/src/utils/runtime.js +86 -0
  74. package/src/utils/scroll.js +100 -0
  75. package/src/utils/strings.js +17 -0
  76. package/src/utils/style.js +80 -0
  77. package/src/utils/types.js +39 -0
  78. package/src/utils/use-derived-namespace.js +112 -0
  79. package/src/utils/use-form-common-props.js +41 -0
  80. package/src/utils/use-form-item.js +80 -0
  81. package/src/utils/use-id.js +40 -0
  82. package/src/utils/use-input.js +33 -0
  83. package/src/components/Dialog/Dialog.vue +0 -253
  84. package/src/components/Dialog/index.js +0 -3
  85. package/src/components/Multisuggest/Multisuggest.vue +0 -858
  86. package/src/locale/index.js +0 -78
  87. package/src/mixins/locale.js +0 -9
  88. package/src/utils/currency.js +0 -180
@@ -1,789 +1,362 @@
1
1
  <template>
2
2
  <div
3
- v-clickoutside="handleClose"
4
- class="el-select tp-autosuggest"
5
- data-is-search="true"
6
- :class="[selectSize ? 'el-select--' + selectSize : '']"
3
+ ref="selectRef"
4
+ v-click-outside:[popperRef]="handleClickOutside"
5
+ :class="['tp-autosuggest', nsSelect.b(), nsSelect.m(selectSize)]"
6
+ @mouseenter="states.inputHovering = true"
7
+ @mouseleave="states.inputHovering = false"
7
8
  @click.stop="toggleMenu"
8
9
  >
9
10
  <el-tooltip
10
- placement="top"
11
- :manual="true"
12
- :value="tooltipVisible"
13
- :content="selectedLabel + ''"
14
- :tabindex="-1"
11
+ ref="tooltipRef"
12
+ :visible="dropdownMenuVisible"
13
+ :placement="placement"
14
+ :teleported="teleported"
15
+ :popper-options="popperOptions"
16
+ :popper-class="['el-select__popper', popperClass]"
17
+ :fallback-placements="['bottom-start', 'top-start', 'right', 'left']"
18
+ :effect="effect"
19
+ pure
20
+ trigger="click"
21
+ :transition="`${nsSelect.namespace.value}-zoom-in-top`"
22
+ :stop-popper-mouse-event="false"
23
+ :gpu-acceleration="false"
24
+ :persistent="persistent"
25
+ @before-show="handleMenuEnter"
26
+ @hide="states.isBeforeHide = false"
15
27
  >
16
- <!-- Div é importante para funcionar o tooltip -->
17
- <div />
18
- </el-tooltip>
19
- <el-input
20
- :id="`${_id}-input`"
21
- ref="reference"
22
- v-model="selectedLabel"
23
- type="text"
24
- :placeholder="currentPlaceholder"
25
- :name="name"
26
- :autocomplete="autoComplete || autocomplete"
27
- :size="selectSize"
28
- :disabled="selectDisabled"
29
- :readonly="readonly"
30
- :validate-event="false"
31
- :class="{ 'is-focus': visible }"
32
- :tabindex="(multiple && filterable) ? '-1' : null"
33
- popper-append-to-body="teste"
34
- @focus="handleFocus"
35
- @blur="handleBlur"
36
- @keyup.native="debouncedOnInputChange"
37
- @keydown.native.down.stop.prevent="navigateOptions('next')"
38
- @keydown.native.up.stop.prevent="navigateOptions('prev')"
39
- @keydown.native.enter.prevent="selectOption"
40
- @keydown.native.esc.stop.prevent="visible = false"
41
- @keydown.native.tab="visible = false"
42
- @paste.native="debouncedOnInputChange"
43
- @mouseenter.native="inputHovering = true"
44
- @mouseleave.native="inputHovering = false"
45
- >
46
- <template v-if="prepend">
47
- <template
48
- v-if="$slots.prepend || typeof(prepend) == 'string'"
49
- slot="prepend"
50
- >
51
- <slot name="prepend">
52
- {{ prepend }}
53
- </slot>
54
- </template>
55
- <template
56
- v-else
57
- slot="prepend"
28
+ <template #default>
29
+ <div ref="wrapperRef"
30
+ :class="[
31
+ nsSelect.is('focused', isFocused),
32
+ nsSelect.is('hovering', states.inputHovering),
33
+ nsSelect.is('disabled', selectDisabled),
34
+ ]"
58
35
  >
59
- <em class="far fa-search" />
60
- </template>
61
- </template>
62
-
63
- <template
64
- v-if="$slots.prefix"
65
- slot="prefix"
66
- >
67
- <slot name="prefix" />
68
- </template>
69
-
70
- <template slot="append">
71
- <el-row
72
- type="flex"
73
- :justify="selectedLabel ? 'space-between' : 'end'"
74
- align="middle"
75
- >
76
- <em
77
- v-if="selectedLabel && !selectDisabled"
78
- :id="`${_id}-btn-clear`"
79
- class="fa fa-times-circle icon-close"
80
- @click.stop.prevent="clearTags"
81
- />
82
- <el-row
83
- align="middle"
84
- type="flex"
85
- justify="space-around"
86
- class="rightContent"
36
+ <div
37
+ ref="selectionRef"
38
+ class="el-select__selection"
87
39
  >
88
- <el-divider
89
- direction="vertical"
90
- class="dividerSuggest"
91
- />
92
-
93
- <em
94
- v-show="!showClose && !selectDisabled"
95
- :id="`${_id}-btn-close`"
96
- :class="['el-select__caret', 'el-input__icon', 'el-icon-' + iconClass]"
97
- />
98
- </el-row>
99
- </el-row>
40
+ <div :class="['el-select__input-wrapper']" >
41
+ <div
42
+ v-if="!selectDisabled"
43
+ class="el-input el-input-group el-input-group--append el-input-group--prepend el-select__input">
44
+ <div class="el-input-group__prepend">
45
+ <div class="tp-autosuggest-input-prepend-icon">
46
+ <em class="far fa-search" />
47
+ </div>
48
+ <el-divider
49
+ direction="vertical"
50
+ class="tp-autosuggest-vertical-divider"
51
+ />
52
+ </div>
53
+ <div class="el-input__wrapper">
54
+ <slot v-if="multiple" name="tag">
55
+ <div
56
+ v-for="item in showTagList"
57
+ :key="getValueKey(item)"
58
+ :class="nsSelect.e('selected-item')"
59
+ >
60
+ <el-tag
61
+ :closable="!selectDisabled && !item.isDisabled"
62
+ :size="collapseTagSize"
63
+ :type="tagType"
64
+ disable-transitions
65
+ :style="tagStyle"
66
+ @close="deleteTag($event, item)"
67
+ >
68
+ <span :class="nsSelect.e('tags-text')">
69
+ {{ item.currentLabel }}
70
+ </span>
71
+ </el-tag>
72
+ </div>
73
+
74
+ <el-tooltip
75
+ v-if="collapseTags && states.selected.length > maxCollapseTags"
76
+ ref="tagTooltipRef"
77
+ :disabled="dropdownMenuVisible || !collapseTagsTooltip"
78
+ :fallback-placements="['bottom', 'top', 'right', 'left']"
79
+ :effect="effect"
80
+ placement="bottom"
81
+ :teleported="teleported"
82
+ >
83
+ <template #default>
84
+ <div
85
+ ref="collapseItemRef"
86
+ :class="nsSelect.e('selected-item')"
87
+ >
88
+ <el-tag
89
+ :closable="false"
90
+ :size="collapseTagSize"
91
+ :type="tagType"
92
+ disable-transitions
93
+ :style="collapseTagStyle"
94
+ >
95
+ <span :class="nsSelect.e('tags-text')">
96
+ + {{ states.selected.length - maxCollapseTags }}
97
+ </span>
98
+ </el-tag>
99
+ </div>
100
+ </template>
101
+ <template #content>
102
+ <div ref="tagMenuRef" :class="nsSelect.e('selection')">
103
+ <div
104
+ v-for="item in collapseTagList"
105
+ :key="getValueKey(item)"
106
+ :class="nsSelect.e('selected-item')"
107
+ >
108
+ <el-tag
109
+ class="in-tooltip"
110
+ :closable="!selectDisabled && !item.isDisabled"
111
+ :size="collapseTagSize"
112
+ :type="tagType"
113
+ disable-transitions
114
+ @close="deleteTag($event, item)"
115
+ >
116
+ <span :class="nsSelect.e('tags-text')">
117
+ {{ item.currentLabel }}
118
+ </span>
119
+ </el-tag>
120
+ </div>
121
+ </div>
122
+ </template>
123
+ </el-tooltip>
124
+ </slot>
125
+ <input
126
+ :id="`${myId}-input`"
127
+ ref="inputRef"
128
+ v-model="states.inputValue"
129
+ type="text"
130
+ class="el-select__input el-input__inner"
131
+ :class="[nsSelect.is(selectSize)]"
132
+ autocomplete="off"
133
+ :size="selectSize"
134
+ :style="inputStyle"
135
+ role="combobox"
136
+ spellcheck="false"
137
+ :aria-activedescendant="hoverOption?.id || ''"
138
+ :aria-controls="contentId"
139
+ :aria-expanded="dropdownMenuVisible"
140
+ :aria-label="ariaLabel"
141
+ aria-autocomplete="none"
142
+ aria-haspopup="listbox"
143
+ :name="name"
144
+ @focus="handleFocus"
145
+ @blur="handleBlur"
146
+ @keydown.down.stop.prevent="navigateOptions('next')"
147
+ @keydown.up.stop.prevent="navigateOptions('prev')"
148
+ @keydown.esc.stop.prevent="handleEsc"
149
+ @keydown.enter.stop.prevent="selectOption"
150
+ @keydown.delete.stop="deletePrevTag"
151
+ @compositionstart="handleCompositionStart"
152
+ @compositionupdate="handleCompositionUpdate"
153
+ @compositionend="handleCompositionEnd"
154
+ @input="onInput"
155
+ @click.stop="toggleMenu"
156
+ />
157
+
158
+ <div
159
+ v-if="shouldShowPlaceholder"
160
+ :class="[
161
+ nsSelect.e('selected-item'),
162
+ nsSelect.e('placeholder'),
163
+ nsSelect.is('transparent', !hasModelValue || (expanded && !states.inputValue)),
164
+ ]"
165
+ >
166
+ <span>{{ currentPlaceholder }}</span>
167
+ </div>
168
+ </div>
169
+ <div class="el-input-group__append">
170
+ <el-icon
171
+ v-if="states.selectedLabel"
172
+ :id="`${myId}-btn-clear`"
173
+ class="tp-autosuggest-clear-icon fa fa-times-circle"
174
+ @click.stop.prevent="clearTags"
175
+ >
176
+ </el-icon>
177
+ <el-row
178
+ :justify="states.selectedLabel ? 'space-between' : 'end'"
179
+ align="middle"
180
+ >
181
+ <el-row
182
+ align="middle"
183
+ justify="space-around"
184
+ class="el-input__close"
185
+ >
186
+ <el-divider
187
+ direction="vertical"
188
+ class="tp-autosuggest-vertical-divider"
189
+ />
190
+ <div
191
+ v-if="!showClose"
192
+ :id="`${myId}-btn-close`"
193
+ class="tp-btn-close"
194
+ >
195
+ <el-icon
196
+ :class="['el-select__caret', 'el-select__icon', iconReverse]"
197
+ >
198
+ <ArrowDown />
199
+ </el-icon>
200
+ </div>
201
+ </el-row>
202
+ </el-row>
203
+ </div>
204
+ </div>
205
+ <!-- DISABLED -->
206
+ <div
207
+ v-else
208
+ class="el-input el-select__input is-disabled"
209
+ >
210
+ <div class="el-input__wrapper">
211
+ <slot v-if="multiple" name="tag">
212
+ <div
213
+ v-for="item in showTagList"
214
+ :key="getValueKey(item)"
215
+ :class="nsSelect.e('selected-item')"
216
+ >
217
+ <el-tag
218
+ :closable="false"
219
+ :size="collapseTagSize"
220
+ :type="tagType"
221
+ disable-transitions
222
+ :style="tagStyle"
223
+ >
224
+ <span :class="nsSelect.e('tags-text')">
225
+ {{ item.currentLabel }}
226
+ </span>
227
+ </el-tag>
228
+ </div>
229
+
230
+ <el-tooltip
231
+ v-if="collapseTags && states.selected.length > maxCollapseTags"
232
+ ref="tagTooltipRef"
233
+ :disabled="dropdownMenuVisible || !collapseTagsTooltip"
234
+ :fallback-placements="['bottom', 'top', 'right', 'left']"
235
+ :effect="effect"
236
+ placement="bottom"
237
+ :teleported="teleported"
238
+ >
239
+ <template #default>
240
+ <div
241
+ ref="collapseItemRef"
242
+ :class="nsSelect.e('selected-item')"
243
+ >
244
+ <el-tag
245
+ :closable="false"
246
+ :size="collapseTagSize"
247
+ :type="tagType"
248
+ disable-transitions
249
+ :style="collapseTagStyle"
250
+ >
251
+ <span :class="nsSelect.e('tags-text')">
252
+ + {{ states.selected.length - maxCollapseTags }}
253
+ </span>
254
+ </el-tag>
255
+ </div>
256
+ </template>
257
+ <template #content>
258
+ <div ref="tagMenuRef" :class="nsSelect.e('selection')">
259
+ <div
260
+ v-for="item in collapseTagList"
261
+ :key="getValueKey(item)"
262
+ :class="nsSelect.e('selected-item')"
263
+ >
264
+ <el-tag
265
+ class="in-tooltip"
266
+ :closable="false"
267
+ :size="collapseTagSize"
268
+ :type="tagType"
269
+ disable-transitions
270
+ >
271
+ <span :class="nsSelect.e('tags-text')">
272
+ {{ item.currentLabel }}
273
+ </span>
274
+ </el-tag>
275
+ </div>
276
+ </div>
277
+ </template>
278
+ </el-tooltip>
279
+ </slot>
280
+ <div
281
+ v-if="shouldShowPlaceholder"
282
+ :class="[
283
+ nsSelect.e('selected-item'),
284
+ nsSelect.e('placeholder'),
285
+ nsSelect.is('transparent', !hasModelValue || (expanded && !states.inputValue)),
286
+ ]"
287
+ >
288
+ <span>{{ currentPlaceholder }}</span>
289
+ </div>
290
+ </div>
291
+ </div>
292
+ </div>
293
+ </div>
294
+ </div>
100
295
  </template>
101
- </el-input>
102
- <transition
103
- name="el-zoom-in-top"
104
- @before-enter="handleMenuEnter"
105
- @after-leave="doDestroy"
106
- >
107
- <el-select-menu
108
- v-show="visible && emptyText !== false"
109
- :id="`${_id}-select`"
110
- ref="popper"
111
- :append-to-body="popperAppendToBody"
112
- >
113
- <el-scrollbar
114
- v-show="options.length > 0 && !loading"
115
- :id="`${_id}-scrollbar`"
116
- ref="scrollbar"
117
- tag="ul"
118
- wrap-class="tp-select-dropdown__wrap el-select-dropdown__wrap"
119
- view-class="tp-select-dropdown__list el-select-dropdown__list"
120
- :class="{ 'is-empty': !allowCreate && query && filteredOptionsCount === 0 }"
121
- >
122
- <el-option
123
- v-for="(item, i) in suggestionsList"
124
- :id="`${_id}-option-${i}`"
125
- :key="i"
126
- :label="item[labelKey]"
127
- :value="item[valueKey]"
128
- :created="item.created"
129
- :class="{'created': item.created}"
296
+ <template #content>
297
+ <el-select-menu ref="menuRef">
298
+ <el-scrollbar
299
+ v-show="states.options.size > 0 && !loading"
300
+ :id="contentId"
301
+ ref="scrollbarRef"
302
+ tag="ul"
303
+ wrap-class="el-select-dropdown__wrap"
304
+ view-class="el-select-dropdown__list"
305
+ :class="[nsSelect.is('empty', filteredOptionsCount === 0)]"
306
+ role="listbox"
307
+ :aria-label="ariaLabel"
308
+ aria-orientation="vertical"
130
309
  >
131
- <template v-if="item.created">
132
- <a :id="`${_id}-btn-create`"><em class="far fa-plus" /> {{ newItem }}</a>
133
- </template>
134
- <slot
135
- v-else
310
+ <el-option
311
+ v-for="(item, i) in suggestionsList"
312
+ :id="`${myId}-option-${i}`"
313
+ :key="i"
314
+ :label="item[labelKey]"
315
+ :value="item[valueKey]"
136
316
  :item="item"
137
- />
138
- </el-option>
139
- </el-scrollbar>
140
- <template v-if="emptyText && (!allowCreate || loading || (allowCreate && options.length === 0 ))">
141
- <slot
142
- v-if="$slots.empty"
143
- name="empty"
144
- />
145
- <p
146
- v-else-if="loading"
147
- class="tp-autosuggest-loading"
317
+ :created="item.created"
318
+ :class="{'created': item.created}"
319
+ >
320
+ <template v-if="item.created">
321
+ <a :id="`${myId}-btn-create`"><em class="far fa-plus" /> {{ newItem }}</a>
322
+ </template>
323
+ <slot
324
+ v-else
325
+ :item="item"
326
+ />
327
+ </el-option>
328
+ </el-scrollbar>
329
+ <div
330
+ v-if="$slots.loading && loading"
331
+ class="el-select-dropdown__loading"
148
332
  >
149
- <tp-skeleton :count="4" />
150
- </p>
151
- <p
152
- v-else
333
+ <slot name="loading" />
334
+ </div>
335
+ <div
336
+ v-else-if="loading || filteredOptionsCount === 0"
153
337
  class="el-select-dropdown__empty"
154
338
  >
155
- {{ emptyText }}
156
- </p>
157
- </template>
158
- </el-select-menu>
159
- </transition>
339
+ <slot name="empty">
340
+ <span>{{ emptyText }}</span>
341
+ </slot>
342
+ </div>
343
+ <div v-if="$slots.footer" class="el-select-dropdown__footer">
344
+ <slot name="footer" />
345
+ </div>
346
+ </el-select-menu>
347
+ </template>
348
+ </el-tooltip>
160
349
  </div>
161
350
  </template>
162
351
 
163
352
  <script>
164
- import debounce from 'throttle-debounce/debounce'
165
- import { Select } from 'element-ui'
166
- import { getValueByPath, valueEquals } from 'element-ui/src/utils/util'
167
-
168
- /**
169
- * Cria um select com opções obtidas de forma assíncrona e remota.
170
- * Basicamente um atalho de configurações
171
- * Vide documentação ElementUI: https://element.eleme.io/#/en-US/component/select
172
- */
173
- export default {
174
- name: 'TpAutosuggest',
175
-
176
- extends: Select,
177
-
178
- props: {
179
- value: {
180
- type: [Boolean, String, Object, Number, Array],
181
- required: false,
182
- default: ''
183
- },
184
-
185
- /**
186
- * Substituição do valor padrão em relação ao ElementUi
187
- */
188
- remote: {
189
- type: Boolean,
190
- required: false,
191
- default: true
192
- },
193
- /**
194
- * Lista ou Objeto contendo conjunto de itens como opções ou sugestões do componente
195
- */
196
- suggestions: {
197
- type: [Array, Object],
198
- required: true
199
- },
200
- /**
201
- * Informa o campo correspondente em cada item referente ao valor sendo selecionado
202
- */
203
- valueKey: {
204
- type: String,
205
- default: 'id'
206
- },
207
- /**
208
- * Identificação do campo correspondente em cada item referente ao texto de exibição.
209
- * Quando utilizado o slot de itens, este campo passa a não ser utilizado
210
- */
211
- labelKey: {
212
- type: String,
213
- default: 'label'
214
- },
215
- /**
216
- * Indica quando o campo pode ser utilizado como filtro.
217
- * Sobrescreve valor padrão do atributo no Select do ElementUI
218
- */
219
- filterable: {
220
- type: Boolean,
221
- required: false,
222
- default: true
223
- },
224
- /**
225
- * Sobrescreve valor padrão do atributo no Select do ElementUI
226
- */
227
- reserveKeyword: {
228
- type: Boolean,
229
- required: false,
230
- default: true
231
- },
232
- /**
233
- * Sobrescreve valor padrão do atributo no Select do ElementUI
234
- */
235
- defaultFirstOption: {
236
- type: Boolean,
237
- required: false,
238
- default: true
239
- },
240
- /**
241
- * Sobrescreve valor padrão do atributo no Select do ElementUI
242
- */
243
- loadOnCreate: {
244
- type: Boolean,
245
- required: false,
246
- default: true
247
- },
248
-
249
- /**
250
- * Quando Boolean: identifica se exibe ou não o ícone de lupa. "False" oculta prepend.
251
- * Quando String: Informa o texto a ser inserido no prepend
252
- */
253
- prepend: {
254
- type: [Boolean, String],
255
- required: false,
256
- default: true
257
- },
258
-
259
- /**
260
- * Método que realiza a busca dos registros remotos para as opções.
261
- *
262
- * *IMPORTANTE*: deve considerar o "valueKey" nas consultas
263
- * pois o valor selecionado será baseado nas opções remotas carregadas ao criar o componente.
264
- */
265
- remoteMethod: {
266
- type: Function,
267
- required: true
268
- },
269
-
270
- /**
271
- * Informa a mensagem de cadastrar novo item
272
- */
273
- msgNewItem: {
274
- type: String,
275
- required: false,
276
- default: 'Cadastrar novo item'
277
- }
278
- },
279
-
280
- data () {
281
- return {
282
- tooltipVisible: false
283
- }
284
- },
285
-
286
- computed: {
287
- _id () {
288
- return this.id || this.$options.name
289
- },
290
- newItem () {
291
- return this.query
292
- ? this.$tpI18n.t('autosuggests.cadastrar', { nameItem: this.query })
293
- : this.$tpI18n.t(`autosuggests.newItem.${this.$parent.$options.name}`)
294
- },
295
-
296
- /**
297
- * Trata o caso que o autosuggest recebe um objeto com o valueKey e labelKey
298
- */
299
- formatedValue () {
300
- let newVal = ''
301
- if (typeof this.value === 'boolean') {
302
- newVal = ''
303
- } else if (Array.isArray(this.value)) {
304
- newVal = this.value
305
- } else if (this.value && typeof this.value === 'object') {
306
- if (!Object.keys(newVal).length) { return {} }
307
- if (!this.value[this.valueKey] && this.value[this.valueKey] !== '') {
308
- if (process.env.DEBUG === 'true') {
309
- console.error(
310
- `Autosuggest '${this.$options.name}' option doesn't have a valueKey '${this.valueKey}' key`
311
- )
312
- }
313
- } else {
314
- newVal = this.value[this.valueKey]
315
- }
316
- }
317
-
318
- return newVal
319
- },
320
- iconClass () {
321
- return this.visible ? 'arrow-up is-reverse' : 'arrow-up'
322
- },
323
- showNewOption () {
324
- const hasExistingOption = this.options
325
- .filter(option => !option.created)
326
- .some(option => option.currentLabel === this.query)
327
-
328
- return this.filterable && this.allowCreate && !hasExistingOption
329
- },
330
- // Monta a lista com ou sem "Cadastrar Novo Item"
331
- suggestionsList () {
332
- if (this.loading) return []
333
-
334
- // transformando em Array
335
- const list =
336
- typeof this.suggestions === 'object'
337
- ? Object.values(this.suggestions)
338
- : this.suggestions
339
-
340
- if (this.allowCreate) {
341
- const createdSuggestion = { created: true }
342
-
343
- createdSuggestion[this.valueKey] = this.query !== '' ? this.query : null
344
- createdSuggestion[this.labelKey] = ''
345
- list.push(createdSuggestion)
346
- }
347
-
348
- return list
349
- },
350
-
351
- emptyText () {
352
- if (this.loading) {
353
- return this.loadingText || this.t('el.select.loading')
354
- }
355
-
356
- if (this.remote && this.query === '' && this.options.length === 0) {
357
- return this.noDataText || this.$tpI18n.t('autosuggests.sem_dados')
358
- }
359
-
360
- if (this.filterable && this.query && this.options.length > 0 && this.filteredOptionsCount === 0) {
361
- return this.noMatchText || this.t('el.select.noMatch')
362
- }
363
-
364
- if (this.options.length === 0) {
365
- return this.noDataText || this.$tpI18n.t('autosuggests.sem_dados')
366
- }
367
-
368
- return null
369
- }
370
- },
371
-
372
- created () {
373
- this.debouncedOnInputChange = debounce(this.debounce, e => {
374
- // Correção para mobile ativar a busca enquanto digita
375
- if (e.isComposing) {
376
- // Se está apagando
377
- if (e.target.value === '') {
378
- this.selectedLabel = this.selectedLabel.slice(0, -1)
379
- } else {
380
- // Pega valor ignorando composition mode
381
- this.selectedLabel = e.target.value
382
- }
383
- }
384
-
385
- this.onInputChange(e)
386
- })
387
- },
388
-
389
- beforeMount () {
390
- this.doRequest = false
391
-
392
- if (this.loadOnCreate) {
393
- this.previousQuery = false
394
- // Chama função do element-ui select que faz o remote method
395
- this.handleQueryChange('')
396
- } else {
397
- // Marca para fazer a requisição no primeiro clique
398
- this.doRequest = true
399
- }
400
- },
401
-
402
- mounted () {
403
- this.$nextTick(() => {
404
- // Componente tooltip -> autosuggest -> input
405
- const componenteInputInterno = this.$children[1].$refs.input
406
-
407
- // Mostra o tooltip só quando
408
- this.createHandler(componenteInputInterno, 'mouseenter', () => {
409
- if (this.selectedLabel) {
410
- this.tooltipVisible = true
411
- }
412
- })
413
- this.createHandler(componenteInputInterno, 'mouseleave', () => {
414
- this.tooltipVisible = false
415
- })
416
- document.addEventListener('focusin', this.fixElSelect)
417
- document.addEventListener('click', this.fixElSelect)
418
- document.addEventListener('touchstart', this.fixElSelect)
419
- })
420
- },
421
-
422
- beforeDestroy () {
423
- document.removeEventListener('focusin', this.fixElSelect, false)
424
- document.removeEventListener('click', this.fixElSelect, false)
425
- document.removeEventListener('touchstart', this.fixElSelect, false)
426
- },
427
-
428
- methods: {
429
- /**
430
- * Adiciona um evento no elemento dinamicamente
431
- * @args el {Object} Elemento que tem o listener
432
- * @args ev {String} Nome do listener (mouseenter, click, etc)
433
- * @args func {Function} Função a ser executada
434
- */
435
- createHandler (el, ev, func) {
436
- if (el) {
437
- el.addEventListener(
438
- ev,
439
- () => {
440
- func()
441
- },
442
- false
443
- )
444
- }
445
- },
446
-
447
- onInputChange () {
448
- if (this.filterable && this.query !== this.selectedLabel) {
449
- this.query = this.selectedLabel
450
- this.handleQueryChange(this.query)
451
- }
452
- },
453
-
454
- emitChange (val) {
455
- if (!valueEquals(this.formatedValue, val)) {
456
- this.$nextTick(() => {
457
- this.$emit('change', val, this.createdSelected)
458
- })
459
- }
460
- },
461
-
462
- // eslint-disable-next-line no-unused-vars
463
- clearTags (event) {
464
- this.selectedLabel = ''
465
- // Faz uma requisição limpa
466
- this.query = ''
467
- this.doRequest = true
468
- this.previousQuery = ''
469
- this.handleQueryChange(this.query)
470
-
471
- // Eventos ao limpar
472
- this.$emit('input', null)
473
-
474
- if (typeof this.value === 'undefined') {
475
- this.$emit('change', null, null)
476
- } else {
477
- this.$emit('change', null, this.value)
478
- }
479
- },
480
-
481
- /**
482
- * Sobrescreve o getOption do select para mostrar o labelValue em vez do idValue
483
- */
484
- getOption (val) {
485
- let value = ''
486
- let initialLabel = false
487
- if (typeof this.value === 'boolean') {
488
- value = ''
489
- } else if (Array.isArray(val)) {
490
- value = val
491
- } else if (val && typeof val === 'object') {
492
- if (!Object.keys(val).length) { return {} }
493
- // Se val for Object converte para outro tipo
494
- if (!this.value[this.valueKey] && this.value[this.valueKey] !== '') {
495
- console.error(
496
- `Autosuggest '${this.$options.name}' option doesn't have a valueKey '${this.valueKey}' key`
497
- )
498
- } else {
499
- // Se mandou a label no objeto value
500
- if (this.value[this.labelKey]) {
501
- initialLabel = this.value[this.labelKey]
502
- }
503
-
504
- value = this.value[this.valueKey]
505
- }
506
- } else {
507
- value = val
508
- }
509
-
510
- let option
511
- const isObject =
512
- Object.prototype.toString.call(value).toLowerCase() ===
513
- '[object object]'
514
- const isNull =
515
- Object.prototype.toString.call(value).toLowerCase() === '[object null]'
516
- const isUndefined =
517
- Object.prototype.toString.call(value).toLowerCase() ===
518
- '[object undefined]'
519
-
520
- for (let i = 0; i <= this.cachedOptions.length - 1; i++) {
521
- const cachedOption = this.cachedOptions[i]
522
- let isEqual = false
523
- if (isObject) {
524
- isEqual = getValueByPath(cachedOption.value, this.valueKey) === getValueByPath(value, this.valueKey)
525
- } else {
526
- isEqual = cachedOption.value === value
527
- if (initialLabel) {
528
- cachedOption.label = initialLabel
529
- }
530
- }
531
-
532
- if (isEqual) {
533
- option = cachedOption
534
- break
535
- }
536
- }
537
-
538
- if (option) return option
539
-
540
- const label = !isObject && !isNull && !isUndefined ? value : ''
541
- const newOption = {
542
- value,
543
- currentLabel: initialLabel || label
544
- }
545
-
546
- if (this.multiple) {
547
- newOption.hitState = false
548
- }
549
-
550
- return newOption
551
- },
552
- checkDefaultFirstOption () {
553
- this.$nextTick(() => {
554
- this.hoverIndex = -1
555
-
556
- for (let i = 0; i !== this.options.length; ++i) {
557
- const option = this.options[i]
558
-
559
- if (this.query) {
560
- // highlight first options that passes the filter
561
- if (!option.disabled && !option.groupDisabled && option.visible) {
562
- this.hoverIndex = i
563
- break
564
- }
565
- } else {
566
- // highlight currently selected option
567
- if (option.itemSelected) {
568
- this.hoverIndex = i
569
- break
570
- }
571
- }
572
- }
573
- })
574
- },
575
- /**
576
- * Sobrescreve a função de abrir menu do select para fazer a busca quando loadOnCreate = false
577
- */
578
- toggleMenu () {
579
- if (!this.selectDisabled) {
580
- // Se mantem visivel quando clica nele aberto
581
- if (this.menuVisibleOnFocus) {
582
- this.menuVisibleOnFocus = false
583
- } else {
584
- this.visible = !this.visible
585
- }
586
-
587
- if (this.doRequest) {
588
- this.handleQueryChange(this.query)
589
- this.doRequest = false
590
- }
591
-
592
- (this.$refs.input || this.$refs.reference).focus()
593
- }
594
- },
595
-
596
- handleClose () {
597
- this.visible = false
598
- // Limpa busca quando fecha
599
- this.doRequest = true
600
- },
601
-
602
- /**
603
- * Sobrescreve função do select
604
- */
605
- handleQueryChange (val) {
606
- const _this6 = this
607
-
608
- // Correção aqui para forçar primeeira request com createOnLoad = false
609
- if (
610
- (!this.doRequest && this.previousQuery === val) ||
611
- this.isOnComposition
612
- ) { return }
613
-
614
- if (
615
- this.previousQuery === null &&
616
- (typeof this.filterMethod === 'function' ||
617
- typeof this.remoteMethod === 'function')
618
- ) {
619
- this.previousQuery = val
620
-
621
- return
622
- }
623
-
624
- this.previousQuery = val
625
- this.$nextTick(() => {
626
- if (_this6.visible) _this6.broadcast('ElSelectDropdown', 'updatePopper')
627
- })
628
- this.hoverIndex = -1
629
-
630
- if (this.multiple && this.filterable) {
631
- this.$nextTick(() => {
632
- const length = _this6.$refs.input.value.length * 15 + 20
633
-
634
- _this6.inputLength = _this6.collapseTags
635
- ? Math.min(50, length)
636
- : length
637
- _this6.managePlaceholder()
638
- _this6.resetInputHeight()
639
- })
640
- }
641
-
642
- if (this.remote && typeof this.remoteMethod === 'function') {
643
- this.hoverIndex = -1
644
- this.remoteMethod(val)
645
- } else if (typeof this.filterMethod === 'function') {
646
- this.filterMethod(val)
647
- this.broadcast('ElOptionGroup', 'queryChange')
648
- } else {
649
- this.filteredOptionsCount = this.optionsCount
650
- this.broadcast('ElOption', 'queryChange', val)
651
- this.broadcast('ElOptionGroup', 'queryChange')
652
- }
653
-
654
- if (
655
- this.defaultFirstOption &&
656
- (this.filterable || this.remote) &&
657
- this.filteredOptionsCount
658
- ) {
659
- this.checkDefaultFirstOption()
660
- }
661
- },
662
-
663
- // Correção para habilitar teclado mobile em iOS
664
- fixElSelect () {
665
- document
666
- .querySelectorAll('.el-select[data-is-search="true"]:hover')
667
- .forEach(() => {
668
- const elInput = document.querySelector(
669
- '.el-select[data-is-search="true"]:hover input[readonly]'
670
- )
671
-
672
- if (elInput) {
673
- elInput.readOnly = false
674
- elInput.blur()
675
- elInput.focus()
676
- }
677
- })
678
- }
679
- }
680
- }
353
+ import { defineComponent } from 'vue'
354
+ import autosuggestCore from '@src/components/Autosuggest/core.js'
355
+ import autosuggestProps from '@src/components/Autosuggest/autosuggest-props.js'
356
+ const autosuggestDefinition = autosuggestCore('TpAutosuggest', autosuggestProps)
357
+ export default defineComponent(autosuggestDefinition)
681
358
  </script>
682
359
 
683
360
  <style lang="scss" scoped>
684
- :deep(){
685
- .el-input-group__append {
686
- padding: 0px 6px 0px 0px;
687
- border: 0;
688
- width: 58px;
689
- max-width: 58px;
690
- .rightContent {
691
- width: 40px;
692
- max-width: 40px;
693
- }
694
- }
695
- }
696
-
697
- input.el-input__inner {
698
- margin-right: 0px;
699
- }
700
-
701
- .el-input__icon {
702
- width: auto;
703
- }
704
-
705
- .icon-close {
706
- color: #606266;
707
- cursor: pointer;
708
- }
709
-
710
- .el-select .el-input__inner {
711
- padding-right: 15px;
712
- }
713
-
714
- .dividerSuggest {
715
- height: 33.59px;
716
- margin: 0px;
717
- }
718
- .tp-autosuggest.el-select {
719
- > .el-input {
720
- display: inline-table;
721
- }
722
- .el-input__suffix {
723
- cursor: pointer;
724
- }
725
- .el-button.is-circle {
726
- padding: 3px;
727
- &:hover {
728
- background-color: #c0c4cc25;
729
- border: 1px solid #dcdfe6;
730
- }
731
- }
732
-
733
- .el-icon-close {
734
- color: #c0c4cc;
735
- }
736
- }
737
-
738
- .padding-x {
739
- padding-right: 2px;
740
- }
741
-
742
- .tp-autosuggest-loading {
743
- text-align: center;
744
- font-size: 1.5em;
745
- padding: 10px;
746
- margin: 0;
747
- }
748
-
749
- .tp-select-dropdown__list.el-select-dropdown__list {
750
- li.el-select-dropdown__item {
751
- line-height: 1.5em;
752
- height: auto;
753
- padding: $--popover-padding;
754
- position: relative;
755
- transition: 100ms all linear;
756
-
757
- &.hover {
758
- padding-left: 20px;
759
-
760
- &::before {
761
- position: absolute;
762
- display: inline-block;
763
- width: 4px;
764
- top: 5px;
765
- bottom: 5px;
766
- left: 5px;
767
- background: $--color-primary;
768
- border-radius: 2px;
769
- }
770
- }
771
-
772
- &.selected {
773
- color: $--color-text-regular;
774
- }
775
- &.created a {
776
- color: $--color-primary;
777
- font-weight: normal;
778
- border-bottom: 1px solid $--color-primary;
779
- line-height: 1.5em;
780
- display: inline-block;
781
- }
782
-
783
- small {
784
- font-size: $--font-size-base;
785
- color: mix($--color-white, $--color-text-secondary, 40%);
786
- }
787
- }
788
- }
361
+ @import "./autosuggest-style"
789
362
  </style>