@gitlab/ui 37.10.0 → 38.1.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/CHANGELOG.md +30 -0
- package/README.md +1 -1
- package/dist/components/base/breadcrumb/breadcrumb.js +10 -5
- package/dist/components/base/{filtered_search/examples/filtered_search.single_unique.example.js → breadcrumb/breadcrumb_item.js} +32 -28
- package/dist/components/base/filtered_search/filtered_search.documentation.js +2 -66
- package/dist/components/base/filtered_search/filtered_search.js +38 -11
- package/dist/components/base/filtered_search/filtered_search_suggestion.documentation.js +2 -8
- package/dist/components/base/filtered_search/filtered_search_suggestion.js +4 -0
- package/dist/components/base/filtered_search/filtered_search_suggestion_list.documentation.js +2 -7
- package/dist/components/base/filtered_search/filtered_search_suggestion_list.js +4 -0
- package/dist/components/base/filtered_search/filtered_search_term.documentation.js +2 -44
- package/dist/components/base/filtered_search/filtered_search_term.js +37 -0
- package/dist/components/base/filtered_search/filtered_search_token.documentation.js +2 -31
- package/dist/components/base/filtered_search/filtered_search_token.js +49 -0
- package/dist/components/base/filtered_search/filtered_search_token_segment.documentation.js +2 -46
- package/dist/components/base/filtered_search/filtered_search_token_segment.js +48 -0
- package/dist/components/base/form/form_radio/form_radio.js +1 -1
- package/dist/components/charts/series_label/series_label.js +6 -1
- package/dist/components/utilities/truncate/truncate.js +2 -2
- package/documentation/documented_stories.js +6 -0
- package/package.json +9 -7
- package/src/components/base/breadcrumb/breadcrumb.spec.js +24 -10
- package/src/components/base/breadcrumb/breadcrumb.vue +11 -6
- package/src/components/base/breadcrumb/breadcrumb_item.spec.js +45 -0
- package/src/components/base/breadcrumb/breadcrumb_item.vue +43 -0
- package/src/components/base/filtered_search/filtered_search.documentation.js +0 -76
- package/src/components/base/filtered_search/filtered_search.md +3 -4
- package/src/components/base/filtered_search/filtered_search.stories.js +248 -13
- package/src/components/base/filtered_search/filtered_search.vue +47 -10
- package/src/components/base/filtered_search/filtered_search_suggestion.documentation.js +0 -6
- package/src/components/base/filtered_search/filtered_search_suggestion.md +1 -7
- package/src/components/base/filtered_search/filtered_search_suggestion.stories.js +26 -18
- package/src/components/base/filtered_search/filtered_search_suggestion.vue +5 -0
- package/src/components/base/filtered_search/filtered_search_suggestion_list.documentation.js +0 -5
- package/src/components/base/filtered_search/filtered_search_suggestion_list.md +1 -7
- package/src/components/base/filtered_search/filtered_search_suggestion_list.stories.js +33 -25
- package/src/components/base/filtered_search/filtered_search_suggestion_list.vue +5 -0
- package/src/components/base/filtered_search/filtered_search_term.documentation.js +0 -41
- package/src/components/base/filtered_search/filtered_search_term.md +0 -2
- package/src/components/base/filtered_search/filtered_search_term.stories.js +33 -26
- package/src/components/base/filtered_search/filtered_search_term.vue +54 -0
- package/src/components/base/filtered_search/filtered_search_token.documentation.js +0 -26
- package/src/components/base/filtered_search/filtered_search_token.md +1 -3
- package/src/components/base/filtered_search/filtered_search_token.stories.js +136 -132
- package/src/components/base/filtered_search/filtered_search_token.vue +63 -0
- package/src/components/base/filtered_search/filtered_search_token_segment.documentation.js +0 -43
- package/src/components/base/filtered_search/filtered_search_token_segment.md +0 -2
- package/src/components/base/filtered_search/filtered_search_token_segment.stories.js +86 -79
- package/src/components/base/filtered_search/filtered_search_token_segment.vue +42 -0
- package/src/components/base/form/form_radio/form_radio.spec.js +21 -8
- package/src/components/base/form/form_radio/form_radio.vue +0 -1
- package/src/components/charts/series_label/series_label.stories.js +6 -3
- package/src/components/charts/series_label/series_label.vue +3 -0
- package/src/components/utilities/truncate/truncate.spec.js +14 -49
- package/src/components/utilities/truncate/truncate.stories.js +1 -59
- package/src/components/utilities/truncate/truncate.vue +3 -21
- package/dist/components/base/filtered_search/examples/filtered_search.default.example.js +0 -422
- package/dist/components/base/filtered_search/examples/filtered_search.friendly.example.js +0 -423
- package/dist/components/base/filtered_search/examples/filtered_search.history.example.js +0 -91
- package/dist/components/base/filtered_search/examples/filtered_search.multi_select.example.js +0 -196
- package/dist/components/base/filtered_search/examples/index.js +0 -32
- package/src/components/base/filtered_search/examples/filtered_search.default.example.vue +0 -298
- package/src/components/base/filtered_search/examples/filtered_search.friendly.example.vue +0 -300
- package/src/components/base/filtered_search/examples/filtered_search.history.example.vue +0 -50
- package/src/components/base/filtered_search/examples/filtered_search.multi_select.example.vue +0 -132
- package/src/components/base/filtered_search/examples/filtered_search.single_unique.example.vue +0 -31
- package/src/components/base/filtered_search/examples/index.js +0 -38
|
@@ -15,6 +15,7 @@ const DEFAULT_OPERATORS = [
|
|
|
15
15
|
];
|
|
16
16
|
|
|
17
17
|
export default {
|
|
18
|
+
name: 'GlFilteredSearchToken',
|
|
18
19
|
components: {
|
|
19
20
|
GlToken,
|
|
20
21
|
GlFilteredSearchTokenSegment,
|
|
@@ -26,11 +27,17 @@ export default {
|
|
|
26
27
|
required: false,
|
|
27
28
|
default: () => [],
|
|
28
29
|
},
|
|
30
|
+
/**
|
|
31
|
+
* Token configuration with available operators and options.
|
|
32
|
+
*/
|
|
29
33
|
config: {
|
|
30
34
|
type: Object,
|
|
31
35
|
required: false,
|
|
32
36
|
default: () => ({}),
|
|
33
37
|
},
|
|
38
|
+
/**
|
|
39
|
+
* Determines if the token is being edited or not.
|
|
40
|
+
*/
|
|
34
41
|
active: {
|
|
35
42
|
type: Boolean,
|
|
36
43
|
required: false,
|
|
@@ -41,11 +48,17 @@ export default {
|
|
|
41
48
|
required: false,
|
|
42
49
|
default: () => [],
|
|
43
50
|
},
|
|
51
|
+
/**
|
|
52
|
+
* Current token value.
|
|
53
|
+
*/
|
|
44
54
|
value: {
|
|
45
55
|
type: Object,
|
|
46
56
|
required: false,
|
|
47
57
|
default: () => ({ operator: '', data: '' }),
|
|
48
58
|
},
|
|
59
|
+
/**
|
|
60
|
+
* Display operators' descriptions instead of their values (e.g., "is" instead of "=").
|
|
61
|
+
*/
|
|
49
62
|
showFriendlyText: {
|
|
50
63
|
type: Boolean,
|
|
51
64
|
required: false,
|
|
@@ -88,6 +101,12 @@ export default {
|
|
|
88
101
|
value: {
|
|
89
102
|
deep: true,
|
|
90
103
|
handler(newValue) {
|
|
104
|
+
/**
|
|
105
|
+
* Emitted when the token changes its value.
|
|
106
|
+
*
|
|
107
|
+
* @event input
|
|
108
|
+
* @type {object} dataObj Object containing the update value.
|
|
109
|
+
*/
|
|
91
110
|
this.$emit('input', newValue);
|
|
92
111
|
},
|
|
93
112
|
},
|
|
@@ -101,6 +120,11 @@ export default {
|
|
|
101
120
|
}
|
|
102
121
|
} else if (this.value.data === '') {
|
|
103
122
|
this.activeSegment = null;
|
|
123
|
+
/**
|
|
124
|
+
* Emitted when token is about to be destroyed.
|
|
125
|
+
*
|
|
126
|
+
* @event destroy
|
|
127
|
+
*/
|
|
104
128
|
this.$emit('destroy');
|
|
105
129
|
}
|
|
106
130
|
},
|
|
@@ -124,6 +148,11 @@ export default {
|
|
|
124
148
|
this.activeSegment = segment;
|
|
125
149
|
|
|
126
150
|
if (!this.active) {
|
|
151
|
+
/**
|
|
152
|
+
* Emitted when this term token is clicked.
|
|
153
|
+
*
|
|
154
|
+
* @event activate
|
|
155
|
+
*/
|
|
127
156
|
this.$emit('activate');
|
|
128
157
|
}
|
|
129
158
|
},
|
|
@@ -138,6 +167,10 @@ export default {
|
|
|
138
167
|
|
|
139
168
|
replaceWithTermIfEmpty() {
|
|
140
169
|
if (this.value.operator === '' && this.value.data === '') {
|
|
170
|
+
/**
|
|
171
|
+
* Emitted when this token is converted to another type
|
|
172
|
+
* @property {object} token Replacement token configuration
|
|
173
|
+
*/
|
|
141
174
|
this.$emit('replace', { type: TERM_TOKEN_TYPE, value: { data: this.config.title } });
|
|
142
175
|
}
|
|
143
176
|
},
|
|
@@ -147,6 +180,11 @@ export default {
|
|
|
147
180
|
|
|
148
181
|
if (newTokenConfig === this.config) {
|
|
149
182
|
this.$nextTick(() => {
|
|
183
|
+
/**
|
|
184
|
+
* Emitted when this term token will lose its focus.
|
|
185
|
+
*
|
|
186
|
+
* @event deactivate
|
|
187
|
+
*/
|
|
150
188
|
this.$emit('deactivate');
|
|
151
189
|
});
|
|
152
190
|
return;
|
|
@@ -193,6 +231,11 @@ export default {
|
|
|
193
231
|
if (this.config.multiSelect) {
|
|
194
232
|
this.$emit('input', { ...this.value, data: this.multiSelectValues.join(COMMA) });
|
|
195
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Emitted when the token entry has been completed.
|
|
236
|
+
*
|
|
237
|
+
* @event complete
|
|
238
|
+
*/
|
|
196
239
|
this.$emit('complete');
|
|
197
240
|
},
|
|
198
241
|
|
|
@@ -208,6 +251,10 @@ export default {
|
|
|
208
251
|
|
|
209
252
|
<template>
|
|
210
253
|
<div class="gl-filtered-search-token" :class="{ 'gl-filtered-search-token-active': active }">
|
|
254
|
+
<!--
|
|
255
|
+
Emitted when the token is submitted.
|
|
256
|
+
@event submit
|
|
257
|
+
-->
|
|
211
258
|
<gl-filtered-search-token-segment
|
|
212
259
|
key="title-segment"
|
|
213
260
|
:value="config.title"
|
|
@@ -261,6 +308,16 @@ export default {
|
|
|
261
308
|
</template>
|
|
262
309
|
</gl-filtered-search-token-segment>
|
|
263
310
|
<!-- eslint-disable vue/no-mutating-props -->
|
|
311
|
+
<!--
|
|
312
|
+
Emitted when a suggestion has been selected.
|
|
313
|
+
@event select
|
|
314
|
+
@type {string} value The value of the selected suggestion.
|
|
315
|
+
-->
|
|
316
|
+
<!--
|
|
317
|
+
Emitted when Space is pressed in-between term text.
|
|
318
|
+
@event split
|
|
319
|
+
@property {array} newTokens Token configurations
|
|
320
|
+
-->
|
|
264
321
|
<gl-filtered-search-token-segment
|
|
265
322
|
v-if="hasDataOrDataSegmentIsCurrentlyActive"
|
|
266
323
|
key="data-segment"
|
|
@@ -279,9 +336,11 @@ export default {
|
|
|
279
336
|
>
|
|
280
337
|
<!-- eslint-enable vue/no-mutating-props -->
|
|
281
338
|
<template #suggestions>
|
|
339
|
+
<!-- @slot The suggestions (implemented with GlFilteredSearchSuggestion). -->
|
|
282
340
|
<slot name="suggestions"></slot>
|
|
283
341
|
</template>
|
|
284
342
|
<template #view="{ inputValue }">
|
|
343
|
+
<!-- @slot Used to customize how the token is rendered. -->
|
|
285
344
|
<slot
|
|
286
345
|
name="view-token"
|
|
287
346
|
v-bind="{
|
|
@@ -300,6 +359,10 @@ export default {
|
|
|
300
359
|
@mousedown="destroyByClose"
|
|
301
360
|
>
|
|
302
361
|
<span class="gl-filtered-search-token-data-content">
|
|
362
|
+
<!--
|
|
363
|
+
@slot Template for token value in inactive state
|
|
364
|
+
@binding {array} suggestions Slot for rendering autocomplete suggestions when no options are provided.
|
|
365
|
+
-->
|
|
303
366
|
<slot name="view" v-bind="{ inputValue }">{{ inputValue }}</slot>
|
|
304
367
|
</span>
|
|
305
368
|
</gl-token>
|
|
@@ -2,47 +2,4 @@ import * as description from './filtered_search_token_segment.md';
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
description,
|
|
5
|
-
bootstrapComponent: null,
|
|
6
|
-
propsInfo: {
|
|
7
|
-
active: {
|
|
8
|
-
additionalInfo: 'If this term token is currently active',
|
|
9
|
-
},
|
|
10
|
-
options: {
|
|
11
|
-
additionalInfo: '',
|
|
12
|
-
},
|
|
13
|
-
optionTextField: {
|
|
14
|
-
additionalInfo: '',
|
|
15
|
-
},
|
|
16
|
-
customInputKeydownHandler: {
|
|
17
|
-
additionalInfo: '',
|
|
18
|
-
},
|
|
19
|
-
value: {
|
|
20
|
-
additionalInfo: 'Current term value',
|
|
21
|
-
},
|
|
22
|
-
searchInputAttributes: {
|
|
23
|
-
additionalInfo: 'HTML attributes to add to the search input',
|
|
24
|
-
},
|
|
25
|
-
isLastToken: {
|
|
26
|
-
additionalInfo: 'If this is the last token',
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
events: [
|
|
30
|
-
{ event: 'activate', description: 'Emitted on mousedown event on the main component' },
|
|
31
|
-
{ event: 'backspace', description: 'Emitted when Backspace is pressed and the value is empty' },
|
|
32
|
-
{
|
|
33
|
-
event: 'complete',
|
|
34
|
-
description: 'Emitted when suggestion is selected from the suggestion list',
|
|
35
|
-
},
|
|
36
|
-
{ event: 'submit', description: 'Emitted when Enter is pressed and no suggestion is selected' },
|
|
37
|
-
{
|
|
38
|
-
event: 'split',
|
|
39
|
-
args: [
|
|
40
|
-
{
|
|
41
|
-
arg: 'newStrings',
|
|
42
|
-
description: '(Array of strings) New strings to be converted into term tokens',
|
|
43
|
-
},
|
|
44
|
-
],
|
|
45
|
-
description: 'Emitted when Space appears in token segment value',
|
|
46
|
-
},
|
|
47
|
-
],
|
|
48
5
|
};
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { withKnobs, boolean } from '@storybook/addon-knobs';
|
|
2
1
|
import PortalVue from 'portal-vue';
|
|
3
2
|
import Vue from 'vue';
|
|
4
3
|
import { GlFilteredSearchSuggestion } from '../../../index';
|
|
5
|
-
import { documentedStoriesOf } from '../../../../documentation/documented_stories';
|
|
6
4
|
import { provide } from './common_story_options';
|
|
7
5
|
import readme from './filtered_search_term.md';
|
|
8
6
|
import GlFilteredSearchTokenSegment from './filtered_search_token_segment.vue';
|
|
@@ -14,84 +12,93 @@ const staticOptions = [
|
|
|
14
12
|
{ icon: 'eye', value: false, title: 'No' },
|
|
15
13
|
];
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
15
|
+
const generateProps = ({ active = true } = {}) => ({
|
|
16
|
+
active,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// eslint-disable-next-line no-unused-vars
|
|
20
|
+
export const Default = (args, { argTypes }) => ({
|
|
21
|
+
components: {
|
|
22
|
+
GlFilteredSearchTokenSegment,
|
|
23
|
+
GlFilteredSearchSuggestion,
|
|
24
|
+
},
|
|
25
|
+
provide,
|
|
26
|
+
props: ['active'],
|
|
27
|
+
data() {
|
|
28
|
+
return {
|
|
29
|
+
value: 'demo1',
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
mounted() {
|
|
33
|
+
this.$nextTick(() => document.activeElement.blur());
|
|
34
|
+
},
|
|
35
|
+
template: `
|
|
36
|
+
<div>
|
|
37
|
+
<div>v-model value: {{ value }} </div>
|
|
38
|
+
<div class="gl-border-1 gl-border-solid gl-border-gray-200">
|
|
39
|
+
<gl-filtered-search-token-segment
|
|
40
|
+
v-model="value"
|
|
41
|
+
class="gl-h-full"
|
|
42
|
+
:active="active"
|
|
43
|
+
>
|
|
44
|
+
<template #suggestions>
|
|
45
|
+
<gl-filtered-search-suggestion value="demo1">Static suggestion 1</gl-filtered-search-suggestion>
|
|
46
|
+
<gl-filtered-search-suggestion value="demo2">Static suggestion 2</gl-filtered-search-suggestion>
|
|
47
|
+
</template>
|
|
48
|
+
</gl-filtered-search-token-segment>
|
|
49
|
+
</div>
|
|
40
50
|
<div>
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
<portal-target name="portal" class="gl-relative" />
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
`,
|
|
55
|
+
});
|
|
56
|
+
Default.args = generateProps();
|
|
57
|
+
|
|
58
|
+
// eslint-disable-next-line no-unused-vars
|
|
59
|
+
export const WithStaticOptions = (args, { argTypes }) => ({
|
|
60
|
+
components: {
|
|
61
|
+
GlFilteredSearchTokenSegment,
|
|
62
|
+
},
|
|
63
|
+
provide,
|
|
64
|
+
props: ['active'],
|
|
65
|
+
data() {
|
|
66
|
+
return {
|
|
67
|
+
value: true,
|
|
68
|
+
staticOptions,
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
mounted() {
|
|
72
|
+
this.$nextTick(() => document.activeElement.blur());
|
|
73
|
+
},
|
|
74
|
+
template: `
|
|
75
|
+
<div>
|
|
76
|
+
<div>v-model value: {{ value }} </div>
|
|
77
|
+
<div class="gl-border-1 gl-border-solid gl-border-gray-200">
|
|
78
|
+
<gl-filtered-search-token-segment
|
|
79
|
+
v-model="value"
|
|
80
|
+
class="gl-h-full"
|
|
81
|
+
:active="active"
|
|
82
|
+
:options="staticOptions"
|
|
83
|
+
option-text-field="title"
|
|
84
|
+
/>
|
|
57
85
|
</div>
|
|
58
|
-
`,
|
|
59
|
-
}))
|
|
60
|
-
.add('with static options', () => ({
|
|
61
|
-
components: {
|
|
62
|
-
GlFilteredSearchTokenSegment,
|
|
63
|
-
},
|
|
64
|
-
provide,
|
|
65
|
-
props: {
|
|
66
|
-
active: {
|
|
67
|
-
type: Boolean,
|
|
68
|
-
default: boolean('active', true),
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
data() {
|
|
72
|
-
return {
|
|
73
|
-
value: true,
|
|
74
|
-
staticOptions,
|
|
75
|
-
};
|
|
76
|
-
},
|
|
77
|
-
mounted() {
|
|
78
|
-
this.$nextTick(() => document.activeElement.blur());
|
|
79
|
-
},
|
|
80
|
-
template: `
|
|
81
86
|
<div>
|
|
82
|
-
<
|
|
83
|
-
<div class="gl-border-1 gl-border-solid gl-border-gray-200">
|
|
84
|
-
<gl-filtered-search-token-segment
|
|
85
|
-
v-model="value"
|
|
86
|
-
class="gl-h-full"
|
|
87
|
-
:active="active"
|
|
88
|
-
:options="staticOptions"
|
|
89
|
-
option-text-field="title"
|
|
90
|
-
/>
|
|
91
|
-
</div>
|
|
92
|
-
<div>
|
|
93
|
-
<portal-target name="portal" class="gl-relative" />
|
|
94
|
-
</div>
|
|
87
|
+
<portal-target name="portal" class="gl-relative" />
|
|
95
88
|
</div>
|
|
96
|
-
|
|
97
|
-
|
|
89
|
+
</div>
|
|
90
|
+
`,
|
|
91
|
+
});
|
|
92
|
+
WithStaticOptions.args = generateProps();
|
|
93
|
+
|
|
94
|
+
export default {
|
|
95
|
+
title: 'base/filtered-search/token-segment',
|
|
96
|
+
component: GlFilteredSearchTokenSegment,
|
|
97
|
+
parameters: {
|
|
98
|
+
docs: {
|
|
99
|
+
description: {
|
|
100
|
+
component: readme,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
};
|
|
@@ -7,6 +7,7 @@ import GlFilteredSearchSuggestionList from './filtered_search_suggestion_list.vu
|
|
|
7
7
|
import { splitOnQuotes, wrapTokenInQuotes } from './filtered_search_utils';
|
|
8
8
|
|
|
9
9
|
export default {
|
|
10
|
+
name: 'GlFilteredSearchTokenSegment',
|
|
10
11
|
components: {
|
|
11
12
|
Portal,
|
|
12
13
|
GlFilteredSearchSuggestionList,
|
|
@@ -15,6 +16,9 @@ export default {
|
|
|
15
16
|
inject: ['portalName', 'alignSuggestions'],
|
|
16
17
|
inheritAttrs: false,
|
|
17
18
|
props: {
|
|
19
|
+
/**
|
|
20
|
+
* If this token segment is currently being edited.
|
|
21
|
+
*/
|
|
18
22
|
active: {
|
|
19
23
|
type: Boolean,
|
|
20
24
|
required: false,
|
|
@@ -45,15 +49,24 @@ export default {
|
|
|
45
49
|
required: false,
|
|
46
50
|
default: () => () => false,
|
|
47
51
|
},
|
|
52
|
+
/**
|
|
53
|
+
* Current term value
|
|
54
|
+
*/
|
|
48
55
|
value: {
|
|
49
56
|
required: true,
|
|
50
57
|
validator: () => true,
|
|
51
58
|
},
|
|
59
|
+
/**
|
|
60
|
+
* HTML attributes to add to the search input
|
|
61
|
+
*/
|
|
52
62
|
searchInputAttributes: {
|
|
53
63
|
type: Object,
|
|
54
64
|
required: false,
|
|
55
65
|
default: () => ({}),
|
|
56
66
|
},
|
|
67
|
+
/**
|
|
68
|
+
* If this is the last token
|
|
69
|
+
*/
|
|
57
70
|
isLastToken: {
|
|
58
71
|
type: Boolean,
|
|
59
72
|
required: false,
|
|
@@ -89,6 +102,11 @@ export default {
|
|
|
89
102
|
},
|
|
90
103
|
|
|
91
104
|
set(v) {
|
|
105
|
+
/**
|
|
106
|
+
* Emitted when this token segment's value changes.
|
|
107
|
+
*
|
|
108
|
+
* @type {object} option The current option.
|
|
109
|
+
*/
|
|
92
110
|
this.$emit('input', this.getMatchingOptionForInputValue(v)?.value ?? v);
|
|
93
111
|
},
|
|
94
112
|
},
|
|
@@ -145,6 +163,10 @@ export default {
|
|
|
145
163
|
this.$emit('input', this.getMatchingOptionForInputValue(firstWord)?.value ?? firstWord);
|
|
146
164
|
|
|
147
165
|
if (otherWords.length) {
|
|
166
|
+
/**
|
|
167
|
+
* Emitted when Space appears in token segment value
|
|
168
|
+
* @property {array|string} newStrings New strings to be converted into term tokens
|
|
169
|
+
*/
|
|
148
170
|
this.$emit('split', otherWords);
|
|
149
171
|
}
|
|
150
172
|
},
|
|
@@ -153,6 +175,9 @@ export default {
|
|
|
153
175
|
methods: {
|
|
154
176
|
emitIfInactive(e) {
|
|
155
177
|
if (!this.active) {
|
|
178
|
+
/**
|
|
179
|
+
* Emitted on mousedown event on the main component.
|
|
180
|
+
*/
|
|
156
181
|
this.$emit('activate');
|
|
157
182
|
e.preventDefault();
|
|
158
183
|
}
|
|
@@ -190,6 +215,11 @@ export default {
|
|
|
190
215
|
applySuggestion(suggestedValue) {
|
|
191
216
|
const formattedSuggestedValue = wrapTokenInQuotes(suggestedValue);
|
|
192
217
|
|
|
218
|
+
/**
|
|
219
|
+
* Emitted when autocomplete entry is selected.
|
|
220
|
+
*
|
|
221
|
+
* @type {string} value The selected value.
|
|
222
|
+
*/
|
|
193
223
|
this.$emit('select', formattedSuggestedValue);
|
|
194
224
|
|
|
195
225
|
if (!this.multiSelect) {
|
|
@@ -205,6 +235,9 @@ export default {
|
|
|
205
235
|
if (key === 'Backspace') {
|
|
206
236
|
if (this.inputValue === '') {
|
|
207
237
|
e.preventDefault();
|
|
238
|
+
/**
|
|
239
|
+
* Emitted when Backspace is pressed and the value is empty
|
|
240
|
+
*/
|
|
208
241
|
this.$emit('backspace');
|
|
209
242
|
}
|
|
210
243
|
return;
|
|
@@ -216,6 +249,9 @@ export default {
|
|
|
216
249
|
if (suggestedValue != null) {
|
|
217
250
|
this.applySuggestion(suggestedValue);
|
|
218
251
|
} else {
|
|
252
|
+
/**
|
|
253
|
+
* Emitted when Enter is pressed and no suggestion is selected
|
|
254
|
+
*/
|
|
219
255
|
this.$emit('submit');
|
|
220
256
|
}
|
|
221
257
|
},
|
|
@@ -227,6 +263,9 @@ export default {
|
|
|
227
263
|
},
|
|
228
264
|
Escape: () => {
|
|
229
265
|
e.preventDefault();
|
|
266
|
+
/**
|
|
267
|
+
* Emitted when suggestion is selected from the suggestion list
|
|
268
|
+
*/
|
|
230
269
|
this.$emit('complete');
|
|
231
270
|
},
|
|
232
271
|
};
|
|
@@ -258,6 +297,9 @@ export default {
|
|
|
258
297
|
if (this.multiSelect) {
|
|
259
298
|
this.$emit('complete');
|
|
260
299
|
} else if (this.active) {
|
|
300
|
+
/**
|
|
301
|
+
* Emitted when this term token will lose its focus.
|
|
302
|
+
*/
|
|
261
303
|
this.$emit('deactivate');
|
|
262
304
|
}
|
|
263
305
|
},
|
|
@@ -5,6 +5,8 @@ import GlFormRadio from './form_radio.vue';
|
|
|
5
5
|
describe('GlFormRadio', () => {
|
|
6
6
|
let wrapper;
|
|
7
7
|
let options;
|
|
8
|
+
let eventHandlers;
|
|
9
|
+
|
|
8
10
|
const firstOption = {
|
|
9
11
|
text: 'One',
|
|
10
12
|
value: 'one',
|
|
@@ -16,6 +18,10 @@ describe('GlFormRadio', () => {
|
|
|
16
18
|
|
|
17
19
|
const createWrapper = () => {
|
|
18
20
|
options = [firstOption, secondOption];
|
|
21
|
+
eventHandlers = {
|
|
22
|
+
input: jest.fn(),
|
|
23
|
+
change: jest.fn(),
|
|
24
|
+
};
|
|
19
25
|
|
|
20
26
|
wrapper = mount({
|
|
21
27
|
data() {
|
|
@@ -32,9 +38,15 @@ describe('GlFormRadio', () => {
|
|
|
32
38
|
:key="option.value"
|
|
33
39
|
v-model="selected"
|
|
34
40
|
:value="option.value"
|
|
41
|
+
@change="changeHandler"
|
|
42
|
+
@input="inputHandler"
|
|
35
43
|
>{{ option.text }}</gl-form-radio>
|
|
36
44
|
</div>
|
|
37
45
|
`,
|
|
46
|
+
methods: {
|
|
47
|
+
changeHandler: eventHandlers.change,
|
|
48
|
+
inputHandler: eventHandlers.input,
|
|
49
|
+
},
|
|
38
50
|
});
|
|
39
51
|
};
|
|
40
52
|
|
|
@@ -79,16 +91,17 @@ describe('GlFormRadio', () => {
|
|
|
79
91
|
});
|
|
80
92
|
|
|
81
93
|
it('emits an input event on each radio, and a change event on the newly selected radio', () => {
|
|
82
|
-
const
|
|
94
|
+
const { input, change } = eventHandlers;
|
|
95
|
+
const { value: clickedRadioValue } = secondOption;
|
|
83
96
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
97
|
+
// The input handler is called twice because each radio emits one input event.
|
|
98
|
+
expect(input).toHaveBeenCalledTimes(2);
|
|
99
|
+
expect(input).toHaveBeenNthCalledWith(1, clickedRadioValue);
|
|
100
|
+
expect(input).toHaveBeenNthCalledWith(2, clickedRadioValue);
|
|
87
101
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
});
|
|
102
|
+
// The change handler is only called once, since only the newly selected radio emits a change event.
|
|
103
|
+
expect(change).toHaveBeenCalledTimes(1);
|
|
104
|
+
expect(change).toHaveBeenCalledWith(clickedRadioValue);
|
|
92
105
|
});
|
|
93
106
|
|
|
94
107
|
it('updates the bound value', () => {
|
|
@@ -35,14 +35,13 @@ const Template = (_args, { argTypes }) => ({
|
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
export const Default = Template.bind({});
|
|
38
|
-
Default.args = generateProps(
|
|
38
|
+
Default.args = generateProps();
|
|
39
39
|
|
|
40
40
|
export const WithLongName = Template.bind({});
|
|
41
|
-
WithLongName.args = generateProps({
|
|
41
|
+
WithLongName.args = generateProps({ text: SERIES_NAME[SERIES_NAME_LONG] });
|
|
42
42
|
|
|
43
43
|
export const WithLongNameWithNoSpaces = Template.bind({});
|
|
44
44
|
WithLongNameWithNoSpaces.args = generateProps({
|
|
45
|
-
color: '',
|
|
46
45
|
text: SERIES_NAME[SERIES_NAME_LONG_WITHOUT_SPACES],
|
|
47
46
|
});
|
|
48
47
|
|
|
@@ -72,6 +71,10 @@ export default {
|
|
|
72
71
|
},
|
|
73
72
|
},
|
|
74
73
|
argTypes: {
|
|
74
|
+
type: {
|
|
75
|
+
control: 'select',
|
|
76
|
+
options: ['solid', 'dashed'],
|
|
77
|
+
},
|
|
75
78
|
color: {
|
|
76
79
|
control: 'color',
|
|
77
80
|
},
|