@gitlab/ui
Version:
GitLab UI Components
811 lines (794 loc) • 28.9 kB
JavaScript
import clamp from 'lodash/clamp';
import uniqueId from 'lodash/uniqueId';
import { stopEvent } from '../../../../utils/utils';
import { GL_DROPDOWN_SHOWN, GL_DROPDOWN_HIDDEN, POSITION_ABSOLUTE, POSITION_FIXED, GL_DROPDOWN_CONTENTS_CLASS, HOME, END, ARROW_UP, ARROW_DOWN, ENTER } from '../constants';
import { buttonCategoryOptions, dropdownVariantOptions, buttonSizeOptions, dropdownPlacements } from '../../../../utils/constants';
import GlButton from '../../button/button';
import GlLoadingIcon from '../../loading_icon/loading_icon';
import GlIntersectionObserver from '../../../utilities/intersection_observer/intersection_observer';
import GlSearchBoxByType from '../../search_box_by_type/search_box_by_type';
import GlBaseDropdown from '../base_dropdown/base_dropdown';
import { translatePlural } from '../../../../utils/i18n';
import GlListboxItem from './listbox_item';
import GlListboxSearchInput from './listbox_search_input';
import GlListboxGroup from './listbox_group';
import { itemsValidator, isOption, flattenedOptions } from './utils';
import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
//
const ITEM_SELECTOR = '[role="option"]';
const ITEM_NULL_KEY = Symbol('null-key');
const HEADER_ITEMS_BORDER_CLASSES = ['gl-border-b-1', 'gl-border-b-solid', 'gl-border-b-dropdown-divider'];
const GROUP_TOP_BORDER_CLASSES = ['gl-border-t-1', 'gl-border-t-solid', 'gl-border-t-dropdown-divider', 'gl-pt-1', 'gl-mt-2'];
const SEARCH_INPUT_SELECTOR = '.gl-listbox-search-input';
var script = {
name: 'GlCollapsibleListbox',
HEADER_ITEMS_BORDER_CLASSES,
events: {
GL_DROPDOWN_SHOWN,
GL_DROPDOWN_HIDDEN
},
components: {
GlBaseDropdown,
GlListboxItem,
GlListboxGroup,
GlButton,
GlSearchBoxByType,
GlListboxSearchInput,
GlLoadingIcon,
GlIntersectionObserver
},
model: {
prop: 'selected',
event: 'select'
},
props: {
/**
* Items to display in the dropdown
*/
items: {
type: Array,
required: false,
default: () => [],
validator: itemsValidator
},
/**
* Array of selected items values for multi-select and selected item value for single-select
*/
selected: {
type: [Array, String, Number, null],
required: false,
default: () => []
},
/**
* Allow multi-selection
*/
multiple: {
type: Boolean,
required: false,
default: false
},
/**
* Toggle button text
*/
toggleText: {
type: String,
required: false,
default: ''
},
/**
* Toggle text to be read by screen readers only
*/
textSrOnly: {
type: Boolean,
required: false,
default: false
},
/** The header text */
headerText: {
type: String,
required: false,
default: ''
},
/**
* Styling option - dropdown's toggle category
*/
category: {
type: String,
required: false,
default: buttonCategoryOptions.primary,
validator: value => value in buttonCategoryOptions
},
/**
* Styling option - dropdown's toggle variant
*/
variant: {
type: String,
required: false,
default: dropdownVariantOptions.default,
validator: value => value in dropdownVariantOptions
},
/**
* The size of the dropdown toggle
*/
size: {
type: String,
required: false,
default: 'medium',
validator: value => value in buttonSizeOptions
},
/**
* Icon name that will be rendered in the toggle button
*/
icon: {
type: String,
required: false,
default: ''
},
/**
* Set to "true" to disable the dropdown
*/
disabled: {
type: Boolean,
required: false,
default: false
},
/**
* Set to "true" when dropdown content (items) is loading
* It will render a small loader in the dropdown toggle and make it disabled
*/
loading: {
type: Boolean,
required: false,
default: false
},
/**
* Additional CSS classes to customize toggle appearance
*/
toggleClass: {
type: [String, Array, Object],
required: false,
default: null
},
/**
* Set to "true" to hide the caret
*/
noCaret: {
type: Boolean,
required: false,
default: false
},
/**
* Align listbox menu with respect to the toggle button
*/
placement: {
type: String,
required: false,
default: 'bottom-start',
validator: value => Object.keys(dropdownPlacements).includes(value)
},
/**
* Center selected item checkmark
*/
isCheckCentered: {
type: Boolean,
required: false,
default: false
},
/**
* The `id` attribute value for the toggle button
*/
toggleId: {
type: String,
required: false,
default: null
},
/**
* The `aria-labelledby` attribute value for the toggle button
* Provide the string of ids seperated by space
*/
toggleAriaLabelledBy: {
type: String,
required: false,
default: null
},
/**
* The `aria-labelledby` attribute value for the list of options
* Provide the string of ids seperated by space
*/
listAriaLabelledBy: {
type: String,
required: false,
default: null
},
/**
* Enable search
*/
searchable: {
type: Boolean,
required: false,
default: false
},
/**
* Set to "true" when items search is in progress.
* It will display loading icon below the search input
*/
searching: {
type: Boolean,
required: false,
default: false
},
/**
* Enables infinite scroll.
* When set to `true`, the `@bottom-reached` event will be fired when
* the bottom of the listbox is scrolled to.
* Does not support groups.
*/
infiniteScroll: {
type: Boolean,
required: false,
default: false
},
/**
* This prop is used for infinite scroll.
* It represents the total number of items that exist,
* even if they have not yet been loaded.
* Do not set this prop if the total number of items is unknown.
*/
totalItems: {
type: Number,
required: false,
default: null
},
/**
* This prop is used for infinite scroll.
* Set to `true` when more items are being loaded.
*/
infiniteScrollLoading: {
type: Boolean,
required: false,
default: false
},
/**
* Message to be displayed when filtering produced no results
*/
noResultsText: {
type: String,
required: false,
default: 'No results found'
},
/**
* Search input placeholder text and aria-label
*/
searchPlaceholder: {
type: String,
required: false,
default: 'Search'
},
/**
* The reset button's label, to be rendered in the header. If this is omitted, the button is not
* rendered.
* The reset button requires a header to be set, so this prop should be used in conjunction with
* headerText.
*/
resetButtonLabel: {
type: String,
required: false,
default: ''
},
/**
* The select all button's label, to be rendered in the header. If this is omitted, the button is not
* rendered.
* The select all button requires a header to be set, so this prop should be used in conjunction with
* headerText.
*/
showSelectAllButtonLabel: {
type: String,
required: false,
default: ''
},
/**
* Render the toggle button as a block element
*/
block: {
type: Boolean,
required: false,
default: false
},
/**
* Custom offset to be applied to Floating UI's offset middleware.
* https://floating-ui.com/docs/offset
*/
dropdownOffset: {
type: [Number, Object],
required: false,
default: undefined
},
/**
* Lets the dropdown extend to match its content's width, up to a maximum width
* defined by the `$gl-new-dropdown-max-width` variable.
*/
fluidWidth: {
type: Boolean,
required: false,
default: false
},
/**
* Strategy to be applied by computePosition. If the dropdown's container is too short for it to
* fit in, setting this to fixed will let it position itself above its container.
* https://floating-ui.com/docs/computePosition#strategy
*/
positioningStrategy: {
type: String,
required: false,
default: POSITION_ABSOLUTE,
validator: strategy => [POSITION_ABSOLUTE, POSITION_FIXED].includes(strategy)
},
/**
* Opens dropdown on render
*/
startOpened: {
type: Boolean,
required: false,
default: false
},
srOnlyResultsLabel: {
type: Function,
required: false,
default: translatePlural('GlCollapsibleListbox.srOnlyResultsLabel', '%d result', '%d results')
}
},
data() {
return {
selectedValues: [],
listboxId: uniqueId('listbox-'),
nextFocusedItemIndex: null,
searchStr: '',
topBoundaryVisible: true,
bottomBoundaryVisible: true
};
},
computed: {
toggleIdComputed() {
return this.toggleId || uniqueId('dropdown-toggle-btn-');
},
listboxTag() {
if (!this.hasItems || isOption(this.items[0])) return 'ul';
return 'div';
},
listboxClasses() {
return {
'top-scrim-visible': !this.topBoundaryVisible,
'bottom-scrim-visible': !this.bottomBoundaryVisible,
[GL_DROPDOWN_CONTENTS_CLASS]: true
};
},
itemTag() {
return this.listboxTag === 'ul' ? 'li' : 'div';
},
flattenedOptions() {
return flattenedOptions(this.items);
},
searchHasOptions() {
return this.flattenedOptions.length > 0 && this.searchStr;
},
hasItems() {
return this.items.length > 0;
},
listboxToggleText() {
if (!this.toggleText) {
if (!this.multiple && this.selectedValues.length) {
var _this$flattenedOption;
return (_this$flattenedOption = this.flattenedOptions.find(_ref => {
let {
value
} = _ref;
return value === this.selectedValues[0];
})) === null || _this$flattenedOption === void 0 ? void 0 : _this$flattenedOption.text;
}
return '';
}
return this.toggleText;
},
selectedIndices() {
return this.selectedValues.map(selected => this.flattenedOptions.findIndex(_ref2 => {
let {
value
} = _ref2;
return value === selected;
})).filter(index => index !== -1).sort();
},
showList() {
return this.flattenedOptions.length && !this.searching;
},
showNoResultsText() {
return !this.flattenedOptions.length && !this.searching;
},
announceSRSearchResults() {
return this.searchable && !this.showNoResultsText;
},
headerId() {
return this.headerText && uniqueId('listbox-header-');
},
showResetButton() {
if (!this.resetButtonLabel) {
return false;
}
/**
* if dropdown has no items
* reset all should be hidden
*/
if (!this.hasItems) {
return false;
}
// hide if no selection
if (!this.selected || this.selected.length === 0) {
return false;
}
// only show reset button if show all button is not there
return !this.showSelectAllButton;
},
showSelectAllButton() {
if (!this.showSelectAllButtonLabel) {
return false;
}
if (!this.multiple) {
return false;
}
/**
* if dropdown has no items
* select all should be hidden
*/
if (!this.hasItems) {
return false;
}
return this.selected.length !== this.flattenedOptions.length;
},
showIntersectionObserver() {
return this.infiniteScroll && !this.infiniteScrollLoading && !this.loading && !this.searching;
},
hasCustomToggle() {
return Boolean(this.$scopedSlots.toggle);
},
hasSelection() {
return Boolean(this.selectedValues.length);
},
toggleButtonClasses() {
const toggleClasses = [this.toggleClass];
if (!this.hasSelection) {
toggleClasses.push('!gl-text-subtle');
}
return toggleClasses;
},
hasHeader() {
return this.headerText || this.searchable;
},
hasFooter() {
return Boolean(this.$scopedSlots.footer);
}
},
watch: {
selected: {
immediate: true,
handler(newSelected) {
if (Array.isArray(newSelected)) {
if (process.env.NODE_ENV !== 'production' && !this.multiple && newSelected.length) {
throw new Error('To allow multi-selection, please, set "multiple" property to "true"');
}
this.selectedValues = [...newSelected];
} else {
this.selectedValues = [newSelected];
}
}
},
items: {
handler() {
this.$nextTick(() => {
/* Every time the list of items changes (on search),
* the observed elements are recreated, thus we need to start obesrving them again */
this.observeScroll();
/**
* Every time the list of items changes, and there is a search string,
* we want to visually highlight the first item
*/
if (this.searchHasOptions) {
this.nextFocusedItemIndex = 0;
} else {
this.nextFocusedItemIndex = null;
}
});
}
},
...(process.env.NODE_ENV !== 'production' ? {
resetButtonLabel: {
immediate: true,
handler(newResetButtonLabel) {
if (newResetButtonLabel && !this.headerText) {
throw new Error('The reset button cannot be rendered without a header. Either provide a header via the headerText prop, or do not provide the resetButtonLabel prop.');
}
}
},
showSelectAllButtonLabel: {
immediate: true,
handler(showSelectAllButtonLabel) {
if (showSelectAllButtonLabel && !this.headerText) {
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.');
}
}
},
infiniteScroll: {
immediate: true,
handler(newValue) {
if (newValue && this.items.some(item => !isOption(item))) {
// eslint-disable-next-line no-console
console.warn('When using grouped options infinite scroll can only be used on the last group.');
}
}
}
} : {})
},
mounted() {
if (this.startOpened) {
this.open();
}
this.observeScroll();
},
beforeDestroy() {
var _this$scrollObserver;
(_this$scrollObserver = this.scrollObserver) === null || _this$scrollObserver === void 0 ? void 0 : _this$scrollObserver.disconnect();
},
methods: {
open() {
this.$refs.baseDropdown.open();
},
close() {
this.$refs.baseDropdown.close();
},
groupClasses(index) {
return index === 0 ? null : GROUP_TOP_BORDER_CLASSES;
},
onShow() {
if (this.searchable) {
this.focusSearchInput();
/**
* If the search string is not empty, highlight the first item
*/
if (this.searchHasOptions) {
this.nextFocusedItemIndex = 0;
}
} else {
var _this$selectedIndices;
this.focusItem((_this$selectedIndices = this.selectedIndices[0]) !== null && _this$selectedIndices !== void 0 ? _this$selectedIndices : 0, this.getFocusableListItemElements());
}
/**
* Emitted when dropdown is shown
*
* @event shown
*/
this.$emit(GL_DROPDOWN_SHOWN);
},
onHide() {
/**
* Emitted when dropdown is hidden
*
* @event hidden
*/
this.$emit(GL_DROPDOWN_HIDDEN);
this.nextFocusedItemIndex = null;
},
onKeydown(event) {
const {
code,
target
} = event;
const elements = this.getFocusableListItemElements();
if (elements.length < 1) return;
let stop = true;
const isSearchInput = target.matches(SEARCH_INPUT_SELECTOR);
if (code === HOME) {
if (isSearchInput) {
return;
}
this.focusItem(0, elements);
} else if (code === END) {
if (isSearchInput) {
return;
}
this.focusItem(elements.length - 1, elements);
} else if (code === ARROW_UP) {
if (isSearchInput) {
return;
}
if (this.searchable && elements.indexOf(target) === 0) {
this.focusSearchInput();
if (!this.searchHasOptions) {
this.nextFocusedItemIndex = null;
}
} else {
this.focusNextItem(event, elements, -1);
}
} else if (code === ARROW_DOWN) {
if (isSearchInput) {
this.focusItem(0, elements);
} else {
this.focusNextItem(event, elements, 1);
}
} else if (code === ENTER && isSearchInput) {
if (this.searchHasOptions && elements.length > 0) {
// Toggle selection state of the first item
const firstItem = this.flattenedOptions[0];
this.onSelect(firstItem, !this.isSelected(firstItem));
}
stop = true;
} else {
stop = false;
}
if (stop) {
stopEvent(event);
}
},
getFocusableListItemElements() {
var _this$$refs$list;
const items = (_this$$refs$list = this.$refs.list) === null || _this$$refs$list === void 0 ? void 0 : _this$$refs$list.querySelectorAll(ITEM_SELECTOR);
return Array.from(items || []);
},
focusNextItem(event, elements, offset) {
const {
target
} = event;
const currentIndex = elements.indexOf(target);
const nextIndex = clamp(currentIndex + offset, 0, elements.length - 1);
this.focusItem(nextIndex, elements);
},
focusItem(index, elements) {
var _elements$index;
this.nextFocusedItemIndex = index;
(_elements$index = elements[index]) === null || _elements$index === void 0 ? void 0 : _elements$index.focus();
},
focusSearchInput() {
this.$refs.searchBox.focusInput();
},
onSelect(item, isSelected) {
if (this.multiple) {
this.onMultiSelect(item.value, isSelected);
} else {
this.onSingleSelect(item.value, isSelected);
}
},
isHighlighted(item) {
return this.nextFocusedItemIndex === this.flattenedOptions.indexOf(item);
},
isSelected(item) {
return this.selectedValues.some(value => value === item.value);
},
isFocused(item) {
return this.nextFocusedItemIndex === this.flattenedOptions.indexOf(item);
},
onSingleSelect(value, isSelected) {
if (isSelected) {
/**
* Emitted when selection is changed
*
* @event select
*/
this.$emit('select', value);
}
this.closeAndFocus();
},
onMultiSelect(value, isSelected) {
if (isSelected) {
this.$emit('select', [...this.selectedValues, value]);
} else {
this.$emit('select', this.selectedValues.filter(selectedValue => selectedValue !== value));
}
},
search(searchTerm) {
/**
* Emitted when the search query string is changed
*
* @event search
* @type {string}
*/
this.$emit('search', searchTerm);
},
onResetButtonClicked() {
/**
* Emitted when the reset button is clicked
*
* @event reset
*/
this.$emit('reset');
},
onSelectAllButtonClicked() {
/**
* Emitted when the select all button is clicked
*
* @event select-all
*/
this.$emit('select-all');
},
closeAndFocus() {
this.$refs.baseDropdown.closeAndFocus();
},
onIntersectionObserverAppear() {
/**
* Emitted when bottom of listbox has been scrolled to.
* Used for infinite scroll.
*
* @event bottom-reached
*/
this.$emit('bottom-reached');
},
listboxItemKey(item) {
if (item.value === null) {
return ITEM_NULL_KEY;
}
return item.value;
},
listboxItemMoreItemsAriaAttributes(index) {
if (this.totalItems === null) {
return {};
}
return {
'aria-setsize': this.totalItems,
'aria-posinset': index + 1
};
},
observeScroll() {
var _this$scrollObserver2;
const root = this.$refs.list;
const options = {
rootMargin: '8px',
root,
threshold: 1.0
};
(_this$scrollObserver2 = this.scrollObserver) === null || _this$scrollObserver2 === void 0 ? void 0 : _this$scrollObserver2.disconnect();
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
var _entry$target;
this[(_entry$target = entry.target) === null || _entry$target === void 0 ? void 0 : _entry$target.$__visibilityProp] = entry.isIntersecting;
});
}, options);
const topBoundary = this.$refs['top-boundary'];
const bottomBoundary = this.$refs['bottom-boundary'];
if (topBoundary) {
topBoundary.$__visibilityProp = 'topBoundaryVisible';
observer.observe(topBoundary);
}
if (bottomBoundary) {
bottomBoundary.$__visibilityProp = 'bottomBoundaryVisible';
observer.observe(bottomBoundary);
}
this.scrollObserver = observer;
},
isOption
}
};
/* script */
const __vue_script__ = script;
/* template */
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.toggleIdComputed,"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,"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]),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-flex gl-min-h-8 gl-items-center !gl-p-4",class:_vm.$options.HEADER_ITEMS_BORDER_CLASSES},[_c('div',{staticClass:"gl-grow gl-pr-2 gl-text-sm gl-font-bold gl-text-strong",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-m-0 !gl-w-auto gl-max-w-1/2 gl-flex-shrink-0 gl-text-ellipsis !gl-px-2 !gl-text-sm focus:!gl-focus-inset",attrs:{"category":"tertiary","size":"small","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-m-0 !gl-w-auto gl-max-w-1/2 gl-flex-shrink-0 gl-text-ellipsis !gl-px-2 !gl-text-sm focus:!gl-focus-inset",attrs:{"category":"tertiary","size":"small","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",class:{ 'gl-listbox-topmost': !_vm.headerText },attrs:{"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.toggleIdComputed,"role":"listbox","tabindex":"0"},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:_vm.listboxItemKey(item),attrs:{"data-testid":("listbox-item-" + (item.value)),"is-highlighted":_vm.isHighlighted(item),"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:_vm.listboxItemKey(option),attrs:{"data-testid":("listbox-item-" + (option.value)),"is-highlighted":_vm.isHighlighted(option),"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-none': _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",function(){return [_vm._v("\n "+_vm._s(_vm.srOnlyResultsLabel(_vm.flattenedOptions.length))+"\n ")]})],2):(_vm.showNoResultsText)?_c('div',{staticClass:"gl-py-3 gl-pl-7 gl-pr-5 gl-text-base gl-text-subtle",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)};
var __vue_staticRenderFns__ = [];
/* style */
const __vue_inject_styles__ = undefined;
/* scoped */
const __vue_scope_id__ = undefined;
/* module identifier */
const __vue_module_identifier__ = undefined;
/* functional template */
const __vue_is_functional_template__ = false;
/* style inject */
/* style inject SSR */
/* style inject shadow dom */
const __vue_component__ = /*#__PURE__*/__vue_normalize__(
{ render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
__vue_inject_styles__,
__vue_script__,
__vue_scope_id__,
__vue_is_functional_template__,
__vue_module_identifier__,
false,
undefined,
undefined,
undefined
);
export { ITEM_NULL_KEY, ITEM_SELECTOR, SEARCH_INPUT_SELECTOR, __vue_component__ as default };