diff --git a/packages/devui-vue/devui/editable-select/src/components/dropdown.tsx b/packages/devui-vue/devui/editable-select/src/components/dropdown.tsx index 711f94ee2ac44c43bff206a3bd0fec436120e1f7..7f1f029badf86652e15551e5ca2334714d1e1c42 100644 --- a/packages/devui-vue/devui/editable-select/src/components/dropdown.tsx +++ b/packages/devui-vue/devui/editable-select/src/components/dropdown.tsx @@ -14,6 +14,7 @@ export default defineComponent({ renderDefaultSlots, renderEmptySlots, selectedIndex, + hoverIndex, loadMore } = select const { maxHeight } = selectProps @@ -22,7 +23,8 @@ export default defineComponent({ const { disabledKey } = selectProps return className('devui-dropdown-item', { disabled: disabledKey ? !!item[disabledKey] : false, - selected: selectedIndex.value === index + selected: selectedIndex.value === index, + 'devui-dropdown-bg': hoverIndex.value === index }) } return ( diff --git a/packages/devui-vue/devui/editable-select/src/composable/use-keyBoard-select.ts b/packages/devui-vue/devui/editable-select/src/composable/use-keyBoard-select.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d9c59f96c1be020259a2c46fe8c39f2879ea92c --- /dev/null +++ b/packages/devui-vue/devui/editable-select/src/composable/use-keyBoard-select.ts @@ -0,0 +1,73 @@ +import { ComputedRef, nextTick, Ref } from 'vue' +import { OptionItem } from '../editable-select-types' +interface keyBoardSelectReturnType { + handleKeydown: (e: KeyboardEvent) => void +} + +export default function keyboardSelect( + dropdownRef: Ref, + visible: Ref, + hoverIndex: Ref, + selectedIndex: Ref, + filteredOptions: ComputedRef, + toggleMenu: () => void, + selectOptionClick: (e: KeyboardEvent, item: OptionItem) => void +): keyBoardSelectReturnType { + const updateHoverIndex = (index: number) => { + hoverIndex.value = index + } + const scrollToActive = (index: number) => { + const dropdownVal = dropdownRef.value + const li = dropdownVal.children[index] + + nextTick(() => { + if (li.scrollIntoViewIfNeeded) { + li.scrollIntoViewIfNeeded(false) + } else { + const containerInfo = dropdownVal.getBoundingClientRect() + const elementInfo = li.getBoundingClientRect() + if (elementInfo.bottom > containerInfo.bottom || elementInfo.top < containerInfo.top) { + li.scrollIntoView(false) + } + } + }) + } + const onKeyboardSelect = (e: KeyboardEvent) => { + const option = filteredOptions.value[hoverIndex.value] + selectOptionClick(e, option) + hoverIndex.value = selectedIndex.value + } + const handleKeydown = (e: KeyboardEvent) => { + const keyCode = e.key || e.code + let index = 0 + if (!visible.value) { + toggleMenu() + } + + if (keyCode === 'Backspace') { + return + } + + if (keyCode === 'ArrowUp') { + index = hoverIndex.value - 1 + if (index < 0) { + index = filteredOptions.value.length - 1 + } + } else if (keyCode === 'ArrowDown') { + index = hoverIndex.value + 1 + if (index > filteredOptions.value.length - 1) { + index = 0 + } + } + + if (keyCode === 'Enter') { + return onKeyboardSelect(e) + } + updateHoverIndex(index) + scrollToActive(index) + } + + return { + handleKeydown + } +} diff --git a/packages/devui-vue/devui/editable-select/src/editable-select.tsx b/packages/devui-vue/devui/editable-select/src/editable-select.tsx index 851816c24a7d2461167380d2fa6181bc317ef063..b137d25b9c2248caecbb711fd6219fb27c128b51 100644 --- a/packages/devui-vue/devui/editable-select/src/editable-select.tsx +++ b/packages/devui-vue/devui/editable-select/src/editable-select.tsx @@ -19,6 +19,7 @@ import './editable-select.scss' import ClickOutside from '../../shared/devui-directive/clickoutside' import { debounce } from 'lodash' import { className } from './utils' +import keyboardSelect from './composable/use-keyboard-select' export default defineComponent({ name: 'DEditableSelect', directives: { ClickOutside }, @@ -66,6 +67,7 @@ export default defineComponent({ const visible = ref(false) const inputValue = ref('') const selectedIndex = ref(0) + const hoverIndex = ref(0) const query = ref(props.modelValue) const position = reactive({ originX: 'left', @@ -155,7 +157,7 @@ export default defineComponent({ } } - const selectOptionClick = (e, item) => { + const selectOptionClick = (e, item: OptionItem) => { const { disabledKey } = props if (disabledKey && item[disabledKey]) { e.stopPropagation() @@ -164,6 +166,7 @@ export default defineComponent({ selectedIndex.value = findIndex(item) inputValue.value = '' ctx.emit('update:modelValue', item.name) + visible.value = false } } @@ -174,6 +177,16 @@ export default defineComponent({ props.loadMore() } } + const { handleKeydown } = keyboardSelect( + dropdownRef, + visible, + hoverIndex, + selectedIndex, + filteredOptions, + toggleMenu, + selectOptionClick + ) + provide('InjectionKey', { dropdownRef, props: reactive({ @@ -182,6 +195,7 @@ export default defineComponent({ visible, emptyText, selectedIndex, + hoverIndex, loadMore, selectOptionClick, renderDefaultSlots, @@ -201,7 +215,14 @@ export default defineComponent({ return ( <>
- +