@coreui/vue-pro
Version:
UI Components Library for Vue.js
143 lines (139 loc) • 6.33 kB
JavaScript
;
var vue = require('vue');
var CElementCover = require('../element-cover/CElementCover.js');
var CVirtualScroller = require('../virtual-scroller/CVirtualScroller.js');
var getNextSibling = require('../../utils/getNextSibling.js');
var getPreviousSibling = require('../../utils/getPreviousSibling.js');
var utils = require('./utils.js');
const CAutocompleteOptions = vue.defineComponent({
name: 'CAutocompleteOptions',
props: {
highlightOptionsOnSearch: Boolean,
loading: Boolean,
options: {
type: Array,
required: true,
},
optionsMaxHeight: [Number, String],
scopedSlots: Object,
searchNoResultsLabel: [Boolean, String],
searchValue: String,
selected: [Object, String, null],
virtualScroller: Boolean,
visible: Boolean,
visibleItems: {
type: Number,
default: 10,
},
},
emits: ['optionClick'],
setup(props, { emit }) {
const handleKeyDown = (event, option) => {
if (event.code === 'Space' || event.key === 'Enter') {
event.preventDefault();
emit('optionClick', option);
}
if (event.key === 'Down' || event.key === 'ArrowDown') {
event.preventDefault();
const target = event.target;
const next = getNextSibling.default(target, '.autocomplete-option:not(.disabled):not(:disabled)');
if (next) {
next.focus();
}
}
if (event.key === 'Up' || event.key === 'ArrowUp') {
event.preventDefault();
const target = event.target;
const prev = getPreviousSibling.default(target, '.autocomplete-option:not(.disabled):not(:disabled)');
if (prev) {
prev.focus();
}
}
if (event.key === 'Home' || event.key === 'End') {
event.preventDefault();
const target = event.target;
const container = target.closest('.autocomplete-options');
if (!container) {
return;
}
const first = event.key === 'Home';
const focusEdgeOption = () => {
const options = container.querySelectorAll('.autocomplete-option:not(.disabled):not(:disabled)');
if (options.length > 0) {
options[first ? 0 : options.length - 1].focus();
}
};
if (props.virtualScroller) {
// The virtualized viewport only mounts a window of options — scroll it to
// the edge so the true first/last options render, then focus after the
// window has re-rendered (scroll event → state update → commit).
container.scrollTop = first ? 0 : container.scrollHeight;
requestAnimationFrame(() => requestAnimationFrame(focusEdgeOption));
return;
}
focusEdgeOption();
}
};
const createOption = (option, index) => vue.h('div', {
class: [
'autocomplete-option',
{
disabled: utils.isOptionDisabled(option),
selected: utils.isOptionSelected(option, props.selected || null),
},
],
key: index,
onClick: () => emit('optionClick', option),
onKeydown: (event) => handleKeyDown(event, option),
onMousedown: (event) => event.preventDefault(),
role: 'option',
'aria-selected': utils.isOptionSelected(option, props.selected || null) ? 'true' : 'false',
...(utils.isOptionDisabled(option) && { 'aria-disabled': 'true' }),
tabindex: 0,
...(props.highlightOptionsOnSearch &&
!props.scopedSlots?.['options'] && {
innerHTML: utils.highlightSubstring(utils.getOptionLabel(option), props.searchValue),
}),
}, props.highlightOptionsOnSearch
? undefined
: props.scopedSlots && props.scopedSlots['options']
? vue.h(props.scopedSlots['options'], { option: option })
: utils.getOptionLabel(option));
const createOptions = (options) => {
if (options.length === 0 && props.searchNoResultsLabel) {
return vue.h('div', { class: 'autocomplete-options-empty', role: 'status' }, props.searchNoResultsLabel);
}
return options.map((option, index) => {
if (typeof option !== 'string' && 'options' in option) {
return vue.h('div', { key: index }, [
vue.h('div', { class: 'autocomplete-optgroup-label' }, [
props.scopedSlots && props.scopedSlots['options-groups']
? vue.h(props.scopedSlots['options-groups'], { option: option })
: option.label,
]),
...(option.options?.map((opt, idx) => createOption(opt, idx)) || []),
]);
}
return createOption(option, index);
});
};
return () => [
props.visible && props.virtualScroller && props.options.length > 0
? vue.h(CVirtualScroller.CVirtualScroller, {
class: 'autocomplete-options',
visibleItems: props.visibleItems,
}, {
default: () => createOptions(props.options),
})
: vue.h('div', {
class: 'autocomplete-options',
...(props.optionsMaxHeight !== 'auto' && {
style: { maxHeight: props.optionsMaxHeight, overflow: 'scroll' },
}),
}, createOptions(props.options)),
props.loading && vue.h(CElementCover.CElementCover),
];
},
});
exports.CAutocompleteOptions = CAutocompleteOptions;
//# sourceMappingURL=CAutocompleteOptions.js.map