element-plus/packages/components/dropdown/src/dropdown.vue

212 lines
5.5 KiB
Vue
Raw Normal View History

2020-11-04 11:24:36 +08:00
<template>
<div class="el-dropdown">
<el-tooltip
ref="popperRef"
:effect="effect"
:fallback-placements="['bottom', 'top', 'right', 'left']"
:gpu-acceleration="false"
:hide-after="hideTimeout"
:manual-mode="true"
:placement="placement"
:popper-class="`el-dropdown__popper ${popperClass}`"
:reference-element="referenceElementRef?.$el"
:trigger="trigger"
:show-after="showTimeout"
:stop-popper-mouse-event="false"
:virtual-ref="triggeringElementRef"
:virtual-triggering="splitButton"
append-to-body
pure
transition="el-zoom-in-top"
@show="$emit('visible-change', true)"
@hide="$emit('visible-change', false)"
>
<template #content>
<el-scrollbar
ref="scrollbar"
:wrap-style="wrapStyle"
tag="ul"
view-class="el-dropdown__list"
>
<el-focus-trap trapped @mount-on-focus="onMountOnFocus">
<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"></slot>
</el-dropdown-collection>
</el-roving-focus-group>
</el-focus-trap>
</el-scrollbar>
</template>
<template v-if="!splitButton" #default>
<div :class="dropdownTriggerKls">
<slot name="default" />
</div>
</template>
</el-tooltip>
<template v-if="splitButton">
<el-button-group>
<el-button
ref="referenceElementRef"
:size="dropdownSize"
:type="type"
@click="handlerMainButtonClick"
>
<slot name="default" />
</el-button>
<el-button
ref="triggeringElementRef"
:size="dropdownSize"
:type="type"
class="el-dropdown__caret-button"
>
<el-icon class="el-dropdown__icon"><arrow-down /></el-icon>
</el-button>
</el-button-group>
</template>
</div>
2020-11-04 11:24:36 +08:00
</template>
2020-11-12 14:43:55 +08:00
<script lang="ts">
2020-08-28 11:44:04 +08:00
import {
computed,
2020-08-28 11:44:04 +08:00
defineComponent,
getCurrentInstance,
provide,
2020-08-28 11:44:04 +08:00
ref,
toRef,
unref,
2020-08-28 11:44:04 +08:00
} 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 ElFocusTrap from '@element-plus/components/focus-trap'
import ElRovingFocusGroup from '@element-plus/components/roving-focus-group'
import { addUnit } from '@element-plus/utils/util'
import { ArrowDown } from '@element-plus/icons-vue'
import { useSize } from '@element-plus/hooks'
import { ElCollection as ElDropdownCollection, dropdownProps } from './dropdown'
import { DROPDOWN_INJECTION_KEY } from './tokens'
epic: refactor icons (#3492) * refactor(components): el-alert icon (#3441) * refactor(components): el-alert icon * fix: el-alert test * fix: [el-alert] lint error * feat(utils): add icon util * refactor(components): el-alert icon * refactor(utils): icon * test: update alert test * refactor: remove el-icon in util * refactor(components): el-notification icon (#3512) * chore: temp save changes * refactor: update icon * fix: var * docs: update icon * fix: type class error * style: remove unused class * fix: update icon type * docs: update icon * fix: update iconComponent * refactor(components): el-dialog icon (#3505) * refactor(components): [el-dialog] icon * fix: typo * refactor: dialog icon ref * refactor: dialog icon * style: update close button size * refactor(components): el-message-box icon (#3507) * refactor(components): message-box icon * refactor(components): message icon * fix: test * refactor: update ref * fix: test * docs: update icon * fix: delete unused code * docs: update type * fix: update close button size * fix: type * fix: icon type class * fix: icon type * fix: update type class * refactor(components): el-popconfirm icon (#3513) * refactor(components): el-popconfirm icon * fix: space styles * docs: update example * docs: update example for trigger event * refactor(components): el-page-header icon (#3518) * refactor(components): el-page-header icon * docs: update icon * fix: space errors * refactor(components): el-steps icon (#3520) * refactor(components): el-backtop icon (#3514) * refactor(components): el-backtop icon * fix: update font size * refactor(components): el-button icon (#3536) * refactor(components): el-button icon * fix: update example * refactor(components): el-button icon * refactor: style simplify Co-authored-by: imswk <syfzxx@vip.qq.com> * refactor(components): el-tree icon (#3590) Co-authored-by: qianjie <qianjie@patsnap.com> * refactor(components): el-avatar icon (#3599) Co-authored-by: qianjie <qianjie@patsnap.com> * refactor(components): el-carousel icon (#3602) Co-authored-by: qianjie <qianjie@patsnap.com> * refactor(components): el-progress icon (#3607) Co-authored-by: qianjie <qianjie@patsnap.com> * refactor(components): el-result icon (#3609) Co-authored-by: qianjie <qianjie@patsnap.com> * refactor(components): el-timeline icon (#3646) Co-authored-by: qianjie <qianjie@patsnap.com> * refactor(components): el-table icon (#3611) Co-authored-by: qianjie <qianjie@patsnap.com> * chore: add vue to gitignore * fix: buildProp error * refactor(components): el-pagination icon (#3605) * test: el-menu deprecated icon font (#3794) * test: el-loading deprecated icon font (#3795) * chore: Update changelog 1.1.0-beta.20 (#3838) * fix: about custom extension of table column (#3437) * refactor(components): el-autocomplete icon (#3783) * refactor(components): el-dropdown icon (#3517) * refactor(components): el-dropdown icon * fix: arrow down icon size * style: revert * fix: font-size * refactor(components): el-link icon (#3538) * refactor(components): el-link icon * refactor: update example * fix: import icons * docs: add tip * refactor: update link icon * fix: icon align * fix: typo * refactor(components): el-select icon (#3780) * refactor(components): el-input icon (#3565) * refactor(components): input icon * docs: update example * refactor(components): el-select icon * docs: icon usage * fix: input style * fix: add scoped * docs: fix icon * fix: icon align * fix: icon align * fix: typo * fix: typo * refactor(components): el-input-number icon (#3566) * refactor(components): el-input-number icon * fix: icon align * refactor(components): el-tag icon (#3793) * refactor(components): el-tag icon * fix: icon align * fix: icon margin * refactor(components): el-switch icon (#3787) * refactor(components): el-switch icon * fix: icon align * docs: add icon usage * refactor(components): el-collapse icon (#3788) * refactor(components): el-collapse icon * docs: update icon demo * fix: typo * refactor(components): el-uplod icon (#3598) * refactor(components): el-uplod icon * docs: update icon useage * docs: fix icon * docs: fix icon * docs: update upload-filled icon * fix: icon align * fix: item icon align * refactor(components): el-select-v2 icon (#3781) * refactor(components): el-select-v2 icon * revert: play/main.ts * fix: icon style * fix: icon solt * refactor(components): el-cascader icon (#3785) * refactor(components): input icon * docs: update example * refactor(components): el-select icon * refactor(components): el-cascader icon * refactor(components): el-tag icon * fix: icon align * fix: icon margin * docs: icon usage * fix: input style * fix: add scoped * test: remove unuesd code * fix: cascader-panel * fix: icon style * fix: icon animation * refactor(components): el-drawer icon (#3796) * refactor(components): el-drawer icon * fix: close icon size * fix: close icon align * refactor(components): el-transfer icon (#3792) * refactor(components): el-transfer icon * fix: icon align * refactor(components): el-image-viewer icon (#3797) * refactor(components): el-image-view icon * fix: icon size * docs: update domo * style: format vue * fix: fullscreen icon * Add cursor for icons Co-authored-by: jeremywuuuuu <15975785+JeremyWuuuuu@users.noreply.github.com> * refactor(components): rate-icon (#3891) * refactor(components): el-rate icon * docs: update example * docs: update * test: update * docs: update * fix: variable rename * fix: demo update * fix: allow half bug * refactor(components): el-time-picker icon (#3834) * refactor(components): el-button icon * refactor(components): date-picker icon * refactor(components): input icon * docs: update example * refactor(components): el-select icon * refactor(components): el-time-select icon * fix: icon width * docs: icon usage * fix: input style * fix: add scoped * fix: icon size * docs: icon display * fix: icon in button * docs: fix error * refactor(components): el-time-picker icon * fix: var * fix: icon align * test: delete unused code * test: fix error * fix: remove unused code * docs: fix typo * docs: update icon * fix: default prefix icon * fix: range picker icon align * Update cursor for picker Co-authored-by: jeremywuuuuu <15975785+JeremyWuuuuu@users.noreply.github.com> * fix(components): el-input close icon * chore: delete fonts * fix: copy full style Co-authored-by: imswk <syfzxx@vip.qq.com> Co-authored-by: bastarder <85257684@qq.com> Co-authored-by: qianjie <qianjie@patsnap.com> Co-authored-by: Element <wallement@gmail.com> Co-authored-by: Alan Wang <948467222@qq.com> Co-authored-by: jeremywuuuuu <15975785+JeremyWuuuuu@users.noreply.github.com>
2021-10-27 23:17:13 +08:00
import type { CSSProperties } from 'vue'
2020-08-28 11:44:04 +08:00
const { ButtonGroup: ElButtonGroup } = ElButton
2020-08-28 11:44:04 +08:00
export default defineComponent({
name: 'ElDropdown',
components: {
ElButton,
ElFocusTrap,
2020-08-28 11:44:04 +08:00
ElButtonGroup,
ElScrollbar,
ElDropdownCollection,
ElTooltip,
ElRovingFocusGroup,
epic: refactor icons (#3492) * refactor(components): el-alert icon (#3441) * refactor(components): el-alert icon * fix: el-alert test * fix: [el-alert] lint error * feat(utils): add icon util * refactor(components): el-alert icon * refactor(utils): icon * test: update alert test * refactor: remove el-icon in util * refactor(components): el-notification icon (#3512) * chore: temp save changes * refactor: update icon * fix: var * docs: update icon * fix: type class error * style: remove unused class * fix: update icon type * docs: update icon * fix: update iconComponent * refactor(components): el-dialog icon (#3505) * refactor(components): [el-dialog] icon * fix: typo * refactor: dialog icon ref * refactor: dialog icon * style: update close button size * refactor(components): el-message-box icon (#3507) * refactor(components): message-box icon * refactor(components): message icon * fix: test * refactor: update ref * fix: test * docs: update icon * fix: delete unused code * docs: update type * fix: update close button size * fix: type * fix: icon type class * fix: icon type * fix: update type class * refactor(components): el-popconfirm icon (#3513) * refactor(components): el-popconfirm icon * fix: space styles * docs: update example * docs: update example for trigger event * refactor(components): el-page-header icon (#3518) * refactor(components): el-page-header icon * docs: update icon * fix: space errors * refactor(components): el-steps icon (#3520) * refactor(components): el-backtop icon (#3514) * refactor(components): el-backtop icon * fix: update font size * refactor(components): el-button icon (#3536) * refactor(components): el-button icon * fix: update example * refactor(components): el-button icon * refactor: style simplify Co-authored-by: imswk <syfzxx@vip.qq.com> * refactor(components): el-tree icon (#3590) Co-authored-by: qianjie <qianjie@patsnap.com> * refactor(components): el-avatar icon (#3599) Co-authored-by: qianjie <qianjie@patsnap.com> * refactor(components): el-carousel icon (#3602) Co-authored-by: qianjie <qianjie@patsnap.com> * refactor(components): el-progress icon (#3607) Co-authored-by: qianjie <qianjie@patsnap.com> * refactor(components): el-result icon (#3609) Co-authored-by: qianjie <qianjie@patsnap.com> * refactor(components): el-timeline icon (#3646) Co-authored-by: qianjie <qianjie@patsnap.com> * refactor(components): el-table icon (#3611) Co-authored-by: qianjie <qianjie@patsnap.com> * chore: add vue to gitignore * fix: buildProp error * refactor(components): el-pagination icon (#3605) * test: el-menu deprecated icon font (#3794) * test: el-loading deprecated icon font (#3795) * chore: Update changelog 1.1.0-beta.20 (#3838) * fix: about custom extension of table column (#3437) * refactor(components): el-autocomplete icon (#3783) * refactor(components): el-dropdown icon (#3517) * refactor(components): el-dropdown icon * fix: arrow down icon size * style: revert * fix: font-size * refactor(components): el-link icon (#3538) * refactor(components): el-link icon * refactor: update example * fix: import icons * docs: add tip * refactor: update link icon * fix: icon align * fix: typo * refactor(components): el-select icon (#3780) * refactor(components): el-input icon (#3565) * refactor(components): input icon * docs: update example * refactor(components): el-select icon * docs: icon usage * fix: input style * fix: add scoped * docs: fix icon * fix: icon align * fix: icon align * fix: typo * fix: typo * refactor(components): el-input-number icon (#3566) * refactor(components): el-input-number icon * fix: icon align * refactor(components): el-tag icon (#3793) * refactor(components): el-tag icon * fix: icon align * fix: icon margin * refactor(components): el-switch icon (#3787) * refactor(components): el-switch icon * fix: icon align * docs: add icon usage * refactor(components): el-collapse icon (#3788) * refactor(components): el-collapse icon * docs: update icon demo * fix: typo * refactor(components): el-uplod icon (#3598) * refactor(components): el-uplod icon * docs: update icon useage * docs: fix icon * docs: fix icon * docs: update upload-filled icon * fix: icon align * fix: item icon align * refactor(components): el-select-v2 icon (#3781) * refactor(components): el-select-v2 icon * revert: play/main.ts * fix: icon style * fix: icon solt * refactor(components): el-cascader icon (#3785) * refactor(components): input icon * docs: update example * refactor(components): el-select icon * refactor(components): el-cascader icon * refactor(components): el-tag icon * fix: icon align * fix: icon margin * docs: icon usage * fix: input style * fix: add scoped * test: remove unuesd code * fix: cascader-panel * fix: icon style * fix: icon animation * refactor(components): el-drawer icon (#3796) * refactor(components): el-drawer icon * fix: close icon size * fix: close icon align * refactor(components): el-transfer icon (#3792) * refactor(components): el-transfer icon * fix: icon align * refactor(components): el-image-viewer icon (#3797) * refactor(components): el-image-view icon * fix: icon size * docs: update domo * style: format vue * fix: fullscreen icon * Add cursor for icons Co-authored-by: jeremywuuuuu <15975785+JeremyWuuuuu@users.noreply.github.com> * refactor(components): rate-icon (#3891) * refactor(components): el-rate icon * docs: update example * docs: update * test: update * docs: update * fix: variable rename * fix: demo update * fix: allow half bug * refactor(components): el-time-picker icon (#3834) * refactor(components): el-button icon * refactor(components): date-picker icon * refactor(components): input icon * docs: update example * refactor(components): el-select icon * refactor(components): el-time-select icon * fix: icon width * docs: icon usage * fix: input style * fix: add scoped * fix: icon size * docs: icon display * fix: icon in button * docs: fix error * refactor(components): el-time-picker icon * fix: var * fix: icon align * test: delete unused code * test: fix error * fix: remove unused code * docs: fix typo * docs: update icon * fix: default prefix icon * fix: range picker icon align * Update cursor for picker Co-authored-by: jeremywuuuuu <15975785+JeremyWuuuuu@users.noreply.github.com> * fix(components): el-input close icon * chore: delete fonts * fix: copy full style Co-authored-by: imswk <syfzxx@vip.qq.com> Co-authored-by: bastarder <85257684@qq.com> Co-authored-by: qianjie <qianjie@patsnap.com> Co-authored-by: Element <wallement@gmail.com> Co-authored-by: Alan Wang <948467222@qq.com> Co-authored-by: jeremywuuuuu <15975785+JeremyWuuuuu@users.noreply.github.com>
2021-10-27 23:17:13 +08:00
ElIcon,
ArrowDown,
2020-08-28 11:44:04 +08:00
},
props: dropdownProps,
2020-08-28 11:44:04 +08:00
emits: ['visible-change', 'click', 'command'],
2020-11-04 11:24:36 +08:00
setup(props, { emit }) {
2020-08-28 11:44:04 +08:00
const _instance = getCurrentInstance()
const triggeringElementRef = ref()
const referenceElementRef = ref()
const popperRef = ref<InstanceType<typeof ElTooltip> | null>(null)
const contentRef = ref<HTMLElement | null>(null)
2020-08-28 11:44:04 +08:00
const visible = ref(false)
const scrollbar = ref(null)
const currentTabId = ref<string | null>(null)
const isUsingKeyboard = ref(false)
const wrapStyle = computed<CSSProperties>(() => ({
maxHeight: addUnit(props.maxHeight),
}))
const dropdownTriggerKls = computed(() => [
[dropdownSize.value ? `el-dropdown--${dropdownSize.value}` : ''],
])
2020-08-28 11:44:04 +08:00
function handleClick() {
popperRef.value?.onClose()
2020-08-28 11:44:04 +08:00
}
const dropdownSize = useSize()
2020-08-28 11:44:04 +08:00
function commandHandler(...args: any[]) {
emit('command', ...args)
2020-08-28 11:44:04 +08:00
}
function onItemEnter() {
// NOOP for now
2020-08-28 11:44:04 +08:00
}
function onItemLeave() {
const contentEl = unref(contentRef)
2020-08-28 11:44:04 +08:00
contentEl?.focus()
currentTabId.value = null
2020-08-28 11:44:04 +08:00
}
function handleCurrentTabIdChange(id: string) {
currentTabId.value = id
2020-08-28 11:44:04 +08:00
}
function handleEntryFocus(e: Event) {
if (!isUsingKeyboard.value) {
e.preventDefault()
e.stopImmediatePropagation()
}
2020-08-28 11:44:04 +08:00
}
provide(DROPDOWN_INJECTION_KEY, {
contentRef,
isUsingKeyboard,
onItemEnter,
onItemLeave,
})
2020-08-28 11:44:04 +08:00
provide('elDropdown', {
instance: _instance,
dropdownSize,
visible,
handleClick,
commandHandler,
trigger: toRef(props, 'trigger'),
hideOnClick: toRef(props, 'hideOnClick'),
2020-08-28 11:44:04 +08:00
})
const onMountOnFocus = (e: Event) => {
e.preventDefault()
contentRef.value?.focus?.({
preventScroll: true,
2020-11-04 11:24:36 +08:00
})
}
2020-08-28 11:44:04 +08:00
const handlerMainButtonClick = (event: MouseEvent) => {
2020-08-28 11:44:04 +08:00
emit('click', event)
}
2020-11-04 11:24:36 +08:00
return {
visible,
scrollbar,
wrapStyle,
dropdownTriggerKls,
2020-11-04 11:24:36 +08:00
dropdownSize,
currentTabId,
handleCurrentTabIdChange,
2020-11-04 11:24:36 +08:00
handlerMainButtonClick,
handleEntryFocus,
onMountOnFocus,
popperRef,
triggeringElementRef,
referenceElementRef,
2020-11-04 11:24:36 +08:00
}
2020-08-28 11:44:04 +08:00
},
})
</script>