fix(dialog): fix click on scrollbar close dialog bug

This commit is contained in:
hrynevych.romann 2024-01-18 22:21:37 +02:00
parent fa1efdbfa4
commit 8dcc3564c3
4 changed files with 20 additions and 2 deletions

View File

@ -9,12 +9,20 @@ import {
useEmitAsProps,
} from 'radix-vue'
import { X } from 'lucide-vue-next'
import type { PointerDownOutsideEvent } from 'radix-vue/dist/DismissableLayer'
import { cn } from '@/lib/utils'
const props = defineProps<DialogContentProps & { class?: string }>()
const emits = defineEmits<DialogContentEmits>()
const emitsAsProps = useEmitAsProps(emits)
function handlePointerDown(event: PointerDownOutsideEvent) {
const originalEvent = event.detail.originalEvent
// Ignore click events on the scrollbar.
if (originalEvent.offsetX > originalEvent.target?.clientWidth || originalEvent.offsetY > originalEvent.target?.clientHeight)
event.preventDefault()
}
</script>
<template>
@ -30,6 +38,7 @@ const emitsAsProps = useEmitAsProps(emits)
)
"
v-bind="{ ...props, ...emitsAsProps }"
@pointer-down-outside="handlePointerDown"
>
<slot />

View File

@ -9,12 +9,20 @@ import {
useEmitAsProps,
} from 'radix-vue'
import { Cross2Icon } from '@radix-icons/vue'
import type { PointerDownOutsideEvent } from 'radix-vue/dist/DismissableLayer'
import { cn } from '@/lib/utils'
const props = defineProps<DialogContentProps & { class?: string }>()
const emits = defineEmits<DialogContentEmits>()
const emitsAsProps = useEmitAsProps(emits)
function handlePointerDown(event: PointerDownOutsideEvent) {
const originalEvent = event.detail.originalEvent
// Ignore click events on the scrollbar.
if (originalEvent.offsetX > originalEvent.target?.clientWidth || originalEvent.offsetY > originalEvent.target?.clientHeight)
event.preventDefault()
}
</script>
<template>
@ -30,6 +38,7 @@ const emitsAsProps = useEmitAsProps(emits)
)
"
v-bind="{ ...props, ...emitsAsProps }"
@pointer-down-outside="handlePointerDown"
>
<slot />

View File

