element-plus/packages/dropdown/src/useDropdown.ts
2020-11-04 11:24:36 +08:00

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()
}