@lodev09/react-native-true-sheet 3.10.0 → 3.11.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +11 -4
  2. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +10 -5
  3. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +2 -5
  4. package/lib/module/TrueSheet.js +3 -0
  5. package/lib/module/TrueSheet.js.map +1 -1
  6. package/lib/module/TrueSheet.web.js +604 -376
  7. package/lib/module/TrueSheet.web.js.map +1 -1
  8. package/lib/module/TrueSheetProvider.js.map +1 -1
  9. package/lib/module/TrueSheetProvider.web.js +141 -100
  10. package/lib/module/TrueSheetProvider.web.js.map +1 -1
  11. package/lib/module/mocks/index.js.map +1 -1
  12. package/lib/module/reanimated/ReanimatedTrueSheet.web.js.map +1 -1
  13. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js +2 -3
  14. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js.map +1 -1
  15. package/lib/module/web/constants.js +16 -0
  16. package/lib/module/web/constants.js.map +1 -0
  17. package/lib/module/web/vaul/README.md +9 -0
  18. package/lib/module/web/vaul/browser.js +30 -0
  19. package/lib/module/web/vaul/browser.js.map +1 -0
  20. package/lib/module/web/vaul/constants.js +14 -0
  21. package/lib/module/web/vaul/constants.js.map +1 -0
  22. package/lib/module/web/vaul/context.js +57 -0
  23. package/lib/module/web/vaul/context.js.map +1 -0
  24. package/lib/module/web/vaul/helpers.js +93 -0
  25. package/lib/module/web/vaul/helpers.js.map +1 -0
  26. package/lib/module/web/vaul/index.js +1206 -0
  27. package/lib/module/web/vaul/index.js.map +1 -0
  28. package/lib/module/web/vaul/style.css +264 -0
  29. package/lib/module/web/vaul/types.js +2 -0
  30. package/lib/module/web/vaul/types.js.map +1 -0
  31. package/lib/module/web/vaul/use-composed-refs.js +34 -0
  32. package/lib/module/web/vaul/use-composed-refs.js.map +1 -0
  33. package/lib/module/web/vaul/use-controllable-state.js +54 -0
  34. package/lib/module/web/vaul/use-controllable-state.js.map +1 -0
  35. package/lib/module/web/vaul/use-position-fixed.js +123 -0
  36. package/lib/module/web/vaul/use-position-fixed.js.map +1 -0
  37. package/lib/module/web/vaul/use-prevent-scroll.js +258 -0
  38. package/lib/module/web/vaul/use-prevent-scroll.js.map +1 -0
  39. package/lib/module/web/vaul/use-scale-background.js +57 -0
  40. package/lib/module/web/vaul/use-scale-background.js.map +1 -0
  41. package/lib/module/web/vaul/use-snap-points.js +294 -0
  42. package/lib/module/web/vaul/use-snap-points.js.map +1 -0
  43. package/lib/typescript/src/TrueSheet.d.ts +2 -2
  44. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  45. package/lib/typescript/src/TrueSheet.types.d.ts +79 -36
  46. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  47. package/lib/typescript/src/TrueSheet.web.d.ts +3 -11
  48. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
  49. package/lib/typescript/src/TrueSheetProvider.d.ts +2 -2
  50. package/lib/typescript/src/TrueSheetProvider.d.ts.map +1 -1
  51. package/lib/typescript/src/TrueSheetProvider.web.d.ts +17 -14
  52. package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -1
  53. package/lib/typescript/src/mocks/index.d.ts +1 -2
  54. package/lib/typescript/src/mocks/index.d.ts.map +1 -1
  55. package/lib/typescript/src/navigation/types.d.ts +1 -1
  56. package/lib/typescript/src/navigation/types.d.ts.map +1 -1
  57. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts +0 -1
  58. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts.map +1 -1
  59. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts +2 -3
  60. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts.map +1 -1
  61. package/lib/typescript/src/web/constants.d.ts +14 -0
  62. package/lib/typescript/src/web/constants.d.ts.map +1 -0
  63. package/lib/typescript/src/web/vaul/browser.d.ts +8 -0
  64. package/lib/typescript/src/web/vaul/browser.d.ts.map +1 -0
  65. package/lib/typescript/src/web/vaul/constants.d.ts +12 -0
  66. package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -0
  67. package/lib/typescript/src/web/vaul/context.d.ts +45 -0
  68. package/lib/typescript/src/web/vaul/context.d.ts.map +1 -0
  69. package/lib/typescript/src/web/vaul/helpers.d.ts +17 -0
  70. package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -0
  71. package/lib/typescript/src/web/vaul/index.d.ts +210 -0
  72. package/lib/typescript/src/web/vaul/index.d.ts.map +1 -0
  73. package/lib/typescript/src/web/vaul/types.d.ts +7 -0
  74. package/lib/typescript/src/web/vaul/types.d.ts.map +1 -0
  75. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts +14 -0
  76. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts.map +1 -0
  77. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts +9 -0
  78. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts.map +1 -0
  79. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts +19 -0
  80. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts.map +1 -0
  81. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts +18 -0
  82. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts.map +1 -0
  83. package/lib/typescript/src/web/vaul/use-scale-background.d.ts +2 -0
  84. package/lib/typescript/src/web/vaul/use-scale-background.d.ts.map +1 -0
  85. package/lib/typescript/src/web/vaul/use-snap-points.d.ts +37 -0
  86. package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -0
  87. package/package.json +4 -4
  88. package/src/TrueSheet.tsx +9 -1
  89. package/src/TrueSheet.types.ts +88 -38
  90. package/src/TrueSheet.web.tsx +675 -450
  91. package/src/TrueSheetProvider.tsx +2 -4
  92. package/src/TrueSheetProvider.web.tsx +193 -125
  93. package/src/mocks/index.ts +1 -2
  94. package/src/navigation/types.ts +0 -1
  95. package/src/reanimated/ReanimatedTrueSheet.web.tsx +0 -1
  96. package/src/reanimated/useReanimatedPositionChangeHandler.web.ts +2 -3
  97. package/src/web/constants.ts +13 -0
  98. package/src/web/vaul/README.md +9 -0
  99. package/src/web/vaul/browser.ts +38 -0
  100. package/src/web/vaul/constants.ts +18 -0
  101. package/src/web/vaul/context.ts +87 -0
  102. package/src/web/vaul/helpers.ts +124 -0
  103. package/src/web/vaul/index.tsx +1590 -0
  104. package/src/web/vaul/style.css +264 -0
  105. package/src/web/vaul/types.ts +7 -0
  106. package/src/web/vaul/use-composed-refs.ts +35 -0
  107. package/src/web/vaul/use-controllable-state.ts +66 -0
  108. package/src/web/vaul/use-position-fixed.ts +147 -0
  109. package/src/web/vaul/use-prevent-scroll.ts +309 -0
  110. package/src/web/vaul/use-scale-background.ts +64 -0
  111. package/src/web/vaul/use-snap-points.ts +433 -0
