@gitlab/ui 63.2.1 → 63.3.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/listbox/listbox.js +37 -1
- package/dist/utils/stories_constants.js +7 -1
- package/package.json +1 -1
- package/src/components/base/new_dropdowns/listbox/listbox.spec.js +63 -0
- package/src/components/base/new_dropdowns/listbox/listbox.stories.js +60 -7
- package/src/components/base/new_dropdowns/listbox/listbox.vue +50 -1
- package/src/utils/stories_constants.js +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [63.3.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v63.2.1...v63.3.0) (2023-05-24)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **GlCollapsibleListbox:** Add select all button in header ([eb74768](https://gitlab.com/gitlab-org/gitlab-ui/commit/eb74768163939bdb1b08a168d58e800b440705c2))
|
|
7
|
+
|
|
1
8
|
## [63.2.1](https://gitlab.com/gitlab-org/gitlab-ui/compare/v63.2.0...v63.2.1) (2023-05-23)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -267,6 +267,17 @@ var script = {
|
|
|
267
267
|
required: false,
|
|
268
268
|
default: ''
|
|
269
269
|
},
|
|
270
|
+
/**
|
|
271
|
+
* The select all button's label, to be rendered in the header. If this is omitted, the button is not
|
|
272
|
+
* rendered.
|
|
273
|
+
* The select all button requires a header to be set, so this prop should be used in conjunction with
|
|
274
|
+
* headerText.
|
|
275
|
+
*/
|
|
276
|
+
showSelectAllButtonLabel: {
|
|
277
|
+
type: String,
|
|
278
|
+
required: false,
|
|
279
|
+
default: ''
|
|
280
|
+
},
|
|
270
281
|
/**
|
|
271
282
|
* Render the toggle button as a block element
|
|
272
283
|
*/
|
|
@@ -366,6 +377,15 @@ var script = {
|
|
|
366
377
|
}
|
|
367
378
|
return Boolean(this.selected);
|
|
368
379
|
},
|
|
380
|
+
showSelectAllButton() {
|
|
381
|
+
if (!this.showSelectAllButtonLabel) {
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
if (!this.multiple) {
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
return this.selected.length === 0;
|
|
388
|
+
},
|
|
369
389
|
showIntersectionObserver() {
|
|
370
390
|
return this.infiniteScroll && !this.infiniteScrollLoading && !this.loading && !this.searching;
|
|
371
391
|
},
|
|
@@ -421,6 +441,14 @@ var script = {
|
|
|
421
441
|
}
|
|
422
442
|
}
|
|
423
443
|
},
|
|
444
|
+
showSelectAllButtonLabel: {
|
|
445
|
+
immediate: true,
|
|
446
|
+
handler(showSelectAllButtonLabel) {
|
|
447
|
+
if (showSelectAllButtonLabel && !this.headerText) {
|
|
448
|
+
throw new Error('The select all button cannot be rendered without a header. Either provide a header via the headerText prop, or do not provide the showSelectAllButtonLabel prop.');
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
},
|
|
424
452
|
infiniteScroll: {
|
|
425
453
|
immediate: true,
|
|
426
454
|
handler(newValue) {
|
|
@@ -576,6 +604,14 @@ var script = {
|
|
|
576
604
|
this.$emit('reset');
|
|
577
605
|
this.closeAndFocus();
|
|
578
606
|
},
|
|
607
|
+
onSelectAllButtonClicked() {
|
|
608
|
+
/**
|
|
609
|
+
* Emitted when the select all button is clicked
|
|
610
|
+
*
|
|
611
|
+
* @event select-all
|
|
612
|
+
*/
|
|
613
|
+
this.$emit('select-all');
|
|
614
|
+
},
|
|
579
615
|
closeAndFocus() {
|
|
580
616
|
this.$refs.baseDropdown.closeAndFocus();
|
|
581
617
|
},
|
|
@@ -632,7 +668,7 @@ var script = {
|
|
|
632
668
|
const __vue_script__ = script;
|
|
633
669
|
|
|
634
670
|
/* template */
|
|
635
|
-
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-base-dropdown',{ref:"baseDropdown",attrs:{"aria-haspopup":"listbox","aria-labelledby":_vm.toggleAriaLabelledBy,"block":_vm.block,"toggle-id":_vm.toggleId,"toggle-text":_vm.listboxToggleText,"toggle-class":_vm.toggleButtonClasses,"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,"popper-options":_vm.popperOptions,"fluid-width":_vm.fluidWidth},on:_vm._d({},[_vm.$options.events.GL_DROPDOWN_SHOWN,_vm.onShow,_vm.$options.events.GL_DROPDOWN_HIDDEN,_vm.onHide]),scopedSlots:_vm._u([(_vm.hasCustomToggle)?{key:"toggle",fn:function(){return [_vm._t("toggle")]},proxy:true}:null],null,true)},[_vm._v(" "),(_vm.headerText)?_c('div',{staticClass:"gl-display-flex gl-align-items-center gl-p-4! gl-min-h-8",class:_vm.$options.HEADER_ITEMS_BORDER_CLASSES},[_c('div',{staticClass:"gl-flex-grow-1 gl-font-weight-bold gl-font-sm gl-pr-2",attrs:{"id":_vm.headerId,"data-testid":"listbox-header-text"}},[_vm._v("\n "+_vm._s(_vm.headerText)+"\n ")]),_vm._v(" "),(_vm.showResetButton)?_c('gl-button',{staticClass:"gl-focus-inset-border-2-blue-400! gl-flex-shrink-0 gl-font-sm! gl-px-2! gl-py-2! gl-w-auto! gl-m-0!",attrs:{"category":"tertiary","data-testid":"listbox-reset-button"},on:{"click":_vm.onResetButtonClicked}},[_vm._v("\n "+_vm._s(_vm.resetButtonLabel)+"\n ")]):_vm._e()],1):_vm._e(),_vm._v(" "),(_vm.searchable)?_c('div',{class:_vm.$options.HEADER_ITEMS_BORDER_CLASSES},[_c('gl-listbox-search-input',{ref:"searchBox",attrs:{"aria-owns":_vm.listboxId,"data-testid":"listbox-search-input","placeholder":_vm.searchPlaceholder},on:{"input":_vm.search,"keydown":[function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"enter",13,$event.key,"Enter")){ return null; }$event.preventDefault();},_vm.onKeydown]},model:{value:(_vm.searchStr),callback:function ($$v) {_vm.searchStr=$$v;},expression:"searchStr"}}),_vm._v(" "),(_vm.searching)?_c('gl-loading-icon',{staticClass:"gl-my-3",attrs:{"data-testid":"listbox-search-loader","size":"md"}}):_vm._e()],1):_vm._e(),_vm._v(" "),(_vm.showList)?_c(_vm.listboxTag,{ref:"list",tag:"component",staticClass:"gl-new-dropdown-contents gl-new-dropdown-contents-with-scrim-overlay",class:_vm.listboxClasses,attrs:{"id":_vm.listboxId,"aria-labelledby":_vm.listAriaLabelledBy || _vm.headerId || _vm.toggleId,"role":"listbox","tabindex":"-1"},on:{"keydown":_vm.onKeydown}},[_c(_vm.itemTag,{tag:"component",staticClass:"top-scrim-wrapper",attrs:{"aria-hidden":"true","data-testid":"top-scrim"}},[_c('div',{staticClass:"top-scrim",class:{ 'top-scrim-light': !_vm.hasHeader, 'top-scrim-dark': _vm.hasHeader }})]),_vm._v(" "),_c(_vm.itemTag,{ref:"top-boundary",tag:"component",attrs:{"aria-hidden":"true"}}),_vm._v(" "),_vm._l((_vm.items),function(item,index){return [(_vm.isOption(item))?[_c('gl-listbox-item',_vm._b({key:item.value,attrs:{"data-testid":("listbox-item-" + (item.value)),"is-selected":_vm.isSelected(item),"is-focused":_vm.isFocused(item),"is-check-centered":_vm.isCheckCentered},on:{"select":function($event){return _vm.onSelect(item, $event)}}},'gl-listbox-item',_vm.listboxItemMoreItemsAriaAttributes(index),false),[_vm._t("list-item",function(){return [_vm._v("\n "+_vm._s(item.text)+"\n ")]},{"item":item})],2)]:[_c('gl-listbox-group',{key:item.text,class:_vm.groupClasses(index),attrs:{"name":item.text,"text-sr-only":item.textSrOnly},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._l((item.options),function(option){return _c('gl-listbox-item',{key:option.value,attrs:{"data-testid":("listbox-item-" + (option.value)),"is-selected":_vm.isSelected(option),"is-focused":_vm.isFocused(option),"is-check-centered":_vm.isCheckCentered},on:{"select":function($event){return _vm.onSelect(option, $event)}}},[_vm._t("list-item",function(){return [_vm._v("\n "+_vm._s(option.text)+"\n ")]},{"item":option})],2)})],2)]]}),_vm._v(" "),(_vm.infiniteScrollLoading)?_c(_vm.itemTag,{tag:"component"},[_c('gl-loading-icon',{staticClass:"gl-my-3",attrs:{"data-testid":"listbox-infinite-scroll-loader","size":"md"}})],1):_vm._e(),_vm._v(" "),(_vm.showIntersectionObserver)?_c('gl-intersection-observer',{on:{"appear":_vm.onIntersectionObserverAppear}}):_vm._e(),_vm._v(" "),_c(_vm.itemTag,{ref:"bottom-boundary",tag:"component",attrs:{"aria-hidden":"true"}}),_vm._v(" "),_c(_vm.itemTag,{tag:"component",staticClass:"bottom-scrim-wrapper",attrs:{"aria-hidden":"true","data-testid":"bottom-scrim"}},[_c('div',{staticClass:"bottom-scrim",class:{ 'gl-rounded-0!': _vm.hasFooter }})])],2):_vm._e(),_vm._v(" "),(_vm.announceSRSearchResults)?_c('span',{staticClass:"gl-sr-only",attrs:{"data-testid":"listbox-number-of-results","aria-live":"assertive"}},[_vm._t("search-summary-sr-only")],2):(_vm.showNoResultsText)?_c('div',{staticClass:"gl-pl-7 gl-pr-5 gl-py-3 gl-font-base gl-text-gray-600",attrs:{"aria-live":"assertive","data-testid":"listbox-no-results-text"}},[_vm._v("\n "+_vm._s(_vm.noResultsText)+"\n ")]):_vm._e(),_vm._v(" "),_vm._t("footer")],2)};
|
|
671
|
+
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-base-dropdown',{ref:"baseDropdown",attrs:{"aria-haspopup":"listbox","aria-labelledby":_vm.toggleAriaLabelledBy,"block":_vm.block,"toggle-id":_vm.toggleId,"toggle-text":_vm.listboxToggleText,"toggle-class":_vm.toggleButtonClasses,"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,"popper-options":_vm.popperOptions,"fluid-width":_vm.fluidWidth},on:_vm._d({},[_vm.$options.events.GL_DROPDOWN_SHOWN,_vm.onShow,_vm.$options.events.GL_DROPDOWN_HIDDEN,_vm.onHide]),scopedSlots:_vm._u([(_vm.hasCustomToggle)?{key:"toggle",fn:function(){return [_vm._t("toggle")]},proxy:true}:null],null,true)},[_vm._v(" "),(_vm.headerText)?_c('div',{staticClass:"gl-display-flex gl-align-items-center gl-p-4! gl-min-h-8",class:_vm.$options.HEADER_ITEMS_BORDER_CLASSES},[_c('div',{staticClass:"gl-flex-grow-1 gl-font-weight-bold gl-font-sm gl-pr-2",attrs:{"id":_vm.headerId,"data-testid":"listbox-header-text"}},[_vm._v("\n "+_vm._s(_vm.headerText)+"\n ")]),_vm._v(" "),(_vm.showResetButton)?_c('gl-button',{staticClass:"gl-focus-inset-border-2-blue-400! gl-flex-shrink-0 gl-font-sm! gl-px-2! gl-py-2! gl-w-auto! gl-m-0! gl-max-w-50p gl-text-overflow-ellipsis",attrs:{"category":"tertiary","data-testid":"listbox-reset-button"},on:{"click":_vm.onResetButtonClicked}},[_vm._v("\n "+_vm._s(_vm.resetButtonLabel)+"\n ")]):_vm._e(),_vm._v(" "),(_vm.showSelectAllButton)?_c('gl-button',{staticClass:"gl-focus-inset-border-2-blue-400! gl-flex-shrink-0 gl-font-sm! gl-px-2! gl-py-2! gl-w-auto! gl-m-0! gl-max-w-50p gl-text-overflow-ellipsis",attrs:{"category":"tertiary","data-testid":"listbox-select-all-button"},on:{"click":_vm.onSelectAllButtonClicked}},[_vm._v("\n "+_vm._s(_vm.showSelectAllButtonLabel)+"\n ")]):_vm._e()],1):_vm._e(),_vm._v(" "),(_vm.searchable)?_c('div',{class:_vm.$options.HEADER_ITEMS_BORDER_CLASSES},[_c('gl-listbox-search-input',{ref:"searchBox",attrs:{"aria-owns":_vm.listboxId,"data-testid":"listbox-search-input","placeholder":_vm.searchPlaceholder},on:{"input":_vm.search,"keydown":[function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"enter",13,$event.key,"Enter")){ return null; }$event.preventDefault();},_vm.onKeydown]},model:{value:(_vm.searchStr),callback:function ($$v) {_vm.searchStr=$$v;},expression:"searchStr"}}),_vm._v(" "),(_vm.searching)?_c('gl-loading-icon',{staticClass:"gl-my-3",attrs:{"data-testid":"listbox-search-loader","size":"md"}}):_vm._e()],1):_vm._e(),_vm._v(" "),(_vm.showList)?_c(_vm.listboxTag,{ref:"list",tag:"component",staticClass:"gl-new-dropdown-contents gl-new-dropdown-contents-with-scrim-overlay",class:_vm.listboxClasses,attrs:{"id":_vm.listboxId,"aria-labelledby":_vm.listAriaLabelledBy || _vm.headerId || _vm.toggleId,"role":"listbox","tabindex":"-1"},on:{"keydown":_vm.onKeydown}},[_c(_vm.itemTag,{tag:"component",staticClass:"top-scrim-wrapper",attrs:{"aria-hidden":"true","data-testid":"top-scrim"}},[_c('div',{staticClass:"top-scrim",class:{ 'top-scrim-light': !_vm.hasHeader, 'top-scrim-dark': _vm.hasHeader }})]),_vm._v(" "),_c(_vm.itemTag,{ref:"top-boundary",tag:"component",attrs:{"aria-hidden":"true"}}),_vm._v(" "),_vm._l((_vm.items),function(item,index){return [(_vm.isOption(item))?[_c('gl-listbox-item',_vm._b({key:item.value,attrs:{"data-testid":("listbox-item-" + (item.value)),"is-selected":_vm.isSelected(item),"is-focused":_vm.isFocused(item),"is-check-centered":_vm.isCheckCentered},on:{"select":function($event){return _vm.onSelect(item, $event)}}},'gl-listbox-item',_vm.listboxItemMoreItemsAriaAttributes(index),false),[_vm._t("list-item",function(){return [_vm._v("\n "+_vm._s(item.text)+"\n ")]},{"item":item})],2)]:[_c('gl-listbox-group',{key:item.text,class:_vm.groupClasses(index),attrs:{"name":item.text,"text-sr-only":item.textSrOnly},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._l((item.options),function(option){return _c('gl-listbox-item',{key:option.value,attrs:{"data-testid":("listbox-item-" + (option.value)),"is-selected":_vm.isSelected(option),"is-focused":_vm.isFocused(option),"is-check-centered":_vm.isCheckCentered},on:{"select":function($event){return _vm.onSelect(option, $event)}}},[_vm._t("list-item",function(){return [_vm._v("\n "+_vm._s(option.text)+"\n ")]},{"item":option})],2)})],2)]]}),_vm._v(" "),(_vm.infiniteScrollLoading)?_c(_vm.itemTag,{tag:"component"},[_c('gl-loading-icon',{staticClass:"gl-my-3",attrs:{"data-testid":"listbox-infinite-scroll-loader","size":"md"}})],1):_vm._e(),_vm._v(" "),(_vm.showIntersectionObserver)?_c('gl-intersection-observer',{on:{"appear":_vm.onIntersectionObserverAppear}}):_vm._e(),_vm._v(" "),_c(_vm.itemTag,{ref:"bottom-boundary",tag:"component",attrs:{"aria-hidden":"true"}}),_vm._v(" "),_c(_vm.itemTag,{tag:"component",staticClass:"bottom-scrim-wrapper",attrs:{"aria-hidden":"true","data-testid":"bottom-scrim"}},[_c('div',{staticClass:"bottom-scrim",class:{ 'gl-rounded-0!': _vm.hasFooter }})])],2):_vm._e(),_vm._v(" "),(_vm.announceSRSearchResults)?_c('span',{staticClass:"gl-sr-only",attrs:{"data-testid":"listbox-number-of-results","aria-live":"assertive"}},[_vm._t("search-summary-sr-only")],2):(_vm.showNoResultsText)?_c('div',{staticClass:"gl-pl-7 gl-pr-5 gl-py-3 gl-font-base gl-text-gray-600",attrs:{"aria-live":"assertive","data-testid":"listbox-no-results-text"}},[_vm._v("\n "+_vm._s(_vm.noResultsText)+"\n ")]):_vm._e(),_vm._v(" "),_vm._t("footer")],2)};
|
|
636
672
|
var __vue_staticRenderFns__ = [];
|
|
637
673
|
|
|
638
674
|
/* style */
|
|
@@ -20,4 +20,10 @@ const SERIES_NAME = {
|
|
|
20
20
|
[SERIES_NAME_LONG_WITHOUT_SPACES]: 'Series_name_long._Lorem_ipsum_dolor_sit_amet,_consectetur_adipiscing_elit._Sed_tincidunt_interdum_sapien_ut_blandit._Nulla_fermentum_nisi_id_euismod_vulputate._END'
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Reused constants for ListBox
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const LISTBOX_CONTAINER_HEIGHT = '370px';
|
|
28
|
+
|
|
29
|
+
export { ARG_TYPE_SUBCATEGORY_ACCESSIBILITY, ARG_TYPE_SUBCATEGORY_INFINITE_SCROLL, ARG_TYPE_SUBCATEGORY_LOOK_AND_FEEL, ARG_TYPE_SUBCATEGORY_SEARCH, ARG_TYPE_SUBCATEGORY_STATE, LISTBOX_CONTAINER_HEIGHT, SERIES_NAME, SERIES_NAME_LONG, SERIES_NAME_LONG_WITHOUT_SPACES, SERIES_NAME_SHORT };
|
package/package.json
CHANGED
|
@@ -41,6 +41,7 @@ describe('GlCollapsibleListbox', () => {
|
|
|
41
41
|
const findLoadingIcon = () => wrapper.find("[data-testid='listbox-search-loader']");
|
|
42
42
|
const findSRNumberOfResultsText = () => wrapper.find("[data-testid='listbox-number-of-results']");
|
|
43
43
|
const findResetButton = () => wrapper.find("[data-testid='listbox-reset-button']");
|
|
44
|
+
const findSelectAllButton = () => wrapper.find("[data-testid='listbox-select-all-button']");
|
|
44
45
|
const findIntersectionObserver = () => wrapper.findComponent(GlIntersectionObserver);
|
|
45
46
|
|
|
46
47
|
it('passes custom popper.js options to the base dropdown', () => {
|
|
@@ -514,6 +515,68 @@ describe('GlCollapsibleListbox', () => {
|
|
|
514
515
|
});
|
|
515
516
|
});
|
|
516
517
|
|
|
518
|
+
describe('with select all action', () => {
|
|
519
|
+
it('throws an error when enabling the select action without a header', () => {
|
|
520
|
+
expect(() => {
|
|
521
|
+
buildWrapper({ showSelectAllButtonLabel: 'Select All' });
|
|
522
|
+
}).toThrow(
|
|
523
|
+
'The select all button cannot be rendered without a header. Either provide a header via the headerText prop, or do not provide the showSelectAllButtonLabel prop.'
|
|
524
|
+
);
|
|
525
|
+
expect(wrapper).toHaveLoggedVueErrors();
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
it.each`
|
|
529
|
+
multiple | expectedResult
|
|
530
|
+
${false} | ${false}
|
|
531
|
+
${true} | ${true}
|
|
532
|
+
`(
|
|
533
|
+
'shows the select all button if the label is provided and the selection is empty and multiple option is $multiple',
|
|
534
|
+
({ multiple, expectedResult }) => {
|
|
535
|
+
buildWrapper({
|
|
536
|
+
headerText: 'Select assignee',
|
|
537
|
+
resetButtonLabel: 'Unassign',
|
|
538
|
+
showSelectAllButtonLabel: 'Select All',
|
|
539
|
+
selected: [],
|
|
540
|
+
items: mockOptions,
|
|
541
|
+
multiple,
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
expect(findResetButton().exists()).toBe(!expectedResult);
|
|
545
|
+
expect(findSelectAllButton().exists()).toBe(expectedResult);
|
|
546
|
+
}
|
|
547
|
+
);
|
|
548
|
+
|
|
549
|
+
it('has the label text "Select All" if the label is provided and the selection is empty', () => {
|
|
550
|
+
buildWrapper({
|
|
551
|
+
headerText: 'Select assignee',
|
|
552
|
+
resetButtonLabel: 'Unassign',
|
|
553
|
+
showSelectAllButtonLabel: 'Select All',
|
|
554
|
+
selected: [],
|
|
555
|
+
items: mockOptions,
|
|
556
|
+
multiple: true,
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
expect(findSelectAllButton().text()).toBe('Select All');
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
it('on click, emits the select-all event and calls closeAndFocus()', () => {
|
|
563
|
+
buildWrapper({
|
|
564
|
+
headerText: 'Select assignee',
|
|
565
|
+
resetButtonLabel: 'Unassign',
|
|
566
|
+
showSelectAllButtonLabel: 'Select All',
|
|
567
|
+
selected: [],
|
|
568
|
+
items: mockOptions,
|
|
569
|
+
multiple: true,
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
expect(wrapper.emitted('select-all')).toBe(undefined);
|
|
573
|
+
|
|
574
|
+
findSelectAllButton().trigger('click');
|
|
575
|
+
|
|
576
|
+
expect(wrapper.emitted('select-all')).toHaveLength(1);
|
|
577
|
+
});
|
|
578
|
+
});
|
|
579
|
+
|
|
517
580
|
describe('when `infiniteScroll` prop is `true`', () => {
|
|
518
581
|
it('should throw an error when items are groups', () => {
|
|
519
582
|
expect(() => {
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
ARG_TYPE_SUBCATEGORY_SEARCH,
|
|
21
21
|
ARG_TYPE_SUBCATEGORY_ACCESSIBILITY,
|
|
22
22
|
ARG_TYPE_SUBCATEGORY_INFINITE_SCROLL,
|
|
23
|
+
LISTBOX_CONTAINER_HEIGHT,
|
|
23
24
|
} from '../../../../utils/stories_constants';
|
|
24
25
|
import { POSITION } from '../../../utilities/truncate/constants';
|
|
25
26
|
import readme from './listbox.md';
|
|
@@ -55,6 +56,7 @@ const generateProps = ({
|
|
|
55
56
|
toggleAriaLabelledBy,
|
|
56
57
|
listAriaLabelledBy,
|
|
57
58
|
resetButtonLabel = defaultValue('resetButtonLabel'),
|
|
59
|
+
showSelectAllButtonLabel = defaultValue('showSelectAllButtonLabel'),
|
|
58
60
|
startOpened = true,
|
|
59
61
|
fluidWidth,
|
|
60
62
|
} = {}) => ({
|
|
@@ -83,6 +85,7 @@ const generateProps = ({
|
|
|
83
85
|
toggleAriaLabelledBy,
|
|
84
86
|
listAriaLabelledBy,
|
|
85
87
|
resetButtonLabel,
|
|
88
|
+
showSelectAllButtonLabel,
|
|
86
89
|
startOpened,
|
|
87
90
|
fluidWidth,
|
|
88
91
|
});
|
|
@@ -114,6 +117,7 @@ const makeBindings = (overrides = {}) =>
|
|
|
114
117
|
':toggle-aria-labelled-by': 'toggleAriaLabelledBy',
|
|
115
118
|
':list-aria-labelled-by': 'listAriaLabelledBy',
|
|
116
119
|
':reset-button-label': 'resetButtonLabel',
|
|
120
|
+
':show-select-all-button-label': 'showSelectAllButtonLabel',
|
|
117
121
|
':fluid-width': 'fluidWidth',
|
|
118
122
|
...overrides,
|
|
119
123
|
})
|
|
@@ -160,7 +164,7 @@ export const Default = (args, { argTypes }) => ({
|
|
|
160
164
|
}),
|
|
161
165
|
});
|
|
162
166
|
Default.args = generateProps({ toggleAriaLabelledBy: 'listbox-label' });
|
|
163
|
-
Default.decorators = [makeContainer({ height:
|
|
167
|
+
Default.decorators = [makeContainer({ height: LISTBOX_CONTAINER_HEIGHT })];
|
|
164
168
|
|
|
165
169
|
export const HeaderAndFooter = (args, { argTypes }) => ({
|
|
166
170
|
props: Object.keys(argTypes),
|
|
@@ -181,7 +185,7 @@ export const HeaderAndFooter = (args, { argTypes }) => ({
|
|
|
181
185
|
}
|
|
182
186
|
},
|
|
183
187
|
methods: {
|
|
184
|
-
|
|
188
|
+
selectAllItems() {
|
|
185
189
|
const allValues = mockOptions.map(({ value }) => value);
|
|
186
190
|
this.selected = [...allValues];
|
|
187
191
|
},
|
|
@@ -193,7 +197,7 @@ export const HeaderAndFooter = (args, { argTypes }) => ({
|
|
|
193
197
|
`
|
|
194
198
|
<template #footer>
|
|
195
199
|
<div class="gl-border-t-solid gl-border-t-1 gl-border-t-gray-100 gl-display-flex gl-flex-direction-column gl-p-2! gl-pt-0!">
|
|
196
|
-
<gl-button @click="
|
|
200
|
+
<gl-button @click="selectAllItems" category="tertiary" block class="gl-justify-content-start! gl-mt-2!"">
|
|
197
201
|
Select all
|
|
198
202
|
</gl-button>
|
|
199
203
|
<gl-button category="tertiary" block class="gl-justify-content-start! gl-mt-2!">
|
|
@@ -216,7 +220,56 @@ HeaderAndFooter.args = generateProps({
|
|
|
216
220
|
multiple: true,
|
|
217
221
|
block: true,
|
|
218
222
|
});
|
|
219
|
-
HeaderAndFooter.decorators = [makeContainer({ height:
|
|
223
|
+
HeaderAndFooter.decorators = [makeContainer({ height: LISTBOX_CONTAINER_HEIGHT })];
|
|
224
|
+
|
|
225
|
+
export const HeaderActions = (args, { argTypes }) => ({
|
|
226
|
+
props: Object.keys(argTypes),
|
|
227
|
+
components: {
|
|
228
|
+
GlCollapsibleListbox,
|
|
229
|
+
GlSearchBoxByType,
|
|
230
|
+
GlButtonGroup,
|
|
231
|
+
GlButton,
|
|
232
|
+
},
|
|
233
|
+
data() {
|
|
234
|
+
return {
|
|
235
|
+
selected: [],
|
|
236
|
+
};
|
|
237
|
+
},
|
|
238
|
+
computed: {
|
|
239
|
+
allValues() {
|
|
240
|
+
return mockOptions.map(({ value }) => value);
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
mounted() {
|
|
244
|
+
if (this.startOpened) {
|
|
245
|
+
openListbox(this);
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
methods: {
|
|
249
|
+
selectAllItems() {
|
|
250
|
+
this.selected = [...this.allValues];
|
|
251
|
+
},
|
|
252
|
+
onReset() {
|
|
253
|
+
this.selected = [];
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
template: template('', {
|
|
257
|
+
bindingOverrides: {
|
|
258
|
+
'@reset': 'onReset',
|
|
259
|
+
'@select-all': 'selectAllItems',
|
|
260
|
+
},
|
|
261
|
+
}),
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
HeaderActions.args = generateProps({
|
|
265
|
+
toggleText: 'Header actions',
|
|
266
|
+
headerText: 'Assign to department',
|
|
267
|
+
resetButtonLabel: 'Unassign',
|
|
268
|
+
showSelectAllButtonLabel: 'Select All',
|
|
269
|
+
multiple: true,
|
|
270
|
+
block: true,
|
|
271
|
+
});
|
|
272
|
+
HeaderActions.decorators = [makeContainer({ height: LISTBOX_CONTAINER_HEIGHT })];
|
|
220
273
|
|
|
221
274
|
export const CustomListItem = (args, { argTypes }) => ({
|
|
222
275
|
props: Object.keys(argTypes),
|
|
@@ -624,7 +677,7 @@ Searchable.args = generateProps({
|
|
|
624
677
|
searchable: true,
|
|
625
678
|
searchPlaceholder: 'Find department',
|
|
626
679
|
});
|
|
627
|
-
Searchable.decorators = [makeContainer({ height:
|
|
680
|
+
Searchable.decorators = [makeContainer({ height: LISTBOX_CONTAINER_HEIGHT })];
|
|
628
681
|
|
|
629
682
|
export const SearchableGroups = (args, { argTypes }) => ({
|
|
630
683
|
props: Object.keys(argTypes),
|
|
@@ -712,7 +765,7 @@ SearchableGroups.args = generateProps({
|
|
|
712
765
|
searchable: true,
|
|
713
766
|
items: mockGroups,
|
|
714
767
|
});
|
|
715
|
-
SearchableGroups.decorators = [makeContainer({ height:
|
|
768
|
+
SearchableGroups.decorators = [makeContainer({ height: LISTBOX_CONTAINER_HEIGHT })];
|
|
716
769
|
|
|
717
770
|
export const InfiniteScroll = (
|
|
718
771
|
args,
|
|
@@ -764,7 +817,7 @@ InfiniteScroll.parameters = {
|
|
|
764
817
|
storyshots: { disable: true },
|
|
765
818
|
};
|
|
766
819
|
InfiniteScroll.args = generateProps();
|
|
767
|
-
InfiniteScroll.decorators = [makeContainer({ height:
|
|
820
|
+
InfiniteScroll.decorators = [makeContainer({ height: LISTBOX_CONTAINER_HEIGHT })];
|
|
768
821
|
|
|
769
822
|
export const WithLongContent = (args, { argTypes: { items, ...argTypes } }) => ({
|
|
770
823
|
props: Object.keys(argTypes),
|
|
@@ -280,6 +280,17 @@ export default {
|
|
|
280
280
|
required: false,
|
|
281
281
|
default: '',
|
|
282
282
|
},
|
|
283
|
+
/**
|
|
284
|
+
* The select all button's label, to be rendered in the header. If this is omitted, the button is not
|
|
285
|
+
* rendered.
|
|
286
|
+
* The select all button requires a header to be set, so this prop should be used in conjunction with
|
|
287
|
+
* headerText.
|
|
288
|
+
*/
|
|
289
|
+
showSelectAllButtonLabel: {
|
|
290
|
+
type: String,
|
|
291
|
+
required: false,
|
|
292
|
+
default: '',
|
|
293
|
+
},
|
|
283
294
|
/**
|
|
284
295
|
* Render the toggle button as a block element
|
|
285
296
|
*/
|
|
@@ -373,6 +384,17 @@ export default {
|
|
|
373
384
|
}
|
|
374
385
|
return Boolean(this.selected);
|
|
375
386
|
},
|
|
387
|
+
showSelectAllButton() {
|
|
388
|
+
if (!this.showSelectAllButtonLabel) {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (!this.multiple) {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return this.selected.length === 0;
|
|
397
|
+
},
|
|
376
398
|
showIntersectionObserver() {
|
|
377
399
|
return this.infiniteScroll && !this.infiniteScrollLoading && !this.loading && !this.searching;
|
|
378
400
|
},
|
|
@@ -432,6 +454,16 @@ export default {
|
|
|
432
454
|
}
|
|
433
455
|
},
|
|
434
456
|
},
|
|
457
|
+
showSelectAllButtonLabel: {
|
|
458
|
+
immediate: true,
|
|
459
|
+
handler(showSelectAllButtonLabel) {
|
|
460
|
+
if (showSelectAllButtonLabel && !this.headerText) {
|
|
461
|
+
throw new Error(
|
|
462
|
+
'The select all button cannot be rendered without a header. Either provide a header via the headerText prop, or do not provide the showSelectAllButtonLabel prop.'
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
},
|
|
435
467
|
infiniteScroll: {
|
|
436
468
|
immediate: true,
|
|
437
469
|
handler(newValue) {
|
|
@@ -591,6 +623,14 @@ export default {
|
|
|
591
623
|
this.$emit('reset');
|
|
592
624
|
this.closeAndFocus();
|
|
593
625
|
},
|
|
626
|
+
onSelectAllButtonClicked() {
|
|
627
|
+
/**
|
|
628
|
+
* Emitted when the select all button is clicked
|
|
629
|
+
*
|
|
630
|
+
* @event select-all
|
|
631
|
+
*/
|
|
632
|
+
this.$emit('select-all');
|
|
633
|
+
},
|
|
594
634
|
closeAndFocus() {
|
|
595
635
|
this.$refs.baseDropdown.closeAndFocus();
|
|
596
636
|
},
|
|
@@ -690,12 +730,21 @@ export default {
|
|
|
690
730
|
<gl-button
|
|
691
731
|
v-if="showResetButton"
|
|
692
732
|
category="tertiary"
|
|
693
|
-
class="gl-focus-inset-border-2-blue-400! gl-flex-shrink-0 gl-font-sm! gl-px-2! gl-py-2! gl-w-auto! gl-m-0!"
|
|
733
|
+
class="gl-focus-inset-border-2-blue-400! gl-flex-shrink-0 gl-font-sm! gl-px-2! gl-py-2! gl-w-auto! gl-m-0! gl-max-w-50p gl-text-overflow-ellipsis"
|
|
694
734
|
data-testid="listbox-reset-button"
|
|
695
735
|
@click="onResetButtonClicked"
|
|
696
736
|
>
|
|
697
737
|
{{ resetButtonLabel }}
|
|
698
738
|
</gl-button>
|
|
739
|
+
<gl-button
|
|
740
|
+
v-if="showSelectAllButton"
|
|
741
|
+
category="tertiary"
|
|
742
|
+
class="gl-focus-inset-border-2-blue-400! gl-flex-shrink-0 gl-font-sm! gl-px-2! gl-py-2! gl-w-auto! gl-m-0! gl-max-w-50p gl-text-overflow-ellipsis"
|
|
743
|
+
data-testid="listbox-select-all-button"
|
|
744
|
+
@click="onSelectAllButtonClicked"
|
|
745
|
+
>
|
|
746
|
+
{{ showSelectAllButtonLabel }}
|
|
747
|
+
</gl-button>
|
|
699
748
|
</div>
|
|
700
749
|
|
|
701
750
|
<div v-if="searchable" :class="$options.HEADER_ITEMS_BORDER_CLASSES">
|
|
@@ -22,3 +22,9 @@ export const SERIES_NAME = {
|
|
|
22
22
|
[SERIES_NAME_LONG_WITHOUT_SPACES]:
|
|
23
23
|
'Series_name_long._Lorem_ipsum_dolor_sit_amet,_consectetur_adipiscing_elit._Sed_tincidunt_interdum_sapien_ut_blandit._Nulla_fermentum_nisi_id_euismod_vulputate._END',
|
|
24
24
|
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Reused constants for ListBox
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
export const LISTBOX_CONTAINER_HEIGHT = '370px';
|