Files
element-plus/packages/components/dropdown/src/dropdown-menu.vue
三咲智子 6503e55277 refactor(utils): migrate utils (#5949)
* refactor(utils-v2): migrate utils

* refactor(utils-v2): migrate utils

* refactor(utils-v2): migrate utils

* refactor(utils): remove

* refactor(utils): rename

* refactor(utils): move EVENT_CODE to constants

* refactor: remove generic
2022-02-11 11:03:15 +08:00

134 lines
3.3 KiB
Vue

<template>
<ul
:ref="dropdownListWrapperRef"
:class="dropdownKls"
:style="rovingFocusGroupRootStyle"
:tabindex="-1"
role="menu"
@blur="onBlur"
@focus="onFocus"
@keydown="handleKeydown"
@mousedown="onMousedown"
>
<slot></slot>
</ul>
</template>
<script lang="ts">
import { computed, defineComponent, inject, unref } from 'vue'
import { composeRefs, composeEventHandlers } from '@element-plus/utils'
import { EVENT_CODE } from '@element-plus/constants'
import { FOCUS_TRAP_INJECTION_KEY } from '@element-plus/components/focus-trap'
import {
ROVING_FOCUS_COLLECTION_INJECTION_KEY,
ROVING_FOCUS_GROUP_INJECTION_KEY,
focusFirst,
} from '@element-plus/components/roving-focus-group'
import { useNamespace } from '@element-plus/hooks'
import { DROPDOWN_INJECTION_KEY } from './tokens'
import {
DROPDOWN_COLLECTION_INJECTION_KEY,
dropdownMenuProps,
FIRST_LAST_KEYS,
LAST_KEYS,
} from './dropdown'
import { useDropdown } from './useDropdown'
export default defineComponent({
name: 'ElDropdownMenu',
props: dropdownMenuProps,
setup(props) {
const ns = useNamespace('dropdown')
const { _elDropdownSize } = useDropdown()
const size = _elDropdownSize.value
const { focusTrapRef, onKeydown } = inject(
FOCUS_TRAP_INJECTION_KEY,
undefined
)!
const { contentRef } = inject(DROPDOWN_INJECTION_KEY, undefined)!
const { collectionRef: dropdownCollectionRef, getItems } = inject(
DROPDOWN_COLLECTION_INJECTION_KEY,
undefined
)!
const {
rovingFocusGroupRef,
rovingFocusGroupRootStyle,
tabIndex,
onBlur,
onFocus,
onMousedown,
} = inject(ROVING_FOCUS_GROUP_INJECTION_KEY, undefined)!
const { collectionRef: rovingFocusGroupCollectionRef } = inject(
ROVING_FOCUS_COLLECTION_INJECTION_KEY,
undefined
)!
const dropdownKls = computed(() => {
return [ns.b('menu'), ns.bm('menu', size?.value)]
})
const dropdownListWrapperRef = composeRefs(
contentRef,
dropdownCollectionRef,
focusTrapRef,
rovingFocusGroupRef,
rovingFocusGroupCollectionRef
)
const composedKeydown = composeEventHandlers(
(e: KeyboardEvent) => {
props.onKeydown?.(e)
},
(e) => {
const { currentTarget, code, target } = e
const isKeydownContained = (currentTarget as Node).contains(
target as Node
)
if (isKeydownContained) {
// TODO: implement typeahead search
}
if (EVENT_CODE.tab === code) {
e.stopImmediatePropagation()
}
e.preventDefault()
if (target !== unref(contentRef)) return
if (!FIRST_LAST_KEYS.includes(code)) return
const items = getItems<{ disabled: boolean }>().filter(
(item) => !item.disabled
)
const targets = items.map((item) => item.ref!)
if (LAST_KEYS.includes(code)) {
targets.reverse()
}
focusFirst(targets)
}
)
const handleKeydown = (e: KeyboardEvent) => {
composedKeydown(e)
onKeydown(e)
}
return {
size,
rovingFocusGroupRootStyle,
tabIndex,
dropdownKls,
dropdownListWrapperRef,
handleKeydown,
onBlur,
onFocus,
onMousedown,
}
},
})
</script>