@@ -0,0 +1,264 @@
1
+ [data-vaul-drawer] {
2
+ touch-action: none;
3
+ will-change: transform;
4
+ transition: transform 0.5s cubic-bezier(0.32, 0.72, 0, 1);
5
+ animation-duration: 0.5s;
6
+ animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1);
7
+ }
8
+
9
+ [data-vaul-drawer][data-vaul-snap-points='false'][data-vaul-drawer-direction='bottom'][data-state='open'] {
10
+ animation-name: slideFromBottom;
11
+ }
12
+ [data-vaul-drawer][data-vaul-snap-points='false'][data-vaul-drawer-direction='bottom'][data-state='closed'] {
13
+ animation-name: slideToBottom;
14
+ }
15
+
16
+ /* Drawers always dismiss by sliding the wrapper off-screen, so we don't want
17
+ vaul's default `slideTo*` drawer keyframes (they'd stack with the wrapper
18
+ translate and look twice as fast). Override with a no-op animation of
19
+ matching duration so Radix Presence still waits for it before unmounting.
20
+ Specificity needs to beat the 4-attribute `slideTo*` selectors above. */
21
+ [data-vaul-drawer][data-vaul-drawer-direction='bottom'][data-vaul-animate='true'][data-state='closed'] {
22
+ animation-name: vaulHold;
23
+ animation-duration: 0.5s;
24
+ }
25
+ @keyframes vaulHold {
26
+ from {
27
+ opacity: 1;
28
+ }
29
+ to {
30
+ opacity: 1;
31
+ }
32
+ }
33
+
34
+ [data-vaul-drawer][data-vaul-snap-points='false'][data-vaul-drawer-direction='top'][data-state='open'] {
35
+ animation-name: slideFromTop;
36
+ }
37
+ [data-vaul-drawer][data-vaul-snap-points='false'][data-vaul-drawer-direction='top'][data-state='closed'] {
38
+ animation-name: slideToTop;
39
+ }
40
+
41
+ [data-vaul-drawer][data-vaul-snap-points='false'][data-vaul-drawer-direction='left'][data-state='open'] {
42
+ animation-name: slideFromLeft;
43
+ }
44
+ [data-vaul-drawer][data-vaul-snap-points='false'][data-vaul-drawer-direction='left'][data-state='closed'] {
45
+ animation-name: slideToLeft;
46
+ }
47
+
48
+ [data-vaul-drawer][data-vaul-snap-points='false'][data-vaul-drawer-direction='right'][data-state='open'] {
49
+ animation-name: slideFromRight;
50
+ }
51
+ [data-vaul-drawer][data-vaul-snap-points='false'][data-vaul-drawer-direction='right'][data-state='closed'] {
52
+ animation-name: slideToRight;
53
+ }
54
+
55
+ [data-vaul-drawer][data-vaul-snap-points='true'][data-vaul-drawer-direction='bottom'] {
56
+ transform: translate3d(0, var(--initial-transform, 100%), 0);
57
+ }
58
+
59
+ [data-vaul-drawer][data-vaul-snap-points='true'][data-vaul-drawer-direction='top'] {
60
+ transform: translate3d(0, calc(var(--initial-transform, 100%) * -1), 0);
61
+ }
62
+
63
+ [data-vaul-drawer][data-vaul-snap-points='true'][data-vaul-drawer-direction='left'] {
64
+ transform: translate3d(calc(var(--initial-transform, 100%) * -1), 0, 0);
65
+ }
66
+
67
+ [data-vaul-drawer][data-vaul-snap-points='true'][data-vaul-drawer-direction='right'] {
68
+ transform: translate3d(var(--initial-transform, 100%), 0, 0);
69
+ }
70
+
71
+ [data-vaul-drawer][data-vaul-delayed-snap-points='true'][data-vaul-drawer-direction='top'] {
72
+ transform: translate3d(0, var(--snap-point-height, 0), 0);
73
+ }
74
+
75
+ [data-vaul-drawer][data-vaul-delayed-snap-points='true'][data-vaul-drawer-direction='bottom'] {
76
+ transform: translate3d(0, var(--snap-point-height, 0), 0);
77
+ }
78
+
79
+ [data-vaul-drawer][data-vaul-delayed-snap-points='true'][data-vaul-drawer-direction='left'] {
80
+ transform: translate3d(var(--snap-point-height, 0), 0, 0);
81
+ }
82
+
83
+ [data-vaul-drawer][data-vaul-delayed-snap-points='true'][data-vaul-drawer-direction='right'] {
84
+ transform: translate3d(var(--snap-point-height, 0), 0, 0);
85
+ }
86
+
87
+ [data-vaul-overlay][data-vaul-snap-points='false'] {
88
+ animation-duration: 0.5s;
89
+ animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1);
90
+ }
91
+ [data-vaul-overlay][data-vaul-snap-points='false'][data-state='open'] {
92
+ animation-name: fadeIn;
93
+ }
94
+ [data-vaul-overlay][data-state='closed'] {
95
+ animation-name: fadeOut;
96
+ }
97
+
98
+ [data-vaul-animate='false'] {
99
+ animation: none !important;
100
+ }
101
+
102
+ [data-vaul-overlay][data-vaul-snap-points='true'] {
103
+ opacity: 0;
104
+ transition: opacity 0.5s cubic-bezier(0.32, 0.72, 0, 1);
105
+ }
106
+
107
+ [data-vaul-drawer]:not([data-vaul-custom-container='true'])::after {
108
+ content: '';
109
+ position: absolute;
110
+ background: inherit;
111
+ background-color: inherit;
112
+ }
113
+
114
+ [data-vaul-drawer][data-vaul-drawer-direction='top']::after {
115
+ top: initial;
116
+ bottom: 100%;
117
+ left: 0;
118
+ right: 0;
119
+ height: 200%;
120
+ }
121
+
122
+ [data-vaul-drawer][data-vaul-drawer-direction='bottom']::after {
123
+ top: 100%;
124
+ bottom: initial;
125
+ left: 0;
126
+ right: 0;
127
+ height: 200%;
128
+ }
129
+
130
+ [data-vaul-drawer][data-vaul-drawer-direction='left']::after {
131
+ left: initial;
132
+ right: 100%;
133
+ top: 0;
134
+ bottom: 0;
135
+ width: 200%;
136
+ }
137
+
138
+ [data-vaul-drawer][data-vaul-drawer-direction='right']::after {
139
+ left: 100%;
140
+ right: initial;
141
+ top: 0;
142
+ bottom: 0;
143
+ width: 200%;
144
+ }
145
+
146
+ [data-vaul-overlay][data-vaul-snap-points='true'][data-vaul-delayed-snap-points='true'][data-vaul-snap-points-overlay='true'] {
147
+ opacity: 1;
148
+ }
149
+
150
+ [data-vaul-handle] {
151
+ display: block;
152
+ position: relative;
153
+ opacity: 0.7;
154
+ background: #e2e2e4;
155
+ margin-left: auto;
156
+ margin-right: auto;
157
+ height: 5px;
158
+ width: 32px;
159
+ border-radius: 1rem;
160
+ touch-action: pan-y;
161
+ }
162
+
163
+ [data-vaul-handle]:hover,
164
+ [data-vaul-handle]:active {
165
+ opacity: 1;
166
+ }
167
+
168
+ [data-vaul-handle-hitarea] {
169
+ position: absolute;
170
+ left: 50%;
171
+ top: 50%;
172
+ transform: translate(-50%, -50%);
173
+ width: max(100%, 2.75rem); /* 44px */
174
+ height: max(100%, 2.75rem); /* 44px */
175
+ touch-action: inherit;
176
+ }
177
+
178
+ @media (hover: hover) and (pointer: fine) {
179
+ [data-vaul-drawer] {
180
+ user-select: none;
181
+ }
182
+ }
183
+
184
+ @media (pointer: fine) {
185
+ [data-vaul-handle-hitarea]: {
186
+ width: 100%;
187
+ height: 100%;
188
+ }
189
+ }
190
+
191
+ @keyframes fadeIn {
192
+ from {
193
+ opacity: 0;
194
+ }
195
+ to {
196
+ opacity: 1;
197
+ }
198
+ }
199
+
200
+ @keyframes fadeOut {
201
+ to {
202
+ opacity: 0;
203
+ }
204
+ }
205
+
206
+ @keyframes slideFromBottom {
207
+ from {
208
+ transform: translate3d(0, var(--initial-transform, 100%), 0);
209
+ }
210
+ to {
211
+ transform: translate3d(0, 0, 0);
212
+ }
213
+ }
214
+
215
+ @keyframes slideToBottom {
216
+ to {
217
+ transform: translate3d(0, var(--initial-transform, 100%), 0);
218
+ }
219
+ }
220
+
221
+ @keyframes slideFromTop {
222
+ from {
223
+ transform: translate3d(0, calc(var(--initial-transform, 100%) * -1), 0);
224
+ }
225
+ to {
226
+ transform: translate3d(0, 0, 0);
227
+ }
228
+ }
229
+
230
+ @keyframes slideToTop {
231
+ to {
232
+ transform: translate3d(0, calc(var(--initial-transform, 100%) * -1), 0);
233
+ }
234
+ }
235
+
236
+ @keyframes slideFromLeft {
237
+ from {
238
+ transform: translate3d(calc(var(--initial-transform, 100%) * -1), 0, 0);
239
+ }
240
+ to {
241
+ transform: translate3d(0, 0, 0);
242
+ }
243
+ }
244
+
245
+ @keyframes slideToLeft {
246
+ to {
247
+ transform: translate3d(calc(var(--initial-transform, 100%) * -1), 0, 0);
248
+ }
249
+ }
250
+
251
+ @keyframes slideFromRight {
252
+ from {
253
+ transform: translate3d(var(--initial-transform, 100%), 0, 0);
254
+ }
255
+ to {
256
+ transform: translate3d(0, 0, 0);
257
+ }
258
+ }
259
+
260
+ @keyframes slideToRight {
261
+ to {
262
+ transform: translate3d(var(--initial-transform, 100%), 0, 0);
263
+ }
264
+ }
@@ -0,0 +1,7 @@
1
+ export type DrawerDirection = 'top' | 'bottom' | 'left' | 'right';
2
+ export interface SnapPoint {
3
+ fraction: number;
4
+ height: number;
5
+ }
6
+
7
+ export type AnyFunction = (...args: any) => any;
@@ -0,0 +1,35 @@
1
+ // This code comes from https://github.com/radix-ui/primitives/tree/main/packages/react/compose-refs
2
+
3
+ import * as React from 'react';
4
+
5
+ type PossibleRef<T> = React.Ref<T> | undefined;
6
+
7
+ /**
8
+ * Set a given ref to a given value
9
+ * This utility takes care of different types of refs: callback refs and RefObject(s)
10
+ */
11
+ function setRef<T>(ref: PossibleRef<T>, value: T) {
12
+ if (typeof ref === 'function') {
13
+ ref(value);
14
+ } else if (ref !== null && ref !== undefined) {
15
+ (ref as React.MutableRefObject<T>).current = value;
16
+ }
17
+ }
18
+
19
+ /**
20
+ * A utility to compose multiple refs together
21
+ * Accepts callback refs and RefObject(s)
22
+ */
23
+ function composeRefs<T>(...refs: PossibleRef<T>[]) {
24
+ return (node: T) => refs.forEach((ref) => setRef(ref, node));
25
+ }
26
+
27
+ /**
28
+ * A custom hook that composes multiple refs
29
+ * Accepts callback refs and RefObject(s)
30
+ */
31
+ function useComposedRefs<T>(...refs: PossibleRef<T>[]) {
32
+ return React.useCallback(composeRefs(...refs), refs);
33
+ }
34
+
35
+ export { composeRefs, useComposedRefs };
@@ -0,0 +1,66 @@
1
+ // This code comes from https://github.com/radix-ui/primitives/blob/main/packages/react/use-controllable-state/src/useControllableState.tsx
2
+
3
+ import React from 'react';
4
+
5
+ type UseControllableStateParams<T> = {
6
+ prop?: T | undefined;
7
+ defaultProp?: T | undefined;
8
+ onChange?: (state: T) => void;
9
+ };
10
+
11
+ type SetStateFn<T> = (prevState?: T) => T;
12
+
13
+ function useCallbackRef<T extends (...args: any[]) => any>(callback: T | undefined): T {
14
+ const callbackRef = React.useRef(callback);
15
+
16
+ React.useEffect(() => {
17
+ callbackRef.current = callback;
18
+ });
19
+
20
+ // https://github.com/facebook/react/issues/19240
21
+ return React.useMemo(() => ((...args) => callbackRef.current?.(...args)) as T, []);
22
+ }
23
+
24
+ function useUncontrolledState<T>({
25
+ defaultProp,
26
+ onChange,
27
+ }: Omit<UseControllableStateParams<T>, 'prop'>) {
28
+ const uncontrolledState = React.useState<T | undefined>(defaultProp);
29
+ const [value] = uncontrolledState;
30
+ const prevValueRef = React.useRef(value);
31
+ const handleChange = useCallbackRef(onChange);
32
+
33
+ React.useEffect(() => {
34
+ if (prevValueRef.current !== value) {
35
+ handleChange(value as T);
36
+ prevValueRef.current = value;
37
+ }
38
+ }, [value, prevValueRef, handleChange]);
39
+
40
+ return uncontrolledState;
41
+ }
42
+ export function useControllableState<T>({
43
+ prop,
44
+ defaultProp,
45
+ onChange = () => {},
46
+ }: UseControllableStateParams<T>) {
47
+ const [uncontrolledProp, setUncontrolledProp] = useUncontrolledState({ defaultProp, onChange });
48
+ const isControlled = prop !== undefined;
49
+ const value = isControlled ? prop : uncontrolledProp;
50
+ const handleChange = useCallbackRef(onChange);
51
+
52
+ const setValue: React.Dispatch<React.SetStateAction<T | undefined>> = React.useCallback(
53
+ (nextValue) => {
54
+ if (isControlled) {
55
+ const setter = nextValue as SetStateFn<T>;
56
+ const next = typeof nextValue === 'function' ? setter(prop) : nextValue;
57
+ if (next !== prop) handleChange(next as T);
58
+ } else {
59
+ setUncontrolledProp(nextValue);
60
+ }
61
+ },
62
+ [isControlled, prop, setUncontrolledProp, handleChange]
63
+ );
64
+
65
+ return [value, setValue] as const;
66
+ }
@@ -0,0 +1,147 @@
1
+ import React from 'react';
2
+ import { isSafari } from './browser';
3
+
4
+ let previousBodyPosition: Record<string, string> | null = null;
5
+
6
+ /**
7
+ * This hook is necessary to prevent buggy behavior on iOS devices (need to test on Android).
8
+ * I won't get into too much detail about what bugs it solves, but so far I've found that setting the body to `position: fixed` is the most reliable way to prevent those bugs.
9
+ * Issues that this hook solves:
10
+ * https://github.com/emilkowalski/vaul/issues/435
11
+ * https://github.com/emilkowalski/vaul/issues/433
12
+ * And more that I discovered, but were just not reported.
13
+ */
14
+
15
+ export function usePositionFixed({
16
+ isOpen,
17
+ modal,
18
+ nested,
19
+ hasBeenOpened,
20
+ preventScrollRestoration,
21
+ noBodyStyles,
22
+ }: {
23
+ isOpen: boolean;
24
+ modal: boolean;
25
+ nested: boolean;
26
+ hasBeenOpened: boolean;
27
+ preventScrollRestoration: boolean;
28
+ noBodyStyles: boolean;
29
+ }) {
30
+ const [activeUrl, setActiveUrl] = React.useState(() =>
31
+ typeof window !== 'undefined' ? window.location.href : ''
32
+ );
33
+ const scrollPos = React.useRef(0);
34
+
35
+ const setPositionFixed = React.useCallback(() => {
36
+ // All browsers on iOS will return true here.
37
+ if (!isSafari()) return;
38
+
39
+ // If previousBodyPosition is already set, don't set it again.
40
+ if (previousBodyPosition === null && isOpen && !noBodyStyles) {
41
+ previousBodyPosition = {
42
+ position: document.body.style.position,
43
+ top: document.body.style.top,
44
+ left: document.body.style.left,
45
+ height: document.body.style.height,
46
+ right: 'unset',
47
+ };
48
+
49
+ // Update the dom inside an animation frame
50
+ const { scrollX, innerHeight } = window;
51
+
52
+ document.body.style.setProperty('position', 'fixed', 'important');
53
+ Object.assign(document.body.style, {
54
+ top: `${-scrollPos.current}px`,
55
+ left: `${-scrollX}px`,
56
+ right: '0px',
57
+ height: 'auto',
58
+ });
59
+
60
+ window.setTimeout(
61
+ () =>
62
+ window.requestAnimationFrame(() => {
63
+ // Attempt to check if the bottom bar appeared due to the position change
64
+ const bottomBarHeight = innerHeight - window.innerHeight;
65
+ if (bottomBarHeight && scrollPos.current >= innerHeight) {
66
+ // Move the content further up so that the bottom bar doesn't hide it
67
+ document.body.style.top = `${-(scrollPos.current + bottomBarHeight)}px`;
68
+ }
69
+ }),
70
+ 300
71
+ );
72
+ }
73
+ }, [isOpen]);
74
+
75
+ const restorePositionSetting = React.useCallback(() => {
76
+ // All browsers on iOS will return true here.
77
+ if (!isSafari()) return;
78
+
79
+ if (previousBodyPosition !== null && !noBodyStyles) {
80
+ // Convert the position from "px" to Int
81
+ const y = -parseInt(document.body.style.top, 10);
82
+ const x = -parseInt(document.body.style.left, 10);
83
+
84
+ // Restore styles
85
+ Object.assign(document.body.style, previousBodyPosition);
86
+
87
+ window.requestAnimationFrame(() => {
88
+ if (preventScrollRestoration && activeUrl !== window.location.href) {
89
+ setActiveUrl(window.location.href);
90
+ return;
91
+ }
92
+
93
+ window.scrollTo(x, y);
94
+ });
95
+
96
+ previousBodyPosition = null;
97
+ }
98
+ }, [activeUrl]);
99
+
100
+ React.useEffect(() => {
101
+ function onScroll() {
102
+ scrollPos.current = window.scrollY;
103
+ }
104
+
105
+ onScroll();
106
+
107
+ window.addEventListener('scroll', onScroll);
108
+
109
+ return () => {
110
+ window.removeEventListener('scroll', onScroll);
111
+ };
112
+ }, []);
113
+
114
+ React.useEffect(() => {
115
+ if (!modal) return;
116
+
117
+ return () => {
118
+ if (typeof document === 'undefined') return;
119
+
120
+ // Another drawer is opened, safe to ignore the execution
121
+ const hasDrawerOpened = !!document.querySelector('[data-vaul-drawer]');
122
+ if (hasDrawerOpened) return;
123
+
124
+ restorePositionSetting();
125
+ };
126
+ }, [modal, restorePositionSetting]);
127
+
128
+ React.useEffect(() => {
129
+ if (nested || !hasBeenOpened) return;
130
+ // This is needed to force Safari toolbar to show **before** the drawer starts animating to prevent a gnarly shift from happening
131
+ if (isOpen) {
132
+ // avoid for standalone mode (PWA)
133
+ const isStandalone = window.matchMedia('(display-mode: standalone)').matches;
134
+ !isStandalone && setPositionFixed();
135
+
136
+ if (!modal) {
137
+ window.setTimeout(() => {
138
+ restorePositionSetting();
139
+ }, 500);
140
+ }
141
+ } else {
142
+ restorePositionSetting();
143
+ }
144
+ }, [isOpen, hasBeenOpened, activeUrl, modal, nested, setPositionFixed, restorePositionSetting]);
145
+
146
+ return { restorePositionSetting };
147
+ }