mirror of
https://github.com/element-plus/element-plus.git
synced 2024-12-21 02:50:11 +08:00
112 lines
3.4 KiB
TypeScript
112 lines
3.4 KiB
TypeScript
import { inject, computed, ref } from 'vue'
|
|
import { generateId, useGlobalConfig } from '@element-plus/utils/util'
|
|
import { EVENT_CODE } from '@element-plus/utils/aria'
|
|
import { on, addClass } from '@element-plus/utils/dom'
|
|
import { IElDropdownInstance } from './dropdown'
|
|
|
|
export const useDropdown = () => {
|
|
const ELEMENT = useGlobalConfig()
|
|
const elDropdown = inject<IElDropdownInstance>('elDropdown', {})
|
|
const _elDropdownSize = computed(() => elDropdown?.dropdownSize)
|
|
|
|
return {
|
|
ELEMENT,
|
|
elDropdown,
|
|
_elDropdownSize,
|
|
}
|
|
}
|
|
|
|
export const initDropdownDomEvent = (dropdownChildren, triggerElm, _instance) => {
|
|
const menuItems = ref<Nullable<HTMLButtonElement[]>>(null)
|
|
const menuItemsArray = ref<Nullable<HTMLElement[]>>(null)
|
|
const dropdownElm = ref<Nullable<HTMLElement>>(null)
|
|
const listId = ref(`dropdown-menu-${generateId()}`)
|
|
dropdownElm.value = dropdownChildren?.subTree.el
|
|
|
|
function removeTabindex() {
|
|
triggerElm.setAttribute('tabindex', '-1')
|
|
menuItemsArray.value?.forEach(item => {
|
|
item.setAttribute('tabindex', '-1')
|
|
})
|
|
}
|
|
|
|
function resetTabindex(ele) {
|
|
removeTabindex()
|
|
ele?.setAttribute('tabindex', '0')
|
|
}
|
|
|
|
function handleTriggerKeyDown(ev: KeyboardEvent) {
|
|
const code = ev.code
|
|
if ([EVENT_CODE.up, EVENT_CODE.down].includes(code)) {
|
|
removeTabindex()
|
|
resetTabindex(menuItems.value[0])
|
|
menuItems.value[0].focus()
|
|
ev.preventDefault()
|
|
ev.stopPropagation()
|
|
} else if (code === EVENT_CODE.enter) {
|
|
_instance.handleClick()
|
|
} else if ([EVENT_CODE.tab, EVENT_CODE.esc].includes(code)) {
|
|
_instance.hide()
|
|
}
|
|
}
|
|
|
|
function handleItemKeyDown(ev) {
|
|
const code = ev.code
|
|
const target = ev.target
|
|
const currentIndex = menuItemsArray.value.indexOf(target)
|
|
const max = menuItemsArray.value.length - 1
|
|
let nextIndex
|
|
if ([EVENT_CODE.up, EVENT_CODE.down].includes(code)) {
|
|
if (code === EVENT_CODE.up) {
|
|
nextIndex = currentIndex !== 0 ? currentIndex - 1 : 0
|
|
} else {
|
|
nextIndex = currentIndex < max ? currentIndex + 1 : max
|
|
}
|
|
removeTabindex()
|
|
resetTabindex(menuItems.value[nextIndex])
|
|
menuItems.value[nextIndex].focus()
|
|
ev.preventDefault()
|
|
ev.stopPropagation()
|
|
} else if (code === EVENT_CODE.enter) {
|
|
triggerElmFocus()
|
|
target.click()
|
|
if (_instance.props.hideOnClick) {
|
|
_instance.hide()
|
|
}
|
|
} else if ([EVENT_CODE.tab, EVENT_CODE.esc].includes(code)) {
|
|
_instance.hide()
|
|
triggerElmFocus()
|
|
}
|
|
}
|
|
|
|
function initAria() {
|
|
dropdownElm.value.setAttribute('id', listId.value)
|
|
triggerElm.setAttribute('aria-haspopup', 'list')
|
|
triggerElm.setAttribute('aria-controls', listId.value)
|
|
if (!_instance.props.splitButton) {
|
|
triggerElm.setAttribute('role', 'button')
|
|
triggerElm.setAttribute('tabindex', _instance.props.tabindex)
|
|
addClass(triggerElm, 'el-dropdown-selfdefine')
|
|
}
|
|
}
|
|
|
|
function initEvent() {
|
|
on(triggerElm, 'keydown', handleTriggerKeyDown)
|
|
on(dropdownElm.value, 'keydown', handleItemKeyDown, true)
|
|
}
|
|
|
|
function initDomOperation() {
|
|
menuItems.value = dropdownElm.value.querySelectorAll("[tabindex='-1']") as unknown as HTMLButtonElement[]
|
|
menuItemsArray.value = [].slice.call(menuItems.value)
|
|
|
|
initEvent()
|
|
initAria()
|
|
}
|
|
|
|
function triggerElmFocus() {
|
|
triggerElm.focus()
|
|
}
|
|
|
|
initDomOperation()
|
|
}
|