@farm-investimentos/front-mfe-components 12.1.0 → 12.1.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.
- package/dist/front-mfe-components.common.js +226 -135
- 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 +226 -135
- 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/ContextMenu/ContextMenu.vue +26 -7
- package/src/components/Select/Select.scss +12 -1
- package/src/components/Select/Select.stories.js +51 -0
- package/src/components/Select/Select.vue +90 -6
- package/src/components/Select/__tests__/Select.spec.js +77 -0
package/package.json
CHANGED
|
@@ -4,10 +4,14 @@
|
|
|
4
4
|
<slot name="activator"></slot>
|
|
5
5
|
</span>
|
|
6
6
|
|
|
7
|
-
<div
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
<div
|
|
8
|
+
ref="popup"
|
|
9
|
+
:class="{
|
|
10
|
+
'farm-contextmenu__popup': true,
|
|
11
|
+
'farm-contextmenu__popup--visible': inputValue,
|
|
12
|
+
}"
|
|
13
|
+
:style="styles"
|
|
14
|
+
>
|
|
11
15
|
<slot></slot>
|
|
12
16
|
</div>
|
|
13
17
|
</div>
|
|
@@ -41,12 +45,19 @@ export default Vue.extend({
|
|
|
41
45
|
type: [Number, String],
|
|
42
46
|
default: 320,
|
|
43
47
|
},
|
|
48
|
+
/**
|
|
49
|
+
* Should stay open when click inside
|
|
50
|
+
*/
|
|
51
|
+
stayOpen: {
|
|
52
|
+
type: Boolean,
|
|
53
|
+
default: false,
|
|
54
|
+
},
|
|
44
55
|
},
|
|
45
56
|
setup(props, { emit }) {
|
|
46
57
|
const parent = ref(null);
|
|
47
58
|
const popup = ref(null);
|
|
48
59
|
const activator = ref(null);
|
|
49
|
-
const { bottom, maxHeight } = toRefs(props);
|
|
60
|
+
const { bottom, maxHeight, stayOpen } = toRefs(props);
|
|
50
61
|
|
|
51
62
|
const styles = reactive({
|
|
52
63
|
minWidth: 0,
|
|
@@ -59,8 +70,16 @@ export default Vue.extend({
|
|
|
59
70
|
|
|
60
71
|
let hasBeenBoostrapped = false;
|
|
61
72
|
|
|
62
|
-
const outClick = (event:
|
|
63
|
-
|
|
73
|
+
const outClick = (event: Record<string, any>) => {
|
|
74
|
+
const isInside =
|
|
75
|
+
event.path.some((e: HTMLElement) => {
|
|
76
|
+
if (e.classList) {
|
|
77
|
+
return e.classList.contains('farm-contextmenu__popup--visible');
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}) && stayOpen.value;
|
|
81
|
+
|
|
82
|
+
if (activator && !activator.value.contains(event.target) && !isInside) {
|
|
64
83
|
emit('input', false);
|
|
65
84
|
inputValue.value = false;
|
|
66
85
|
}
|
|
@@ -15,4 +15,15 @@
|
|
|
15
15
|
&--rotate {
|
|
16
16
|
transform: rotate(180deg);
|
|
17
17
|
}
|
|
18
|
-
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.farm-select__checkbox {
|
|
21
|
+
margin-right: 8px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
::v-deep .farm-listitem:hover .farm-checkbox .farm-icon {
|
|
25
|
+
color: var(--farm-primary-lighten);
|
|
26
|
+
}
|
|
27
|
+
::v-deep .farm-listitem:hover .farm-checkbox.farm-checkbox--checked .farm-icon {
|
|
28
|
+
color: white;
|
|
29
|
+
}
|
|
@@ -195,3 +195,54 @@ export const NoItems = () => ({
|
|
|
195
195
|
v-model: {{ v }}
|
|
196
196
|
</div>`,
|
|
197
197
|
});
|
|
198
|
+
|
|
199
|
+
export const Multiple = () => ({
|
|
200
|
+
data() {
|
|
201
|
+
return {
|
|
202
|
+
v: null,
|
|
203
|
+
items: [
|
|
204
|
+
{ value: 0, text: 'value 0' },
|
|
205
|
+
{ value: 1, text: 'value 1' },
|
|
206
|
+
{ value: 2, text: 'value 2' },
|
|
207
|
+
{ value: 3, text: 'value 3' },
|
|
208
|
+
],
|
|
209
|
+
};
|
|
210
|
+
},
|
|
211
|
+
template: `<div style="width: 400px">
|
|
212
|
+
<farm-select v-model="v" :items="items" multiple />
|
|
213
|
+
v-model: {{ v }}
|
|
214
|
+
</div>`,
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
export const MultipleInitValue = () => ({
|
|
218
|
+
data() {
|
|
219
|
+
return {
|
|
220
|
+
v: [2, 3],
|
|
221
|
+
items: [
|
|
222
|
+
{ id: 0, label: 'value 0' },
|
|
223
|
+
{ id: 1, label: 'value 1' },
|
|
224
|
+
{ id: 2, label: 'value 2' },
|
|
225
|
+
{ id: 3, label: 'value 3' },
|
|
226
|
+
],
|
|
227
|
+
};
|
|
228
|
+
},
|
|
229
|
+
methods: {
|
|
230
|
+
click() {
|
|
231
|
+
this.$refs.select.reset();
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
template: `<div style="width: 400px">
|
|
235
|
+
<farm-select
|
|
236
|
+
v-model="v"
|
|
237
|
+
item-value="id"
|
|
238
|
+
item-text="label"
|
|
239
|
+
ref="select"
|
|
240
|
+
multiple
|
|
241
|
+
:items="items"
|
|
242
|
+
/>
|
|
243
|
+
v-model: {{ v }}
|
|
244
|
+
<farm-btn @click="click">
|
|
245
|
+
reset
|
|
246
|
+
</farm-btn>
|
|
247
|
+
</div>`,
|
|
248
|
+
});
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
}"
|
|
12
12
|
v-if="!readonly && !disabled"
|
|
13
13
|
>
|
|
14
|
-
<farm-contextmenu bottom v-model="isVisible">
|
|
14
|
+
<farm-contextmenu bottom v-model="isVisible" :stay-open="multiple">
|
|
15
15
|
<farm-list v-if="!readonly">
|
|
16
16
|
<farm-listitem
|
|
17
17
|
v-for="(item, index) in items"
|
|
@@ -22,7 +22,21 @@
|
|
|
22
22
|
:class="{ 'farm-listitem--selected': item[itemValue] === innerValue }"
|
|
23
23
|
@click="selectItem(item)"
|
|
24
24
|
>
|
|
25
|
-
<farm-
|
|
25
|
+
<farm-checkbox
|
|
26
|
+
class="farm-select__checkbox"
|
|
27
|
+
v-model="checked"
|
|
28
|
+
value="1"
|
|
29
|
+
size="sm"
|
|
30
|
+
v-if="isChecked(item)"
|
|
31
|
+
></farm-checkbox>
|
|
32
|
+
<farm-checkbox
|
|
33
|
+
class="farm-select__checkbox"
|
|
34
|
+
v-model="checked"
|
|
35
|
+
value="2"
|
|
36
|
+
size="sm"
|
|
37
|
+
v-else-if="multiple"
|
|
38
|
+
></farm-checkbox
|
|
39
|
+
><farm-caption bold tag="span">{{ item[itemText] }}</farm-caption>
|
|
26
40
|
</farm-listitem>
|
|
27
41
|
<farm-listitem v-if="!items || items.length === 0">
|
|
28
42
|
{{ noDataText }}
|
|
@@ -68,7 +82,7 @@ export default Vue.extend({
|
|
|
68
82
|
/**
|
|
69
83
|
* v-model binding
|
|
70
84
|
*/
|
|
71
|
-
value: { type: [String, Number], default: '' },
|
|
85
|
+
value: { type: [String, Number, Array], default: '' },
|
|
72
86
|
hint: {
|
|
73
87
|
type: String,
|
|
74
88
|
default: null,
|
|
@@ -123,14 +137,24 @@ export default Vue.extend({
|
|
|
123
137
|
type: String,
|
|
124
138
|
default: 'Não há dados',
|
|
125
139
|
},
|
|
140
|
+
/**
|
|
141
|
+
* Set a multiple select
|
|
142
|
+
*/
|
|
143
|
+
multiple: {
|
|
144
|
+
type: Boolean,
|
|
145
|
+
default: false,
|
|
146
|
+
},
|
|
126
147
|
},
|
|
127
148
|
setup(props, { emit }) {
|
|
128
|
-
const { rules, items, itemText, itemValue, disabled } = toRefs(props);
|
|
149
|
+
const { rules, items, itemText, itemValue, disabled, multiple } = toRefs(props);
|
|
129
150
|
const innerValue = ref(props.value);
|
|
130
151
|
const isTouched = ref(false);
|
|
131
152
|
const isBlured = ref(false);
|
|
132
153
|
const isVisible = ref(false);
|
|
133
154
|
const selectedText = ref('');
|
|
155
|
+
const multipleValues = ref(Array.isArray(props.value) ? [...props.value] : []);
|
|
156
|
+
const checked = ref('1');
|
|
157
|
+
const notChecked = ref(false);
|
|
134
158
|
|
|
135
159
|
const { errorBucket, valid, validatable } = validateFormStateBuilder();
|
|
136
160
|
|
|
@@ -169,6 +193,7 @@ export default Vue.extend({
|
|
|
169
193
|
() => {
|
|
170
194
|
isTouched.value = true;
|
|
171
195
|
isBlured.value = true;
|
|
196
|
+
validate(innerValue.value);
|
|
172
197
|
emit('input', innerValue.value);
|
|
173
198
|
emit('change', innerValue.value);
|
|
174
199
|
}
|
|
@@ -193,8 +218,13 @@ export default Vue.extend({
|
|
|
193
218
|
return;
|
|
194
219
|
}
|
|
195
220
|
innerValue.value = null;
|
|
221
|
+
multipleValues.value = [];
|
|
196
222
|
selectedText.value = '';
|
|
197
223
|
isTouched.value = true;
|
|
224
|
+
if (multiple.value) {
|
|
225
|
+
innerValue.value = [];
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
198
228
|
emit('input', innerValue.value);
|
|
199
229
|
};
|
|
200
230
|
|
|
@@ -209,7 +239,21 @@ export default Vue.extend({
|
|
|
209
239
|
};
|
|
210
240
|
|
|
211
241
|
const selectItem = item => {
|
|
212
|
-
|
|
242
|
+
if (multiple.value) {
|
|
243
|
+
const alreadyAdded = multipleValues.value.findIndex(
|
|
244
|
+
val => val === item[itemValue.value]
|
|
245
|
+
);
|
|
246
|
+
checked.value = '1';
|
|
247
|
+
if (alreadyAdded !== -1) {
|
|
248
|
+
multipleValues.value.splice(alreadyAdded, 1);
|
|
249
|
+
} else {
|
|
250
|
+
multipleValues.value.push(item[itemValue.value]);
|
|
251
|
+
}
|
|
252
|
+
innerValue.value = [...multipleValues.value];
|
|
253
|
+
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
213
257
|
innerValue.value = item[itemValue.value];
|
|
214
258
|
isVisible.value = false;
|
|
215
259
|
};
|
|
@@ -224,16 +268,51 @@ export default Vue.extend({
|
|
|
224
268
|
};
|
|
225
269
|
|
|
226
270
|
const updateSelectedTextValue = () => {
|
|
227
|
-
if (
|
|
271
|
+
if (
|
|
272
|
+
!items.value ||
|
|
273
|
+
items.value.length === 0 ||
|
|
274
|
+
innerValue.value === null ||
|
|
275
|
+
(multiple.value && multipleValues.value.length === 0)
|
|
276
|
+
) {
|
|
228
277
|
selectedText.value = '';
|
|
229
278
|
return;
|
|
230
279
|
}
|
|
231
280
|
const selectedItem = items.value.find(
|
|
232
281
|
item => item[itemValue.value] == innerValue.value
|
|
233
282
|
);
|
|
283
|
+
|
|
234
284
|
if (selectedItem) {
|
|
235
285
|
selectedText.value = selectedItem[itemText.value];
|
|
236
286
|
}
|
|
287
|
+
|
|
288
|
+
addLabelToMultiple();
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
const addLabelToMultiple = () => {
|
|
292
|
+
if (multiple.value && Array.isArray(innerValue.value) && innerValue.value.length > 0) {
|
|
293
|
+
const labelItem = items.value.find(
|
|
294
|
+
item => item[itemValue.value] === innerValue.value[0]
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
if (innerValue.value.length === 0) {
|
|
298
|
+
selectedText.value = '';
|
|
299
|
+
return;
|
|
300
|
+
} else if (innerValue.value.length === 1) {
|
|
301
|
+
selectedText.value = labelItem[itemText.value];
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
selectedText.value = `${labelItem[itemText.value]} (+${
|
|
306
|
+
innerValue.value.length - 1
|
|
307
|
+
} ${innerValue.value.length - 1 === 1 ? 'outro' : 'outros'})`;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const isChecked = item => {
|
|
312
|
+
return (
|
|
313
|
+
multiple.value &&
|
|
314
|
+
multipleValues.value.findIndex(val => val === item[itemValue.value]) !== -1
|
|
315
|
+
);
|
|
237
316
|
};
|
|
238
317
|
|
|
239
318
|
return {
|
|
@@ -256,6 +335,11 @@ export default Vue.extend({
|
|
|
256
335
|
clickInput,
|
|
257
336
|
updateSelectedTextValue,
|
|
258
337
|
makePristine,
|
|
338
|
+
checked,
|
|
339
|
+
notChecked,
|
|
340
|
+
isChecked,
|
|
341
|
+
multipleValues,
|
|
342
|
+
addLabelToMultiple,
|
|
259
343
|
};
|
|
260
344
|
},
|
|
261
345
|
});
|
|
@@ -47,5 +47,82 @@ describe('Select component', () => {
|
|
|
47
47
|
component.makePristine();
|
|
48
48
|
expect(component.isTouched).toBeFalsy();
|
|
49
49
|
});
|
|
50
|
+
|
|
51
|
+
describe('isChecked', () => {
|
|
52
|
+
it('should return false when multiple is false', async () => {
|
|
53
|
+
component.multipleValues = [0, 1, 2];
|
|
54
|
+
const result = component.isChecked({ value: 1 });
|
|
55
|
+
expect(result).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
it('should return true when multiple is true and item is checked', async () => {
|
|
58
|
+
await wrapper.setProps({
|
|
59
|
+
multiple: true,
|
|
60
|
+
});
|
|
61
|
+
component.multipleValues = [0, 1, 2];
|
|
62
|
+
const result = component.isChecked({ value: 1 });
|
|
63
|
+
expect(result).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
it('should return false when item is not checked', async () => {
|
|
66
|
+
await wrapper.setProps({
|
|
67
|
+
multiple: true,
|
|
68
|
+
});
|
|
69
|
+
component.multipleValues = [0, 1, 2];
|
|
70
|
+
const result = component.isChecked({ value: 3 });
|
|
71
|
+
expect(result).toBe(false);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe('addLabelToMultiple', () => {
|
|
75
|
+
it('should not do anything when multiple is false', async () => {
|
|
76
|
+
component.addLabelToMultiple();
|
|
77
|
+
|
|
78
|
+
expect(component.selectedText).toBe('');
|
|
79
|
+
});
|
|
80
|
+
it('should return a selectedText to a selected item', async () => {
|
|
81
|
+
await wrapper.setProps({
|
|
82
|
+
multiple: true,
|
|
83
|
+
items: [
|
|
84
|
+
{ value: 0, text: 'value 0' },
|
|
85
|
+
{ value: 1, text: 'value 1' },
|
|
86
|
+
{ value: 2, text: 'value 2' },
|
|
87
|
+
{ value: 3, text: 'value 3' },
|
|
88
|
+
],
|
|
89
|
+
value: [0],
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
component.addLabelToMultiple();
|
|
93
|
+
expect(component.selectedText).toBe('value 0');
|
|
94
|
+
});
|
|
95
|
+
it('should return a selectedText to two selected item', async () => {
|
|
96
|
+
await wrapper.setProps({
|
|
97
|
+
multiple: true,
|
|
98
|
+
items: [
|
|
99
|
+
{ value: 0, text: 'value 0' },
|
|
100
|
+
{ value: 1, text: 'value 1' },
|
|
101
|
+
{ value: 2, text: 'value 2' },
|
|
102
|
+
{ value: 3, text: 'value 3' },
|
|
103
|
+
],
|
|
104
|
+
value: [0, 1],
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
component.addLabelToMultiple();
|
|
108
|
+
expect(component.selectedText).toBe('value 0 (+1 outro)');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should return a selectedText to three or more selected item', async () => {
|
|
112
|
+
await wrapper.setProps({
|
|
113
|
+
multiple: true,
|
|
114
|
+
items: [
|
|
115
|
+
{ value: 0, text: 'value 0' },
|
|
116
|
+
{ value: 1, text: 'value 1' },
|
|
117
|
+
{ value: 2, text: 'value 2' },
|
|
118
|
+
{ value: 3, text: 'value 3' },
|
|
119
|
+
],
|
|
120
|
+
value: [0, 1, 2],
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
component.addLabelToMultiple();
|
|
124
|
+
expect(component.selectedText).toBe('value 0 (+2 outros)');
|
|
125
|
+
});
|
|
126
|
+
});
|
|
50
127
|
});
|
|
51
128
|
});
|