mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-15 01:41:20 +08:00
265 lines
6.9 KiB
Vue
265 lines
6.9 KiB
Vue
<template>
|
|
<div :class="[ns.b(), ns.is('disabled', disabled)]">
|
|
<el-tooltip
|
|
ref="popperRef"
|
|
:role="role"
|
|
:effect="effect"
|
|
:fallback-placements="['bottom', 'top']"
|
|
:popper-options="popperOptions"
|
|
:gpu-acceleration="false"
|
|
:hide-after="trigger === 'hover' ? hideTimeout : 0"
|
|
:manual-mode="true"
|
|
:placement="placement"
|
|
:popper-class="[ns.e('popper'), popperClass]"
|
|
:reference-element="referenceElementRef?.$el"
|
|
:trigger="trigger"
|
|
:trigger-keys="triggerKeys"
|
|
:trigger-target-el="contentRef"
|
|
:show-after="trigger === 'hover' ? showTimeout : 0"
|
|
:stop-popper-mouse-event="false"
|
|
:virtual-ref="triggeringElementRef"
|
|
:virtual-triggering="splitButton"
|
|
:disabled="disabled"
|
|
:transition="`${ns.namespace.value}-zoom-in-top`"
|
|
teleported
|
|
pure
|
|
persistent
|
|
@before-show="handleBeforeShowTooltip"
|
|
@show="handleShowTooltip"
|
|
@before-hide="handleBeforeHideTooltip"
|
|
>
|
|
<template #content>
|
|
<el-scrollbar
|
|
ref="scrollbar"
|
|
:wrap-style="wrapStyle"
|
|
tag="div"
|
|
:view-class="ns.e('list')"
|
|
>
|
|
<el-roving-focus-group
|
|
:loop="loop"
|
|
:current-tab-id="currentTabId"
|
|
orientation="horizontal"
|
|
@current-tab-id-change="handleCurrentTabIdChange"
|
|
@entry-focus="handleEntryFocus"
|
|
>
|
|
<el-dropdown-collection>
|
|
<slot name="dropdown" />
|
|
</el-dropdown-collection>
|
|
</el-roving-focus-group>
|
|
</el-scrollbar>
|
|
</template>
|
|
<template v-if="!splitButton" #default>
|
|
<el-only-child :id="triggerId" role="button" :tabindex="tabindex">
|
|
<slot name="default" />
|
|
</el-only-child>
|
|
</template>
|
|
</el-tooltip>
|
|
<template v-if="splitButton">
|
|
<el-button-group>
|
|
<el-button
|
|
ref="referenceElementRef"
|
|
v-bind="buttonProps"
|
|
:size="dropdownSize"
|
|
:type="type"
|
|
:disabled="disabled"
|
|
:tabindex="tabindex"
|
|
@click="handlerMainButtonClick"
|
|
>
|
|
<slot name="default" />
|
|
</el-button>
|
|
<el-button
|
|
:id="triggerId"
|
|
ref="triggeringElementRef"
|
|
v-bind="buttonProps"
|
|
role="button"
|
|
:size="dropdownSize"
|
|
:type="type"
|
|
:class="ns.e('caret-button')"
|
|
:disabled="disabled"
|
|
:tabindex="tabindex"
|
|
:aria-label="t('el.dropdown.toggleDropdown')"
|
|
>
|
|
<el-icon :class="ns.e('icon')"><arrow-down /></el-icon>
|
|
</el-button>
|
|
</el-button-group>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
<script lang="ts">
|
|
// @ts-nocheck
|
|
import {
|
|
computed,
|
|
defineComponent,
|
|
getCurrentInstance,
|
|
provide,
|
|
ref,
|
|
toRef,
|
|
unref,
|
|
} from 'vue'
|
|
import ElButton from '@element-plus/components/button'
|
|
import ElTooltip from '@element-plus/components/tooltip'
|
|
import ElScrollbar from '@element-plus/components/scrollbar'
|
|
import ElIcon from '@element-plus/components/icon'
|
|
import ElRovingFocusGroup from '@element-plus/components/roving-focus-group'
|
|
import { ElOnlyChild } from '@element-plus/components/slot'
|
|
import { addUnit } from '@element-plus/utils'
|
|
import { ArrowDown } from '@element-plus/icons-vue'
|
|
import { EVENT_CODE } from '@element-plus/constants'
|
|
import { useId, useLocale, useNamespace, useSize } from '@element-plus/hooks'
|
|
import { ElCollection as ElDropdownCollection, dropdownProps } from './dropdown'
|
|
import { DROPDOWN_INJECTION_KEY } from './tokens'
|
|
|
|
import type { CSSProperties } from 'vue'
|
|
|
|
const { ButtonGroup: ElButtonGroup } = ElButton
|
|
|
|
export default defineComponent({
|
|
name: 'ElDropdown',
|
|
components: {
|
|
ElButton,
|
|
ElButtonGroup,
|
|
ElScrollbar,
|
|
ElDropdownCollection,
|
|
ElTooltip,
|
|
ElRovingFocusGroup,
|
|
ElOnlyChild,
|
|
ElIcon,
|
|
ArrowDown,
|
|
},
|
|
props: dropdownProps,
|
|
emits: ['visible-change', 'click', 'command'],
|
|
setup(props, { emit }) {
|
|
const _instance = getCurrentInstance()
|
|
const ns = useNamespace('dropdown')
|
|
const { t } = useLocale()
|
|
|
|
const triggeringElementRef = ref()
|
|
const referenceElementRef = ref()
|
|
const popperRef = ref<InstanceType<typeof ElTooltip> | null>(null)
|
|
const contentRef = ref<HTMLElement | null>(null)
|
|
const scrollbar = ref(null)
|
|
const currentTabId = ref<string | null>(null)
|
|
const isUsingKeyboard = ref(false)
|
|
const triggerKeys = [EVENT_CODE.enter, EVENT_CODE.space, EVENT_CODE.down]
|
|
|
|
const wrapStyle = computed<CSSProperties>(() => ({
|
|
maxHeight: addUnit(props.maxHeight),
|
|
}))
|
|
const dropdownTriggerKls = computed(() => [ns.m(dropdownSize.value)])
|
|
|
|
const defaultTriggerId = useId().value
|
|
const triggerId = computed<string>(() => {
|
|
return props.id || defaultTriggerId
|
|
})
|
|
|
|
function handleClick() {
|
|
handleClose()
|
|
}
|
|
|
|
function handleClose() {
|
|
popperRef.value?.onClose()
|
|
}
|
|
|
|
function handleOpen() {
|
|
popperRef.value?.onOpen()
|
|
}
|
|
|
|
const dropdownSize = useSize()
|
|
|
|
function commandHandler(...args: any[]) {
|
|
emit('command', ...args)
|
|
}
|
|
|
|
function onItemEnter() {
|
|
// NOOP for now
|
|
}
|
|
|
|
function onItemLeave() {
|
|
const contentEl = unref(contentRef)
|
|
|
|
contentEl?.focus()
|
|
currentTabId.value = null
|
|
}
|
|
|
|
function handleCurrentTabIdChange(id: string) {
|
|
currentTabId.value = id
|
|
}
|
|
|
|
function handleEntryFocus(e: Event) {
|
|
if (!isUsingKeyboard.value) {
|
|
e.preventDefault()
|
|
e.stopImmediatePropagation()
|
|
}
|
|
}
|
|
|
|
function handleBeforeShowTooltip() {
|
|
emit('visible-change', true)
|
|
}
|
|
|
|
function handleShowTooltip(event?: Event) {
|
|
if (event?.type === 'keydown') {
|
|
contentRef.value.focus()
|
|
}
|
|
}
|
|
|
|
function handleBeforeHideTooltip() {
|
|
emit('visible-change', false)
|
|
}
|
|
|
|
provide(DROPDOWN_INJECTION_KEY, {
|
|
contentRef,
|
|
role: computed(() => props.role),
|
|
triggerId,
|
|
isUsingKeyboard,
|
|
onItemEnter,
|
|
onItemLeave,
|
|
})
|
|
|
|
provide('elDropdown', {
|
|
instance: _instance,
|
|
dropdownSize,
|
|
handleClick,
|
|
commandHandler,
|
|
trigger: toRef(props, 'trigger'),
|
|
hideOnClick: toRef(props, 'hideOnClick'),
|
|
})
|
|
|
|
const onFocusAfterTrapped = (e: Event) => {
|
|
e.preventDefault()
|
|
contentRef.value?.focus?.({
|
|
preventScroll: true,
|
|
})
|
|
}
|
|
|
|
const handlerMainButtonClick = (event: MouseEvent) => {
|
|
emit('click', event)
|
|
}
|
|
|
|
return {
|
|
t,
|
|
ns,
|
|
scrollbar,
|
|
wrapStyle,
|
|
dropdownTriggerKls,
|
|
dropdownSize,
|
|
triggerId,
|
|
triggerKeys,
|
|
currentTabId,
|
|
handleCurrentTabIdChange,
|
|
handlerMainButtonClick,
|
|
handleEntryFocus,
|
|
handleClose,
|
|
handleOpen,
|
|
handleBeforeShowTooltip,
|
|
handleShowTooltip,
|
|
handleBeforeHideTooltip,
|
|
onFocusAfterTrapped,
|
|
popperRef,
|
|
contentRef,
|
|
triggeringElementRef,
|
|
referenceElementRef,
|
|
}
|
|
},
|
|
})
|
|
</script>
|