@gitlab/ui 66.31.1 → 66.32.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 +14 -0
- package/dist/components/base/new_dropdowns/base_dropdown/base_dropdown.js +25 -10
- package/dist/components/base/new_dropdowns/constants.js +2 -1
- package/dist/components/base/new_dropdowns/disclosure/disclosure_dropdown.js +11 -2
- package/dist/components/base/new_dropdowns/listbox/listbox.js +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/tokens/css/tokens.css +1 -1
- package/dist/tokens/css/tokens.dark.css +2 -2
- 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/package.json +7 -7
- package/src/components/base/new_dropdowns/base_dropdown/base_dropdown.spec.js +57 -1
- package/src/components/base/new_dropdowns/base_dropdown/base_dropdown.vue +25 -9
- package/src/components/base/new_dropdowns/constants.js +1 -0
- package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.md +21 -0
- package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.spec.js +15 -0
- package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.vue +11 -0
- package/src/components/base/new_dropdowns/listbox/listbox.scss +10 -0
- package/src/components/base/new_dropdowns/listbox/listbox.vue +1 -0
- package/src/scss/fonts.scss +34 -2
- package/src/scss/storybook.scss +1 -0
- package/src/scss/storybook_dark_mode.scss +1 -1
package/dist/tokens/js/tokens.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "66.
|
|
3
|
+
"version": "66.32.1",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -88,12 +88,12 @@
|
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
90
|
"@arkweid/lefthook": "0.7.7",
|
|
91
|
-
"@babel/core": "^7.23.
|
|
92
|
-
"@babel/preset-env": "^7.
|
|
91
|
+
"@babel/core": "^7.23.2",
|
|
92
|
+
"@babel/preset-env": "^7.23.2",
|
|
93
93
|
"@babel/preset-react": "^7.22.15",
|
|
94
|
-
"@gitlab/eslint-plugin": "19.
|
|
95
|
-
"@gitlab/fonts": "^1.
|
|
96
|
-
"@gitlab/stylelint-config": "5.0.
|
|
94
|
+
"@gitlab/eslint-plugin": "19.2.0",
|
|
95
|
+
"@gitlab/fonts": "^1.3.0",
|
|
96
|
+
"@gitlab/stylelint-config": "5.0.1",
|
|
97
97
|
"@gitlab/svgs": "3.66.0",
|
|
98
98
|
"@rollup/plugin-commonjs": "^11.1.0",
|
|
99
99
|
"@rollup/plugin-node-resolve": "^7.1.3",
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
"babel-loader": "^8.0.5",
|
|
123
123
|
"babel-plugin-require-context-hook": "^1.0.0",
|
|
124
124
|
"bootstrap": "4.6.2",
|
|
125
|
-
"cypress": "13.3.
|
|
125
|
+
"cypress": "13.3.1",
|
|
126
126
|
"cypress-axe": "^1.4.0",
|
|
127
127
|
"dompurify": "^3.0.0",
|
|
128
128
|
"emoji-regex": "^10.0.0",
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
GL_DROPDOWN_FOCUS_CONTENT,
|
|
7
7
|
GL_DROPDOWN_HIDDEN,
|
|
8
8
|
GL_DROPDOWN_SHOWN,
|
|
9
|
+
GL_DROPDOWN_BEFORE_CLOSE,
|
|
9
10
|
GL_DROPDOWN_CONTENTS_CLASS,
|
|
10
11
|
} from '../constants';
|
|
11
12
|
import { waitForAnimationFrame } from '../../../../utils/test_utils';
|
|
@@ -28,7 +29,7 @@ const DEFAULT_BTN_TOGGLE_CLASSES = [
|
|
|
28
29
|
describe('base dropdown', () => {
|
|
29
30
|
let wrapper;
|
|
30
31
|
|
|
31
|
-
const buildWrapper = (propsData, slots = {}) => {
|
|
32
|
+
const buildWrapper = (propsData, slots = {}, listeners = {}) => {
|
|
32
33
|
wrapper = mount(GlBaseDropdown, {
|
|
33
34
|
propsData: {
|
|
34
35
|
toggleId: 'dropdown-toggle-btn-1',
|
|
@@ -39,6 +40,7 @@ describe('base dropdown', () => {
|
|
|
39
40
|
...slots,
|
|
40
41
|
},
|
|
41
42
|
attachTo: document.body,
|
|
43
|
+
listeners,
|
|
42
44
|
});
|
|
43
45
|
};
|
|
44
46
|
|
|
@@ -332,6 +334,60 @@ describe('base dropdown', () => {
|
|
|
332
334
|
});
|
|
333
335
|
});
|
|
334
336
|
|
|
337
|
+
describe('beforeClose event', () => {
|
|
338
|
+
let event;
|
|
339
|
+
|
|
340
|
+
beforeEach(() => {
|
|
341
|
+
event = undefined;
|
|
342
|
+
buildWrapper(undefined, undefined, {
|
|
343
|
+
[GL_DROPDOWN_BEFORE_CLOSE]({ originalEvent, preventDefault }) {
|
|
344
|
+
event = originalEvent;
|
|
345
|
+
preventDefault();
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it('should prevent closing', async () => {
|
|
351
|
+
const toggle = findDefaultDropdownToggle();
|
|
352
|
+
const menu = findDropdownMenu();
|
|
353
|
+
|
|
354
|
+
await toggle.trigger('click');
|
|
355
|
+
|
|
356
|
+
menu.element.focus();
|
|
357
|
+
await menu.trigger('keydown.esc');
|
|
358
|
+
expect(menu.classes('gl-display-block!')).toBe(true);
|
|
359
|
+
expect(toggle.attributes('aria-expanded')).toBeDefined();
|
|
360
|
+
expect(wrapper.emitted(GL_DROPDOWN_HIDDEN)).toBeUndefined();
|
|
361
|
+
expect(toggle.element).not.toHaveFocus();
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
it('should contain original keyboard event', async () => {
|
|
365
|
+
const toggle = findDefaultDropdownToggle();
|
|
366
|
+
const menu = findDropdownMenu();
|
|
367
|
+
await toggle.trigger('click');
|
|
368
|
+
await menu.trigger('keydown.esc');
|
|
369
|
+
expect(event.type).toBe('keydown');
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it('should contain original toggle click event', async () => {
|
|
373
|
+
const toggle = findDefaultDropdownToggle();
|
|
374
|
+
await toggle.trigger('click');
|
|
375
|
+
await toggle.trigger('click');
|
|
376
|
+
expect(event.type).toBe('click');
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it('should contain original outside click event', async () => {
|
|
380
|
+
const outsideElement = document.createElement('div');
|
|
381
|
+
document.body.appendChild(outsideElement);
|
|
382
|
+
|
|
383
|
+
const toggle = findDefaultDropdownToggle();
|
|
384
|
+
await toggle.trigger('click');
|
|
385
|
+
const click = new MouseEvent('click', { bubbles: true });
|
|
386
|
+
outsideElement.dispatchEvent(click);
|
|
387
|
+
expect(event).toBe(click);
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
335
391
|
describe('Custom toggle', () => {
|
|
336
392
|
const customToggleTestId = 'custom-toggle';
|
|
337
393
|
const toggleContent = `<button data-testid="${customToggleTestId}">Custom toggle</button>`;
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
GL_DROPDOWN_SHOWN,
|
|
13
13
|
GL_DROPDOWN_HIDDEN,
|
|
14
|
+
GL_DROPDOWN_BEFORE_CLOSE,
|
|
14
15
|
GL_DROPDOWN_FOCUS_CONTENT,
|
|
15
16
|
ENTER,
|
|
16
17
|
SPACE,
|
|
@@ -202,7 +203,7 @@ export default {
|
|
|
202
203
|
...this.ariaAttributes,
|
|
203
204
|
listeners: {
|
|
204
205
|
keydown: (event) => this.onKeydown(event),
|
|
205
|
-
click: () => this.toggle(),
|
|
206
|
+
click: (event) => this.toggle(event),
|
|
206
207
|
},
|
|
207
208
|
};
|
|
208
209
|
}
|
|
@@ -212,7 +213,7 @@ export default {
|
|
|
212
213
|
class: 'gl-new-dropdown-custom-toggle',
|
|
213
214
|
listeners: {
|
|
214
215
|
keydown: (event) => this.onKeydown(event),
|
|
215
|
-
click: () => this.toggle(),
|
|
216
|
+
click: (event) => this.toggle(event),
|
|
216
217
|
},
|
|
217
218
|
};
|
|
218
219
|
},
|
|
@@ -333,7 +334,17 @@ export default {
|
|
|
333
334
|
this.observer?.disconnect();
|
|
334
335
|
this.stopAutoUpdate?.();
|
|
335
336
|
},
|
|
336
|
-
async toggle() {
|
|
337
|
+
async toggle(event) {
|
|
338
|
+
if (event && this.visible) {
|
|
339
|
+
let prevented = false;
|
|
340
|
+
this.$emit(GL_DROPDOWN_BEFORE_CLOSE, {
|
|
341
|
+
originalEvent: event,
|
|
342
|
+
preventDefault() {
|
|
343
|
+
prevented = true;
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
if (prevented) return false;
|
|
347
|
+
}
|
|
337
348
|
this.visible = !this.visible;
|
|
338
349
|
|
|
339
350
|
if (this.visible) {
|
|
@@ -352,6 +363,9 @@ export default {
|
|
|
352
363
|
this.stopFloating();
|
|
353
364
|
this.$emit(GL_DROPDOWN_HIDDEN);
|
|
354
365
|
}
|
|
366
|
+
|
|
367
|
+
// this is to check whether `toggle` was prevented or not
|
|
368
|
+
return true;
|
|
355
369
|
},
|
|
356
370
|
open() {
|
|
357
371
|
if (this.visible) {
|
|
@@ -359,18 +373,20 @@ export default {
|
|
|
359
373
|
}
|
|
360
374
|
this.toggle();
|
|
361
375
|
},
|
|
362
|
-
close() {
|
|
376
|
+
close(event) {
|
|
363
377
|
if (!this.visible) {
|
|
364
378
|
return;
|
|
365
379
|
}
|
|
366
|
-
this.toggle();
|
|
380
|
+
this.toggle(event);
|
|
367
381
|
},
|
|
368
|
-
closeAndFocus() {
|
|
382
|
+
async closeAndFocus(event) {
|
|
369
383
|
if (!this.visible) {
|
|
370
384
|
return;
|
|
371
385
|
}
|
|
372
|
-
this.toggle();
|
|
373
|
-
|
|
386
|
+
const hasToggled = await this.toggle(event);
|
|
387
|
+
if (hasToggled) {
|
|
388
|
+
this.focusToggle();
|
|
389
|
+
}
|
|
374
390
|
},
|
|
375
391
|
focusToggle() {
|
|
376
392
|
this.toggleElement.focus();
|
|
@@ -392,7 +408,7 @@ export default {
|
|
|
392
408
|
}
|
|
393
409
|
|
|
394
410
|
if ((code === ENTER && toggleOnEnter) || (code === SPACE && toggleOnSpace)) {
|
|
395
|
-
this.toggle();
|
|
411
|
+
this.toggle(event);
|
|
396
412
|
}
|
|
397
413
|
|
|
398
414
|
if (code === ARROW_DOWN) {
|
|
@@ -38,6 +38,27 @@ The disclosure dropdown is closed by any of the following:
|
|
|
38
38
|
- clicking anywhere outside the component
|
|
39
39
|
- clicking the action or link inside the dropdown
|
|
40
40
|
|
|
41
|
+
Before closing, `GlDisclosureDropdown` emits a `beforeClose` event with these properties:
|
|
42
|
+
|
|
43
|
+
1. `originalEvent` – the event that triggered closing of the dropdown
|
|
44
|
+
2. `preventDefault` – a method which will prevent closing of the dropdown
|
|
45
|
+
|
|
46
|
+
An example of using this event to prevent the dropdown from closing:
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<gl-disclosure-dropdown @beforeClose="$event.preventDefault()" />
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Note that this method will also prevent the dropdown from closing even if the trigger button is clicked.
|
|
53
|
+
|
|
54
|
+
You can use the `preventDefault` to filter out events that are causing undesired dropdown closing:
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<gl-disclosure-dropdown
|
|
58
|
+
@beforeClose="(e) => { ignoreElement.contains(e.originalEvent.target) && e.preventDefault() }"
|
|
59
|
+
/>
|
|
60
|
+
```
|
|
61
|
+
|
|
41
62
|
After closing, `GlDisclosureDropdown` emits a `hidden` event.
|
|
42
63
|
|
|
43
64
|
### Setting disclosure dropdown items
|
|
@@ -5,6 +5,7 @@ import GlBaseDropdown from '../base_dropdown/base_dropdown.vue';
|
|
|
5
5
|
import {
|
|
6
6
|
GL_DROPDOWN_SHOWN,
|
|
7
7
|
GL_DROPDOWN_HIDDEN,
|
|
8
|
+
GL_DROPDOWN_BEFORE_CLOSE,
|
|
8
9
|
GL_DROPDOWN_FOCUS_CONTENT,
|
|
9
10
|
ARROW_DOWN,
|
|
10
11
|
ARROW_UP,
|
|
@@ -100,6 +101,20 @@ describe('GlDisclosureDropdown', () => {
|
|
|
100
101
|
});
|
|
101
102
|
});
|
|
102
103
|
|
|
104
|
+
describe('onClose', () => {
|
|
105
|
+
let data;
|
|
106
|
+
|
|
107
|
+
beforeEach(() => {
|
|
108
|
+
buildWrapper();
|
|
109
|
+
data = { event: {}, preventDefault() {} };
|
|
110
|
+
findBaseDropdown().vm.$emit(GL_DROPDOWN_BEFORE_CLOSE, data);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should re-emit the event', () => {
|
|
114
|
+
expect(wrapper.emitted(GL_DROPDOWN_BEFORE_CLOSE)).toStrictEqual([[data]]);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
103
118
|
describe('onHide', () => {
|
|
104
119
|
beforeEach(() => {
|
|
105
120
|
buildWrapper();
|
|
@@ -6,6 +6,7 @@ import { stopEvent, filterVisible } from '../../../../utils/utils';
|
|
|
6
6
|
import {
|
|
7
7
|
GL_DROPDOWN_SHOWN,
|
|
8
8
|
GL_DROPDOWN_HIDDEN,
|
|
9
|
+
GL_DROPDOWN_BEFORE_CLOSE,
|
|
9
10
|
GL_DROPDOWN_FOCUS_CONTENT,
|
|
10
11
|
ENTER,
|
|
11
12
|
SPACE,
|
|
@@ -35,6 +36,7 @@ export default {
|
|
|
35
36
|
events: {
|
|
36
37
|
GL_DROPDOWN_SHOWN,
|
|
37
38
|
GL_DROPDOWN_HIDDEN,
|
|
39
|
+
GL_DROPDOWN_BEFORE_CLOSE,
|
|
38
40
|
GL_DROPDOWN_FOCUS_CONTENT,
|
|
39
41
|
},
|
|
40
42
|
components: {
|
|
@@ -250,6 +252,14 @@ export default {
|
|
|
250
252
|
*/
|
|
251
253
|
this.$emit(GL_DROPDOWN_SHOWN);
|
|
252
254
|
},
|
|
255
|
+
onBeforeClose(event) {
|
|
256
|
+
/**
|
|
257
|
+
* Emitted when dropdown is about to be closed
|
|
258
|
+
*
|
|
259
|
+
* @event beforeClose
|
|
260
|
+
*/
|
|
261
|
+
this.$emit(GL_DROPDOWN_BEFORE_CLOSE, event);
|
|
262
|
+
},
|
|
253
263
|
onHide() {
|
|
254
264
|
/**
|
|
255
265
|
* Emitted when dropdown is hidden
|
|
@@ -349,6 +359,7 @@ export default {
|
|
|
349
359
|
class="gl-disclosure-dropdown"
|
|
350
360
|
@[$options.events.GL_DROPDOWN_SHOWN]="onShow"
|
|
351
361
|
@[$options.events.GL_DROPDOWN_HIDDEN]="onHide"
|
|
362
|
+
@[$options.events.GL_DROPDOWN_BEFORE_CLOSE]="onBeforeClose"
|
|
352
363
|
@[$options.events.GL_DROPDOWN_FOCUS_CONTENT]="onKeydown"
|
|
353
364
|
>
|
|
354
365
|
<template v-if="hasCustomToggle" #toggle>
|
|
@@ -28,6 +28,16 @@ $clear-button-size: 24px;
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// top container radius minus its border size to avoid the small gap between the focus ring and container
|
|
32
|
+
$input-focus-ring-border-radius: calc($gl-border-radius-large - $gl-border-size-1);
|
|
33
|
+
|
|
34
|
+
&.gl-listbox-topmost {
|
|
35
|
+
.gl-listbox-search-input {
|
|
36
|
+
border-top-left-radius: $input-focus-ring-border-radius;
|
|
37
|
+
border-top-right-radius: $input-focus-ring-border-radius;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
31
41
|
.gl-listbox-search-icon {
|
|
32
42
|
@include gl-absolute;
|
|
33
43
|
top: calc(50% - #{$search-icon-size} / 2);
|
package/src/scss/fonts.scss
CHANGED
|
@@ -13,18 +13,34 @@ Usage:
|
|
|
13
13
|
*/
|
|
14
14
|
font-display: block;
|
|
15
15
|
font-style: normal;
|
|
16
|
-
|
|
16
|
+
/* stylelint-disable-next-line property-no-unknown */
|
|
17
|
+
font-named-instance: 'Regular';
|
|
17
18
|
src: url('../../static/fonts/GitLabSans.woff2') format('woff2');
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
@font-face {
|
|
22
|
+
font-family: 'GitLab Sans';
|
|
23
|
+
font-weight: 100 900;
|
|
24
|
+
/**
|
|
25
|
+
* Applications should use a less aggressive font-display value than this.
|
|
26
|
+
* This is done to make sure Storybook Previews load the font.
|
|
27
|
+
*/
|
|
28
|
+
font-display: block;
|
|
29
|
+
font-style: italic;
|
|
30
|
+
/* stylelint-disable-next-line property-no-unknown */
|
|
31
|
+
font-named-instance: 'Regular';
|
|
32
|
+
src: url('../../static/fonts/GitLabSans-Italic.woff2') format('woff2');
|
|
33
|
+
}
|
|
34
|
+
|
|
20
35
|
/* -------------------------------------------------------
|
|
21
36
|
Monospaced font: GitLab Mono.
|
|
22
37
|
|
|
23
38
|
Usage:
|
|
24
|
-
html { font-family: 'GitLab Mono',
|
|
39
|
+
html { font-family: 'GitLab Mono', monospace; }
|
|
25
40
|
*/
|
|
26
41
|
@font-face {
|
|
27
42
|
font-family: 'GitLab Mono';
|
|
43
|
+
font-weight: 100 900;
|
|
28
44
|
/**
|
|
29
45
|
* Applications should use a less aggressive font-display value than this.
|
|
30
46
|
* This is done to make sure Storybook Previews load the font.
|
|
@@ -33,3 +49,19 @@ Usage:
|
|
|
33
49
|
font-style: normal;
|
|
34
50
|
src: url('../../static/fonts/GitLabMono.woff2') format('woff2');
|
|
35
51
|
}
|
|
52
|
+
|
|
53
|
+
@font-face {
|
|
54
|
+
font-family: 'GitLab Mono';
|
|
55
|
+
font-weight: 100 900;
|
|
56
|
+
/**
|
|
57
|
+
* Applications should use a less aggressive font-display value than this.
|
|
58
|
+
* This is done to make sure Storybook Previews load the font.
|
|
59
|
+
*/
|
|
60
|
+
font-display: block;
|
|
61
|
+
font-style: italic;
|
|
62
|
+
src: url('../../static/fonts/GitLabMono-Italic.woff2') format('woff2');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
* {
|
|
66
|
+
font-synthesis: none;
|
|
67
|
+
}
|
package/src/scss/storybook.scss
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@import 'variables';
|
|
2
|
+
@import '../../dist/tokens/css/tokens.dark';
|
|
2
3
|
|
|
3
4
|
// conditional overrides for dark mode for use in storybook.
|
|
4
5
|
// Because we only use application.css from gitlab (and not
|
|
@@ -15,7 +16,6 @@
|
|
|
15
16
|
// Note that we are assigning variables with different values due to the way GitLab inverts variables in dark mode.
|
|
16
17
|
// e.g. text color is usually $gray-900, but in dark mode $gray-900 variable gets inverted to $gray-50
|
|
17
18
|
--gl-text-color: #{$gray-50};
|
|
18
|
-
--gray-600: #{$gray-300};
|
|
19
19
|
|
|
20
20
|
color-scheme: dark;
|
|
21
21
|
|