@gitlab/ui 72.14.0 → 73.0.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/CHANGELOG.md +20 -0
- package/dist/components/base/sorting/sorting.js +4 -9
- package/dist/index.js +0 -1
- package/dist/tokens/css/tokens.css +1 -1
- package/dist/tokens/css/tokens.dark.css +1 -1
- package/dist/tokens/js/tokens.dark.js +1 -1
- package/dist/tokens/js/tokens.js +1 -1
- package/dist/tokens/scss/_tokens.dark.scss +1 -1
- package/dist/tokens/scss/_tokens.scss +1 -1
- package/dist/utility_classes.css +1 -1
- package/dist/utility_classes.css.map +1 -1
- package/dist/utils/play_utils.js +11 -0
- package/package.json +4 -1
- package/src/components/base/button/button.stories.js +22 -7
- package/src/components/base/filtered_search/filtered_search.stories.js +10 -3
- package/src/components/base/filtered_search/filtered_search_suggestion_list.stories.js +6 -3
- package/src/components/base/filtered_search/filtered_search_term.stories.js +2 -3
- package/src/components/base/filtered_search/filtered_search_token.stories.js +5 -20
- package/src/components/base/filtered_search/filtered_search_token_segment.stories.js +3 -6
- package/src/components/base/form/form_combobox/form_combobox.stories.js +23 -9
- package/src/components/base/sorting/sorting.md +0 -63
- package/src/components/base/sorting/sorting.spec.js +11 -87
- package/src/components/base/sorting/sorting.stories.js +13 -47
- package/src/components/base/sorting/sorting.vue +2 -20
- package/src/components/base/toast/toast.stories.js +12 -9
- package/src/components/base/token_selector/token_selector.stories.js +8 -3
- package/src/components/base/tooltip/tooltip.stories.js +13 -3
- package/src/components/utilities/animated_number/animated_number.stories.js +0 -13
- package/src/index.js +0 -1
- package/src/scss/utilities.scss +2 -2
- package/src/scss/utility-mixins/typography.scss +1 -1
- package/src/utils/play_utils.js +9 -0
- package/dist/components/base/sorting/sorting_item.js +0 -109
- package/src/components/base/sorting/sorting_item.md +0 -5
- package/src/components/base/sorting/sorting_item.spec.js +0 -65
- package/src/components/base/sorting/sorting_item.stories.js +0 -50
- package/src/components/base/sorting/sorting_item.vue +0 -69
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "73.0.1",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -107,9 +107,12 @@
|
|
|
107
107
|
"@storybook/addon-a11y": "7.6.10",
|
|
108
108
|
"@storybook/addon-docs": "7.6.10",
|
|
109
109
|
"@storybook/addon-essentials": "7.6.10",
|
|
110
|
+
"@storybook/addon-interactions": "7.6.10",
|
|
110
111
|
"@storybook/addon-viewport": "7.6.10",
|
|
111
112
|
"@storybook/builder-webpack5": "7.6.10",
|
|
113
|
+
"@storybook/jest": "0.2.3",
|
|
112
114
|
"@storybook/test-runner": "0.16.0",
|
|
115
|
+
"@storybook/testing-library": "0.2.2",
|
|
113
116
|
"@storybook/theming": "7.6.10",
|
|
114
117
|
"@storybook/vue": "7.6.10",
|
|
115
118
|
"@storybook/vue-webpack5": "7.6.10",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import GlDropdown from '../dropdown/dropdown.vue';
|
|
2
2
|
import GlDropdownItem from '../dropdown/dropdown_item.vue';
|
|
3
3
|
import GlSorting from '../sorting/sorting.vue';
|
|
4
|
-
import GlSortingItem from '../sorting/sorting_item.vue';
|
|
5
4
|
import {
|
|
6
5
|
buttonCategoryOptions,
|
|
7
6
|
buttonVariantOptions,
|
|
@@ -501,15 +500,31 @@ BadgeWithSROnlyText.parameters = { controls: { disable: true } };
|
|
|
501
500
|
|
|
502
501
|
export const SortingDropdownSplitButton = (args, { argTypes }) => ({
|
|
503
502
|
props: Object.keys(argTypes),
|
|
504
|
-
components: { GlSorting
|
|
503
|
+
components: { GlSorting },
|
|
505
504
|
template: `
|
|
506
|
-
<gl-sorting
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
505
|
+
<gl-sorting
|
|
506
|
+
text="Sorting options"
|
|
507
|
+
:sort-options="sortOptions"
|
|
508
|
+
sort-by="first"
|
|
509
|
+
/>
|
|
511
510
|
`,
|
|
512
511
|
});
|
|
512
|
+
SortingDropdownSplitButton.args = {
|
|
513
|
+
sortOptions: [
|
|
514
|
+
{
|
|
515
|
+
value: 'first',
|
|
516
|
+
text: 'First item',
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
value: 'second',
|
|
520
|
+
text: 'Second item',
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
value: 'last',
|
|
524
|
+
text: 'Last item',
|
|
525
|
+
},
|
|
526
|
+
],
|
|
527
|
+
};
|
|
513
528
|
SortingDropdownSplitButton.parameters = { controls: { disable: true } };
|
|
514
529
|
|
|
515
530
|
export default {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import last from 'lodash/last';
|
|
2
|
+
import { userEvent, within, waitFor } from '@storybook/testing-library';
|
|
3
|
+
import { expect } from '@storybook/jest';
|
|
2
4
|
import GlLoadingIcon from '../loading_icon/loading_icon.vue';
|
|
3
5
|
import GlIcon from '../icon/icon.vue';
|
|
4
6
|
import GlToken from '../token/token.vue';
|
|
@@ -451,9 +453,6 @@ export const WithHistoryItems = () => ({
|
|
|
451
453
|
return typeof val === 'string';
|
|
452
454
|
},
|
|
453
455
|
},
|
|
454
|
-
mounted() {
|
|
455
|
-
this.$nextTick(() => this.$el.querySelector('.gl-dropdown-toggle').click());
|
|
456
|
-
},
|
|
457
456
|
template: `
|
|
458
457
|
<div>
|
|
459
458
|
{{ value }}
|
|
@@ -471,6 +470,14 @@ export const WithHistoryItems = () => ({
|
|
|
471
470
|
</div>
|
|
472
471
|
`,
|
|
473
472
|
});
|
|
473
|
+
WithHistoryItems.play = async ({ canvasElement }) => {
|
|
474
|
+
const canvas = within(canvasElement);
|
|
475
|
+
const button = canvas.getByRole('button', { name: 'Toggle history' });
|
|
476
|
+
await userEvent.click(button);
|
|
477
|
+
await waitFor(() =>
|
|
478
|
+
expect(within(document).getByRole('menu', { name: 'Toggle history' })).toBeVisible()
|
|
479
|
+
);
|
|
480
|
+
};
|
|
474
481
|
|
|
475
482
|
export const WithFriendlyText = () => ({
|
|
476
483
|
components,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { userEvent, within } from '@storybook/testing-library';
|
|
1
2
|
import GlFilteredSearchSuggestionList from './filtered_search_suggestion_list.vue';
|
|
2
3
|
import GlFilteredSearchSuggestion from './filtered_search_suggestion.vue';
|
|
3
4
|
import { provide } from './common_story_options';
|
|
@@ -20,9 +21,6 @@ export const Default = () => ({
|
|
|
20
21
|
);
|
|
21
22
|
},
|
|
22
23
|
},
|
|
23
|
-
mounted() {
|
|
24
|
-
this.$refs.suggestions.nextItem();
|
|
25
|
-
},
|
|
26
24
|
template: `
|
|
27
25
|
<div>
|
|
28
26
|
<button @click="$refs.suggestions.prevItem()">prev</button>
|
|
@@ -36,6 +34,11 @@ export const Default = () => ({
|
|
|
36
34
|
</div>
|
|
37
35
|
`,
|
|
38
36
|
});
|
|
37
|
+
Default.play = async ({ canvasElement }) => {
|
|
38
|
+
const canvas = within(canvasElement);
|
|
39
|
+
const button = canvas.getByRole('button', { name: 'next' });
|
|
40
|
+
await userEvent.click(button);
|
|
41
|
+
};
|
|
39
42
|
|
|
40
43
|
export default {
|
|
41
44
|
title: 'base/filtered-search/suggestion-list',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import PortalVue from 'portal-vue';
|
|
2
2
|
import Vue from 'vue';
|
|
3
|
+
import { triggerBlurEvent } from '../../../utils/play_utils';
|
|
3
4
|
import { provide } from './common_story_options';
|
|
4
5
|
import readme from './filtered_search_term.md';
|
|
5
6
|
import GlFilteredSearchTerm from './filtered_search_term.vue';
|
|
@@ -26,9 +27,6 @@ export const Default = (_args, { argTypes }) => ({
|
|
|
26
27
|
availableTokens,
|
|
27
28
|
};
|
|
28
29
|
},
|
|
29
|
-
mounted() {
|
|
30
|
-
this.$nextTick(() => document.activeElement.blur());
|
|
31
|
-
},
|
|
32
30
|
template: `
|
|
33
31
|
<div>
|
|
34
32
|
<div> {{ value.data }} </div>
|
|
@@ -47,6 +45,7 @@ export const Default = (_args, { argTypes }) => ({
|
|
|
47
45
|
`,
|
|
48
46
|
});
|
|
49
47
|
Default.args = generateProps();
|
|
48
|
+
Default.play = triggerBlurEvent;
|
|
50
49
|
|
|
51
50
|
export default {
|
|
52
51
|
title: 'base/filtered-search/term',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import PortalVue from 'portal-vue';
|
|
2
2
|
import Vue from 'vue';
|
|
3
|
+
import { triggerBlurEvent } from '../../../utils/play_utils';
|
|
3
4
|
import GlIcon from '../icon/icon.vue';
|
|
4
5
|
import GlDatepicker from '../datepicker/datepicker.vue';
|
|
5
6
|
import { provide } from './common_story_options';
|
|
@@ -30,11 +31,6 @@ export const Default = (args, { argTypes }) => ({
|
|
|
30
31
|
},
|
|
31
32
|
};
|
|
32
33
|
},
|
|
33
|
-
mounted() {
|
|
34
|
-
this.$nextTick(() => {
|
|
35
|
-
document.activeElement.blur();
|
|
36
|
-
});
|
|
37
|
-
},
|
|
38
34
|
template: `
|
|
39
35
|
<div>
|
|
40
36
|
<div> {{ value }} </div>
|
|
@@ -58,6 +54,7 @@ export const Default = (args, { argTypes }) => ({
|
|
|
58
54
|
`,
|
|
59
55
|
});
|
|
60
56
|
Default.args = generateProps();
|
|
57
|
+
Default.play = triggerBlurEvent;
|
|
61
58
|
|
|
62
59
|
// eslint-disable-next-line no-unused-vars
|
|
63
60
|
export const WithCustomOperatorsOptions = (args, { argTypes }) => ({
|
|
@@ -80,11 +77,6 @@ export const WithCustomOperatorsOptions = (args, { argTypes }) => ({
|
|
|
80
77
|
},
|
|
81
78
|
};
|
|
82
79
|
},
|
|
83
|
-
mounted() {
|
|
84
|
-
this.$nextTick(() => {
|
|
85
|
-
document.activeElement.blur();
|
|
86
|
-
});
|
|
87
|
-
},
|
|
88
80
|
template: `
|
|
89
81
|
<div>
|
|
90
82
|
<div> {{ value }} </div>
|
|
@@ -108,6 +100,7 @@ export const WithCustomOperatorsOptions = (args, { argTypes }) => ({
|
|
|
108
100
|
`,
|
|
109
101
|
});
|
|
110
102
|
WithCustomOperatorsOptions.args = generateProps();
|
|
103
|
+
WithCustomOperatorsOptions.play = triggerBlurEvent;
|
|
111
104
|
|
|
112
105
|
// eslint-disable-next-line no-unused-vars
|
|
113
106
|
export const WithStaticOptions = (args, { argTypes }) => ({
|
|
@@ -130,11 +123,6 @@ export const WithStaticOptions = (args, { argTypes }) => ({
|
|
|
130
123
|
},
|
|
131
124
|
};
|
|
132
125
|
},
|
|
133
|
-
mounted() {
|
|
134
|
-
this.$nextTick(() => {
|
|
135
|
-
document.activeElement.blur();
|
|
136
|
-
});
|
|
137
|
-
},
|
|
138
126
|
template: `
|
|
139
127
|
<div>
|
|
140
128
|
<div> {{ value }} </div>
|
|
@@ -153,6 +141,7 @@ export const WithStaticOptions = (args, { argTypes }) => ({
|
|
|
153
141
|
`,
|
|
154
142
|
});
|
|
155
143
|
WithStaticOptions.args = generateProps();
|
|
144
|
+
WithStaticOptions.play = triggerBlurEvent;
|
|
156
145
|
|
|
157
146
|
// eslint-disable-next-line no-unused-vars
|
|
158
147
|
export const WithDataSegmentInputAttributes = (args, { argTypes }) => ({
|
|
@@ -178,11 +167,6 @@ export const WithDataSegmentInputAttributes = (args, { argTypes }) => ({
|
|
|
178
167
|
},
|
|
179
168
|
};
|
|
180
169
|
},
|
|
181
|
-
mounted() {
|
|
182
|
-
this.$nextTick(() => {
|
|
183
|
-
document.activeElement.blur();
|
|
184
|
-
});
|
|
185
|
-
},
|
|
186
170
|
template: `
|
|
187
171
|
<div>
|
|
188
172
|
<div> {{ value }} </div>
|
|
@@ -200,6 +184,7 @@ export const WithDataSegmentInputAttributes = (args, { argTypes }) => ({
|
|
|
200
184
|
`,
|
|
201
185
|
});
|
|
202
186
|
WithDataSegmentInputAttributes.args = generateProps();
|
|
187
|
+
WithDataSegmentInputAttributes.play = triggerBlurEvent;
|
|
203
188
|
|
|
204
189
|
export default {
|
|
205
190
|
title: 'base/filtered-search/token',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import PortalVue from 'portal-vue';
|
|
2
2
|
import Vue from 'vue';
|
|
3
|
+
import { triggerBlurEvent } from '../../../utils/play_utils';
|
|
3
4
|
import GlFilteredSearchSuggestion from './filtered_search_suggestion.vue';
|
|
4
5
|
import { provide } from './common_story_options';
|
|
5
6
|
import readme from './filtered_search_token_segment.md';
|
|
@@ -38,9 +39,6 @@ export const Default = (args, { argTypes }) => ({
|
|
|
38
39
|
value: 'demo1',
|
|
39
40
|
};
|
|
40
41
|
},
|
|
41
|
-
mounted() {
|
|
42
|
-
this.$nextTick(() => document.activeElement.blur());
|
|
43
|
-
},
|
|
44
42
|
template: `
|
|
45
43
|
<div>
|
|
46
44
|
<div>v-model value: {{ value }} </div>
|
|
@@ -63,6 +61,7 @@ export const Default = (args, { argTypes }) => ({
|
|
|
63
61
|
`,
|
|
64
62
|
});
|
|
65
63
|
Default.args = generateProps();
|
|
64
|
+
Default.play = triggerBlurEvent;
|
|
66
65
|
|
|
67
66
|
// eslint-disable-next-line no-unused-vars
|
|
68
67
|
export const WithStaticOptions = (args, { argTypes }) => ({
|
|
@@ -77,9 +76,6 @@ export const WithStaticOptions = (args, { argTypes }) => ({
|
|
|
77
76
|
staticOptions,
|
|
78
77
|
};
|
|
79
78
|
},
|
|
80
|
-
mounted() {
|
|
81
|
-
this.$nextTick(() => document.activeElement.blur());
|
|
82
|
-
},
|
|
83
79
|
template: `
|
|
84
80
|
<div>
|
|
85
81
|
<div>v-model value: {{ value }} </div>
|
|
@@ -99,6 +95,7 @@ export const WithStaticOptions = (args, { argTypes }) => ({
|
|
|
99
95
|
`,
|
|
100
96
|
});
|
|
101
97
|
WithStaticOptions.args = generateProps();
|
|
98
|
+
WithStaticOptions.play = triggerBlurEvent;
|
|
102
99
|
|
|
103
100
|
export default {
|
|
104
101
|
title: 'base/filtered-search/token-segment',
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { userEvent, within, waitFor } from '@storybook/testing-library';
|
|
2
|
+
import { expect } from '@storybook/jest';
|
|
1
3
|
import { makeContainer } from '../../../../utils/story_decorators/container';
|
|
2
4
|
import { stringTokenList, labelText, objectTokenList, actionsList } from './constants';
|
|
3
5
|
import readme from './form_combobox.md';
|
|
@@ -41,12 +43,9 @@ Default.args = generateProps();
|
|
|
41
43
|
export const WithObjectValue = (args, { argTypes }) => ({
|
|
42
44
|
components: { GlFormCombobox },
|
|
43
45
|
props: Object.keys(argTypes),
|
|
44
|
-
mounted() {
|
|
45
|
-
this.$nextTick(() => this.$refs.combobox.openSuggestions(objectTokenList));
|
|
46
|
-
},
|
|
47
46
|
data: () => {
|
|
48
47
|
return {
|
|
49
|
-
value: '
|
|
48
|
+
value: '',
|
|
50
49
|
};
|
|
51
50
|
},
|
|
52
51
|
template: `
|
|
@@ -68,25 +67,40 @@ export const WithObjectValue = (args, { argTypes }) => ({
|
|
|
68
67
|
});
|
|
69
68
|
WithObjectValue.args = generateProps({ tokenList: objectTokenList, matchValueToAttr: 'title' });
|
|
70
69
|
WithObjectValue.decorators = [makeContainer({ height: '370px' })];
|
|
70
|
+
WithObjectValue.play = async ({ canvasElement }) => {
|
|
71
|
+
const canvas = within(canvasElement);
|
|
72
|
+
const searchbox = canvas.getByRole('searchbox');
|
|
73
|
+
userEvent.type(searchbox, 'g');
|
|
74
|
+
|
|
75
|
+
await waitFor(() =>
|
|
76
|
+
expect(within(document).getByRole('menuitem', { name: '1 giraffe' })).toBeVisible()
|
|
77
|
+
);
|
|
78
|
+
};
|
|
71
79
|
|
|
72
80
|
export const WithActions = (args, { argTypes }) => ({
|
|
73
81
|
components: { GlFormCombobox },
|
|
74
82
|
props: Object.keys(argTypes),
|
|
75
|
-
|
|
76
|
-
this.$nextTick(() => this.$refs.combobox.openSuggestions(['dog']));
|
|
77
|
-
},
|
|
83
|
+
template,
|
|
78
84
|
data: () => {
|
|
79
85
|
return {
|
|
80
|
-
value: '
|
|
86
|
+
value: '',
|
|
81
87
|
};
|
|
82
88
|
},
|
|
83
|
-
template,
|
|
84
89
|
});
|
|
85
90
|
WithActions.args = generateProps({
|
|
86
91
|
tokenList: stringTokenList,
|
|
87
92
|
actionList: actionsList,
|
|
88
93
|
});
|
|
89
94
|
WithActions.decorators = [makeContainer({ height: '180px' })];
|
|
95
|
+
WithActions.play = async ({ canvasElement }) => {
|
|
96
|
+
const canvas = within(canvasElement);
|
|
97
|
+
const searchbox = canvas.getByRole('searchbox');
|
|
98
|
+
userEvent.type(searchbox, 'dog');
|
|
99
|
+
|
|
100
|
+
await waitFor(() =>
|
|
101
|
+
expect(within(document).getByRole('menuitem', { name: 'dog' })).toBeVisible()
|
|
102
|
+
);
|
|
103
|
+
};
|
|
90
104
|
|
|
91
105
|
export default {
|
|
92
106
|
title: 'base/form/form-combobox',
|
|
@@ -78,66 +78,3 @@ export default {
|
|
|
78
78
|
}
|
|
79
79
|
</script>
|
|
80
80
|
```
|
|
81
|
-
|
|
82
|
-
## Deprecated usage
|
|
83
|
-
|
|
84
|
-
> **NOTE:** This documents the deprecated API, which will be removed in a future major release.
|
|
85
|
-
|
|
86
|
-
The dropdown part of the sorting component is a standard `gl-dropdown` component, with the items
|
|
87
|
-
exposed as a slot. Inside the `gl-sorting` component, you should add a list of `gl-sorting-item`
|
|
88
|
-
components to construct your sorting options. The check icon will be displayed when a
|
|
89
|
-
`gl-sorting-item` has its `active` prop set to `true`.
|
|
90
|
-
|
|
91
|
-
The `gl-sorting` component expects its parent component to manage the `text` and `is-ascending`
|
|
92
|
-
props. It does not track these using internal state.
|
|
93
|
-
|
|
94
|
-
A sort update should be triggered by clicking a `gl-sorting-item` component (and therefore should
|
|
95
|
-
have a `@click` event bound or a `href` prop in the case of navigation) or by clicking the direction
|
|
96
|
-
button. You should bind a function to the `sortDirectionChange` event to receive the new
|
|
97
|
-
`is-ascending` value and re-order your data appropriately.
|
|
98
|
-
|
|
99
|
-
A complete implementation example might look like:
|
|
100
|
-
|
|
101
|
-
```html
|
|
102
|
-
<template>
|
|
103
|
-
<gl-sorting
|
|
104
|
-
:text="dropdownText"
|
|
105
|
-
:is-ascending="isAscending"
|
|
106
|
-
@sortDirectionChange="onDirectionChange"
|
|
107
|
-
>
|
|
108
|
-
<gl-sorting-item @click="onSortItemClick('Item 1')">Item 1</gl-sorting-item>
|
|
109
|
-
<gl-sorting-item @click="onSortItemClick('Item 2')">Item 2</gl-sorting-item>
|
|
110
|
-
<gl-sorting-item @click="onSortItemClick('Item 3')">Item 3</gl-sorting-item>
|
|
111
|
-
</gl-sorting>
|
|
112
|
-
</template>
|
|
113
|
-
|
|
114
|
-
<script>
|
|
115
|
-
import { GlSorting, GlSortingItem } from '@gitlab/ui';
|
|
116
|
-
|
|
117
|
-
export default {
|
|
118
|
-
components: {
|
|
119
|
-
GlSorting,
|
|
120
|
-
GlSortingItem,
|
|
121
|
-
},
|
|
122
|
-
data() {
|
|
123
|
-
return {
|
|
124
|
-
isAscending: false,
|
|
125
|
-
dropdownText: 'Sort...'
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
methods: {
|
|
129
|
-
onSortItemClick(sortByItem) {
|
|
130
|
-
this.dropdownText = sortByItem;
|
|
131
|
-
this.sortMyData(sortByItem, this.isAscending);
|
|
132
|
-
},
|
|
133
|
-
onDirectionChange(isAscending) {
|
|
134
|
-
this.isAscending = isAscending;
|
|
135
|
-
this.sortMyData(this.dropdownText, this.isAscending);
|
|
136
|
-
},
|
|
137
|
-
sortMyData(sortBy, isAscending) {
|
|
138
|
-
// Use sortBy and direction to sort your data
|
|
139
|
-
},
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
</script>
|
|
143
|
-
```
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
2
|
import { useMockIntersectionObserver } from '~/utils/use_mock_intersection_observer';
|
|
3
3
|
import GlCollapsibleListbox from '../new_dropdowns/listbox/listbox.vue';
|
|
4
|
-
import GlDropdown from '../dropdown/dropdown.vue';
|
|
5
4
|
import GlIcon from '../icon/icon.vue';
|
|
6
5
|
import GlSorting from './sorting.vue';
|
|
7
6
|
|
|
@@ -18,7 +17,6 @@ describe('sorting component', () => {
|
|
|
18
17
|
|
|
19
18
|
const selectDropdownButton = () => wrapper.find('button');
|
|
20
19
|
const selectDirectionButton = () => wrapper.findAll('button').at(1);
|
|
21
|
-
const selectDropdown = () => wrapper.findComponent(GlDropdown);
|
|
22
20
|
const findListbox = () => wrapper.findComponent(GlCollapsibleListbox);
|
|
23
21
|
const findListboxItem = (text) =>
|
|
24
22
|
wrapper
|
|
@@ -35,91 +33,6 @@ describe('sorting component', () => {
|
|
|
35
33
|
});
|
|
36
34
|
};
|
|
37
35
|
|
|
38
|
-
it('should display default text in dropdown', () => {
|
|
39
|
-
createComponent();
|
|
40
|
-
|
|
41
|
-
expect(selectDropdownButton().text()).toBe(defaultDropdownText);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should have a default sort direction of desc and displays the descending icon', () => {
|
|
45
|
-
createComponent();
|
|
46
|
-
|
|
47
|
-
expect(selectDirectionButton().findComponent(GlIcon).props('name')).toBe('sort-highest');
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should show new text value when passed in as a prop', () => {
|
|
51
|
-
const newDropdownText = 'Some new text';
|
|
52
|
-
|
|
53
|
-
createComponent({
|
|
54
|
-
text: newDropdownText,
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
expect(selectDropdownButton().text()).toBe(newDropdownText);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should accept isAscending true as a default sort direction and display the ascending icon', () => {
|
|
61
|
-
createComponent({
|
|
62
|
-
isAscending: true,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
expect(selectDirectionButton().findComponent(GlIcon).props('name')).toBe('sort-lowest');
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('should emit the sortDirectionChange event when direction button is clicked', () => {
|
|
69
|
-
createComponent();
|
|
70
|
-
|
|
71
|
-
selectDirectionButton().trigger('click');
|
|
72
|
-
|
|
73
|
-
expect(wrapper.emitted('sortDirectionChange')[0]).toEqual([true]);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should allow custom sort direction text to be applied', () => {
|
|
77
|
-
const newDirectionTooltip = 'New tooltip text';
|
|
78
|
-
|
|
79
|
-
createComponent({
|
|
80
|
-
sortDirectionToolTip: newDirectionTooltip,
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
expect(selectDirectionButton().attributes('title')).toBe(newDirectionTooltip);
|
|
84
|
-
expect(selectDirectionButton().attributes('aria-label')).toBe(newDirectionTooltip);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('adds classes passed in `dropdownClass` prop to dropdown', () => {
|
|
88
|
-
createComponent({
|
|
89
|
-
dropdownClass: 'foo-bar',
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
expect(selectDropdown().classes()).toContain('foo-bar');
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('adds classes passed in `dropdownToggleClass` prop to dropdown toggle', () => {
|
|
96
|
-
createComponent({
|
|
97
|
-
dropdownToggleClass: 'foo-bar',
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
expect(selectDropdownButton().classes()).toEqual(expect.arrayContaining(['foo-bar']));
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('adds classes passed in `sortDirectionToggleClass` prop to sort direction toggle', () => {
|
|
104
|
-
createComponent({
|
|
105
|
-
sortDirectionToggleClass: 'foo-bar',
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
expect(selectDirectionButton().classes()).toEqual(
|
|
109
|
-
expect.arrayContaining(['sorting-direction-button', 'foo-bar'])
|
|
110
|
-
);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('sets aria-label of sort direction button', async () => {
|
|
114
|
-
createComponent();
|
|
115
|
-
|
|
116
|
-
expect(selectDirectionButton().attributes('aria-label')).toBe('Sort direction: descending');
|
|
117
|
-
|
|
118
|
-
await wrapper.setProps({ isAscending: true });
|
|
119
|
-
|
|
120
|
-
expect(selectDirectionButton().attributes('aria-label')).toBe('Sort direction: ascending');
|
|
121
|
-
});
|
|
122
|
-
|
|
123
36
|
describe('using listbox', () => {
|
|
124
37
|
useMockIntersectionObserver();
|
|
125
38
|
|
|
@@ -129,6 +42,16 @@ describe('sorting component', () => {
|
|
|
129
42
|
expect(selectDropdownButton().text()).toBe(defaultDropdownText);
|
|
130
43
|
});
|
|
131
44
|
|
|
45
|
+
it('should show new text value when passed in as a prop', () => {
|
|
46
|
+
const newDropdownText = 'Some new text';
|
|
47
|
+
|
|
48
|
+
createComponent({
|
|
49
|
+
text: newDropdownText,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
expect(selectDropdownButton().text()).toBe(newDropdownText);
|
|
53
|
+
});
|
|
54
|
+
|
|
132
55
|
it('should use the selected sort option text in dropdown if text is not given', () => {
|
|
133
56
|
createComponent({ text: null, sortOptions: [{ value: 0, text: 'Foo' }], sortBy: 0 });
|
|
134
57
|
|
|
@@ -194,6 +117,7 @@ describe('sorting component', () => {
|
|
|
194
117
|
});
|
|
195
118
|
|
|
196
119
|
expect(selectDirectionButton().attributes('title')).toBe(newDirectionTooltip);
|
|
120
|
+
expect(selectDirectionButton().attributes('aria-label')).toBe(newDirectionTooltip);
|
|
197
121
|
});
|
|
198
122
|
|
|
199
123
|
it('adds classes passed in `dropdownClass` prop to dropdown', () => {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { userEvent, within, waitFor } from '@storybook/testing-library';
|
|
2
|
+
import { expect } from '@storybook/jest';
|
|
1
3
|
import { makeContainer } from '../../../utils/story_decorators/container';
|
|
2
|
-
import GlSortingItem from './sorting_item.vue';
|
|
3
4
|
import GlSorting from './sorting.vue';
|
|
4
5
|
import readme from './sorting.md';
|
|
5
6
|
|
|
6
7
|
const components = {
|
|
7
8
|
GlSorting,
|
|
8
|
-
GlSortingItem,
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
const propDefault = (prop) => GlSorting.props[prop].default;
|
|
@@ -33,59 +33,24 @@ const generateProps = ({
|
|
|
33
33
|
const template = `
|
|
34
34
|
<gl-sorting
|
|
35
35
|
:text="text"
|
|
36
|
+
:sort-options="sortOptions"
|
|
37
|
+
:sort-by="sortBy"
|
|
36
38
|
:is-ascending="isAscending"
|
|
37
39
|
:sort-direction-tool-tip="sortDirectionToolTip"
|
|
38
40
|
:dropdown-class="dropdownClass"
|
|
39
41
|
:dropdown-toggle-class="dropdownToggleClass"
|
|
40
42
|
:sort-direction-toggle-class="sortDirectionToggleClass"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<gl-sorting-item>Second item</gl-sorting-item>
|
|
44
|
-
<gl-sorting-item>Last item</gl-sorting-item>
|
|
45
|
-
</gl-sorting>`;
|
|
43
|
+
/>
|
|
44
|
+
`;
|
|
46
45
|
|
|
47
46
|
const Template = (args) => ({
|
|
48
47
|
components,
|
|
49
48
|
props: Object.keys(args),
|
|
50
|
-
mounted() {
|
|
51
|
-
this.$nextTick(() => this.$el.querySelector('.gl-dropdown-toggle').click());
|
|
52
|
-
},
|
|
53
49
|
template,
|
|
54
50
|
});
|
|
55
51
|
|
|
56
52
|
export const Default = Template.bind({});
|
|
57
53
|
Object.assign(Default, {
|
|
58
|
-
args: generateProps(),
|
|
59
|
-
parameters: {
|
|
60
|
-
controls: {
|
|
61
|
-
// These props/events only apply when using the listbox form, so don't
|
|
62
|
-
// show their controls.
|
|
63
|
-
exclude: ['sortBy', 'sortOptions', 'sortByChange'],
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
export const UsingListbox = (args) => ({
|
|
69
|
-
components,
|
|
70
|
-
props: Object.keys(args),
|
|
71
|
-
mounted() {
|
|
72
|
-
// The first button is the dropdown trigger.
|
|
73
|
-
this.$nextTick(() => this.$el.querySelector('button').click());
|
|
74
|
-
},
|
|
75
|
-
template: `
|
|
76
|
-
<gl-sorting
|
|
77
|
-
:text="text"
|
|
78
|
-
:sort-options="sortOptions"
|
|
79
|
-
:sort-by="sortBy"
|
|
80
|
-
:is-ascending="isAscending"
|
|
81
|
-
:sort-direction-tool-tip="sortDirectionToolTip"
|
|
82
|
-
:dropdown-class="dropdownClass"
|
|
83
|
-
:dropdown-toggle-class="dropdownToggleClass"
|
|
84
|
-
:sort-direction-toggle-class="sortDirectionToggleClass"
|
|
85
|
-
/>
|
|
86
|
-
`,
|
|
87
|
-
});
|
|
88
|
-
Object.assign(UsingListbox, {
|
|
89
54
|
args: generateProps({
|
|
90
55
|
text: '',
|
|
91
56
|
sortOptions: [
|
|
@@ -104,13 +69,14 @@ Object.assign(UsingListbox, {
|
|
|
104
69
|
],
|
|
105
70
|
sortBy: 'first',
|
|
106
71
|
}),
|
|
107
|
-
parameters: {
|
|
108
|
-
controls: {
|
|
109
|
-
// The default slot is deprecated, so don't show it in the controls.
|
|
110
|
-
exclude: ['default'],
|
|
111
|
-
},
|
|
112
|
-
},
|
|
72
|
+
parameters: {},
|
|
113
73
|
});
|
|
74
|
+
Default.play = async ({ canvasElement }) => {
|
|
75
|
+
const canvas = within(canvasElement);
|
|
76
|
+
const button = canvas.getByTestId('base-dropdown-toggle');
|
|
77
|
+
await userEvent.click(button);
|
|
78
|
+
await waitFor(() => expect(canvas.getByRole('listbox')).toBeVisible());
|
|
79
|
+
};
|
|
114
80
|
|
|
115
81
|
export default {
|
|
116
82
|
title: 'base/sorting',
|