@farm-investimentos/front-mfe-components 15.3.5 → 15.4.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/front-mfe-components.common.js +1065 -116
- package/dist/front-mfe-components.common.js.map +1 -1
- package/dist/front-mfe-components.css +1 -1
- package/dist/front-mfe-components.umd.js +1065 -116
- package/dist/front-mfe-components.umd.js.map +1 -1
- package/dist/front-mfe-components.umd.min.js +1 -1
- package/dist/front-mfe-components.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/components/DatePicker/DatePicker.stories.js +30 -1
- package/src/components/DatePicker/DatePicker.vue +19 -2
- package/src/components/SelectAutoComplete/SelectAutoComplete.scss +49 -0
- package/src/components/SelectAutoComplete/SelectAutoComplete.stories.js +328 -0
- package/src/components/SelectAutoComplete/SelectAutoComplete.vue +532 -0
- package/src/components/SelectAutoComplete/__tests__/SelectAutoComplete.spec.js +130 -0
- package/src/components/SelectAutoComplete/__tests__/useSelectAutoComplete.spec.js +28 -0
- package/src/components/SelectAutoComplete/composables/index.ts +3 -0
- package/src/components/SelectAutoComplete/composables/useSelectAutoComplete.ts +37 -0
- package/src/components/SelectAutoComplete/index.ts +4 -0
- package/src/main.ts +1 -1
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div ref="outsideClickHandler" @click="handleOutsideClick">
|
|
3
|
+
<div
|
|
4
|
+
:class="{
|
|
5
|
+
'farm-textfield': true,
|
|
6
|
+
'farm-textfield--validatable': rules.length > 0,
|
|
7
|
+
'farm-textfield--touched': isTouched,
|
|
8
|
+
'farm-textfield--blured': isBlured,
|
|
9
|
+
'farm-textfield--error': hasError,
|
|
10
|
+
'farm-textfield--disabled': disabled,
|
|
11
|
+
'farm-textfield--focused': isFocus || isVisible,
|
|
12
|
+
'farm-textfield--hiddendetails': hideDetails,
|
|
13
|
+
}"
|
|
14
|
+
v-if="!readonly && !disabled"
|
|
15
|
+
:id="customId"
|
|
16
|
+
>
|
|
17
|
+
<farm-contextmenu bottom v-model="isVisible" :stay-open="multiple" ref="contextmenu">
|
|
18
|
+
<farm-list v-if="!readonly" ref="listRef" @keyup="onKeyUp">
|
|
19
|
+
<farm-listitem
|
|
20
|
+
tabindex="0"
|
|
21
|
+
v-for="(item, index) in showFilteredItems ? filteredItems : items"
|
|
22
|
+
clickable
|
|
23
|
+
hoverColorVariation="lighten"
|
|
24
|
+
hover-color="primary"
|
|
25
|
+
:key="'contextmenu_item_' + index"
|
|
26
|
+
:class="{ 'farm-listitem--selected': item[itemValue] === innerValue }"
|
|
27
|
+
@click='selectItem(item)'
|
|
28
|
+
>
|
|
29
|
+
<farm-checkbox
|
|
30
|
+
class="farm-select__checkbox"
|
|
31
|
+
v-model="checked"
|
|
32
|
+
value="1"
|
|
33
|
+
size="sm"
|
|
34
|
+
v-if="isChecked(item)"
|
|
35
|
+
/>
|
|
36
|
+
<farm-checkbox
|
|
37
|
+
class="farm-select__checkbox"
|
|
38
|
+
v-model="checked"
|
|
39
|
+
value="2"
|
|
40
|
+
size="sm"
|
|
41
|
+
v-else-if="multiple"
|
|
42
|
+
/>
|
|
43
|
+
<farm-caption bold tag="span">{{ item[itemText] }}</farm-caption>
|
|
44
|
+
</farm-listitem>
|
|
45
|
+
<farm-listitem v-if=" (!items || items.length === 0) || (showFilteredItems && filteredItems.length === 0)">
|
|
46
|
+
{{ noDataText }}
|
|
47
|
+
</farm-listitem>
|
|
48
|
+
</farm-list>
|
|
49
|
+
<template v-slot:activator="{}">
|
|
50
|
+
<div class="farm-textfield--input farm-textfield--input--iconed">
|
|
51
|
+
<input
|
|
52
|
+
v-bind="$attrs"
|
|
53
|
+
v-model="selectedText"
|
|
54
|
+
ref="inputField"
|
|
55
|
+
:id="$props.id"
|
|
56
|
+
@focusin="onFocus(true)"
|
|
57
|
+
@focusout="onFocus(false)"
|
|
58
|
+
@input="onInput"
|
|
59
|
+
@blur="onBlur"
|
|
60
|
+
@keyup="onKeyUp"
|
|
61
|
+
autocomplete="off"
|
|
62
|
+
/>
|
|
63
|
+
<farm-icon color="gray" :class="{ 'farm-icon--rotate': isVisible }" @click="addFocusToInput">
|
|
64
|
+
menu-down
|
|
65
|
+
</farm-icon>
|
|
66
|
+
</div>
|
|
67
|
+
</template>
|
|
68
|
+
</farm-contextmenu>
|
|
69
|
+
<farm-caption v-if="showErrorText" color="error" variation="regular">
|
|
70
|
+
{{ errorBucket[0] }}
|
|
71
|
+
</farm-caption>
|
|
72
|
+
<farm-caption
|
|
73
|
+
v-if="hint && !showErrorText"
|
|
74
|
+
class="farm-select__hint-text"
|
|
75
|
+
:class="{ 'farm-select__hint-text--show': persistentHint || isFocus }"
|
|
76
|
+
color="gray"
|
|
77
|
+
variation="regular"
|
|
78
|
+
>
|
|
79
|
+
{{ hint }}
|
|
80
|
+
</farm-caption>
|
|
81
|
+
</div>
|
|
82
|
+
<farm-textfield-v2 v-else v-model="selectedText" :disabled="disabled" :readonly="readonly" />
|
|
83
|
+
</div>
|
|
84
|
+
</template>
|
|
85
|
+
|
|
86
|
+
<script lang="ts">
|
|
87
|
+
import { computed, onBeforeMount, onMounted, PropType, ref, toRefs, watch, defineComponent } from 'vue';
|
|
88
|
+
import validateFormStateBuilder from '../../composition/validateFormStateBuilder';
|
|
89
|
+
import validateFormFieldBuilder from '../../composition/validateFormFieldBuilder';
|
|
90
|
+
import validateFormMethodBuilder from '../../composition/validateFormMethodBuilder';
|
|
91
|
+
import deepEqual from '../../composition/deepEqual';
|
|
92
|
+
import randomId from '../../helpers/randomId';
|
|
93
|
+
import { useSelectAutoComplete } from './composables';
|
|
94
|
+
|
|
95
|
+
export default defineComponent({
|
|
96
|
+
name: 'farm-select-auto-complete',
|
|
97
|
+
inheritAttrs: true,
|
|
98
|
+
props: {
|
|
99
|
+
/**
|
|
100
|
+
* v-model binding
|
|
101
|
+
*/
|
|
102
|
+
value: { type: [String, Number, Array], default: '' },
|
|
103
|
+
hint: {
|
|
104
|
+
type: String,
|
|
105
|
+
default: null,
|
|
106
|
+
},
|
|
107
|
+
/**
|
|
108
|
+
* Always show hint text
|
|
109
|
+
*/
|
|
110
|
+
persistentHint: {
|
|
111
|
+
type: Boolean,
|
|
112
|
+
default: true,
|
|
113
|
+
},
|
|
114
|
+
/**
|
|
115
|
+
* Disabled the input
|
|
116
|
+
*/
|
|
117
|
+
disabled: {
|
|
118
|
+
type: Boolean,
|
|
119
|
+
default: false,
|
|
120
|
+
},
|
|
121
|
+
/**
|
|
122
|
+
* Puts input in readonly state
|
|
123
|
+
*/
|
|
124
|
+
readonly: {
|
|
125
|
+
type: Boolean,
|
|
126
|
+
default: false,
|
|
127
|
+
},
|
|
128
|
+
/**
|
|
129
|
+
* Array of rules used for validation
|
|
130
|
+
*/
|
|
131
|
+
rules: {
|
|
132
|
+
type: Array as PropType<Array<Function>>,
|
|
133
|
+
default: () => [],
|
|
134
|
+
},
|
|
135
|
+
/**
|
|
136
|
+
* An array of objects. Will look for a text, value and disabled keys.
|
|
137
|
+
* This can be changed using the item-text ad item-value
|
|
138
|
+
*/
|
|
139
|
+
items: {
|
|
140
|
+
type: Array,
|
|
141
|
+
default: () => [],
|
|
142
|
+
},
|
|
143
|
+
/**
|
|
144
|
+
* Set property of items's text value
|
|
145
|
+
*/
|
|
146
|
+
itemText: {
|
|
147
|
+
type: String,
|
|
148
|
+
default: 'text',
|
|
149
|
+
},
|
|
150
|
+
/**
|
|
151
|
+
* Set property of items's value
|
|
152
|
+
*/
|
|
153
|
+
itemValue: {
|
|
154
|
+
type: String,
|
|
155
|
+
default: 'value',
|
|
156
|
+
},
|
|
157
|
+
/**
|
|
158
|
+
* No data text
|
|
159
|
+
*/
|
|
160
|
+
noDataText: {
|
|
161
|
+
type: String,
|
|
162
|
+
default: 'Não há dados',
|
|
163
|
+
},
|
|
164
|
+
/**
|
|
165
|
+
* Set a multiple select
|
|
166
|
+
*/
|
|
167
|
+
multiple: {
|
|
168
|
+
type: Boolean,
|
|
169
|
+
default: false,
|
|
170
|
+
},
|
|
171
|
+
/**
|
|
172
|
+
* Hides hint and validation errors
|
|
173
|
+
*/
|
|
174
|
+
hideDetails: {
|
|
175
|
+
type: Boolean,
|
|
176
|
+
default: false,
|
|
177
|
+
},
|
|
178
|
+
/**
|
|
179
|
+
* Select id
|
|
180
|
+
*/
|
|
181
|
+
id: {
|
|
182
|
+
type: String,
|
|
183
|
+
default: '',
|
|
184
|
+
},
|
|
185
|
+
/**
|
|
186
|
+
* The updated bound model<br />
|
|
187
|
+
* _event_
|
|
188
|
+
*/
|
|
189
|
+
input: {
|
|
190
|
+
type: Function,
|
|
191
|
+
// eslint-disable-next-line
|
|
192
|
+
default: (value: [String, Number, Array<any>]) => {},
|
|
193
|
+
},
|
|
194
|
+
/**
|
|
195
|
+
* Emitted when the select is changed by user interaction<br />
|
|
196
|
+
* _event_
|
|
197
|
+
*/
|
|
198
|
+
change: {
|
|
199
|
+
type: Function,
|
|
200
|
+
// eslint-disable-next-line
|
|
201
|
+
default: (value: [String, Number, Array<any>]) => {},
|
|
202
|
+
},
|
|
203
|
+
/**
|
|
204
|
+
* Emitted when any key is pressed<br />
|
|
205
|
+
* _event_
|
|
206
|
+
*/
|
|
207
|
+
keyup: {
|
|
208
|
+
type: Function,
|
|
209
|
+
// eslint-disable-next-line
|
|
210
|
+
default: (event: Event) => {},
|
|
211
|
+
},
|
|
212
|
+
/**
|
|
213
|
+
* Emitted when the select is blurred<br />
|
|
214
|
+
* _event_
|
|
215
|
+
*/
|
|
216
|
+
blur: {
|
|
217
|
+
type: Function,
|
|
218
|
+
// eslint-disable-next-line
|
|
219
|
+
default: (event: Event) => {},
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
setup(props, { emit }) {
|
|
223
|
+
const { rules, items, itemText, itemValue, disabled, multiple } = toRefs(props);
|
|
224
|
+
|
|
225
|
+
const {
|
|
226
|
+
multipleValues,
|
|
227
|
+
innerValue,
|
|
228
|
+
isTouched,
|
|
229
|
+
isFocus,
|
|
230
|
+
isBlured,
|
|
231
|
+
isVisible,
|
|
232
|
+
selectedText,
|
|
233
|
+
checked,
|
|
234
|
+
notChecked,
|
|
235
|
+
filteredItems,
|
|
236
|
+
inputField,
|
|
237
|
+
} = useSelectAutoComplete(props);
|
|
238
|
+
|
|
239
|
+
const listRef = ref();
|
|
240
|
+
|
|
241
|
+
const contextmenu = ref(null);
|
|
242
|
+
|
|
243
|
+
const { errorBucket, valid, validatable } = validateFormStateBuilder();
|
|
244
|
+
|
|
245
|
+
let fieldValidator = validateFormFieldBuilder(rules.value);
|
|
246
|
+
let validate = validateFormMethodBuilder(errorBucket, valid, fieldValidator);
|
|
247
|
+
|
|
248
|
+
const hasError = computed(() => {
|
|
249
|
+
return errorBucket.value.length > 0;
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const customId = 'farm-select-' + (props.id || randomId(2));
|
|
253
|
+
|
|
254
|
+
const showErrorText = computed(() => hasError.value && isTouched.value);
|
|
255
|
+
|
|
256
|
+
const searchText = ref('');
|
|
257
|
+
|
|
258
|
+
const filterOptions = () => {
|
|
259
|
+
searchText.value = selectedText.value.toLowerCase();
|
|
260
|
+
if (!searchText || searchText.value.includes('+')) {
|
|
261
|
+
filteredItems.value = items.value;
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
filteredItems.value = items.value.filter(
|
|
266
|
+
(item) => item[itemText.value].toLowerCase().includes(searchText.value)
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
if (filteredItems.value.length === 0 && searchText.value.trim() !== '') {
|
|
270
|
+
filteredItems.value = [];
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const showFilteredItems = computed(() => {
|
|
275
|
+
return isVisible.value && searchText.value.trim() !== '';
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
watch(
|
|
279
|
+
() => props.value,
|
|
280
|
+
newValue => {
|
|
281
|
+
innerValue.value = newValue;
|
|
282
|
+
errorBucket.value = [];
|
|
283
|
+
|
|
284
|
+
if (
|
|
285
|
+
(multiple.value && newValue === null) ||
|
|
286
|
+
(Array.isArray(newValue) && newValue.length === 0)
|
|
287
|
+
) {
|
|
288
|
+
multipleValues.value = [];
|
|
289
|
+
}
|
|
290
|
+
if (Array.isArray(newValue) && newValue.length > 0) {
|
|
291
|
+
multipleValues.value = [...newValue];
|
|
292
|
+
}
|
|
293
|
+
validate(newValue);
|
|
294
|
+
updateSelectedTextValue();
|
|
295
|
+
emit('input', newValue);
|
|
296
|
+
}
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
watch(
|
|
300
|
+
() => props.items,
|
|
301
|
+
() => {
|
|
302
|
+
errorBucket.value = [];
|
|
303
|
+
validate(innerValue.value);
|
|
304
|
+
updateSelectedTextValue();
|
|
305
|
+
}
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
watch(
|
|
309
|
+
() => innerValue.value,
|
|
310
|
+
() => {
|
|
311
|
+
isTouched.value = true;
|
|
312
|
+
isBlured.value = true;
|
|
313
|
+
validate(innerValue.value);
|
|
314
|
+
emit('input', innerValue.value);
|
|
315
|
+
}
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
watch(
|
|
319
|
+
() => props.rules,
|
|
320
|
+
(newVal, oldVal) => {
|
|
321
|
+
if (deepEqual(newVal, oldVal)) return;
|
|
322
|
+
fieldValidator = validateFormFieldBuilder(rules.value);
|
|
323
|
+
validate(innerValue.value);
|
|
324
|
+
}
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
const handleOutsideClick = (event) => {
|
|
329
|
+
clearSearchAndReturnSelection(event);
|
|
330
|
+
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
onBeforeMount(() => {
|
|
334
|
+
validate(innerValue.value);
|
|
335
|
+
updateSelectedTextValue();
|
|
336
|
+
document.removeEventListener('click', handleOutsideClick);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
onMounted(() => {
|
|
340
|
+
document.addEventListener('click', handleOutsideClick);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
const reset = () => {
|
|
344
|
+
if (disabled.value) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
innerValue.value = null;
|
|
348
|
+
multipleValues.value = [];
|
|
349
|
+
selectedText.value = '';
|
|
350
|
+
isTouched.value = true;
|
|
351
|
+
if (multiple.value) {
|
|
352
|
+
innerValue.value = [];
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
emit('input', innerValue.value);
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const onBlur = (event: Event) => {
|
|
359
|
+
isBlured.value = true;
|
|
360
|
+
validate(innerValue.value);
|
|
361
|
+
emit('blur', event);
|
|
362
|
+
|
|
363
|
+
setTimeout(() => {
|
|
364
|
+
if (multiple.value){
|
|
365
|
+
searchText.value = '';
|
|
366
|
+
addLabelToMultiple();
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
}, 100);
|
|
370
|
+
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
const clearSearchAndReturnSelection = (event) => {
|
|
374
|
+
if (!event.srcElement.className.includes('farm-listitem')) {
|
|
375
|
+
if (innerValue.value !== null) {
|
|
376
|
+
if (!selectedText.value) {
|
|
377
|
+
innerValue.value = null;
|
|
378
|
+
}
|
|
379
|
+
searchText.value = '';
|
|
380
|
+
}
|
|
381
|
+
updateSelectedTextValue();
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const onFocus = (focus: boolean) => {
|
|
386
|
+
|
|
387
|
+
isFocus.value = focus;
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
const selectItem = item => {
|
|
391
|
+
|
|
392
|
+
if (multiple.value) {
|
|
393
|
+
const alreadyAdded = multipleValues.value.findIndex(
|
|
394
|
+
val => val === item[itemValue.value]
|
|
395
|
+
);
|
|
396
|
+
checked.value = '1';
|
|
397
|
+
if (alreadyAdded !== -1) {
|
|
398
|
+
multipleValues.value.splice(alreadyAdded, 1);
|
|
399
|
+
} else {
|
|
400
|
+
multipleValues.value.push(item[itemValue.value]);
|
|
401
|
+
}
|
|
402
|
+
innerValue.value = [...multipleValues.value];
|
|
403
|
+
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
innerValue.value = item[itemValue.value];
|
|
408
|
+
isVisible.value = false;
|
|
409
|
+
|
|
410
|
+
setTimeout(() => {
|
|
411
|
+
emit('change', innerValue.value);
|
|
412
|
+
searchText.value = '';
|
|
413
|
+
}, 100);
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
const clickInput = () => {
|
|
417
|
+
|
|
418
|
+
isTouched.value = true;
|
|
419
|
+
emit('click');
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
const makePristine = () => {
|
|
423
|
+
isTouched.value = false;
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
const updateSelectedTextValue = () => {
|
|
427
|
+
if (
|
|
428
|
+
!items.value ||
|
|
429
|
+
items.value.length === 0 ||
|
|
430
|
+
innerValue.value === null ||
|
|
431
|
+
(multiple.value && multipleValues.value.length === 0)
|
|
432
|
+
) {
|
|
433
|
+
selectedText.value = '';
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
const selectedItem = items.value.find(
|
|
437
|
+
item => item[itemValue.value] == innerValue.value
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
if (selectedItem) {
|
|
441
|
+
selectedText.value = selectedItem[itemText.value];
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
addLabelToMultiple();
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
const addLabelToMultiple = () => {
|
|
448
|
+
if (multiple.value && Array.isArray(innerValue.value) && innerValue.value.length > 0) {
|
|
449
|
+
const labelItem = items.value.find(
|
|
450
|
+
item => item[itemValue.value] === innerValue.value[0]
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
if (innerValue.value.length === 0) {
|
|
454
|
+
selectedText.value = '';
|
|
455
|
+
return;
|
|
456
|
+
} else if (innerValue.value.length === 1) {
|
|
457
|
+
selectedText.value = labelItem[itemText.value];
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
selectedText.value = `${labelItem[itemText.value]} (+${
|
|
462
|
+
innerValue.value.length - 1
|
|
463
|
+
} ${innerValue.value.length - 1 === 1 ? 'outro' : 'outros'})`;
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
const isChecked = item => {
|
|
468
|
+
return (
|
|
469
|
+
multiple.value &&
|
|
470
|
+
multipleValues.value.findIndex(val => val === item[itemValue.value]) !== -1
|
|
471
|
+
);
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
const onInput = () => {
|
|
475
|
+
isVisible.value = true;
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
function onKeyUp(event) {
|
|
479
|
+
if (props.readonly) return;
|
|
480
|
+
filterOptions();
|
|
481
|
+
event.preventDefault();
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function addFocusToInput() {
|
|
485
|
+
inputField.value.focus();
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
return {
|
|
489
|
+
items,
|
|
490
|
+
innerValue,
|
|
491
|
+
selectedText,
|
|
492
|
+
errorBucket,
|
|
493
|
+
valid,
|
|
494
|
+
validatable,
|
|
495
|
+
hasError,
|
|
496
|
+
isTouched,
|
|
497
|
+
isBlured,
|
|
498
|
+
isFocus,
|
|
499
|
+
isVisible,
|
|
500
|
+
customId,
|
|
501
|
+
showErrorText,
|
|
502
|
+
contextmenu,
|
|
503
|
+
validate,
|
|
504
|
+
reset,
|
|
505
|
+
selectItem,
|
|
506
|
+
onBlur,
|
|
507
|
+
onFocus,
|
|
508
|
+
clickInput,
|
|
509
|
+
updateSelectedTextValue,
|
|
510
|
+
makePristine,
|
|
511
|
+
checked,
|
|
512
|
+
notChecked,
|
|
513
|
+
isChecked,
|
|
514
|
+
multipleValues,
|
|
515
|
+
addLabelToMultiple,
|
|
516
|
+
inputField,
|
|
517
|
+
onKeyUp,
|
|
518
|
+
addFocusToInput,
|
|
519
|
+
filterOptions,
|
|
520
|
+
onInput,
|
|
521
|
+
listRef,
|
|
522
|
+
filteredItems,
|
|
523
|
+
showFilteredItems,
|
|
524
|
+
searchText,
|
|
525
|
+
handleOutsideClick
|
|
526
|
+
};
|
|
527
|
+
},
|
|
528
|
+
});
|
|
529
|
+
</script>
|
|
530
|
+
<style lang="scss" scoped>
|
|
531
|
+
@import 'SelectAutoComplete';
|
|
532
|
+
</style>
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import SelectAutoComplete from '../SelectAutoComplete.vue';
|
|
3
|
+
|
|
4
|
+
describe('SelectAutoComplet component', () => {
|
|
5
|
+
let wrapper;
|
|
6
|
+
let component;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
wrapper = shallowMount(SelectAutoComplete);
|
|
10
|
+
component = wrapper.vm;
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test('Created hook', () => {
|
|
14
|
+
expect(wrapper).toBeDefined();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
describe('mount component', () => {
|
|
19
|
+
it('renders correctly', () => {
|
|
20
|
+
expect(wrapper.element).toMatchSnapshot();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('methods', () => {
|
|
25
|
+
it('reset', () => {
|
|
26
|
+
component.reset();
|
|
27
|
+
expect(component.isTouched).toBeTruthy();
|
|
28
|
+
expect(component.innerValue).toEqual(null);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('onBlur', () => {
|
|
32
|
+
component.onBlur();
|
|
33
|
+
expect(component.isBlured).toBeTruthy();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('clickInput', () => {
|
|
37
|
+
component.clickInput();
|
|
38
|
+
expect(component.isTouched).toBeTruthy();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('updateSelectedTextValue', () => {
|
|
42
|
+
component.updateSelectedTextValue();
|
|
43
|
+
expect(component.selectedText).toBeDefined();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('makePristine', () => {
|
|
47
|
+
component.isTouched = true;
|
|
48
|
+
component.makePristine();
|
|
49
|
+
expect(component.isTouched).toBeFalsy();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('isChecked', () => {
|
|
53
|
+
it('should return false when multiple is false', async () => {
|
|
54
|
+
component.multipleValues = [0, 1, 2];
|
|
55
|
+
const result = component.isChecked({ value: 1 });
|
|
56
|
+
expect(result).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
it('should return true when multiple is true and item is checked', async () => {
|
|
59
|
+
await wrapper.setProps({
|
|
60
|
+
multiple: true,
|
|
61
|
+
});
|
|
62
|
+
component.multipleValues = [0, 1, 2];
|
|
63
|
+
const result = component.isChecked({ value: 1 });
|
|
64
|
+
expect(result).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
it('should return false when item is not checked', async () => {
|
|
67
|
+
await wrapper.setProps({
|
|
68
|
+
multiple: true,
|
|
69
|
+
});
|
|
70
|
+
component.multipleValues = [0, 1, 2];
|
|
71
|
+
const result = component.isChecked({ value: 3 });
|
|
72
|
+
expect(result).toBe(false);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('addLabelToMultiple', () => {
|
|
77
|
+
it('should not do anything when multiple is false', async () => {
|
|
78
|
+
component.addLabelToMultiple();
|
|
79
|
+
|
|
80
|
+
expect(component.selectedText).toBe('');
|
|
81
|
+
});
|
|
82
|
+
it('should return a selectedText to a selected item', async () => {
|
|
83
|
+
await wrapper.setProps({
|
|
84
|
+
multiple: true,
|
|
85
|
+
items: [
|
|
86
|
+
{ value: 0, text: 'value 0' },
|
|
87
|
+
{ value: 1, text: 'value 1' },
|
|
88
|
+
{ value: 2, text: 'value 2' },
|
|
89
|
+
{ value: 3, text: 'value 3' },
|
|
90
|
+
],
|
|
91
|
+
value: [0],
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
component.addLabelToMultiple();
|
|
95
|
+
expect(component.selectedText).toBe('value 0');
|
|
96
|
+
});
|
|
97
|
+
it('should return a selectedText to two selected item', async () => {
|
|
98
|
+
await wrapper.setProps({
|
|
99
|
+
multiple: true,
|
|
100
|
+
items: [
|
|
101
|
+
{ value: 0, text: 'value 0' },
|
|
102
|
+
{ value: 1, text: 'value 1' },
|
|
103
|
+
{ value: 2, text: 'value 2' },
|
|
104
|
+
{ value: 3, text: 'value 3' },
|
|
105
|
+
],
|
|
106
|
+
value: [0, 1],
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
component.addLabelToMultiple();
|
|
110
|
+
expect(component.selectedText).toBe('value 0 (+1 outro)');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should return a selectedText to three or more selected item', async () => {
|
|
114
|
+
await wrapper.setProps({
|
|
115
|
+
multiple: true,
|
|
116
|
+
items: [
|
|
117
|
+
{ value: 0, text: 'value 0' },
|
|
118
|
+
{ value: 1, text: 'value 1' },
|
|
119
|
+
{ value: 2, text: 'value 2' },
|
|
120
|
+
{ value: 3, text: 'value 3' },
|
|
121
|
+
],
|
|
122
|
+
value: [0, 1, 2],
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
component.addLabelToMultiple();
|
|
126
|
+
expect(component.selectedText).toBe('value 0 (+2 outros)');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import useSelectAutoComplete from '../composables/useSelectAutoComplete';
|
|
2
|
+
|
|
3
|
+
describe('useSelectAutoComplete', () => {
|
|
4
|
+
it('should initialize with empty arrays and false values', () => {
|
|
5
|
+
const props = { value: [] };
|
|
6
|
+
const result = useSelectAutoComplete(props);
|
|
7
|
+
|
|
8
|
+
expect(result.multipleValues.value).toEqual([]);
|
|
9
|
+
expect(result.innerValue.value).toEqual([]);
|
|
10
|
+
expect(result.isTouched.value).toBe(false);
|
|
11
|
+
expect(result.isFocus.value).toBe(false);
|
|
12
|
+
expect(result.isBlured.value).toBe(false);
|
|
13
|
+
expect(result.isVisible.value).toBe(false);
|
|
14
|
+
expect(result.selectedText.value).toBe('');
|
|
15
|
+
expect(result.checked.value).toBe('1');
|
|
16
|
+
expect(result.notChecked.value).toBe(false);
|
|
17
|
+
expect(result.inputField.value).toBe(undefined);
|
|
18
|
+
expect(result.filteredItems.value).toBe(undefined);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should initialize with provided values', () => {
|
|
22
|
+
const props = { value: 'test' };
|
|
23
|
+
const result = useSelectAutoComplete(props);
|
|
24
|
+
|
|
25
|
+
expect(result.multipleValues.value).toEqual([]);
|
|
26
|
+
expect(result.innerValue.value).toBe('test');
|
|
27
|
+
});
|
|
28
|
+
});
|