diff --git a/packages/ui/src/components/va-select/VaSelect.demo.vue b/packages/ui/src/components/va-select/VaSelect.demo.vue index cd64ed6d8e..223e0dfff9 100644 --- a/packages/ui/src/components/va-select/VaSelect.demo.vue +++ b/packages/ui/src/components/va-select/VaSelect.demo.vue @@ -858,8 +858,8 @@ export default { }, disabledOptions: { options: [ - { id: '0', text: 'one', value: 'one', disabled: true }, - { id: '1', text: 'two', value: 'two' }, + { id: '0', text: 'one', value: 'one' }, + { id: '1', text: 'two', value: 'two', disabled: true }, { id: '2', text: 'three', value: 'three', disabled: true }, { id: '3', text: 'four', value: 'four' }, { id: '4', text: 'five', value: 'five' }, diff --git a/packages/ui/src/components/va-select/VaSelect.vue b/packages/ui/src/components/va-select/VaSelect.vue index 0c4c78721f..01245bdd7e 100644 --- a/packages/ui/src/components/va-select/VaSelect.vue +++ b/packages/ui/src/components/va-select/VaSelect.vue @@ -101,10 +101,8 @@ v-model:hoveredOption="hoveredOption" :style="{ maxHeight: $props.maxHeight }" v-bind="optionsListPropsComputed" - @select-option="selectOption" + @select-option="selectHoveredOption" @no-previous-option-to-hover="focusSearchBar" - @keydown.enter.stop.prevent="selectHoveredOption" - @keydown.space.stop.prevent="selectHoveredOption" @keydown.tab.stop.prevent="searchBar && searchBar.focus()" @keydown="onHintedSearch" @scroll-bottom="onScrollBottom" @@ -588,7 +586,7 @@ export default defineComponent({ })) const optionsListPropsComputed = computed(() => ({ - ...pick(props, ['textBy', 'trackBy', 'groupBy', 'valueBy', 'disabledBy', 'color', 'virtualScroller', 'highlightMatchedText', 'minSearchChars', 'delay']), + ...pick(props, ['textBy', 'trackBy', 'groupBy', 'valueBy', 'disabledBy', 'color', 'virtualScroller', 'highlightMatchedText', 'minSearchChars', 'delay', 'selectedTopShown']), autoSelectFirstOption: props.autoSelectFirstOption || props.autocomplete, search: searchInput.value || autocompleteValue.value, tabindex: tabIndexComputed.value, diff --git a/packages/ui/src/components/va-select/components/VaSelectOptionList/VaSelectOptionList.vue b/packages/ui/src/components/va-select/components/VaSelectOptionList/VaSelectOptionList.vue index 544f0267e8..85b803502c 100644 --- a/packages/ui/src/components/va-select/components/VaSelectOptionList/VaSelectOptionList.vue +++ b/packages/ui/src/components/va-select/components/VaSelectOptionList/VaSelectOptionList.vue @@ -7,6 +7,8 @@ @keydown.left.stop.prevent="focusPreviousOption" @keydown.down.stop.prevent="focusNextOption" @keydown.right.stop.prevent="focusNextOption" + @keydown.enter.stop.prevent="selectOption" + @keydown.space.stop.prevent="selectOption" @scroll.passive="onScroll" > @@ -111,6 +115,7 @@ export default defineComponent({ highlightMatchedText: { type: Boolean, default: true }, minSearchChars: { type: Number, default: 0 }, autoSelectFirstOption: { type: Boolean, default: false }, + selectedTopShown: { type: Boolean, default: false }, }, setup (props, { emit }) { @@ -150,7 +155,7 @@ export default defineComponent({ return currentSelectedOptionText.value.toLowerCase() === props.search?.toLowerCase() }) - const filteredOptions = computed(() => { + const filteredOptions = computed((): SelectOption[] => { if (!props.search || props.search.length < props.minSearchChars || isSearchedOptionSelected.value) { return props.options } @@ -187,7 +192,18 @@ export default defineComponent({ } const updateFocusedOption = (option?: SelectOption) => { updateCurrentOption(option ?? null, 'keyboard') } - const selectOption = (option: SelectOption) => !getDisabled(option) && emit('select-option', option) + const selectOption = () => { + const previousOption = + previousOptionComputed.value && typeof previousOptionComputed.value === 'object' + ? { ...previousOptionComputed.value } + : previousOptionComputed.value + + emit('select-option') + + if (props.selectedTopShown) { + updateHoveredOption(previousOption) + } + } const groupedOptions = computed(() => Object.values(optionGroupsThrottled.value).flat()) const currentOptions = computed(() => @@ -211,6 +227,26 @@ export default defineComponent({ return searchBaseOrdered.slice(startIndex).find((option) => !getDisabled(option)) } + const previousOptionComputed = computed((): SelectOption | undefined => { + const previousOptionIndex = currentOptionIndex.value - 1 + const previousOption = currentOptions.value[previousOptionIndex] + const previousOptionCheck = isValueExists(previousOption) && !(previousOptionIndex === 0 && getDisabled(previousOption)) + + if (previousOptionCheck) { + return findNextActiveOption(currentOptionIndex.value - 1, true) + } + + return undefined + }) + + const handleMouseMove = (option: SelectOption) => { + if (!props.selectedTopShown) { updateHoveredOption(option) } + } + + const handleMouseEnter = (option: SelectOption) => { + if (props.selectedTopShown) { updateHoveredOption(option) } + } + // public const focusPreviousOption = () => { if (!isValueExists(currentOptionComputed.value)) { @@ -218,11 +254,8 @@ export default defineComponent({ return } - const previousOptionIndex = currentOptionIndex.value - 1 - const previousOption = currentOptions.value[previousOptionIndex] - const previousOptionCheck = isValueExists(previousOption) && !(previousOptionIndex === 0 && getDisabled(previousOption)) - if (previousOptionCheck) { - updateFocusedOption(findNextActiveOption(currentOptionIndex.value - 1, true)) + if (isValueExists(previousOptionComputed.value)) { + updateFocusedOption(previousOptionComputed.value) } else { emit('no-previous-option-to-hover') } @@ -289,6 +322,8 @@ export default defineComponent({ setItemRef, getDisabled, selectOption, + handleMouseMove, + handleMouseEnter, updateHoveredOption, handleScrollToBottom,