mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
fix(components): [popconfirm] unable to capture focus (#22310)
* fix(components): [popconfirm] unable to capture focus * fix: test * chore: revert event
This commit is contained in:
@@ -55,7 +55,6 @@ popconfirm/trigger-event
|
||||
| ---------------------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | -------------- |
|
||||
| title | Title | ^[string] | — |
|
||||
| effect ^(2.11.2) | Tooltip theme, built-in theme: `dark` / `light` | ^[enum]`'dark' \| 'light'` / ^[string] | light |
|
||||
| close-on-press-escape ^(2.11.2) | whether the popConfirm can be closed by pressing ESC | ^[boolean] | true |
|
||||
| confirm-button-text | Confirm button text | ^[string] | — |
|
||||
| cancel-button-text | Cancel button text | ^[string] | — |
|
||||
| confirm-button-type | Confirm button type | ^[enum]`'primary' \| 'success' \| 'warning' \| 'danger' \| 'info' \| 'text'` | primary |
|
||||
|
||||
@@ -43,14 +43,11 @@ describe('Popconfirm.vue', () => {
|
||||
})
|
||||
|
||||
it('should close the Popconfirm when pressing Escape', async () => {
|
||||
const onCancel = vi.fn()
|
||||
|
||||
const wrapper = mount({
|
||||
setup() {
|
||||
return () => (
|
||||
<Popconfirm
|
||||
closeOnPressEscape={false}
|
||||
onCancel={onCancel}
|
||||
hide-after={0}
|
||||
v-slots={{
|
||||
reference: () => <div class="reference">{AXIOM}</div>,
|
||||
}}
|
||||
@@ -65,13 +62,11 @@ describe('Popconfirm.vue', () => {
|
||||
|
||||
triggerEvent(document.body, 'keydown', EVENT_CODE.esc)
|
||||
await nextTick()
|
||||
expect(onCancel).toHaveBeenCalledTimes(0)
|
||||
await rAF()
|
||||
|
||||
await wrapper.setProps({ closeOnPressEscape: true })
|
||||
|
||||
triggerEvent(document.body, 'keydown', EVENT_CODE.esc)
|
||||
await nextTick()
|
||||
expect(onCancel).toHaveBeenCalledTimes(1)
|
||||
expect(document.querySelector(selector)!.getAttribute('style')).toContain(
|
||||
'display: none'
|
||||
)
|
||||
})
|
||||
|
||||
describe('teleported API', () => {
|
||||
|
||||
@@ -82,13 +82,6 @@ export const popconfirmProps = buildProps({
|
||||
type: [String, Number],
|
||||
default: 150,
|
||||
},
|
||||
/**
|
||||
* @description whether the popConfirm can be closed by pressing ESC
|
||||
*/
|
||||
closeOnPressEscape: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
} as const)
|
||||
|
||||
export const popconfirmEmits = {
|
||||
@@ -99,8 +92,7 @@ export const popconfirmEmits = {
|
||||
/**
|
||||
* @description triggers when click cancel button
|
||||
*/
|
||||
cancel: (e: MouseEvent | KeyboardEvent) =>
|
||||
e instanceof MouseEvent || e instanceof KeyboardEvent,
|
||||
cancel: (e: MouseEvent) => e instanceof MouseEvent,
|
||||
}
|
||||
|
||||
export type PopconfirmEmits = typeof popconfirmEmits
|
||||
|
||||
@@ -10,42 +10,42 @@
|
||||
:fallback-placements="['bottom', 'top', 'right', 'left']"
|
||||
:hide-after="hideAfter"
|
||||
:persistent="persistent"
|
||||
loop
|
||||
@show="showPopper"
|
||||
>
|
||||
<template #content>
|
||||
<el-focus-trap loop trapped @release-requested="onCloseRequested">
|
||||
<div :class="ns.b()">
|
||||
<div :class="ns.e('main')">
|
||||
<el-icon
|
||||
v-if="!hideIcon && icon"
|
||||
:class="ns.e('icon')"
|
||||
:style="{ color: iconColor }"
|
||||
>
|
||||
<component :is="icon" />
|
||||
</el-icon>
|
||||
{{ title }}
|
||||
</div>
|
||||
<div :class="ns.e('action')">
|
||||
<slot name="actions" :confirm="confirm" :cancel="cancel">
|
||||
<el-button
|
||||
size="small"
|
||||
:type="cancelButtonType === 'text' ? '' : cancelButtonType"
|
||||
:text="cancelButtonType === 'text'"
|
||||
@click="cancel"
|
||||
>
|
||||
{{ finalCancelButtonText }}
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
:type="confirmButtonType === 'text' ? '' : confirmButtonType"
|
||||
:text="confirmButtonType === 'text'"
|
||||
@click="confirm"
|
||||
>
|
||||
{{ finalConfirmButtonText }}
|
||||
</el-button>
|
||||
</slot>
|
||||
</div>
|
||||
<div ref="rootRef" tabindex="-1" :class="ns.b()">
|
||||
<div :class="ns.e('main')">
|
||||
<el-icon
|
||||
v-if="!hideIcon && icon"
|
||||
:class="ns.e('icon')"
|
||||
:style="{ color: iconColor }"
|
||||
>
|
||||
<component :is="icon" />
|
||||
</el-icon>
|
||||
{{ title }}
|
||||
</div>
|
||||
</el-focus-trap>
|
||||
<div :class="ns.e('action')">
|
||||
<slot name="actions" :confirm="confirm" :cancel="cancel">
|
||||
<el-button
|
||||
size="small"
|
||||
:type="cancelButtonType === 'text' ? '' : cancelButtonType"
|
||||
:text="cancelButtonType === 'text'"
|
||||
@click="cancel"
|
||||
>
|
||||
{{ finalCancelButtonText }}
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
:type="confirmButtonType === 'text' ? '' : confirmButtonType"
|
||||
:text="confirmButtonType === 'text'"
|
||||
@click="confirm"
|
||||
>
|
||||
{{ finalConfirmButtonText }}
|
||||
</el-button>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="$slots.reference">
|
||||
<slot name="reference" />
|
||||
@@ -61,7 +61,6 @@ import ElTooltip from '@element-plus/components/tooltip'
|
||||
import { useLocale, useNamespace } from '@element-plus/hooks'
|
||||
import { addUnit } from '@element-plus/utils'
|
||||
import { popconfirmEmits, popconfirmProps } from './popconfirm'
|
||||
import ElFocusTrap from '@element-plus/components/focus-trap'
|
||||
|
||||
import type { TooltipInstance } from '@element-plus/components/tooltip'
|
||||
|
||||
@@ -75,10 +74,16 @@ const emit = defineEmits(popconfirmEmits)
|
||||
const { t } = useLocale()
|
||||
const ns = useNamespace('popconfirm')
|
||||
const tooltipRef = ref<TooltipInstance>()
|
||||
const rootRef = ref<HTMLElement>()
|
||||
|
||||
const popperRef = computed(() => {
|
||||
return unref(tooltipRef)?.popperRef
|
||||
})
|
||||
|
||||
const showPopper = () => {
|
||||
rootRef.value?.focus?.()
|
||||
}
|
||||
|
||||
const hidePopper = () => {
|
||||
tooltipRef.value?.onClose?.()
|
||||
}
|
||||
@@ -93,17 +98,11 @@ const confirm = (e: MouseEvent) => {
|
||||
emit('confirm', e)
|
||||
hidePopper()
|
||||
}
|
||||
const cancel = (e: MouseEvent | KeyboardEvent) => {
|
||||
const cancel = (e: MouseEvent) => {
|
||||
emit('cancel', e)
|
||||
hidePopper()
|
||||
}
|
||||
|
||||
const onCloseRequested = (event: KeyboardEvent) => {
|
||||
if (props.closeOnPressEscape) {
|
||||
cancel(event)
|
||||
}
|
||||
}
|
||||
|
||||
const finalConfirmButtonText = computed(
|
||||
() => props.confirmButtonText || t('el.popconfirm.confirmButtonText')
|
||||
)
|
||||
|
||||
@@ -113,6 +113,7 @@ export const popperContentProps = buildProps({
|
||||
virtualTriggering: Boolean,
|
||||
zIndex: Number,
|
||||
...useAriaProps(['ariaLabel']),
|
||||
loop: Boolean,
|
||||
} as const)
|
||||
export type PopperContentProps = ExtractPropTypes<typeof popperContentProps>
|
||||
export type PopperContentPropsPublic = __ExtractPublicPropTypes<
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
@mouseleave="(e) => $emit('mouseleave', e)"
|
||||
>
|
||||
<el-focus-trap
|
||||
:loop="loop"
|
||||
:trapped="trapped"
|
||||
:trap-on-focus-in="true"
|
||||
:focus-trap-el="contentRef"
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
:trigger-target-el="triggerTargetEl"
|
||||
:visible="shouldShow"
|
||||
:z-index="zIndex"
|
||||
:loop="loop"
|
||||
@mouseenter="onContentEnter"
|
||||
@mouseleave="onContentLeave"
|
||||
@blur="onBlur"
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
:virtual-triggering="virtualTriggering"
|
||||
:z-index="zIndex"
|
||||
:append-to="appendTo"
|
||||
:loop="loop"
|
||||
>
|
||||
<slot name="content">
|
||||
<span v-if="rawContent" v-html="content" />
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
@use 'common/var' as *;
|
||||
|
||||
@include b(popconfirm) {
|
||||
outline: none;
|
||||
@include e(main) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user