fix(components): [image-viewer] unable to capture focus (#17919)

* fix(components): [image-viewer] unable to capture focus

closed #7180

* fix: error

* fix: style

* fix: add release-requested
This commit is contained in:
qiang 2024-11-20 09:33:59 +08:00 committed by GitHub
parent 84fb6933c3
commit b80744c045
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 82 additions and 59 deletions

View File

@ -7,67 +7,76 @@
:class="ns.e('wrapper')"
:style="{ zIndex }"
>
<div :class="ns.e('mask')" @click.self="hideOnClickModal && hide()" />
<el-focus-trap
loop
trapped
:focus-trap-el="wrapper"
focus-start-el="container"
@focusout-prevented="onFocusoutPrevented"
@release-requested="onCloseRequested"
>
<div :class="ns.e('mask')" @click.self="hideOnClickModal && hide()" />
<!-- CLOSE -->
<span :class="[ns.e('btn'), ns.e('close')]" @click="hide">
<el-icon>
<Close />
</el-icon>
</span>
<!-- ARROW -->
<template v-if="!isSingle">
<span :class="arrowPrevKls" @click="prev">
<!-- CLOSE -->
<span :class="[ns.e('btn'), ns.e('close')]" @click="hide">
<el-icon>
<ArrowLeft />
<Close />
</el-icon>
</span>
<span :class="arrowNextKls" @click="next">
<el-icon>
<ArrowRight />
</el-icon>
</span>
</template>
<!-- ACTIONS -->
<div :class="[ns.e('btn'), ns.e('actions')]">
<div :class="ns.e('actions__inner')">
<el-icon @click="handleActions('zoomOut')">
<ZoomOut />
</el-icon>
<el-icon @click="handleActions('zoomIn')">
<ZoomIn />
</el-icon>
<i :class="ns.e('actions__divider')" />
<el-icon @click="toggleMode">
<component :is="mode.icon" />
</el-icon>
<i :class="ns.e('actions__divider')" />
<el-icon @click="handleActions('anticlockwise')">
<RefreshLeft />
</el-icon>
<el-icon @click="handleActions('clockwise')">
<RefreshRight />
</el-icon>
<!-- ARROW -->
<template v-if="!isSingle">
<span :class="arrowPrevKls" @click="prev">
<el-icon>
<ArrowLeft />
</el-icon>
</span>
<span :class="arrowNextKls" @click="next">
<el-icon>
<ArrowRight />
</el-icon>
</span>
</template>
<!-- ACTIONS -->
<div :class="[ns.e('btn'), ns.e('actions')]">
<div :class="ns.e('actions__inner')">
<el-icon @click="handleActions('zoomOut')">
<ZoomOut />
</el-icon>
<el-icon @click="handleActions('zoomIn')">
<ZoomIn />
</el-icon>
<i :class="ns.e('actions__divider')" />
<el-icon @click="toggleMode">
<component :is="mode.icon" />
</el-icon>
<i :class="ns.e('actions__divider')" />
<el-icon @click="handleActions('anticlockwise')">
<RefreshLeft />
</el-icon>
<el-icon @click="handleActions('clockwise')">
<RefreshRight />
</el-icon>
</div>
</div>
</div>
<!-- CANVAS -->
<div :class="ns.e('canvas')">
<img
v-for="(url, i) in urlList"
v-show="i === activeIndex"
:ref="(el) => (imgRefs[i] = el as HTMLImageElement)"
:key="url"
:src="url"
:style="imgStyle"
:class="ns.e('img')"
:crossorigin="crossorigin"
@load="handleImgLoad"
@error="handleImgError"
@mousedown="handleMouseDown"
/>
</div>
<slot />
<!-- CANVAS -->
<div :class="ns.e('canvas')">
<img
v-for="(url, i) in urlList"
v-show="i === activeIndex"
:ref="(el) => (imgRefs[i] = el as HTMLImageElement)"
:key="url"
:src="url"
:style="imgStyle"
:class="ns.e('img')"
:crossorigin="crossorigin"
@load="handleImgLoad"
@error="handleImgError"
@mousedown="handleMouseDown"
/>
</div>
<slot />
</el-focus-trap>
</div>
</transition>
</el-teleport>
@ -89,6 +98,7 @@ import { throttle } from 'lodash-unified'
import { useLocale, useNamespace, useZIndex } from '@element-plus/hooks'
import { EVENT_CODE } from '@element-plus/constants'
import { keysOf } from '@element-plus/utils'
import ElFocusTrap from '@element-plus/components/focus-trap'
import ElTeleport from '@element-plus/components/teleport'
import ElIcon from '@element-plus/components/icon'
import {
@ -352,6 +362,18 @@ function handleActions(action: ImageViewerAction, options = {}) {
transform.value.enableTransition = enableTransition
}
function onFocusoutPrevented(event: CustomEvent) {
if (event.detail?.focusReason === 'pointer') {
event.preventDefault()
}
}
function onCloseRequested() {
if (props.closeOnPressEscape) {
hide()
}
}
watch(currentImg, () => {
nextTick(() => {
const $img = imgRefs.value[0]
@ -368,9 +390,6 @@ watch(activeIndex, (val) => {
onMounted(() => {
registerEventListener()
// add tabindex then wrapper can be focusable via Javascript
// focus wrapper so arrow key can't cause inner scroll behavior underneath
wrapper.value?.focus?.()
})
defineExpose({

View File

@ -17,6 +17,10 @@
right: 0;
bottom: 0;
left: 0;
&:focus {
outline: none !important;
}
}
@include e(btn) {