mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
* 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
134 lines
3.3 KiB
Vue
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>
|