@gitlab/ui 38.0.1 → 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 +7 -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 -0
- 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/charts/series_label/series_label.js +6 -1
- 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 +45 -0
- 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/charts/series_label/series_label.stories.js +6 -3
- package/src/components/charts/series_label/series_label.vue +3 -0
- 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
|
@@ -1,82 +1,6 @@
|
|
|
1
|
-
import examples from './examples';
|
|
2
1
|
import * as description from './filtered_search.md';
|
|
3
2
|
|
|
4
3
|
export default {
|
|
5
4
|
description,
|
|
6
5
|
followsDesignSystem: true,
|
|
7
|
-
bootstrapComponent: null,
|
|
8
|
-
examples,
|
|
9
|
-
propsInfo: {
|
|
10
|
-
value: {
|
|
11
|
-
additionalInfo: 'If provided, used as value of filtered search',
|
|
12
|
-
},
|
|
13
|
-
historyItems: {
|
|
14
|
-
additionalInfo: 'If provided, used as history items for this component',
|
|
15
|
-
},
|
|
16
|
-
availableTokens: {
|
|
17
|
-
additionalInfo: 'Available tokens',
|
|
18
|
-
},
|
|
19
|
-
placeholder: {
|
|
20
|
-
additionalInfo: 'If provided, used as history items for this component',
|
|
21
|
-
},
|
|
22
|
-
recentSearchesHeader: {
|
|
23
|
-
additionalInfo: 'i18n for recent searches title within history dropdown',
|
|
24
|
-
},
|
|
25
|
-
clearButtonTitle: {
|
|
26
|
-
additionalInfo: 'i18n for clear button title',
|
|
27
|
-
},
|
|
28
|
-
closeButtonTitle: {
|
|
29
|
-
additionalInfo: 'i18n for close button title within history dropdown',
|
|
30
|
-
},
|
|
31
|
-
clearRecentSearchesText: {
|
|
32
|
-
additionalInfo: 'i18n for recent searches clear text',
|
|
33
|
-
},
|
|
34
|
-
suggestionsListClass: {
|
|
35
|
-
additionalInfo:
|
|
36
|
-
'Additional classes to add to the suggestion list menu. NOTE: this not reactive, and the value must be available and fixed when the component is instantiated',
|
|
37
|
-
},
|
|
38
|
-
searchButtonAttributes: {
|
|
39
|
-
additionalInfo: 'HTML attributes to add to the search button',
|
|
40
|
-
},
|
|
41
|
-
searchInputAttributes: {
|
|
42
|
-
additionalInfo: 'HTML attributes to add to the search input',
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
events: [
|
|
46
|
-
{
|
|
47
|
-
event: 'clear',
|
|
48
|
-
description: 'Emitted when search is cleared',
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
event: 'submit',
|
|
52
|
-
args: [
|
|
53
|
-
{
|
|
54
|
-
arg: 'tokens',
|
|
55
|
-
description: '(Array)',
|
|
56
|
-
},
|
|
57
|
-
],
|
|
58
|
-
description: 'Emitted when search is submitted',
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
event: 'history-item-selected',
|
|
62
|
-
args: [
|
|
63
|
-
{
|
|
64
|
-
arg: 'value',
|
|
65
|
-
description: 'History item',
|
|
66
|
-
},
|
|
67
|
-
],
|
|
68
|
-
description: 'Emitted when item from history is selected',
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
event: 'clear-history',
|
|
72
|
-
description: 'Emitted when clear history button is clicked',
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
slots: [
|
|
76
|
-
{
|
|
77
|
-
name: 'history-item',
|
|
78
|
-
description:
|
|
79
|
-
'Slot to customize history item in history dropdown. Used only if using history items',
|
|
80
|
-
},
|
|
81
|
-
],
|
|
82
6
|
};
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# Filtered Search
|
|
2
|
-
|
|
3
1
|
The filtered search component is responsible for managing search with possible filters.
|
|
4
2
|
|
|
5
3
|
## Usage
|
|
@@ -61,6 +59,7 @@ const availableTokens = [
|
|
|
61
59
|
Pass the list of tokens to the search component. Optionally, you can use `v-model` to receive
|
|
62
60
|
realtime updates:
|
|
63
61
|
|
|
64
|
-
```
|
|
65
|
-
|
|
62
|
+
```html
|
|
63
|
+
|
|
64
|
+
<gl-filtered-search :available-tokens="tokens" v-model="value" />
|
|
66
65
|
```
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { withKnobs } from '@storybook/addon-knobs';
|
|
2
|
-
import { documentedStoriesOf } from '../../../../documentation/documented_stories';
|
|
3
1
|
import {
|
|
4
2
|
GlFilteredSearch,
|
|
5
3
|
GlFilteredSearchToken,
|
|
6
4
|
GlFilteredSearchSuggestion,
|
|
5
|
+
GlFilteredSearchSuggestionList,
|
|
6
|
+
GlFilteredSearchTerm,
|
|
7
|
+
GlFilteredSearchTokenSegment,
|
|
7
8
|
GlLoadingIcon,
|
|
8
9
|
GlToken,
|
|
9
10
|
GlAvatar,
|
|
10
11
|
} from '../../../index';
|
|
11
12
|
import { setStoryTimeout } from '../../../utils/test_utils';
|
|
13
|
+
import { makeContainer } from '../../../utils/story_decorators/container';
|
|
12
14
|
import readme from './filtered_search.md';
|
|
13
15
|
|
|
14
16
|
const fakeUsers = [
|
|
@@ -296,19 +298,252 @@ const components = {
|
|
|
296
298
|
GlFilteredSearch,
|
|
297
299
|
};
|
|
298
300
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
301
|
+
export const Default = () => ({
|
|
302
|
+
data() {
|
|
303
|
+
return {
|
|
304
|
+
tokens,
|
|
305
|
+
value: [
|
|
306
|
+
{ type: 'author', value: { data: 'beta', operator: '=' } },
|
|
307
|
+
{ type: 'label', value: { data: 'Bug', operator: '=' } },
|
|
308
|
+
'raw text',
|
|
309
|
+
],
|
|
310
|
+
};
|
|
311
|
+
},
|
|
312
|
+
components,
|
|
313
|
+
template: `<gl-filtered-search :available-tokens="tokens" :value="value" />`,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
export const WithHistoryItems = () => ({
|
|
317
|
+
components,
|
|
318
|
+
data() {
|
|
319
|
+
return {
|
|
320
|
+
tokens: [
|
|
321
|
+
{
|
|
322
|
+
type: 'demotoken',
|
|
323
|
+
title: 'Unique',
|
|
324
|
+
icon: 'document',
|
|
325
|
+
token: 'gl-filtered-search-token',
|
|
326
|
+
operators: [{ value: '=', description: 'is', default: 'true' }],
|
|
327
|
+
options: [
|
|
328
|
+
{ icon: 'heart', title: 'heart', value: 1 },
|
|
329
|
+
{ icon: 'hook', title: 'hook', value: 2 },
|
|
330
|
+
],
|
|
331
|
+
unique: true,
|
|
332
|
+
},
|
|
333
|
+
],
|
|
334
|
+
value: [],
|
|
335
|
+
historyItems: [
|
|
336
|
+
[{ type: 'demotoken', value: { operator: '=', data: 1 } }, 'item 1'],
|
|
337
|
+
['item 2', { type: 'demotoken', value: { operator: '=', data: 2 } }],
|
|
338
|
+
],
|
|
339
|
+
};
|
|
340
|
+
},
|
|
341
|
+
methods: {
|
|
342
|
+
isString(val) {
|
|
343
|
+
return typeof val === 'string';
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
mounted() {
|
|
347
|
+
this.$nextTick(() => this.$el.querySelector('.gl-dropdown-toggle').click());
|
|
348
|
+
},
|
|
349
|
+
template: `
|
|
350
|
+
<div>
|
|
351
|
+
{{ value }}
|
|
352
|
+
<gl-filtered-search v-model="value" :available-tokens="tokens" :history-items="historyItems">
|
|
353
|
+
<template #history-item="{ historyItem }">
|
|
354
|
+
<template v-for="(token, idx) in historyItem">
|
|
355
|
+
<span v-if="isString(token)" :key="idx" class="gl-px-1">{{ token }}</span>
|
|
356
|
+
<span v-else :key="idx" class="gl-px-1">
|
|
357
|
+
<strong>{{ token.type }}</strong> {{ token.value.operator }}
|
|
358
|
+
<strong>{{ token.value.data }}</strong>
|
|
359
|
+
</span>
|
|
360
|
+
</template>
|
|
361
|
+
</template>
|
|
362
|
+
</gl-filtered-search>
|
|
363
|
+
</div>
|
|
364
|
+
`,
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
export const WithFriendlyText = () => ({
|
|
368
|
+
components,
|
|
369
|
+
data() {
|
|
370
|
+
return {
|
|
371
|
+
tokens: [
|
|
372
|
+
{
|
|
373
|
+
type: 'weight',
|
|
374
|
+
icon: 'weight',
|
|
375
|
+
title: 'Weight',
|
|
376
|
+
unique: true,
|
|
377
|
+
token: 'gl-filtered-search-token',
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
type: 'confidential',
|
|
381
|
+
icon: 'eye-slash',
|
|
382
|
+
title: 'Confidential',
|
|
383
|
+
unique: true,
|
|
384
|
+
token: 'gl-filtered-search-token',
|
|
385
|
+
options: [
|
|
386
|
+
{ icon: 'eye-slash', value: 'Yes', title: 'Yes' },
|
|
387
|
+
{ icon: 'eye', value: 'No', title: 'No' },
|
|
388
|
+
],
|
|
389
|
+
},
|
|
390
|
+
],
|
|
391
|
+
value: [
|
|
392
|
+
{ type: 'weight', value: { data: '3', operator: '=' } },
|
|
393
|
+
{ type: 'confidential', value: { data: 'Yes', operator: '!=' } },
|
|
394
|
+
],
|
|
395
|
+
};
|
|
396
|
+
},
|
|
397
|
+
template: `
|
|
398
|
+
<gl-filtered-search
|
|
399
|
+
v-model="value"
|
|
400
|
+
:available-tokens="tokens"
|
|
401
|
+
:show-friendly-text="true"
|
|
402
|
+
/>
|
|
403
|
+
`,
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
export const WithMultiSelect = () => {
|
|
407
|
+
const MultiUserToken = {
|
|
408
|
+
props: ['value', 'active', 'config'],
|
|
409
|
+
inheritAttrs: false,
|
|
302
410
|
data() {
|
|
303
411
|
return {
|
|
304
|
-
|
|
305
|
-
value: [
|
|
306
|
-
|
|
307
|
-
{ type: 'label', value: { data: 'Bug', operator: '=' } },
|
|
308
|
-
'raw text',
|
|
309
|
-
],
|
|
412
|
+
users: fakeUsers,
|
|
413
|
+
selectedUsernames: this.value.data ? this.value.data.split(',') : [],
|
|
414
|
+
activeUser: null,
|
|
310
415
|
};
|
|
311
416
|
},
|
|
417
|
+
computed: {
|
|
418
|
+
filteredUsers() {
|
|
419
|
+
return this.users.filter((user) => user.username.includes(this.value.data));
|
|
420
|
+
},
|
|
421
|
+
selectedUsers() {
|
|
422
|
+
return this.config.multiSelect
|
|
423
|
+
? this.users.filter((user) => this.selectedUsernames.includes(user.username))
|
|
424
|
+
: this.users.filter((user) => user.username === this.activeUser);
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
methods: {
|
|
428
|
+
loadView() {
|
|
429
|
+
this.activeUser = fakeUsers.find((u) => u.username === this.value.data);
|
|
430
|
+
},
|
|
431
|
+
loadSuggestions() {
|
|
432
|
+
this.users = fakeUsers;
|
|
433
|
+
},
|
|
434
|
+
handleSelect(username) {
|
|
435
|
+
if (!this.config.multiSelect) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (this.selectedUsernames.includes(username)) {
|
|
440
|
+
this.selectedUsernames = this.selectedUsernames.filter((user) => user !== username);
|
|
441
|
+
} else {
|
|
442
|
+
this.selectedUsernames.push(username);
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
isLastUser(index) {
|
|
446
|
+
return index === this.selectedUsers.length - 1;
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
watch: {
|
|
450
|
+
// eslint-disable-next-line func-names
|
|
451
|
+
'value.data': function () {
|
|
452
|
+
if (this.active) {
|
|
453
|
+
this.loadSuggestions();
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
active: {
|
|
457
|
+
immediate: true,
|
|
458
|
+
handler(newValue) {
|
|
459
|
+
if (!newValue) {
|
|
460
|
+
this.loadView();
|
|
461
|
+
} else {
|
|
462
|
+
this.loadSuggestions();
|
|
463
|
+
}
|
|
464
|
+
},
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
template: `
|
|
468
|
+
<gl-filtered-search-token
|
|
469
|
+
v-bind="{ ...this.$props, ...this.$attrs }"
|
|
470
|
+
v-on="$listeners"
|
|
471
|
+
:multi-select-values="selectedUsernames"
|
|
472
|
+
@select="handleSelect"
|
|
473
|
+
>
|
|
474
|
+
<template #view="{ inputValue }">
|
|
475
|
+
<template v-for="(user, index) in selectedUsers">
|
|
476
|
+
<gl-avatar :size="16" :entity-name="user.username" shape="circle" />
|
|
477
|
+
{{ user.name }}
|
|
478
|
+
<span v-if="!isLastUser(index)" class="gl-mx-2">, </span>
|
|
479
|
+
</template>
|
|
480
|
+
</template>
|
|
481
|
+
<template #suggestions>
|
|
482
|
+
<gl-filtered-search-suggestion :key="user.id" v-for="user in filteredUsers" :value="user.username">
|
|
483
|
+
<div class="gl-display-flex gl-align-items-center">
|
|
484
|
+
<gl-icon
|
|
485
|
+
v-if="config.multiSelect"
|
|
486
|
+
name="check"
|
|
487
|
+
class="gl-mr-3 gl-text-gray-700"
|
|
488
|
+
:class="{ 'gl-visibility-hidden': !selectedUsernames.includes(user.username) }"
|
|
489
|
+
/>
|
|
490
|
+
<gl-avatar :size="32" :entity-name="user.username" />
|
|
491
|
+
<div>
|
|
492
|
+
<p class="gl-m-0">{{ user.name }}</p>
|
|
493
|
+
<p class="gl-m-0">@{{ user.username }}</p>
|
|
494
|
+
</div>
|
|
495
|
+
</div>
|
|
496
|
+
</gl-filtered-search-suggestion>
|
|
497
|
+
</template>
|
|
498
|
+
</gl-filtered-search-token>
|
|
499
|
+
`,
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
return {
|
|
312
503
|
components,
|
|
313
|
-
|
|
314
|
-
|
|
504
|
+
data() {
|
|
505
|
+
return {
|
|
506
|
+
tokens: [
|
|
507
|
+
{
|
|
508
|
+
type: 'assignee',
|
|
509
|
+
icon: 'user',
|
|
510
|
+
title: 'Assignee',
|
|
511
|
+
token: MultiUserToken,
|
|
512
|
+
operators: [
|
|
513
|
+
{ value: '=', description: 'is', default: 'true' },
|
|
514
|
+
{ value: '!=', description: 'is not one of' },
|
|
515
|
+
{ value: '||', description: 'is one of' },
|
|
516
|
+
],
|
|
517
|
+
multiSelect: true,
|
|
518
|
+
},
|
|
519
|
+
],
|
|
520
|
+
value: [{ type: 'assignee', value: { data: 'alpha,beta', operator: '=' } }],
|
|
521
|
+
};
|
|
522
|
+
},
|
|
523
|
+
template: `
|
|
524
|
+
<gl-filtered-search v-model="value" :available-tokens="tokens" />
|
|
525
|
+
`,
|
|
526
|
+
};
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
export default {
|
|
530
|
+
title: 'base/filtered-search',
|
|
531
|
+
// Make room for suggestion lists
|
|
532
|
+
decorators: [makeContainer({ height: '250px' })],
|
|
533
|
+
component: GlFilteredSearch,
|
|
534
|
+
subcomponents: {
|
|
535
|
+
GlFilteredSearchSuggestion,
|
|
536
|
+
GlFilteredSearchSuggestionList,
|
|
537
|
+
GlFilteredSearchTerm,
|
|
538
|
+
GlFilteredSearchTokenSegment,
|
|
539
|
+
GlFilteredSearchToken,
|
|
540
|
+
},
|
|
541
|
+
parameters: {
|
|
542
|
+
docs: {
|
|
543
|
+
description: {
|
|
544
|
+
component: readme,
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
},
|
|
548
|
+
argTypes: {},
|
|
549
|
+
};
|
|
@@ -31,6 +31,7 @@ function initialState() {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export default {
|
|
34
|
+
name: 'GlFilteredSearch',
|
|
34
35
|
components: {
|
|
35
36
|
GlSearchBoxByClick,
|
|
36
37
|
GlIcon,
|
|
@@ -51,16 +52,25 @@ export default {
|
|
|
51
52
|
},
|
|
52
53
|
inheritAttrs: false,
|
|
53
54
|
props: {
|
|
55
|
+
/**
|
|
56
|
+
* If provided, used as value of filtered search
|
|
57
|
+
*/
|
|
54
58
|
value: {
|
|
55
59
|
required: false,
|
|
56
60
|
type: Array,
|
|
57
61
|
default: () => [],
|
|
58
62
|
},
|
|
63
|
+
/**
|
|
64
|
+
* Available tokens
|
|
65
|
+
*/
|
|
59
66
|
availableTokens: {
|
|
60
67
|
type: Array,
|
|
61
68
|
required: false,
|
|
62
69
|
default: () => [],
|
|
63
70
|
},
|
|
71
|
+
/**
|
|
72
|
+
* If provided, used as history items for this component
|
|
73
|
+
*/
|
|
64
74
|
placeholder: {
|
|
65
75
|
type: String,
|
|
66
76
|
required: false,
|
|
@@ -76,21 +86,34 @@ export default {
|
|
|
76
86
|
required: false,
|
|
77
87
|
default: null,
|
|
78
88
|
},
|
|
89
|
+
/**
|
|
90
|
+
* Additional classes to add to the suggestion list menu. NOTE: this not reactive, and the value
|
|
91
|
+
* must be available and fixed when the component is instantiated
|
|
92
|
+
*/
|
|
79
93
|
suggestionsListClass: {
|
|
80
94
|
type: [String, Array, Object],
|
|
81
95
|
required: false,
|
|
82
96
|
default: null,
|
|
83
97
|
},
|
|
98
|
+
/**
|
|
99
|
+
* Display operators' descriptions instead of their values (e.g., "is" instead of "=").
|
|
100
|
+
*/
|
|
84
101
|
showFriendlyText: {
|
|
85
102
|
type: Boolean,
|
|
86
103
|
required: false,
|
|
87
104
|
default: false,
|
|
88
105
|
},
|
|
106
|
+
/**
|
|
107
|
+
* HTML attributes to add to the search button
|
|
108
|
+
*/
|
|
89
109
|
searchButtonAttributes: {
|
|
90
110
|
type: Object,
|
|
91
111
|
required: false,
|
|
92
112
|
default: () => ({}),
|
|
93
113
|
},
|
|
114
|
+
/**
|
|
115
|
+
* HTML attributes to add to the search input
|
|
116
|
+
*/
|
|
94
117
|
searchInputAttributes: {
|
|
95
118
|
type: Object,
|
|
96
119
|
required: false,
|
|
@@ -141,6 +164,10 @@ export default {
|
|
|
141
164
|
this.tokens.push(createTerm());
|
|
142
165
|
}
|
|
143
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Emitted when the tokens (value) changes
|
|
169
|
+
* @property {array} tokens
|
|
170
|
+
*/
|
|
144
171
|
this.$emit('input', this.tokens);
|
|
145
172
|
},
|
|
146
173
|
deep: true,
|
|
@@ -261,6 +288,10 @@ export default {
|
|
|
261
288
|
},
|
|
262
289
|
|
|
263
290
|
submit() {
|
|
291
|
+
/**
|
|
292
|
+
* Emitted when search is submitted
|
|
293
|
+
* @property {array} tokens
|
|
294
|
+
*/
|
|
264
295
|
this.$emit('submit', normalizeTokens(cloneDeep(this.tokens)));
|
|
265
296
|
},
|
|
266
297
|
|
|
@@ -273,6 +304,19 @@ export default {
|
|
|
273
304
|
</script>
|
|
274
305
|
|
|
275
306
|
<template>
|
|
307
|
+
<!--
|
|
308
|
+
Emitted when search is cleared
|
|
309
|
+
@event clear
|
|
310
|
+
-->
|
|
311
|
+
<!--
|
|
312
|
+
Emitted when item from history is selected
|
|
313
|
+
@event history-item-selected
|
|
314
|
+
@property {object} value History item
|
|
315
|
+
-->
|
|
316
|
+
<!--
|
|
317
|
+
Emitted when clear history button is clicked
|
|
318
|
+
@event clear-history
|
|
319
|
+
-->
|
|
276
320
|
<gl-search-box-by-click
|
|
277
321
|
v-bind="$attrs"
|
|
278
322
|
:value="tokens"
|
|
@@ -287,6 +331,7 @@ export default {
|
|
|
287
331
|
@clear-history="$emit('clear-history')"
|
|
288
332
|
>
|
|
289
333
|
<template #history-item="slotScope">
|
|
334
|
+
<!-- @slot Slot to customize history item in history dropdown. Used only if using history items -->
|
|
290
335
|
<slot name="history-item" v-bind="slotScope"></slot>
|
|
291
336
|
</template>
|
|
292
337
|
<template #input>
|
|
@@ -2,10 +2,4 @@ import description from './filtered_search_suggestion.md';
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
description,
|
|
5
|
-
bootstrapComponent: 'b-dropdown-item',
|
|
6
|
-
propsInfo: {
|
|
7
|
-
value: {
|
|
8
|
-
additionalInfo: 'Value which will be emitted if this suggestion will be selected in list',
|
|
9
|
-
},
|
|
10
|
-
},
|
|
11
5
|
};
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
# Filtered Search Suggestion
|
|
2
|
-
|
|
3
|
-
<!-- STORY -->
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
1
|
The filtered search suggestion component is a wrapper around `GlDropdownItem`, which registers
|
|
8
2
|
suggestions in a top-level suggestion list:
|
|
9
3
|
|
|
10
|
-
```
|
|
4
|
+
```html
|
|
11
5
|
<gl-filtered-search-suggestion-list>
|
|
12
6
|
<gl-filtered-search-suggestion value="foo">Example suggestion</gl-filtered-search-suggestion>
|
|
13
7
|
<gl-filtered-search-suggestion value="bar">Example suggestion 2</gl-filtered-search-suggestion>
|
|
@@ -1,25 +1,33 @@
|
|
|
1
|
-
import { withKnobs } from '@storybook/addon-knobs';
|
|
2
1
|
import { GlFilteredSearchSuggestion } from '../../../index';
|
|
3
|
-
import { documentedStoriesOf } from '../../../../documentation/documented_stories';
|
|
4
2
|
import readme from './filtered_search_suggestion.md';
|
|
5
3
|
|
|
6
4
|
const noop = () => {};
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
export const Default = () => ({
|
|
7
|
+
components: { GlFilteredSearchSuggestion },
|
|
8
|
+
provide: {
|
|
9
|
+
filteredSearchSuggestionListInstance: {
|
|
10
|
+
register: noop,
|
|
11
|
+
unregister: noop,
|
|
12
|
+
$emit: noop,
|
|
13
|
+
activeItem: null,
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
template: `
|
|
17
|
+
<ul>
|
|
18
|
+
<gl-filtered-search-suggestion value="demo">Demo suggestion</gl-filtered-search-suggestion>
|
|
19
|
+
</ul>
|
|
20
|
+
`,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export default {
|
|
24
|
+
title: 'base/filtered-search/suggestion',
|
|
25
|
+
component: GlFilteredSearchSuggestion,
|
|
26
|
+
parameters: {
|
|
27
|
+
docs: {
|
|
28
|
+
description: {
|
|
29
|
+
component: readme,
|
|
18
30
|
},
|
|
19
31
|
},
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
<gl-filtered-search-suggestion value="demo">Demo suggestion</gl-filtered-search-suggestion>
|
|
23
|
-
</ul>
|
|
24
|
-
`,
|
|
25
|
-
}));
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
import GlDropdownItem from '../dropdown/dropdown_item.vue';
|
|
3
3
|
|
|
4
4
|
export default {
|
|
5
|
+
name: 'GlFilteredSearchSuggestion',
|
|
5
6
|
components: {
|
|
6
7
|
GlDropdownItem,
|
|
7
8
|
},
|
|
8
9
|
inject: ['filteredSearchSuggestionListInstance'],
|
|
9
10
|
inheritAttrs: false,
|
|
10
11
|
props: {
|
|
12
|
+
/**
|
|
13
|
+
* Value that will be emitted if this suggestion is selected.
|
|
14
|
+
*/
|
|
11
15
|
value: {
|
|
12
16
|
required: true,
|
|
13
17
|
validator: () => true,
|
|
@@ -52,6 +56,7 @@ export default {
|
|
|
52
56
|
href="#"
|
|
53
57
|
@mousedown.native.prevent="emitValue"
|
|
54
58
|
>
|
|
59
|
+
<!-- @slot The suggestion content. -->
|
|
55
60
|
<slot></slot>
|
|
56
61
|
</gl-dropdown-item>
|
|
57
62
|
</template>
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
# Filtered Search Suggestion
|
|
2
|
-
|
|
3
|
-
<!-- STORY -->
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
1
|
The filtered search suggestion list component is responsible for managing underlying suggestion instances.
|
|
8
2
|
You obtain the ref for this component and manage suggestion selection via the component public API:
|
|
9
3
|
|
|
@@ -11,7 +5,7 @@ You obtain the ref for this component and manage suggestion selection via the co
|
|
|
11
5
|
- `nextItem()` - Selects the next suggestion. If last suggestion was selected, selection is cleared.
|
|
12
6
|
- `prevItem()` - Selects the previous suggestion. If first suggestion was selected, selection is cleared.
|
|
13
7
|
|
|
14
|
-
```
|
|
8
|
+
```html
|
|
15
9
|
<gl-filtered-search-suggestion-list ref="suggestions">
|
|
16
10
|
<gl-filtered-search-suggestion value="foo">Example suggestion</gl-filtered-search-suggestion>
|
|
17
11
|
<gl-filtered-search-suggestion value="bar">Example suggestion 2</gl-filtered-search-suggestion>
|