@gitlab/ui 66.31.1 → 66.32.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/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/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/package.json +3 -3
- 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/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [66.32.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v66.31.1...v66.32.0) (2023-10-16)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **GlDisclosureDropdown:** add a beforeClose event ([cb4fdb1](https://gitlab.com/gitlab-org/gitlab-ui/commit/cb4fdb10f3669e80c688ea8e442f6dd9cb7ce973))
|
|
7
|
+
|
|
1
8
|
## [66.31.1](https://gitlab.com/gitlab-org/gitlab-ui/compare/v66.31.0...v66.31.1) (2023-10-13)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import uniqueId from 'lodash/uniqueId';
|
|
2
2
|
import { offset, autoPlacement, size, autoUpdate, computePosition } from '@floating-ui/dom';
|
|
3
3
|
import { buttonCategoryOptions, dropdownVariantOptions, buttonSizeOptions, dropdownPlacements, dropdownAllowedAutoPlacements } from '../../../../utils/constants';
|
|
4
|
-
import { POSITION_ABSOLUTE, POSITION_FIXED, GL_DROPDOWN_CONTENTS_CLASS, GL_DROPDOWN_SHOWN, GL_DROPDOWN_HIDDEN, ENTER, SPACE, ARROW_DOWN, GL_DROPDOWN_FOCUS_CONTENT } from '../constants';
|
|
4
|
+
import { POSITION_ABSOLUTE, POSITION_FIXED, GL_DROPDOWN_CONTENTS_CLASS, GL_DROPDOWN_BEFORE_CLOSE, GL_DROPDOWN_SHOWN, GL_DROPDOWN_HIDDEN, ENTER, SPACE, ARROW_DOWN, GL_DROPDOWN_FOCUS_CONTENT } from '../constants';
|
|
5
5
|
import { isElementFocusable, isElementTabbable, logWarning } from '../../../../utils/utils';
|
|
6
6
|
import GlButton from '../../button/button';
|
|
7
7
|
import GlIcon from '../../icon/icon';
|
|
@@ -187,7 +187,7 @@ var script = {
|
|
|
187
187
|
...this.ariaAttributes,
|
|
188
188
|
listeners: {
|
|
189
189
|
keydown: event => this.onKeydown(event),
|
|
190
|
-
click:
|
|
190
|
+
click: event => this.toggle(event)
|
|
191
191
|
}
|
|
192
192
|
};
|
|
193
193
|
}
|
|
@@ -196,7 +196,7 @@ var script = {
|
|
|
196
196
|
class: 'gl-new-dropdown-custom-toggle',
|
|
197
197
|
listeners: {
|
|
198
198
|
keydown: event => this.onKeydown(event),
|
|
199
|
-
click:
|
|
199
|
+
click: event => this.toggle(event)
|
|
200
200
|
}
|
|
201
201
|
};
|
|
202
202
|
},
|
|
@@ -314,7 +314,17 @@ var script = {
|
|
|
314
314
|
(_this$observer = this.observer) === null || _this$observer === void 0 ? void 0 : _this$observer.disconnect();
|
|
315
315
|
(_this$stopAutoUpdate = this.stopAutoUpdate) === null || _this$stopAutoUpdate === void 0 ? void 0 : _this$stopAutoUpdate.call(this);
|
|
316
316
|
},
|
|
317
|
-
async toggle() {
|
|
317
|
+
async toggle(event) {
|
|
318
|
+
if (event && this.visible) {
|
|
319
|
+
let prevented = false;
|
|
320
|
+
this.$emit(GL_DROPDOWN_BEFORE_CLOSE, {
|
|
321
|
+
originalEvent: event,
|
|
322
|
+
preventDefault() {
|
|
323
|
+
prevented = true;
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
if (prevented) return false;
|
|
327
|
+
}
|
|
318
328
|
this.visible = !this.visible;
|
|
319
329
|
if (this.visible) {
|
|
320
330
|
// The dropdown needs to be actually visible before we compute its position with Floating UI.
|
|
@@ -331,6 +341,9 @@ var script = {
|
|
|
331
341
|
this.stopFloating();
|
|
332
342
|
this.$emit(GL_DROPDOWN_HIDDEN);
|
|
333
343
|
}
|
|
344
|
+
|
|
345
|
+
// this is to check whether `toggle` was prevented or not
|
|
346
|
+
return true;
|
|
334
347
|
},
|
|
335
348
|
open() {
|
|
336
349
|
if (this.visible) {
|
|
@@ -338,18 +351,20 @@ var script = {
|
|
|
338
351
|
}
|
|
339
352
|
this.toggle();
|
|
340
353
|
},
|
|
341
|
-
close() {
|
|
354
|
+
close(event) {
|
|
342
355
|
if (!this.visible) {
|
|
343
356
|
return;
|
|
344
357
|
}
|
|
345
|
-
this.toggle();
|
|
358
|
+
this.toggle(event);
|
|
346
359
|
},
|
|
347
|
-
closeAndFocus() {
|
|
360
|
+
async closeAndFocus(event) {
|
|
348
361
|
if (!this.visible) {
|
|
349
362
|
return;
|
|
350
363
|
}
|
|
351
|
-
this.toggle();
|
|
352
|
-
|
|
364
|
+
const hasToggled = await this.toggle(event);
|
|
365
|
+
if (hasToggled) {
|
|
366
|
+
this.focusToggle();
|
|
367
|
+
}
|
|
353
368
|
},
|
|
354
369
|
focusToggle() {
|
|
355
370
|
this.toggleElement.focus();
|
|
@@ -370,7 +385,7 @@ var script = {
|
|
|
370
385
|
toggleOnEnter = false;
|
|
371
386
|
}
|
|
372
387
|
if (code === ENTER && toggleOnEnter || code === SPACE && toggleOnSpace) {
|
|
373
|
-
this.toggle();
|
|
388
|
+
this.toggle(event);
|
|
374
389
|
}
|
|
375
390
|
if (code === ARROW_DOWN) {
|
|
376
391
|
this.$emit(GL_DROPDOWN_FOCUS_CONTENT, event);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// base dropdown events
|
|
2
2
|
const GL_DROPDOWN_SHOWN = 'shown';
|
|
3
3
|
const GL_DROPDOWN_HIDDEN = 'hidden';
|
|
4
|
+
const GL_DROPDOWN_BEFORE_CLOSE = 'beforeClose';
|
|
4
5
|
const GL_DROPDOWN_FOCUS_CONTENT = 'focusContent';
|
|
5
6
|
|
|
6
7
|
// KEY Codes
|
|
@@ -17,4 +18,4 @@ const POSITION_ABSOLUTE = 'absolute';
|
|
|
17
18
|
const POSITION_FIXED = 'fixed';
|
|
18
19
|
const GL_DROPDOWN_CONTENTS_CLASS = 'gl-new-dropdown-contents';
|
|
19
20
|
|
|
20
|
-
export { ARROW_DOWN, ARROW_UP, END, ENTER, GL_DROPDOWN_CONTENTS_CLASS, GL_DROPDOWN_FOCUS_CONTENT, GL_DROPDOWN_HIDDEN, GL_DROPDOWN_SHOWN, HOME, POSITION_ABSOLUTE, POSITION_FIXED, SPACE };
|
|
21
|
+
export { ARROW_DOWN, ARROW_UP, END, ENTER, GL_DROPDOWN_BEFORE_CLOSE, GL_DROPDOWN_CONTENTS_CLASS, GL_DROPDOWN_FOCUS_CONTENT, GL_DROPDOWN_HIDDEN, GL_DROPDOWN_SHOWN, HOME, POSITION_ABSOLUTE, POSITION_FIXED, SPACE };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import clamp from 'lodash/clamp';
|
|
2
2
|
import uniqueId from 'lodash/uniqueId';
|
|
3
3
|
import { stopEvent, filterVisible } from '../../../../utils/utils';
|
|
4
|
-
import { GL_DROPDOWN_SHOWN, GL_DROPDOWN_HIDDEN, GL_DROPDOWN_FOCUS_CONTENT, POSITION_ABSOLUTE, POSITION_FIXED, HOME, END, ARROW_UP, ARROW_DOWN, ENTER, SPACE, GL_DROPDOWN_CONTENTS_CLASS } from '../constants';
|
|
4
|
+
import { GL_DROPDOWN_SHOWN, GL_DROPDOWN_HIDDEN, GL_DROPDOWN_BEFORE_CLOSE, GL_DROPDOWN_FOCUS_CONTENT, POSITION_ABSOLUTE, POSITION_FIXED, HOME, END, ARROW_UP, ARROW_DOWN, ENTER, SPACE, GL_DROPDOWN_CONTENTS_CLASS } from '../constants';
|
|
5
5
|
import { buttonCategoryOptions, dropdownVariantOptions, buttonSizeOptions, dropdownPlacements } from '../../../../utils/constants';
|
|
6
6
|
import GlBaseDropdown from '../base_dropdown/base_dropdown';
|
|
7
7
|
import GlDisclosureDropdownItem, { ITEM_CLASS } from './disclosure_dropdown_item';
|
|
@@ -16,6 +16,7 @@ var script = {
|
|
|
16
16
|
events: {
|
|
17
17
|
GL_DROPDOWN_SHOWN,
|
|
18
18
|
GL_DROPDOWN_HIDDEN,
|
|
19
|
+
GL_DROPDOWN_BEFORE_CLOSE,
|
|
19
20
|
GL_DROPDOWN_FOCUS_CONTENT
|
|
20
21
|
},
|
|
21
22
|
components: {
|
|
@@ -232,6 +233,14 @@ var script = {
|
|
|
232
233
|
*/
|
|
233
234
|
this.$emit(GL_DROPDOWN_SHOWN);
|
|
234
235
|
},
|
|
236
|
+
onBeforeClose(event) {
|
|
237
|
+
/**
|
|
238
|
+
* Emitted when dropdown is about to be closed
|
|
239
|
+
*
|
|
240
|
+
* @event beforeClose
|
|
241
|
+
*/
|
|
242
|
+
this.$emit(GL_DROPDOWN_BEFORE_CLOSE, event);
|
|
243
|
+
},
|
|
235
244
|
onHide() {
|
|
236
245
|
/**
|
|
237
246
|
* Emitted when dropdown is hidden
|
|
@@ -311,7 +320,7 @@ var script = {
|
|
|
311
320
|
const __vue_script__ = script;
|
|
312
321
|
|
|
313
322
|
/* template */
|
|
314
|
-
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-base-dropdown',{ref:"baseDropdown",staticClass:"gl-disclosure-dropdown",attrs:{"aria-labelledby":_vm.toggleAriaLabelledBy,"toggle-id":_vm.toggleId,"toggle-text":_vm.toggleText,"toggle-class":_vm.toggleClass,"text-sr-only":_vm.textSrOnly,"category":_vm.category,"variant":_vm.variant,"size":_vm.size,"icon":_vm.icon,"disabled":_vm.disabled,"loading":_vm.loading,"no-caret":_vm.noCaret,"placement":_vm.placement,"block":_vm.block,"offset":_vm.dropdownOffset,"fluid-width":_vm.fluidWidth,"positioning-strategy":_vm.positioningStrategy},on:_vm._d({},[_vm.$options.events.GL_DROPDOWN_SHOWN,_vm.onShow,_vm.$options.events.GL_DROPDOWN_HIDDEN,_vm.onHide,_vm.$options.events.GL_DROPDOWN_FOCUS_CONTENT,_vm.onKeydown]),scopedSlots:_vm._u([(_vm.hasCustomToggle)?{key:"toggle",fn:function(){return [_vm._t("toggle")]},proxy:true}:null],null,true)},[_vm._v(" "),_vm._t("header"),_vm._v(" "),_c(_vm.disclosureTag,{ref:"content",tag:"component",class:_vm.$options.GL_DROPDOWN_CONTENTS_CLASS,attrs:{"id":_vm.disclosureId,"aria-labelledby":_vm.listAriaLabelledBy || _vm.toggleId,"data-testid":"disclosure-content","tabindex":"-1"},on:{"keydown":_vm.onKeydown,"click":_vm.handleAutoClose}},[_vm._t("default",function(){return [_vm._l((_vm.items),function(item,index){return [(_vm.isItem(item))?[_c('gl-disclosure-dropdown-item',{key:_vm.uniqueItemId(),attrs:{"item":item},on:{"action":_vm.handleAction},scopedSlots:_vm._u([{key:"list-item",fn:function(){return [_vm._t("list-item",null,{"item":item})]},proxy:true}],null,true)})]:[_c('gl-disclosure-dropdown-group',{key:item.name,attrs:{"bordered":index !== 0,"group":item},on:{"action":_vm.handleAction},scopedSlots:_vm._u([(_vm.$scopedSlots['group-label'])?{key:"group-label",fn:function(){return [_vm._t("group-label",null,{"group":item})]},proxy:true}:null],null,true)},[_vm._v(" "),(_vm.$scopedSlots['list-item'])?_vm._l((item.items),function(groupItem){return _c('gl-disclosure-dropdown-item',{key:_vm.uniqueItemId(),attrs:{"item":groupItem},on:{"action":_vm.handleAction},scopedSlots:_vm._u([{key:"list-item",fn:function(){return [_vm._t("list-item",null,{"item":groupItem})]},proxy:true}],null,true)})}):_vm._e()],2)]]})]})],2),_vm._v(" "),_vm._t("footer")],2)};
|
|
323
|
+
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-base-dropdown',{ref:"baseDropdown",staticClass:"gl-disclosure-dropdown",attrs:{"aria-labelledby":_vm.toggleAriaLabelledBy,"toggle-id":_vm.toggleId,"toggle-text":_vm.toggleText,"toggle-class":_vm.toggleClass,"text-sr-only":_vm.textSrOnly,"category":_vm.category,"variant":_vm.variant,"size":_vm.size,"icon":_vm.icon,"disabled":_vm.disabled,"loading":_vm.loading,"no-caret":_vm.noCaret,"placement":_vm.placement,"block":_vm.block,"offset":_vm.dropdownOffset,"fluid-width":_vm.fluidWidth,"positioning-strategy":_vm.positioningStrategy},on:_vm._d({},[_vm.$options.events.GL_DROPDOWN_SHOWN,_vm.onShow,_vm.$options.events.GL_DROPDOWN_HIDDEN,_vm.onHide,_vm.$options.events.GL_DROPDOWN_BEFORE_CLOSE,_vm.onBeforeClose,_vm.$options.events.GL_DROPDOWN_FOCUS_CONTENT,_vm.onKeydown]),scopedSlots:_vm._u([(_vm.hasCustomToggle)?{key:"toggle",fn:function(){return [_vm._t("toggle")]},proxy:true}:null],null,true)},[_vm._v(" "),_vm._t("header"),_vm._v(" "),_c(_vm.disclosureTag,{ref:"content",tag:"component",class:_vm.$options.GL_DROPDOWN_CONTENTS_CLASS,attrs:{"id":_vm.disclosureId,"aria-labelledby":_vm.listAriaLabelledBy || _vm.toggleId,"data-testid":"disclosure-content","tabindex":"-1"},on:{"keydown":_vm.onKeydown,"click":_vm.handleAutoClose}},[_vm._t("default",function(){return [_vm._l((_vm.items),function(item,index){return [(_vm.isItem(item))?[_c('gl-disclosure-dropdown-item',{key:_vm.uniqueItemId(),attrs:{"item":item},on:{"action":_vm.handleAction},scopedSlots:_vm._u([{key:"list-item",fn:function(){return [_vm._t("list-item",null,{"item":item})]},proxy:true}],null,true)})]:[_c('gl-disclosure-dropdown-group',{key:item.name,attrs:{"bordered":index !== 0,"group":item},on:{"action":_vm.handleAction},scopedSlots:_vm._u([(_vm.$scopedSlots['group-label'])?{key:"group-label",fn:function(){return [_vm._t("group-label",null,{"group":item})]},proxy:true}:null],null,true)},[_vm._v(" "),(_vm.$scopedSlots['list-item'])?_vm._l((item.items),function(groupItem){return _c('gl-disclosure-dropdown-item',{key:_vm.uniqueItemId(),attrs:{"item":groupItem},on:{"action":_vm.handleAction},scopedSlots:_vm._u([{key:"list-item",fn:function(){return [_vm._t("list-item",null,{"item":groupItem})]},proxy:true}],null,true)})}):_vm._e()],2)]]})]})],2),_vm._v(" "),_vm._t("footer")],2)};
|
|
315
324
|
var __vue_staticRenderFns__ = [];
|
|
316
325
|
|
|
317
326
|
/* style */
|
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.0",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -88,8 +88,8 @@
|
|
|
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
94
|
"@gitlab/eslint-plugin": "19.0.0",
|
|
95
95
|
"@gitlab/fonts": "^1.2.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>
|