@webitel/ui-sdk 24.2.7 → 24.2.8
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/img/sprite/call-merge-filled.svg +5 -0
- package/dist/img/sprite/index.js +1 -0
- package/dist/ui-sdk.css +1 -1
- package/dist/ui-sdk.mjs +2290 -2227
- package/dist/ui-sdk.umd.js +14 -14
- package/package.json +1 -1
- package/src/components/wt-select/_multiselect.scss +12 -8
- package/src/components/wt-select/mixins/multiselectMixin.js +3 -1
- package/src/components/wt-select/wt-select.vue +66 -14
- package/src/components/wt-tags-input/__tests__/WtTagsInput.spec.js +1 -1
- package/src/components/wt-tags-input/mixin/__tests__/taggableMixin.spec.js +24 -0
- package/src/components/wt-tags-input/mixin/taggableMixin.js +36 -0
- package/src/components/wt-tags-input/wt-tags-input.vue +13 -31
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
|
|
2
2
|
.multiselect :deep {
|
|
3
|
-
cursor: pointer;
|
|
4
3
|
position: relative;
|
|
4
|
+
cursor: pointer;
|
|
5
5
|
|
|
6
6
|
.multiselect__select {
|
|
7
7
|
position: absolute;
|
|
8
8
|
top: var(--select-icon-top-pos);
|
|
9
9
|
right: var(--select-caret-right-pos);
|
|
10
|
-
padding: 0; // reset default
|
|
11
|
-
transition: var(--transition);
|
|
12
10
|
width: fit-content; // reset default
|
|
13
11
|
height: fit-content; // reset default
|
|
12
|
+
padding: 0; // reset default
|
|
13
|
+
transition: var(--transition);
|
|
14
14
|
background: transparent;
|
|
15
15
|
|
|
16
16
|
&:before {
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
.multiselect__placeholder {
|
|
46
46
|
@extend %typo-body-1;
|
|
47
47
|
@include wt-placeholder;
|
|
48
|
-
background: transparent;
|
|
49
|
-
color: var(--wt-text-field-text-color);
|
|
50
|
-
padding: 0; // reset default
|
|
51
48
|
margin: 0; // reset default
|
|
49
|
+
padding: 0; // reset default
|
|
50
|
+
color: var(--wt-text-field-text-color);
|
|
51
|
+
background: transparent;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
.multiselect__custom-tag,
|
|
@@ -58,9 +58,9 @@
|
|
|
58
58
|
|
|
59
59
|
.multiselect__placeholder {
|
|
60
60
|
@extend %wt-placeholder;
|
|
61
|
+
display: block;
|
|
61
62
|
overflow: hidden;
|
|
62
63
|
max-width: 100%;
|
|
63
|
-
display: block;
|
|
64
64
|
|
|
65
65
|
// text overflow 3 dots
|
|
66
66
|
white-space: nowrap;
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
border: var(--select-tags-border);
|
|
75
75
|
border-color: var(--wt-text-field-select-option-wrapper-border-color);
|
|
76
76
|
border-radius: var(--border-radius);
|
|
77
|
-
box-shadow: var(--elevation-10);
|
|
78
77
|
background: transparent;
|
|
78
|
+
box-shadow: var(--elevation-10);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
// select options
|
|
@@ -108,6 +108,10 @@
|
|
|
108
108
|
.multiselect__select .wt-icon__icon {
|
|
109
109
|
fill: var(--icon-active-color);
|
|
110
110
|
}
|
|
111
|
+
|
|
112
|
+
.multiselect__custom-value-arrow {
|
|
113
|
+
transform: none;
|
|
114
|
+
}
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
.wt-select--loading,
|
|
@@ -110,10 +110,12 @@ export default {
|
|
|
110
110
|
return option[this.defaultOptionLabel] || option;
|
|
111
111
|
},
|
|
112
112
|
handleSearchChange(search) {
|
|
113
|
+
// search can be used in non-api mode too
|
|
114
|
+
this.searchParams.search = search;
|
|
115
|
+
|
|
113
116
|
if (!this.isApiMode) return;
|
|
114
117
|
this.isLoading = true;
|
|
115
118
|
this.searchParams.page = 1;
|
|
116
|
-
this.searchParams.search = search;
|
|
117
119
|
this.fetchOptions();
|
|
118
120
|
},
|
|
119
121
|
|
|
@@ -11,21 +11,20 @@
|
|
|
11
11
|
>
|
|
12
12
|
<wt-label
|
|
13
13
|
v-if="hasLabel"
|
|
14
|
-
v-bind="labelProps"
|
|
15
14
|
:disabled="disabled"
|
|
16
15
|
:invalid="invalid"
|
|
17
16
|
class="wt-select__label"
|
|
17
|
+
v-bind="labelProps"
|
|
18
18
|
>
|
|
19
19
|
<!-- @slot Custom input label -->
|
|
20
20
|
<slot
|
|
21
|
-
v-bind="{ label }"
|
|
22
21
|
name="label"
|
|
22
|
+
v-bind="{ label }"
|
|
23
23
|
>
|
|
24
24
|
{{ requiredLabel }}
|
|
25
25
|
</slot>
|
|
26
26
|
</wt-label>
|
|
27
27
|
<vue-multiselect
|
|
28
|
-
v-bind="$attrs"
|
|
29
28
|
ref="vue-multiselect"
|
|
30
29
|
:allow-empty="allowEmpty"
|
|
31
30
|
:disabled="disabled"
|
|
@@ -33,12 +32,13 @@
|
|
|
33
32
|
:label="selectOptionLabel"
|
|
34
33
|
:limit="1"
|
|
35
34
|
:loading="false"
|
|
35
|
+
:model-value="selectValue"
|
|
36
36
|
:multiple="multiple"
|
|
37
37
|
:options="selectOptions"
|
|
38
38
|
:placeholder="placeholder || label"
|
|
39
39
|
:track-by="trackBy"
|
|
40
|
-
:model-value="selectValue"
|
|
41
40
|
class="wt-select__select"
|
|
41
|
+
v-bind="$attrs"
|
|
42
42
|
@close="isOpened = false"
|
|
43
43
|
@open="isOpened = true"
|
|
44
44
|
v-on="listeners"
|
|
@@ -62,8 +62,8 @@
|
|
|
62
62
|
<!-- Slot for custom label template for single select-->
|
|
63
63
|
<template #singleLabel="{ option }">
|
|
64
64
|
<slot
|
|
65
|
-
v-bind="{ option, optionLabel }"
|
|
66
65
|
name="singleLabel"
|
|
66
|
+
v-bind="{ option, optionLabel }"
|
|
67
67
|
>
|
|
68
68
|
<span class="multiselect__single-label">
|
|
69
69
|
{{ getOptionLabel({ option, optionLabel }) }}
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
<!-- Slot for custom option template -->
|
|
75
75
|
<template #option="{ option }">
|
|
76
76
|
<slot
|
|
77
|
-
v-bind="{ option, optionLabel }"
|
|
78
77
|
name="option"
|
|
78
|
+
v-bind="{ option, optionLabel }"
|
|
79
79
|
>
|
|
80
80
|
{{ getOptionLabel({ option, optionLabel }) }}
|
|
81
81
|
</slot>
|
|
@@ -83,8 +83,19 @@
|
|
|
83
83
|
|
|
84
84
|
<!-- Element for opening and closing the dropdown -->
|
|
85
85
|
<template #caret="{ toggle }">
|
|
86
|
+
<!-- In mode allowCustomValues, adding is done by clicking on this icon -->
|
|
87
|
+
<!-- [https://my.webitel.com/browse/WTEL-3181]-->
|
|
88
|
+
<wt-icon-btn
|
|
89
|
+
v-if="allowCustomValues && searchParams.search"
|
|
90
|
+
:disabled="disabled"
|
|
91
|
+
class="multiselect__select multiselect__custom-value-arrow"
|
|
92
|
+
icon="call-merge-filled"
|
|
93
|
+
@mousedown.prevent.stop="handleCustomValue(toggle)"
|
|
94
|
+
/>
|
|
95
|
+
<!-- To view a list of possible values, click on this icon -->
|
|
86
96
|
<!-- @mousedown.native.prevent.stop="toggle": https://github.com/shentao/vue-multiselect/issues/1204#issuecomment-615114727 -->
|
|
87
97
|
<wt-icon-btn
|
|
98
|
+
v-else
|
|
88
99
|
:disabled="disabled"
|
|
89
100
|
class="multiselect__select"
|
|
90
101
|
icon="arrow-down"
|
|
@@ -130,11 +141,16 @@
|
|
|
130
141
|
</template>
|
|
131
142
|
|
|
132
143
|
<script>
|
|
144
|
+
import taggableMixin from '../wt-tags-input/mixin/taggableMixin';
|
|
133
145
|
import multiselectMixin from './mixins/multiselectMixin';
|
|
134
146
|
|
|
135
147
|
export default {
|
|
136
148
|
name: 'WtSelect',
|
|
137
|
-
mixins: [
|
|
149
|
+
mixins: [
|
|
150
|
+
multiselectMixin,
|
|
151
|
+
// taggableMixin is used to add custom select values, see [https://my.webitel.com/browse/WTEL-3181]
|
|
152
|
+
taggableMixin,
|
|
153
|
+
],
|
|
138
154
|
props: {
|
|
139
155
|
value: {},
|
|
140
156
|
|
|
@@ -147,12 +163,45 @@ export default {
|
|
|
147
163
|
type: Boolean,
|
|
148
164
|
default: true,
|
|
149
165
|
},
|
|
166
|
+
// for taggableMixin functionality
|
|
167
|
+
allowCustomValues: {
|
|
168
|
+
type: Boolean,
|
|
169
|
+
default: false,
|
|
170
|
+
description: 'See wt-tags-input "taggable" prop.',
|
|
171
|
+
},
|
|
172
|
+
// for taggableMixin functionality
|
|
173
|
+
handleCustomValuesAdditionManually: {
|
|
174
|
+
type: Boolean,
|
|
175
|
+
default: false,
|
|
176
|
+
description: 'See wt-tags-input "manualTagging" prop.',
|
|
177
|
+
},
|
|
150
178
|
},
|
|
151
|
-
emits: [
|
|
179
|
+
emits: [
|
|
180
|
+
'reset',
|
|
181
|
+
'search-change',
|
|
182
|
+
'input',
|
|
183
|
+
'closed',
|
|
184
|
+
'custom-value', // fires when allowCustomValues and new customValue is added
|
|
185
|
+
],
|
|
152
186
|
data: () => ({
|
|
153
187
|
isOpened: false,
|
|
154
188
|
}),
|
|
189
|
+
computed: {
|
|
190
|
+
// for taggableMixin
|
|
191
|
+
taggable() { return this.allowCustomValues; },
|
|
192
|
+
// for taggableMixin
|
|
193
|
+
manualTagging() { return this.handleCustomValuesAdditionManually; },
|
|
194
|
+
},
|
|
155
195
|
methods: {
|
|
196
|
+
// for taggableMixin functionality
|
|
197
|
+
handleCustomValue(toggle) {
|
|
198
|
+
toggle();
|
|
199
|
+
this.tag(this.searchParams.search);
|
|
200
|
+
},
|
|
201
|
+
// for taggableMixin functionality
|
|
202
|
+
emitTagEvent(searchQuery, id) {
|
|
203
|
+
this.$emit('custom-value', searchQuery, id);
|
|
204
|
+
},
|
|
156
205
|
clearValue() {
|
|
157
206
|
let value = '';
|
|
158
207
|
if (Array.isArray(this.value)) value = [];
|
|
@@ -215,17 +264,19 @@ export default {
|
|
|
215
264
|
.wt-select.wt-select--multiple:not(.wt-select--clearable) {
|
|
216
265
|
.multiselect :deep {
|
|
217
266
|
$multiselect-limit-right-pos: calc(
|
|
218
|
-
var(--select-caret-right-pos)
|
|
219
|
-
+ var(--icon-md-size)
|
|
267
|
+
var(--select-caret-right-pos)// caret offet from border
|
|
268
|
+
+ var(--icon-md-size)// caret size
|
|
220
269
|
+ var(--input-padding) // caret-to-chip offset
|
|
221
270
|
);
|
|
271
|
+
|
|
222
272
|
.multiselect__tags {
|
|
223
273
|
padding-right: calc(
|
|
224
274
|
$multiselect-limit-right-pos
|
|
225
|
-
+ 50px
|
|
275
|
+
+ 50px// chip
|
|
226
276
|
+ var(--input-padding) // chip-to-content offset
|
|
227
277
|
);
|
|
228
278
|
}
|
|
279
|
+
|
|
229
280
|
.multiselect__limit {
|
|
230
281
|
right: $multiselect-limit-right-pos;
|
|
231
282
|
}
|
|
@@ -236,14 +287,15 @@ export default {
|
|
|
236
287
|
.wt-select.wt-select--clearable:not(.wt-select--multiple) {
|
|
237
288
|
.multiselect :deep {
|
|
238
289
|
$multiselect-clear-right-pos: calc(
|
|
239
|
-
var(--select-caret-right-pos)
|
|
240
|
-
+ var(--icon-md-size)
|
|
290
|
+
var(--select-caret-right-pos)// caret offset from border
|
|
291
|
+
+ var(--icon-md-size)// caret size
|
|
241
292
|
+ var(--input-padding) // caret-to-chip offset
|
|
242
293
|
);
|
|
294
|
+
|
|
243
295
|
.multiselect__tags {
|
|
244
296
|
padding-right: calc(
|
|
245
297
|
$multiselect-clear-right-pos
|
|
246
|
-
+ var(--icon-md-size)
|
|
298
|
+
+ var(--icon-md-size)// clear
|
|
247
299
|
+ var(--input-padding) // clear-to-content offset
|
|
248
300
|
);
|
|
249
301
|
}
|
|
@@ -25,7 +25,7 @@ describe('WtTagsInput', () => {
|
|
|
25
25
|
},
|
|
26
26
|
});
|
|
27
27
|
wrapper.findComponent({ name: 'vue-multiselect' }).vm.$emit('tag', tag);
|
|
28
|
-
expect(wrapper.emitted().input[0]
|
|
28
|
+
expect(wrapper.emitted().input[0]).toEqual([tag]);
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
it('in manual mode doesnt emit "input" event at native "tag" event', () => {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { mount, shallowMount } from '@vue/test-utils';
|
|
2
|
+
import taggableMixin from '../taggableMixin';
|
|
3
|
+
|
|
4
|
+
describe('taggableMixin', () => {
|
|
5
|
+
const Component = {
|
|
6
|
+
render() {},
|
|
7
|
+
mixins: [taggableMixin],
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
it('renders a component', () => {
|
|
11
|
+
const wrapper = shallowMount(Component);
|
|
12
|
+
expect(wrapper.exists()).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('Methods are called correctly', () => {
|
|
16
|
+
const searchQuery = '123';
|
|
17
|
+
const wrapper = mount(Component);
|
|
18
|
+
|
|
19
|
+
wrapper.vm.$emit('tag', searchQuery);
|
|
20
|
+
|
|
21
|
+
expect(wrapper.emitted().tag).toBeTruthy()
|
|
22
|
+
expect(wrapper.emitted().input).toBeFalsy();
|
|
23
|
+
});
|
|
24
|
+
})
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
methods: {
|
|
3
|
+
// TODO: WHAT IS "ID" PARAM?!
|
|
4
|
+
// this functionality allows you to add custom values to the list of values
|
|
5
|
+
// [https://my.webitel.com/browse/WTEL-3181]
|
|
6
|
+
tag(searchQuery, id) {
|
|
7
|
+
this.emitTagEvent(searchQuery, id);
|
|
8
|
+
|
|
9
|
+
const tag = this.trackBy ? {
|
|
10
|
+
[this.optionLabel || 'name']: searchQuery,
|
|
11
|
+
[this.trackBy]: id || searchQuery,
|
|
12
|
+
} : searchQuery;
|
|
13
|
+
|
|
14
|
+
const isTagExist = (newTag) => {
|
|
15
|
+
if (typeof newTag === 'string') {
|
|
16
|
+
return this.options.some((elem) => elem === newTag);
|
|
17
|
+
}
|
|
18
|
+
return this.options.some((elem) => elem[this.trackBy] ===
|
|
19
|
+
newTag[this.trackBy]);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
if (isTagExist(tag)) return;
|
|
23
|
+
|
|
24
|
+
this.options.unshift(tag);
|
|
25
|
+
if (!this.manualTagging) {
|
|
26
|
+
const value = this.multiple ? [...this.value, tag] : tag;
|
|
27
|
+
this.input(value);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
// method to override
|
|
31
|
+
emitTagEvent(searchQuery, id) {
|
|
32
|
+
this.$emit('tag', searchQuery, id);
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
@@ -9,35 +9,35 @@
|
|
|
9
9
|
>
|
|
10
10
|
<wt-label
|
|
11
11
|
v-if="hasLabel"
|
|
12
|
-
v-bind="labelProps"
|
|
13
12
|
:disabled="disabled"
|
|
14
13
|
:invalid="invalid"
|
|
15
14
|
class="wt-tags-input__label"
|
|
15
|
+
v-bind="labelProps"
|
|
16
16
|
>
|
|
17
17
|
<!-- @slot Custom input label -->
|
|
18
18
|
<slot
|
|
19
|
-
v-bind="{ label }"
|
|
20
19
|
name="label"
|
|
20
|
+
v-bind="{ label }"
|
|
21
21
|
>
|
|
22
22
|
{{ requiredLabel }}
|
|
23
23
|
</slot>
|
|
24
24
|
</wt-label>
|
|
25
25
|
|
|
26
26
|
<vue-multiselect
|
|
27
|
-
v-bind="$attrs"
|
|
28
27
|
ref="vue-multiselect"
|
|
29
28
|
:close-on-select="false"
|
|
30
29
|
:disabled="disabled"
|
|
31
30
|
:internal-search="!searchMethod"
|
|
32
31
|
:label="selectOptionLabel"
|
|
33
32
|
:loading="false"
|
|
33
|
+
:model-value="selectValue"
|
|
34
34
|
:options="selectOptions"
|
|
35
35
|
:placeholder="placeholder || label"
|
|
36
36
|
:taggable="taggable"
|
|
37
37
|
:track-by="trackBy"
|
|
38
|
-
:model-value="selectValue"
|
|
39
38
|
class="wt-tags-input__select"
|
|
40
39
|
multiple
|
|
40
|
+
v-bind="$attrs"
|
|
41
41
|
v-on="listeners"
|
|
42
42
|
>
|
|
43
43
|
<!-- Slot that is used for all selected options (tags)-->
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
<wt-chip class="multiselect__custom-tag">
|
|
46
46
|
{{ getTagOptionLabel({ option, optionLabel }) }}
|
|
47
47
|
<wt-icon-btn
|
|
48
|
+
color="on-primary"
|
|
48
49
|
icon="close--filled"
|
|
49
50
|
size="sm"
|
|
50
|
-
color="on-primary"
|
|
51
51
|
@click="remove(option)"
|
|
52
52
|
/>
|
|
53
53
|
</wt-chip>
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
<!-- Slot for custom option template -->
|
|
57
57
|
<template #option="{ option }">
|
|
58
58
|
<slot
|
|
59
|
-
v-bind="{ option, optionLabel }"
|
|
60
59
|
name="option"
|
|
60
|
+
v-bind="{ option, optionLabel }"
|
|
61
61
|
>
|
|
62
62
|
{{ getTagOptionLabel({ option, optionLabel }) }}
|
|
63
63
|
</slot>
|
|
@@ -103,10 +103,15 @@
|
|
|
103
103
|
|
|
104
104
|
<script>
|
|
105
105
|
import multiselectMixin from '../wt-select/mixins/multiselectMixin';
|
|
106
|
+
import taggableMixin from './mixin/taggableMixin';
|
|
106
107
|
|
|
107
108
|
export default {
|
|
108
109
|
name: 'WtTagsInput',
|
|
109
|
-
mixins: [
|
|
110
|
+
mixins: [
|
|
111
|
+
multiselectMixin,
|
|
112
|
+
// taggableMixin is used to add custom select values, see [https://my.webitel.com/browse/WTEL-3181
|
|
113
|
+
taggableMixin,
|
|
114
|
+
],
|
|
110
115
|
props: {
|
|
111
116
|
value: {
|
|
112
117
|
type: Array,
|
|
@@ -135,29 +140,6 @@ export default {
|
|
|
135
140
|
defaultOptionLabel: 'label',
|
|
136
141
|
}),
|
|
137
142
|
methods: {
|
|
138
|
-
tag(searchQuery, id) {
|
|
139
|
-
this.$emit('tag', searchQuery, id);
|
|
140
|
-
|
|
141
|
-
const tag = this.trackBy ? {
|
|
142
|
-
[this.optionLabel || 'name']: searchQuery,
|
|
143
|
-
[this.trackBy]: id || searchQuery,
|
|
144
|
-
} : searchQuery;
|
|
145
|
-
|
|
146
|
-
const isTagExist = (newTag) => {
|
|
147
|
-
if (typeof newTag === 'string') {
|
|
148
|
-
return this.options.some((elem) => elem === newTag);
|
|
149
|
-
}
|
|
150
|
-
return this.options.some((elem) => elem[this.trackBy] === newTag[this.trackBy]);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (isTagExist(tag)) return;
|
|
154
|
-
|
|
155
|
-
this.options.unshift(tag);
|
|
156
|
-
if (!this.manualTagging) {
|
|
157
|
-
const value = [...this.value, tag];
|
|
158
|
-
this.input(value);
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
143
|
getTagOptionLabel({ optionLabel, option }) {
|
|
162
144
|
/*
|
|
163
145
|
Multiselect creates new tags with "label" property by default, so we need to handle
|
|
@@ -187,12 +169,12 @@ export default {
|
|
|
187
169
|
// paddings recalc
|
|
188
170
|
.wt-tags-input .multiselect :deep {
|
|
189
171
|
.multiselect__tags {
|
|
190
|
-
padding-bottom: 0;
|
|
191
172
|
padding-right: calc(
|
|
192
173
|
var(--input-padding)
|
|
193
174
|
+ var(--icon-md-size)
|
|
194
175
|
+ var(--select-caret-right-pos)
|
|
195
176
|
);
|
|
177
|
+
padding-bottom: 0;
|
|
196
178
|
|
|
197
179
|
.multiselect__tags-wrap {
|
|
198
180
|
display: flex;
|