11<script setup lang="ts">
2- import { computed , watch } from ' vue'
2+ import { computed , watch , onUnmounted } from ' vue'
33
44interface Props {
55 modelValue: boolean
66 position? : ' bottom' | ' top' | ' left' | ' right'
77 backdrop? : boolean
88 closeOnBackdrop? : boolean
9+ lockScroll? : boolean
910}
1011
1112const props = withDefaults (defineProps <Props >(), {
1213 position: ' bottom' ,
1314 backdrop: true ,
1415 closeOnBackdrop: true ,
16+ lockScroll: true ,
1517})
1618
1719const emit = defineEmits <{
@@ -39,29 +41,46 @@ const drawerClasses = computed(() => {
3941 return ` ${base } ${positions [props .position ]} `
4042})
4143
44+ let isLockedByThisInstance = false
45+
46+ const lockScroll = () => {
47+ if (props .lockScroll && ! isLockedByThisInstance ) {
48+ document .body .style .overflow = ' hidden'
49+ isLockedByThisInstance = true
50+ }
51+ }
52+
53+ const unlockScroll = () => {
54+ if (isLockedByThisInstance ) {
55+ document .body .style .overflow = ' '
56+ isLockedByThisInstance = false
57+ }
58+ }
59+
4260// Prevent body scroll when drawer is open
4361watch (() => props .modelValue , (isOpen ) => {
4462 if (isOpen ) {
45- document . body . style . overflow = ' hidden '
63+ lockScroll ()
4664 } else {
47- document . body . style . overflow = ' '
65+ unlockScroll ()
4866 }
67+ }, { immediate: true })
68+
69+ // Ensure scroll is unlocked when component is destroyed
70+ onUnmounted (() => {
71+ unlockScroll ()
4972})
5073 </script >
5174
5275<template >
5376 <Teleport to =" body" >
54- <div v-if =" modelValue" class =" fixed inset-0 z-60" >
55- <div
56- v-if =" backdrop"
57- class =" absolute inset-0 bg-black/50 backdrop-blur-sm"
77+ <div v-if =" modelValue" class =" fixed inset-0 z-60" :class =" { 'pointer-events-none': !backdrop }" >
78+ <div v-if =" backdrop" class =" absolute inset-0 bg-black/50 backdrop-blur-sm pointer-events-auto"
5879 @click =" handleBackdropClick" ></div >
5980
60- <div :class =" drawerClasses" >
81+ <div :class =" [ drawerClasses, { 'pointer-events-auto': !backdrop }] " >
6182 <!-- Drag handle for bottom drawer -->
62- <div
63- v-if =" position === 'bottom'"
64- class =" w-12 h-1 bg-border-subtle rounded-full mx-auto mb-6" ></div >
83+ <div v-if =" position === 'bottom'" class =" w-12 h-1 bg-border-subtle rounded-full mx-auto mb-6" ></div >
6584
6685 <!-- Header slot -->
6786 <div v-if =" $slots.header" class =" mb-6" >
@@ -101,6 +120,7 @@ watch(() => props.modelValue, (isOpen) => {
101120 from {
102121 transform : translateY (100% );
103122 }
123+
104124 to {
105125 transform : translateY (0 );
106126 }
@@ -110,6 +130,7 @@ watch(() => props.modelValue, (isOpen) => {
110130 from {
111131 transform : translateY (-100% );
112132 }
133+
113134 to {
114135 transform : translateY (0 );
115136 }
@@ -119,6 +140,7 @@ watch(() => props.modelValue, (isOpen) => {
119140 from {
120141 transform : translateX (-100% );
121142 }
143+
122144 to {
123145 transform : translateX (0 );
124146 }
@@ -128,9 +150,9 @@ watch(() => props.modelValue, (isOpen) => {
128150 from {
129151 transform : translateX (100% );
130152 }
153+
131154 to {
132155 transform : translateX (0 );
133156 }
134157}
135158 </style >
136-
0 commit comments