1
- import { type Ref , onMounted , onUnmounted , ref , watch } from 'vue'
1
+ import { onMounted , onUnmounted , type Ref , ref , watch } from 'vue'
2
+ import { isSafari } from './browser'
2
3
3
4
interface BodyPosition {
4
5
position : string
5
6
top : string
6
7
left : string
7
8
height : string
9
+ right : string
8
10
}
9
11
10
12
interface PositionFixedOptions {
11
13
isOpen : Ref < boolean >
12
14
modal : Ref < boolean >
13
15
nested : Ref < boolean >
14
16
hasBeenOpened : Ref < boolean >
17
+ preventScrollRestoration : Ref < boolean >
18
+ noBodyStyles : Ref < boolean >
15
19
}
16
20
17
21
let previousBodyPosition : BodyPosition | null = null
18
22
19
23
export function usePositionFixed ( options : PositionFixedOptions ) {
20
- const { isOpen, modal, nested, hasBeenOpened } = options
24
+ const { isOpen, modal, nested, hasBeenOpened, preventScrollRestoration , noBodyStyles } = options
21
25
const activeUrl = ref ( typeof window !== 'undefined' ? window . location . href : '' )
22
26
const scrollPos = ref ( 0 )
23
27
24
28
function setPositionFixed ( ) : void {
25
- if ( previousBodyPosition === null && isOpen . value ) {
29
+ if ( ! isSafari ( ) )
30
+ return
31
+
32
+ // If previousBodyPosition is already set, don't set it again.
33
+ if ( previousBodyPosition === null && isOpen . value && ! noBodyStyles . value ) {
26
34
previousBodyPosition = {
27
35
position : document . body . style . position ,
28
36
top : document . body . style . top ,
29
37
left : document . body . style . left ,
30
38
height : document . body . style . height ,
39
+ right : 'unset' ,
31
40
}
32
41
33
42
const { scrollX, innerHeight } = window
34
43
35
- document . body . style . position = 'fixed'
36
- document . body . style . top = `-${ scrollPos . value } px`
37
- document . body . style . left = `-${ scrollX } px`
38
- document . body . style . right = '0px'
39
- document . body . style . height = 'auto'
44
+ document . body . style . setProperty ( 'position' , 'fixed' , 'important' )
45
+ Object . assign ( document . body . style , {
46
+ top : `${ - scrollPos . value } px` ,
47
+ left : `${ - scrollX } px` ,
48
+ right : '0px' ,
49
+ height : 'auto' ,
50
+ } )
40
51
41
52
setTimeout ( ( ) => {
42
53
requestAnimationFrame ( ( ) => {
@@ -52,7 +63,11 @@ export function usePositionFixed(options: PositionFixedOptions) {
52
63
}
53
64
54
65
function restorePositionSetting ( ) : void {
55
- if ( previousBodyPosition !== null ) {
66
+ // All browsers on iOS will return true here.
67
+ if ( ! isSafari ( ) )
68
+ return
69
+
70
+ if ( previousBodyPosition !== null && ! noBodyStyles . value ) {
56
71
// Convert the position from "px" to Int
57
72
const y = - Number . parseInt ( document . body . style . top , 10 )
58
73
const x = - Number . parseInt ( document . body . style . left , 10 )
@@ -61,7 +76,7 @@ export function usePositionFixed(options: PositionFixedOptions) {
61
76
Object . assign ( document . body . style , previousBodyPosition )
62
77
63
78
requestAnimationFrame ( ( ) => {
64
- if ( activeUrl . value !== window . location . href ) {
79
+ if ( preventScrollRestoration && activeUrl . value !== window . location . href ) {
65
80
activeUrl . value = window . location . href
66
81
return
67
82
}
@@ -86,7 +101,7 @@ export function usePositionFixed(options: PositionFixedOptions) {
86
101
} )
87
102
} )
88
103
89
- watch ( [ isOpen , hasBeenOpened , activeUrl ] , ( ) => {
104
+ watch ( [ isOpen , hasBeenOpened , activeUrl , modal , nested , setPositionFixed , restorePositionSetting ] , ( ) => {
90
105
if ( nested . value || ! hasBeenOpened . value )
91
106
return
92
107
0 commit comments