Skip to content

Commit 027c06a

Browse files
devzombenjamincanac
andcommitted
fix(Drawer): prevent unwanted close when dismissible is false (#5085)
Co-authored-by: Benjamin Canac <[email protected]>
1 parent b6d04c2 commit 027c06a

File tree

5 files changed

+40
-7
lines changed

5 files changed

+40
-7
lines changed

docs/content/3.components/drawer.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ This allows you to move the trigger outside of the Drawer or remove it entirely.
293293

294294
### Disable dismissal
295295

296-
Set the `dismissible` prop to `false` to prevent the Drawer from being closed when clicking outside of it or pressing escape.
296+
Set the `dismissible` prop to `false` to prevent the Drawer from being closed when clicking outside of it or pressing escape. A `close:prevent` event will be emitted when the user tries to close it.
297297

298298
::component-example
299299
---

playground/app/pages/components/drawer.vue

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,21 @@ const inset = ref(false)
4242
</template>
4343
</UDrawer>
4444

45+
<UDrawer
46+
title="Drawer prevent close"
47+
description="This drawer has `dismissible: false` prop so it won't close when clicking outside."
48+
:dismissible="false"
49+
:modal="false"
50+
:overlay="false"
51+
:inset="inset"
52+
>
53+
<UButton label="Open unclosable" color="neutral" variant="outline" />
54+
55+
<template #body>
56+
<Placeholder class="h-96 w-full" />
57+
</template>
58+
</UDrawer>
59+
4560
<UDrawer title="Drawer with bottom direction" direction="bottom" :inset="inset">
4661
<UButton color="neutral" variant="outline" label="Open on bottom" />
4762

playground/app/pages/components/modal.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ function openModal() {
5656
<UButton label="Open fullscreen" color="neutral" variant="outline" />
5757
</UModal>
5858

59-
<UModal title="Modal prevent close" description="This modal has `dismissible: false` prop so it won't close when clicking outside." :dismissible="false">
59+
<UModal title="Modal prevent close" description="This modal has `dismissible: false` prop so it won't close when clicking outside." :dismissible="false" :modal="false" :overlay="false">
6060
<UButton label="Open unclosable" color="neutral" variant="subtle" />
6161
</UModal>
6262

playground/app/pages/components/slideover.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ function openSlideover() {
100100
</template>
101101
</USlideover>
102102

103-
<USlideover title="Slideover prevent close" description="This slideover has `dismissible: false` prop so it won't close when clicking outside." :dismissible="false">
103+
<USlideover title="Slideover prevent close" description="This slideover has `dismissible: false` prop so it won't close when clicking outside." :dismissible="false" :modal="false" :overlay="false">
104104
<UButton label="Open unclosable" color="neutral" variant="subtle" />
105105

106106
<template #body>

src/runtime/components/Drawer.vue

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ export interface DrawerProps extends Pick<DrawerRootProps, 'activeSnapPoint' | '
4646
ui?: Drawer['slots']
4747
}
4848
49-
export interface DrawerEmits extends DrawerRootEmits {}
49+
export interface DrawerEmits extends DrawerRootEmits {
50+
(e: 'close:prevent'): void
51+
}
5052
5153
export interface DrawerSlots {
5254
default(props?: {}): any
@@ -84,9 +86,25 @@ const appConfig = useAppConfig() as Drawer['AppConfig']
8486
const rootProps = useForwardPropsEmits(reactivePick(props, 'activeSnapPoint', 'closeThreshold', 'shouldScaleBackground', 'setBackgroundColorOnScale', 'scrollLockTimeout', 'fixed', 'dismissible', 'modal', 'open', 'defaultOpen', 'nested', 'direction', 'noBodyStyles', 'handleOnly', 'preventScrollRestoration', 'snapPoints'), emits)
8587
const portalProps = usePortal(toRef(() => props.portal))
8688
const contentProps = toRef(() => props.content)
87-
const contentEvents = {
88-
closeAutoFocus: (e: Event) => e.preventDefault()
89-
}
89+
const contentEvents = computed(() => {
90+
const defaultEvents = {
91+
closeAutoFocus: (e: Event) => e.preventDefault()
92+
}
93+
94+
if (!props.dismissible) {
95+
const events = ['pointerDownOutside', 'interactOutside', 'escapeKeyDown']
96+
97+
return events.reduce((acc, curr) => {
98+
acc[curr] = (e: Event) => {
99+
e.preventDefault()
100+
emits('close:prevent')
101+
}
102+
return acc
103+
}, defaultEvents as Record<typeof events[number] | keyof typeof defaultEvents, (e: Event) => void>)
104+
}
105+
106+
return defaultEvents
107+
})
90108
91109
const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.drawer || {}) })({
92110
direction: props.direction,

0 commit comments

Comments
 (0)