Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions playgrounds/nuxt/app/pages/components/modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const LazyModalExample = defineAsyncComponent(() => import('../../components/Mod
const open = ref(false)
const count = ref(0)
const overlay = useOverlay()
const toast = useToast()

const modal = overlay.create(LazyModalExample, {
props: {
Expand All @@ -18,6 +19,15 @@ function openModal() {

modal.open({ count: count.value })
}

function showToast() {
toast.add({
title: 'Toast displayed!',
description: 'This toast was triggered from the modal.',
color: 'success',
icon: 'i-lucide-check-circle'
})
}
</script>

<template>
Expand Down Expand Up @@ -92,5 +102,19 @@ function openModal() {
<UButton label="Close with scoped slot close" @click="close" />
</template>
</UModal>

<UModal title="Modal with toast" description="Touch bug repro: tap 'Show Toast' multiple times, modal closes unexpectedly on touch devices.">
<UButton label="Open with toast" color="neutral" variant="subtle" />

<template #body>
<UButton
label="Show Toast"
color="neutral"
variant="outline"
icon="i-lucide-bell"
@click="showToast"
/>
</template>
</UModal>
</div>
</template>
29 changes: 19 additions & 10 deletions src/runtime/components/Modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -118,20 +118,29 @@ const contentEvents = computed(() => {
}, {} as Record<typeof events[number], (e: Event) => void>)
}

if (props.scrollable) {
return {
// FIXME: This is a workaround to prevent the modal from closing when clicking on the scrollbar https://reka-ui.com/docs/components/dialog#scrollable-overlay but it's not working on Mac OS.
pointerDownOutside: (e: any) => {
const originalEvent = e.detail.originalEvent
const target = originalEvent.target as HTMLElement
if (originalEvent.offsetX > target.clientWidth || originalEvent.offsetY > target.clientHeight) {
e.preventDefault()
}
const handlePointerDownOutside = (e: any) => {
const originalEvent = e.detail.originalEvent
const target = originalEvent.target as HTMLElement

// Fix for touch devices: prevent modal from closing when the target is part of another overlay layer (toast, popover, etc.)
// or when the target is no longer in the DOM (e.g., toast was dismissed)
if (!target || !document.body.contains(target) || target.closest('[data-dismissable-layer]')) {
e.preventDefault()
return
}

// Scrollable mode: prevent closing when clicking on scrollbar
// FIXME: This is a workaround to prevent the modal from closing when clicking on the scrollbar https://reka-ui.com/docs/components/dialog#scrollable-overlay but it's not working on Mac OS.
if (props.scrollable) {
if (originalEvent.offsetX > target.clientWidth || originalEvent.offsetY > target.clientHeight) {
e.preventDefault()
}
}
}

return {}
return {
pointerDownOutside: handlePointerDownOutside
}
})

const [DefineContentTemplate, ReuseContentTemplate] = createReusableTemplate()
Expand Down
Loading