11<script lang="ts" setup>
2- import { computed , ref } from ' vue' ;
2+ import { computed , ref , onMounted , onUnmounted , watch } from ' vue' ;
33import { usePointerSwipe } from ' @vueuse/core' ;
44import {
55 Dialog ,
@@ -17,7 +17,7 @@ const props = withDefaults(
1717 }>(),
1818 {
1919 closeable: true ,
20- maxHeight: ' 85vh ' ,
20+ maxHeight: ' 85dvh ' ,
2121 }
2222);
2323
@@ -30,15 +30,54 @@ const sheetRef = ref<HTMLElement | null>(null);
3030const dragHandleRef = ref <HTMLElement | null >(null );
3131const translateY = ref (0 );
3232const isDragging = ref (false );
33+ const keyboardHeight = ref (0 );
34+
35+ // Handle iOS Safari virtual keyboard using visualViewport API
36+ function handleViewportResize() {
37+ if (window .visualViewport ) {
38+ const viewport = window .visualViewport ;
39+ // Calculate keyboard height as the difference between window height and viewport height
40+ const newKeyboardHeight = window .innerHeight - viewport .height ;
41+ keyboardHeight .value = Math .max (0 , newKeyboardHeight );
42+ }
43+ }
44+
45+ // Set up visualViewport listeners when sheet is shown
46+ watch (() => props .show , (isVisible ) => {
47+ if (isVisible && window .visualViewport ) {
48+ window .visualViewport .addEventListener (' resize' , handleViewportResize );
49+ window .visualViewport .addEventListener (' scroll' , handleViewportResize );
50+ handleViewportResize ();
51+ } else if (window .visualViewport ) {
52+ window .visualViewport .removeEventListener (' resize' , handleViewportResize );
53+ window .visualViewport .removeEventListener (' scroll' , handleViewportResize );
54+ keyboardHeight .value = 0 ;
55+ }
56+ }, { immediate: true });
57+
58+ onUnmounted (() => {
59+ if (window .visualViewport ) {
60+ window .visualViewport .removeEventListener (' resize' , handleViewportResize );
61+ window .visualViewport .removeEventListener (' scroll' , handleViewportResize );
62+ }
63+ });
3364
3465const sheetStyle = computed (() => {
66+ const style: Record <string , string > = {};
67+
68+ // Apply keyboard offset for iOS Safari
69+ if (keyboardHeight .value > 0 ) {
70+ style .transform = ` translateY(-${keyboardHeight .value }px) ` ;
71+ style .transition = ' transform 0.25s ease-out' ;
72+ }
73+
74+ // Apply drag offset
3575 if (isDragging .value && translateY .value > 0 ) {
36- return {
37- transform: ` translateY(${translateY .value }px) ` ,
38- transition: ' none' ,
39- };
76+ style .transform = ` translateY(${translateY .value }px) ` ;
77+ style .transition = ' none' ;
4078 }
41- return {};
79+
80+ return style ;
4281});
4382
4483const { distanceY } = usePointerSwipe (dragHandleRef , {
@@ -145,6 +184,7 @@ function close() {
145184 z-index : 102 ;
146185 width : 100% ;
147186 max-width : 640px ;
187+ max-height : 85 dvh; // Use dynamic viewport height for iOS Safari keyboard support
148188 background : var (--color-surface );
149189 border-radius : var (--radius-xl ) var (--radius-xl ) 0 0 ;
150190 box-shadow : var (--shadow-lg );
@@ -153,6 +193,11 @@ function close() {
153193 flex-direction : column ;
154194 pointer-events : auto ;
155195 @include safeAreaBottom (padding-bottom );
196+
197+ // Fallback for browsers that don't support dvh
198+ @supports not (max-height : 1 dvh) {
199+ max-height : 85vh ;
200+ }
156201 }
157202
158203 & __handle {
@@ -191,6 +236,13 @@ function close() {
191236 overflow-y : auto ;
192237 padding : 16px 20px ;
193238 -webkit-overflow-scrolling : touch ;
239+
240+ // Ensure inputs scroll into view when focused on iOS Safari
241+ :deep (input ),
242+ :deep (textarea ),
243+ :deep (select ) {
244+ scroll-margin-bottom : 20px ;
245+ }
194246 }
195247}
196248 </style >
0 commit comments