Skip to content

Commit 90e5ae7

Browse files
Merge pull request #342 from vue-final/fix/esc
fix: should focus vfmContent element when click outside
2 parents 7b9152a + 4a5ab5f commit 90e5ae7

File tree

3 files changed

+51
-48
lines changed

3 files changed

+51
-48
lines changed

packages/vue-final-modal/src/components/CoreModal/CoreModal.vue

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ const {
5151
} as any as InternalVfm)
5252
5353
const vfmRootEl = ref<HTMLDivElement>()
54+
const vfmContentEl = ref<HTMLDivElement>()
5455
5556
const { focus, blur } = useFocusTrap(props, { focusEl: vfmRootEl })
5657
const { zIndex, refreshZIndex, resetZIndex } = useZIndex(props)
@@ -89,14 +90,13 @@ const {
8990
},
9091
})
9192
92-
const { onEsc, onMouseupRoot, onMousedown } = useToClose(props, emit, { vfmRootEl, visible, modelValueLocal })
93+
const { onEsc, onMouseupRoot, onMousedown } = useToClose(props, emit, { vfmRootEl, vfmContentEl, visible, modelValueLocal })
9394
9495
const {
95-
vfmContentEl,
9696
swipeBannerEl,
9797
bindSwipe,
9898
onTouchStartSwipeBanner,
99-
} = useSwipeToClose(props, { modelValueLocal })
99+
} = useSwipeToClose(props, { vfmContentEl, modelValueLocal })
100100
101101
const hideOverlay = toRef(props, 'hideOverlay')
102102
const modalInstance = computed<Modal>(() => ({
@@ -175,15 +175,14 @@ onBeforeUnmount(() => {
175175
:style="{ zIndex }"
176176
role="dialog"
177177
aria-modal="true"
178-
@keydown.esc="onEsc"
178+
@keydown.esc="() => onEsc()"
179179
@mouseup.self="() => onMouseupRoot()"
180180
@mousedown.self="e => onMousedown(e)"
181181
>
182182
<Transition v-if="!hideOverlay" v-bind="overlayTransition" appear v-on="overlayListeners">
183183
<div
184184
v-if="overlayVisible"
185185
class="vfm__overlay vfm--overlay vfm--absolute vfm--inset vfm--prevent-none"
186-
style="z-index: -1"
187186
:class="overlayClass"
188187
:style="overlayStyle"
189188
aria-hidden="true"
@@ -240,6 +239,7 @@ onBeforeUnmount(() => {
240239
left: 0;
241240
}
242241
.vfm--overlay {
242+
z-index: -1;
243243
background-color: rgba(0, 0, 0, 0.5);
244244
}
245245
.vfm--prevent-none {
@@ -274,11 +274,11 @@ onBeforeUnmount(() => {
274274
}
275275
.vfm-slide-down-enter-from,
276276
.vfm-slide-down-leave-to {
277-
transform: translateY(100vh);
277+
transform: translateY(100vh) !important;
278278
}
279279
.vfm-slide-up-enter-from,
280280
.vfm-slide-up-leave-to {
281-
transform: translateY(-100vh);
281+
transform: translateY(-100vh) !important;
282282
}
283283
284284
.vfm-slide-right-enter-active,
@@ -289,11 +289,11 @@ onBeforeUnmount(() => {
289289
}
290290
.vfm-slide-right-enter-from,
291291
.vfm-slide-right-leave-to {
292-
transform: translateX(100vw);
292+
transform: translateX(100vw) !important;
293293
}
294294
.vfm-slide-left-enter-from,
295295
.vfm-slide-left-leave-to {
296-
transform: translateX(-100vw);
296+
transform: translateX(-100vw) !important;
297297
}
298298
299299
.vfm-swipe-banner-back,

packages/vue-final-modal/src/components/CoreModal/useToClose.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@ export function useToClose(
77
emit: InstanceType<typeof CoreModal>['$emit'],
88
options: {
99
vfmRootEl: Ref<HTMLDivElement | undefined>
10+
vfmContentEl: Ref<HTMLDivElement | undefined>
1011
visible: Ref<boolean>
1112
modelValueLocal: Ref<boolean>
1213
}) {
13-
const { vfmRootEl, visible, modelValueLocal } = options
14+
const { vfmRootEl, vfmContentEl, visible, modelValueLocal } = options
1415
const lastMousedownEl = ref<EventTarget | null>()
1516

1617
function onEsc() {
1718
if (visible.value && props.escToClose)
18-
(modelValueLocal.value = false)
19+
modelValueLocal.value = false
1920
}
2021

2122
function onMousedown(e?: MouseEvent) {
@@ -27,10 +28,13 @@ export function useToClose(
2728
if (lastMousedownEl.value !== vfmRootEl.value)
2829
return
2930

30-
if (props.clickToClose)
31+
if (props.clickToClose) {
3132
modelValueLocal.value = false
32-
else
33+
}
34+
else {
35+
vfmContentEl.value?.focus()
3336
emit('clickOutside')
37+
}
3438
}
3539

3640
return {

packages/vue-final-modal/src/useSwipeToClose.ts

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ import { clamp, noop } from './utils'
88
export function useSwipeToClose(
99
props: InstanceType<typeof CoreModal>['$props'],
1010
options: {
11+
vfmContentEl: Ref<HTMLDivElement | undefined>
1112
modelValueLocal: Ref<boolean>
1213
},
1314
) {
14-
const { modelValueLocal } = options
15+
const { vfmContentEl, modelValueLocal } = options
1516
const LIMIT_DISTANCE = 0.1
1617
const LIMIT_SPEED = 300
1718

18-
const vfmContentEl = ref<HTMLDivElement>()
1919
const swipeBannerEl = ref<HTMLDivElement>()
2020
const swipeEl = computed(() => {
2121
if (props.swipeToClose === undefined || props.swipeToClose === 'none')
@@ -84,7 +84,6 @@ export function useSwipeToClose(
8484
const validSpeed = swipeEnd - swipeStart <= LIMIT_SPEED
8585

8686
if (shouldCloseModal && allowSwipe && validDirection && (validDistance || validSpeed)) {
87-
offset.value = 0
8887
modelValueLocal.value = false
8988
return
9089
}
@@ -93,6 +92,25 @@ export function useSwipeToClose(
9392
},
9493
})
9594

95+
const bindSwipe = computed(() => {
96+
if (props.swipeToClose === 'none')
97+
return
98+
const translateDirection = (() => {
99+
switch (props.swipeToClose) {
100+
case 'up':
101+
case 'down':
102+
return 'translateY'
103+
case 'left':
104+
case 'right':
105+
return 'translateX'
106+
}
107+
})()
108+
return {
109+
class: { 'vfm-bounce-back': !isSwiping.value },
110+
style: { transform: `${translateDirection}(${-offset.value}px)` },
111+
}
112+
})
113+
96114
watch(
97115
() => isCollapsed.value,
98116
(val) => {
@@ -101,6 +119,14 @@ export function useSwipeToClose(
101119
},
102120
)
103121

122+
watch(
123+
() => modelValueLocal.value,
124+
(val) => {
125+
if (val)
126+
offset.value = 0
127+
},
128+
)
129+
104130
watch(
105131
() => offset.value,
106132
(newValue, oldValue) => {
@@ -117,6 +143,11 @@ export function useSwipeToClose(
117143
},
118144
)
119145

146+
function onTouchStartSwipeBanner(e: TouchEvent) {
147+
if (props.preventNavigationGestures)
148+
e.preventDefault()
149+
}
150+
120151
function canSwipe(target?: null | EventTarget): boolean {
121152
const tagName = (target as HTMLElement)?.tagName
122153
if (!tagName || ['INPUT', 'TEXTAREA'].includes(tagName))
@@ -143,38 +174,6 @@ export function useSwipeToClose(
143174
return allow && canSwipe((target as HTMLElement)?.parentElement)
144175
}
145176

146-
watch(
147-
() => modelValueLocal.value,
148-
(val) => {
149-
if (val)
150-
offset.value = 0
151-
},
152-
)
153-
154-
const bindSwipe = computed(() => {
155-
if (props.swipeToClose === 'none')
156-
return
157-
const translateDirection = (() => {
158-
switch (props.swipeToClose) {
159-
case 'up':
160-
case 'down':
161-
return 'translateY'
162-
case 'left':
163-
case 'right':
164-
return 'translateX'
165-
}
166-
})()
167-
return {
168-
class: { 'vfm-bounce-back': !isSwiping.value },
169-
style: isSwiping.value ? { transform: `${translateDirection}(${-offset.value}px)` } : '',
170-
}
171-
})
172-
173-
function onTouchStartSwipeBanner(e: TouchEvent) {
174-
if (props.preventNavigationGestures)
175-
e.preventDefault()
176-
}
177-
178177
return {
179178
vfmContentEl,
180179
swipeBannerEl,

0 commit comments

Comments
 (0)