@ -31,7 +31,7 @@
},
{
"name": "DialogScrollContent.vue",
"content": "<script setup lang=\"ts\">\nimport {\n DialogClose,\n DialogContent,\n type DialogContentEmits,\n type DialogContentProps,\n DialogOverlay,\n DialogPortal,\n useEmitAsProps,\n} from 'radix-vue'\nimport { X } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<DialogContentProps & { class?: string }>()\nconst emits = defineEmits<DialogContentEmits>()\n\nconst emitsAsProps = useEmitAsProps(emits)\n</script>\n\n<template>\n <DialogPortal>\n <DialogOverlay\n class=\"fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\"\n >\n <DialogContent\n :class=\"\n cn(\n 'relative z-50 grid w-full max-w-lg my-8 gap-4 border border-border bg-background p-6 shadow-lg duration-200 sm:rounded-lg md:w-full',\n props.class,\n )\n \"\n v-bind=\"{ ...props, ...emitsAsProps }\"\n >\n <slot />\n\n <DialogClose\n class=\"absolute top-3 right-3 p-0.5 transition-colors rounded-md hover:bg-secondary\"\n >\n <X class=\"w-4 h-4\" />\n <span class=\"sr-only\">Close</span>\n </DialogClose>\n </DialogContent>\n </DialogOverlay>\n </DialogPortal>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport {\n DialogClose,\n DialogContent,\n type DialogContentEmits,\n type DialogContentProps,\n DialogOverlay,\n DialogPortal,\n useEmitAsProps,\n} from 'radix-vue'\nimport { X } from 'lucide-vue-next'\nimport type { PointerDownOutsideEvent } from 'radix-vue/dist/DismissableLayer'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<DialogContentProps & { class?: string }>()\nconst emits = defineEmits<DialogContentEmits>()\n\nconst emitsAsProps = useEmitAsProps(emits)\n\nfunction handlePointerDown(event: PointerDownOutsideEvent) {\n const originalEvent = event.detail.originalEvent\n // Ignore click events on the scrollbar.\n if (originalEvent.offsetX > originalEvent.target?.clientWidth || originalEvent.offsetY > originalEvent.target?.clientHeight)\n event.preventDefault()\n}\n</script>\n\n<template>\n <DialogPortal>\n <DialogOverlay\n class=\"fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\"\n >\n <DialogContent\n :class=\"\n cn(\n 'relative z-50 grid w-full max-w-lg my-8 gap-4 border border-border bg-background p-6 shadow-lg duration-200 sm:rounded-lg md:w-full',\n props.class,\n )\n \"\n v-bind=\"{ ...props, ...emitsAsProps }\"\n @pointer-down-outside=\"handlePointerDown\"\n >\n <slot />\n\n <DialogClose\n class=\"absolute top-3 right-3 p-0.5 transition-colors rounded-md hover:bg-secondary\"\n >\n <X class=\"w-4 h-4\" />\n <span class=\"sr-only\">Close</span>\n </DialogClose>\n </DialogContent>\n </DialogOverlay>\n </DialogPortal>\n</template>\n"
},
{
"name": "DialogTitle.vue",

View File

@ -31,7 +31,7 @@
},
{
"name": "DialogScrollContent.vue",
"content": "<script setup lang=\"ts\">\nimport {\n DialogClose,\n DialogContent,\n type DialogContentEmits,\n type DialogContentProps,\n DialogOverlay,\n DialogPortal,\n useEmitAsProps,\n} from 'radix-vue'\nimport { Cross2Icon } from '@radix-icons/vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<DialogContentProps & { class?: string }>()\nconst emits = defineEmits<DialogContentEmits>()\n\nconst emitsAsProps = useEmitAsProps(emits)\n</script>\n\n<template>\n <DialogPortal>\n <DialogOverlay\n class=\"fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\"\n >\n <DialogContent\n :class=\"\n cn(\n 'relative z-50 grid w-full max-w-lg my-8 gap-4 border border-border bg-background p-6 shadow-lg duration-200 sm:rounded-lg md:w-full',\n props.class,\n )\n \"\n v-bind=\"{ ...props, ...emitsAsProps }\"\n >\n <slot />\n\n <DialogClose\n class=\"absolute top-4 right-4 p-0.5 transition-colors rounded-md hover:bg-secondary\"\n >\n <Cross2Icon class=\"w-4 h-4\" />\n <span class=\"sr-only\">Close</span>\n </DialogClose>\n </DialogContent>\n </DialogOverlay>\n </DialogPortal>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport {\n DialogClose,\n DialogContent,\n type DialogContentEmits,\n type DialogContentProps,\n DialogOverlay,\n DialogPortal,\n useEmitAsProps,\n} from 'radix-vue'\nimport { Cross2Icon } from '@radix-icons/vue'\nimport type { PointerDownOutsideEvent } from 'radix-vue/dist/DismissableLayer'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<DialogContentProps & { class?: string }>()\nconst emits = defineEmits<DialogContentEmits>()\n\nconst emitsAsProps = useEmitAsProps(emits)\n\nfunction handlePointerDown(event: PointerDownOutsideEvent) {\n const originalEvent = event.detail.originalEvent\n // Ignore click events on the scrollbar.\n if (originalEvent.offsetX > originalEvent.target?.clientWidth || originalEvent.offsetY > originalEvent.target?.clientHeight)\n event.preventDefault()\n}\n</script>\n\n<template>\n <DialogPortal>\n <DialogOverlay\n class=\"fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\"\n >\n <DialogContent\n :class=\"\n cn(\n 'relative z-50 grid w-full max-w-lg my-8 gap-4 border border-border bg-background p-6 shadow-lg duration-200 sm:rounded-lg md:w-full',\n props.class,\n )\n \"\n v-bind=\"{ ...props, ...emitsAsProps }\"\n @pointer-down-outside=\"handlePointerDown\"\n >\n <slot />\n\n <DialogClose\n class=\"absolute top-4 right-4 p-0.5 transition-colors rounded-md hover:bg-secondary\"\n >\n <Cross2Icon class=\"w-4 h-4\" />\n <span class=\"sr-only\">Close</span>\n </DialogClose>\n </DialogContent>\n </DialogOverlay>\n </DialogPortal>\n</template>\n"
},
{
"name": "DialogTitle.vue",