@gitlab/ui 42.20.0 → 42.22.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 +21 -0
- package/dist/components/base/alert/alert.js +1 -0
- package/dist/components/base/badge/badge.js +1 -0
- package/dist/components/base/button/button.js +2 -0
- package/dist/components/base/drawer/drawer.js +1 -0
- package/dist/components/base/dropdown/dropdown.js +1 -0
- package/dist/components/base/filtered_search/filtered_search_token_segment.js +1 -0
- package/dist/components/base/form/form_combobox/form_combobox.js +31 -35
- package/dist/components/base/form/form_group/form_group.js +1 -0
- package/dist/components/base/modal/modal.js +4 -1
- package/dist/components/base/toggle/toggle.js +1 -0
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/utility_classes.css +1 -1
- package/dist/utility_classes.css.map +1 -1
- package/package.json +3 -3
- package/src/components/base/alert/alert.vue +1 -0
- package/src/components/base/badge/badge.vue +1 -0
- package/src/components/base/button/button.vue +2 -0
- package/src/components/base/carousel/carousel.vue +1 -0
- package/src/components/base/carousel/carousel_slide.vue +1 -0
- package/src/components/base/drawer/drawer.vue +1 -0
- package/src/components/base/dropdown/dropdown.vue +1 -0
- package/src/components/base/filtered_search/filtered_search_token_segment.vue +1 -0
- package/src/components/base/form/form_combobox/form_combobox.scss +1 -5
- package/src/components/base/form/form_combobox/form_combobox.spec.js +26 -14
- package/src/components/base/form/form_combobox/form_combobox.vue +38 -32
- package/src/components/base/form/form_group/form_group.vue +2 -0
- package/src/components/base/form/form_select/form_select.scss +1 -0
- package/src/components/base/form/form_select/form_select.vue +1 -0
- package/src/components/base/modal/modal.vue +3 -0
- package/src/components/base/table/table.scss +4 -0
- package/src/components/base/table/table.stories.js +12 -2
- package/src/components/base/tabs/tab/tab.vue +1 -0
- package/src/components/base/tabs/tabs/scrollable_tabs.vue +1 -0
- package/src/components/base/tabs/tabs/tabs.vue +1 -0
- package/src/components/base/toggle/toggle.vue +1 -0
- package/src/scss/utilities.scss +8 -0
- package/src/scss/utility-mixins/flex.scss +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "42.
|
|
3
|
+
"version": "42.22.1",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -81,9 +81,9 @@
|
|
|
81
81
|
"@arkweid/lefthook": "0.7.7",
|
|
82
82
|
"@babel/core": "^7.10.2",
|
|
83
83
|
"@babel/preset-env": "^7.10.2",
|
|
84
|
-
"@gitlab/eslint-plugin": "
|
|
84
|
+
"@gitlab/eslint-plugin": "14.0.0",
|
|
85
85
|
"@gitlab/stylelint-config": "4.1.0",
|
|
86
|
-
"@gitlab/svgs": "2.
|
|
86
|
+
"@gitlab/svgs": "2.28.0",
|
|
87
87
|
"@rollup/plugin-commonjs": "^11.1.0",
|
|
88
88
|
"@rollup/plugin-node-resolve": "^7.1.3",
|
|
89
89
|
"@rollup/plugin-replace": "^2.3.2",
|
|
@@ -74,6 +74,7 @@ export default {
|
|
|
74
74
|
return this.icon !== '';
|
|
75
75
|
},
|
|
76
76
|
hasIconOnly() {
|
|
77
|
+
// eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots
|
|
77
78
|
return Object.keys(this.$slots).length === 0 && this.hasIcon;
|
|
78
79
|
},
|
|
79
80
|
isButtonDisabled() {
|
|
@@ -111,6 +112,7 @@ export default {
|
|
|
111
112
|
},
|
|
112
113
|
},
|
|
113
114
|
mounted() {
|
|
115
|
+
// eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots
|
|
114
116
|
if (!this.$slots.default && !this.$attrs['aria-label'] && !this.$props.label) {
|
|
115
117
|
logWarning('[gl-button]: Accessible name missing. Please add inner text or aria-label.');
|
|
116
118
|
}
|
|
@@ -10,6 +10,7 @@ export default {
|
|
|
10
10
|
</script>
|
|
11
11
|
<template>
|
|
12
12
|
<b-carousel v-bind="$attrs" v-on="$listeners">
|
|
13
|
+
<!-- eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots -->
|
|
13
14
|
<template v-for="slot in Object.keys($slots)" #[slot]>
|
|
14
15
|
<slot :name="slot"></slot>
|
|
15
16
|
</template>
|
|
@@ -9,6 +9,7 @@ export default {
|
|
|
9
9
|
</script>
|
|
10
10
|
<template>
|
|
11
11
|
<b-carousel-slide v-bind="$attrs" v-on="$listeners">
|
|
12
|
+
<!-- eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots -->
|
|
12
13
|
<template v-for="slot in Object.keys($slots)" #[slot]>
|
|
13
14
|
<slot :name="slot"></slot>
|
|
14
15
|
</template>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nextTick } from 'vue';
|
|
1
2
|
import { mount } from '@vue/test-utils';
|
|
2
3
|
import GlDropdownItem from '../../dropdown/dropdown_item.vue';
|
|
3
4
|
import GlFormInput from '../form_input/form_input.vue';
|
|
@@ -65,7 +66,9 @@ describe('GlFormCombobox', () => {
|
|
|
65
66
|
const findInput = () => wrapper.findComponent(GlFormInput);
|
|
66
67
|
const findInputValue = () => findInput().element.value;
|
|
67
68
|
const setInput = (val) => findInput().setValue(val);
|
|
68
|
-
const arrowDown = () =>
|
|
69
|
+
const arrowDown = () => findDropdown().trigger('keydown.down');
|
|
70
|
+
const arrowUp = () => findDropdown().trigger('keydown.up');
|
|
71
|
+
const enter = () => wrapper.find('[aria-selected="true"]').trigger('keydown.enter');
|
|
69
72
|
const findFirstAction = () => wrapper.find('[data-testid="combobox-action"]');
|
|
70
73
|
|
|
71
74
|
beforeAll(() => {
|
|
@@ -128,8 +131,10 @@ describe('GlFormCombobox', () => {
|
|
|
128
131
|
describe('on down arrow + enter', () => {
|
|
129
132
|
it('selects the next item in the list and closes the dropdown', async () => {
|
|
130
133
|
await setInput(partialToken);
|
|
131
|
-
|
|
132
|
-
await
|
|
134
|
+
arrowDown();
|
|
135
|
+
await nextTick();
|
|
136
|
+
enter();
|
|
137
|
+
await nextTick();
|
|
133
138
|
|
|
134
139
|
if (valueType === 'string') {
|
|
135
140
|
expect(findInputValue()).toBe(partialTokenMatch[0]);
|
|
@@ -141,7 +146,9 @@ describe('GlFormCombobox', () => {
|
|
|
141
146
|
it('loops to the top when it reaches the bottom', async () => {
|
|
142
147
|
await setInput(partialToken);
|
|
143
148
|
doTimes(findDropdownOptions().length + 1, arrowDown);
|
|
144
|
-
await
|
|
149
|
+
await nextTick();
|
|
150
|
+
enter();
|
|
151
|
+
await nextTick();
|
|
145
152
|
|
|
146
153
|
if (valueType === 'string') {
|
|
147
154
|
expect(findInputValue()).toBe(partialTokenMatch[0]);
|
|
@@ -157,8 +164,10 @@ describe('GlFormCombobox', () => {
|
|
|
157
164
|
|
|
158
165
|
await wrapper.vm.$nextTick();
|
|
159
166
|
doTimes(3, arrowDown);
|
|
160
|
-
|
|
161
|
-
|
|
167
|
+
arrowUp();
|
|
168
|
+
await nextTick();
|
|
169
|
+
enter();
|
|
170
|
+
await nextTick();
|
|
162
171
|
|
|
163
172
|
await wrapper.vm.$nextTick();
|
|
164
173
|
|
|
@@ -172,9 +181,11 @@ describe('GlFormCombobox', () => {
|
|
|
172
181
|
|
|
173
182
|
it('loops to the bottom when it reaches the top', async () => {
|
|
174
183
|
await setInput(partialToken);
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
await
|
|
184
|
+
arrowDown();
|
|
185
|
+
arrowUp();
|
|
186
|
+
await nextTick();
|
|
187
|
+
enter();
|
|
188
|
+
await nextTick();
|
|
178
189
|
|
|
179
190
|
if (valueType === 'string') {
|
|
180
191
|
expect(findInputValue()).toBe(partialTokenMatch[partialTokenMatch.length - 1]);
|
|
@@ -187,11 +198,11 @@ describe('GlFormCombobox', () => {
|
|
|
187
198
|
});
|
|
188
199
|
|
|
189
200
|
describe('on enter with no item highlighted', () => {
|
|
190
|
-
it('does
|
|
201
|
+
it('does nothing', async () => {
|
|
191
202
|
await setInput(partialToken);
|
|
192
203
|
await findInput().trigger('keydown.enter');
|
|
193
204
|
expect(findInputValue()).toBe(partialToken);
|
|
194
|
-
expect(findDropdown().isVisible()).toBe(
|
|
205
|
+
expect(findDropdown().isVisible()).toBe(true);
|
|
195
206
|
});
|
|
196
207
|
});
|
|
197
208
|
|
|
@@ -268,9 +279,10 @@ describe('GlFormCombobox', () => {
|
|
|
268
279
|
|
|
269
280
|
it('keyboard navigation and executes function on enter', async () => {
|
|
270
281
|
await setInput('dog');
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
282
|
+
doTimes(2, arrowDown);
|
|
283
|
+
await nextTick();
|
|
284
|
+
enter();
|
|
285
|
+
await nextTick();
|
|
274
286
|
|
|
275
287
|
expect(actionSpy).toHaveBeenCalled();
|
|
276
288
|
expect(findDropdown().isVisible()).toBe(false);
|
|
@@ -54,6 +54,14 @@ export default {
|
|
|
54
54
|
required: false,
|
|
55
55
|
default: false,
|
|
56
56
|
},
|
|
57
|
+
/**
|
|
58
|
+
* Placeholder text for input field
|
|
59
|
+
*/
|
|
60
|
+
placeholder: {
|
|
61
|
+
type: String,
|
|
62
|
+
required: false,
|
|
63
|
+
default: undefined,
|
|
64
|
+
},
|
|
57
65
|
},
|
|
58
66
|
data() {
|
|
59
67
|
return {
|
|
@@ -88,16 +96,8 @@ export default {
|
|
|
88
96
|
},
|
|
89
97
|
watch: {
|
|
90
98
|
tokenList(newList) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// For API driven tokens, we don't need extra filtering
|
|
94
|
-
return token;
|
|
95
|
-
}
|
|
96
|
-
return token.toLowerCase().includes(this.value.toLowerCase());
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
if (filteredTokens.length) {
|
|
100
|
-
this.openSuggestions(filteredTokens);
|
|
99
|
+
if (newList.length) {
|
|
100
|
+
this.openSuggestions(newList);
|
|
101
101
|
} else {
|
|
102
102
|
this.results = [];
|
|
103
103
|
this.arrowCounter = -1;
|
|
@@ -121,35 +121,33 @@ export default {
|
|
|
121
121
|
this.closeSuggestions();
|
|
122
122
|
}
|
|
123
123
|
},
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
focusItem(index) {
|
|
125
|
+
this.$refs.suggestionsMenu
|
|
126
|
+
.querySelectorAll('.gl-new-dropdown-item')
|
|
127
|
+
[index]?.querySelector('button')
|
|
128
|
+
.focus();
|
|
129
|
+
},
|
|
130
|
+
onArrowDown(e) {
|
|
131
|
+
e.preventDefault();
|
|
132
|
+
let newCount = this.arrowCounter + 1;
|
|
126
133
|
|
|
127
134
|
if (newCount >= this.allItems.length) {
|
|
128
|
-
|
|
129
|
-
return;
|
|
135
|
+
newCount = 0;
|
|
130
136
|
}
|
|
131
137
|
|
|
132
138
|
this.arrowCounter = newCount;
|
|
133
|
-
this
|
|
139
|
+
this.focusItem(newCount);
|
|
134
140
|
},
|
|
135
|
-
onArrowUp() {
|
|
136
|
-
|
|
141
|
+
onArrowUp(e) {
|
|
142
|
+
e.preventDefault();
|
|
143
|
+
let newCount = this.arrowCounter - 1;
|
|
137
144
|
|
|
138
145
|
if (newCount < 0) {
|
|
139
|
-
|
|
140
|
-
return;
|
|
146
|
+
newCount = this.allItems.length - 1;
|
|
141
147
|
}
|
|
142
148
|
|
|
143
149
|
this.arrowCounter = newCount;
|
|
144
|
-
this
|
|
145
|
-
},
|
|
146
|
-
onEnter() {
|
|
147
|
-
const focusedItem = this.allItems[this.arrowCounter] || this.value;
|
|
148
|
-
if (focusedItem.fn) {
|
|
149
|
-
this.selectAction(focusedItem);
|
|
150
|
-
} else {
|
|
151
|
-
this.selectToken(focusedItem);
|
|
152
|
-
}
|
|
150
|
+
this.focusItem(newCount);
|
|
153
151
|
},
|
|
154
152
|
onEsc() {
|
|
155
153
|
if (!this.showSuggestions) {
|
|
@@ -198,6 +196,9 @@ export default {
|
|
|
198
196
|
this.$emit('input', this.value);
|
|
199
197
|
this.closeSuggestions();
|
|
200
198
|
},
|
|
199
|
+
resetCounter() {
|
|
200
|
+
this.arrowCounter = -1;
|
|
201
|
+
},
|
|
201
202
|
},
|
|
202
203
|
};
|
|
203
204
|
</script>
|
|
@@ -219,10 +220,11 @@ export default {
|
|
|
219
220
|
:aria-controls="suggestionsId"
|
|
220
221
|
aria-haspopup="listbox"
|
|
221
222
|
:autofocus="autofocus"
|
|
223
|
+
:placeholder="placeholder"
|
|
222
224
|
@input="onEntry"
|
|
225
|
+
@focus="resetCounter"
|
|
223
226
|
@keydown.down="onArrowDown"
|
|
224
227
|
@keydown.up="onArrowUp"
|
|
225
|
-
@keydown.enter.prevent="onEnter"
|
|
226
228
|
@keydown.esc.stop="onEsc"
|
|
227
229
|
@keydown.tab="closeSuggestions"
|
|
228
230
|
/>
|
|
@@ -231,8 +233,12 @@ export default {
|
|
|
231
233
|
<ul
|
|
232
234
|
v-show="showSuggestions && !userDismissedResults"
|
|
233
235
|
:id="suggestionsId"
|
|
236
|
+
ref="suggestionsMenu"
|
|
234
237
|
data-testid="combobox-dropdown"
|
|
235
|
-
class="dropdown-menu
|
|
238
|
+
class="dropdown-menu gl-w-full gl-form-combobox-inner gl-list-style-none gl-pl-0 gl-mb-0 gl-display-flex gl-flex-direction-column"
|
|
239
|
+
@keydown.down="onArrowDown"
|
|
240
|
+
@keydown.up="onArrowUp"
|
|
241
|
+
@keydown.esc.stop="onEsc"
|
|
236
242
|
>
|
|
237
243
|
<li class="gl-overflow-y-auto show-dropdown">
|
|
238
244
|
<ul class="gl-list-style-none gl-pl-0 gl-mb-0">
|
|
@@ -241,10 +247,10 @@ export default {
|
|
|
241
247
|
ref="results"
|
|
242
248
|
:key="i"
|
|
243
249
|
role="option"
|
|
244
|
-
:class="{ 'gl-bg-gray-50': i === arrowCounter }"
|
|
245
250
|
:aria-selected="i === arrowCounter"
|
|
246
251
|
tabindex="-1"
|
|
247
252
|
@click="selectToken(result)"
|
|
253
|
+
@keydown.enter.native="selectToken(result)"
|
|
248
254
|
>
|
|
249
255
|
<!-- @slot The suggestion result item to display. -->
|
|
250
256
|
<slot name="result" :item="result">{{ result }}</slot>
|
|
@@ -258,11 +264,11 @@ export default {
|
|
|
258
264
|
v-for="(action, i) in actionList"
|
|
259
265
|
:key="i + resultsLength"
|
|
260
266
|
role="option"
|
|
261
|
-
:class="{ 'gl-bg-gray-50': i + resultsLength === arrowCounter }"
|
|
262
267
|
:aria-selected="i + resultsLength === arrowCounter"
|
|
263
268
|
tabindex="-1"
|
|
264
269
|
data-testid="combobox-action"
|
|
265
270
|
@click="selectAction(action)"
|
|
271
|
+
@keydown.enter.native="selectAction(action)"
|
|
266
272
|
>
|
|
267
273
|
<!-- @slot The action item to display. -->
|
|
268
274
|
<slot name="action" :item="action">{{ action.label }}</slot>
|
|
@@ -48,6 +48,7 @@ export default {
|
|
|
48
48
|
return defaultClass;
|
|
49
49
|
},
|
|
50
50
|
hasLabelDescription() {
|
|
51
|
+
// eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots
|
|
51
52
|
return Boolean(this.labelDescription || this.$slots['label-description']);
|
|
52
53
|
},
|
|
53
54
|
},
|
|
@@ -67,6 +68,7 @@ export default {
|
|
|
67
68
|
</gl-form-text>
|
|
68
69
|
</template>
|
|
69
70
|
|
|
71
|
+
<!-- eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots -->
|
|
70
72
|
<template v-for="slot in Object.keys($slots)" #[slot]>
|
|
71
73
|
<slot :name="slot"></slot>
|
|
72
74
|
</template>
|
|
@@ -10,6 +10,7 @@ export default {
|
|
|
10
10
|
</script>
|
|
11
11
|
<template>
|
|
12
12
|
<b-form-select class="gl-form-select" v-bind="$attrs" v-on="$listeners">
|
|
13
|
+
<!-- eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots -->
|
|
13
14
|
<template v-for="slot in Object.keys($slots)" #[slot]>
|
|
14
15
|
<slot :name="slot"></slot>
|
|
15
16
|
</template>
|
|
@@ -88,9 +88,11 @@ export default {
|
|
|
88
88
|
},
|
|
89
89
|
computed: {
|
|
90
90
|
shouldRenderModalOk() {
|
|
91
|
+
// eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots
|
|
91
92
|
return Boolean(this.$slots['modal-ok']);
|
|
92
93
|
},
|
|
93
94
|
shouldRenderModalCancel() {
|
|
95
|
+
// eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots
|
|
94
96
|
return Boolean(this.$slots['modal-cancel']);
|
|
95
97
|
},
|
|
96
98
|
shouldRenderModalFooter() {
|
|
@@ -98,6 +100,7 @@ export default {
|
|
|
98
100
|
this.actionCancel ||
|
|
99
101
|
this.actionSecondary ||
|
|
100
102
|
this.actionPrimary ||
|
|
103
|
+
// eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots
|
|
101
104
|
this.$slots['modal-footer']
|
|
102
105
|
);
|
|
103
106
|
},
|
|
@@ -18,10 +18,16 @@ const tableItems = [
|
|
|
18
18
|
},
|
|
19
19
|
];
|
|
20
20
|
|
|
21
|
-
const generateProps = ({
|
|
21
|
+
const generateProps = ({
|
|
22
|
+
fixed = false,
|
|
23
|
+
footClone = false,
|
|
24
|
+
stacked = false,
|
|
25
|
+
caption = '',
|
|
26
|
+
} = {}) => ({
|
|
22
27
|
fixed,
|
|
23
28
|
footClone,
|
|
24
29
|
stacked,
|
|
30
|
+
caption,
|
|
25
31
|
});
|
|
26
32
|
|
|
27
33
|
export const Default = (args, { argTypes }) => ({
|
|
@@ -37,7 +43,11 @@ export const Default = (args, { argTypes }) => ({
|
|
|
37
43
|
hover
|
|
38
44
|
selectable
|
|
39
45
|
selected-variant="primary"
|
|
40
|
-
|
|
46
|
+
>
|
|
47
|
+
<template v-if="caption" #table-caption>
|
|
48
|
+
{{ caption }}
|
|
49
|
+
</template>
|
|
50
|
+
</gl-table>
|
|
41
51
|
`,
|
|
42
52
|
fields: [
|
|
43
53
|
{
|
|
@@ -107,6 +107,7 @@ export default {
|
|
|
107
107
|
v-bind="passthroughAttrs"
|
|
108
108
|
v-on="$listeners"
|
|
109
109
|
>
|
|
110
|
+
<!-- eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots -->
|
|
110
111
|
<template v-for="slot in Object.keys($slots)" #[slot]>
|
|
111
112
|
<slot :name="slot"></slot>
|
|
112
113
|
</template>
|
package/src/scss/utilities.scss
CHANGED
|
@@ -3404,6 +3404,14 @@
|
|
|
3404
3404
|
flex-basis: 0 !important;
|
|
3405
3405
|
}
|
|
3406
3406
|
|
|
3407
|
+
.gl-flex-basis-third {
|
|
3408
|
+
flex-basis: 33%;
|
|
3409
|
+
}
|
|
3410
|
+
|
|
3411
|
+
.gl-flex-basis-third\! {
|
|
3412
|
+
flex-basis: 33% !important;
|
|
3413
|
+
}
|
|
3414
|
+
|
|
3407
3415
|
.gl-flex-basis-half {
|
|
3408
3416
|
flex-basis: 50%;
|
|
3409
3417
|
}
|