base-vaul 0.0.1 → 0.1.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.
- package/dist/index.cjs +1314 -0
- package/dist/index.css +256 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +186 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +170 -131
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1181 -1540
- package/dist/index.mjs.map +1 -0
- package/package.json +33 -27
- package/dist/index.d.ts +0 -147
- package/dist/index.js +0 -1668
package/dist/index.mjs
CHANGED
|
@@ -1,1641 +1,1282 @@
|
|
|
1
|
-
|
|
2
|
-
function __insertCSS(code) {
|
|
3
|
-
if (!code || typeof document == 'undefined') return
|
|
4
|
-
let head = document.head || document.getElementsByTagName('head')[0]
|
|
5
|
-
let style = document.createElement('style')
|
|
6
|
-
style.type = 'text/css'
|
|
7
|
-
head.appendChild(style)
|
|
8
|
-
;style.styleSheet ? (style.styleSheet.cssText = code) : style.appendChild(document.createTextNode(code))
|
|
9
|
-
}
|
|
1
|
+
"use client";
|
|
10
2
|
|
|
11
|
-
import { Dialog } from
|
|
12
|
-
import * as React from
|
|
13
|
-
import
|
|
3
|
+
import { Dialog } from "@base-ui/react";
|
|
4
|
+
import * as React$1 from "react";
|
|
5
|
+
import React, { useEffect, useLayoutEffect, useMemo } from "react";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
14
7
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
},
|
|
48
|
-
shouldScaleBackground: false,
|
|
49
|
-
setBackgroundColorOnScale: true,
|
|
50
|
-
noBodyStyles: false,
|
|
51
|
-
container: null,
|
|
52
|
-
autoFocus: false
|
|
8
|
+
import './index.css';
|
|
9
|
+
//#region src/context.ts
|
|
10
|
+
const DrawerContext = React.createContext({
|
|
11
|
+
drawerRef: { current: null },
|
|
12
|
+
overlayRef: { current: null },
|
|
13
|
+
onPress: () => {},
|
|
14
|
+
onRelease: () => {},
|
|
15
|
+
onDrag: () => {},
|
|
16
|
+
onNestedDrag: () => {},
|
|
17
|
+
onNestedOpenChange: () => {},
|
|
18
|
+
onNestedRelease: () => {},
|
|
19
|
+
openProp: void 0,
|
|
20
|
+
dismissible: false,
|
|
21
|
+
isOpen: false,
|
|
22
|
+
isDragging: false,
|
|
23
|
+
keyboardIsOpen: { current: false },
|
|
24
|
+
snapPointsOffset: null,
|
|
25
|
+
snapPoints: null,
|
|
26
|
+
handleOnly: false,
|
|
27
|
+
modal: false,
|
|
28
|
+
shouldFade: false,
|
|
29
|
+
activeSnapPoint: null,
|
|
30
|
+
onOpenChange: () => {},
|
|
31
|
+
setActiveSnapPoint: () => {},
|
|
32
|
+
closeDrawer: () => {},
|
|
33
|
+
direction: "bottom",
|
|
34
|
+
shouldAnimate: { current: true },
|
|
35
|
+
shouldScaleBackground: false,
|
|
36
|
+
setBackgroundColorOnScale: true,
|
|
37
|
+
noBodyStyles: false,
|
|
38
|
+
container: null,
|
|
39
|
+
autoFocus: false
|
|
53
40
|
});
|
|
54
|
-
const useDrawerContext = ()=>{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
return context;
|
|
41
|
+
const useDrawerContext = () => {
|
|
42
|
+
const context = React.useContext(DrawerContext);
|
|
43
|
+
if (!context) throw new Error("useDrawerContext must be used within a Drawer.Root");
|
|
44
|
+
return context;
|
|
60
45
|
};
|
|
61
46
|
|
|
62
|
-
|
|
63
|
-
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/browser.ts
|
|
64
49
|
function isMobileFirefox() {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
/FxiOS/.test(userAgent) // iOS Firefox
|
|
68
|
-
);
|
|
50
|
+
const userAgent = navigator.userAgent;
|
|
51
|
+
return typeof window !== "undefined" && (/Firefox/.test(userAgent) && /Mobile/.test(userAgent) || /FxiOS/.test(userAgent));
|
|
69
52
|
}
|
|
70
53
|
function isMac() {
|
|
71
|
-
|
|
54
|
+
return testPlatform(/^Mac/);
|
|
72
55
|
}
|
|
73
56
|
function isIPhone() {
|
|
74
|
-
|
|
57
|
+
return testPlatform(/^iPhone/);
|
|
75
58
|
}
|
|
76
59
|
function isSafari() {
|
|
77
|
-
|
|
60
|
+
return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
78
61
|
}
|
|
79
62
|
function isIPad() {
|
|
80
|
-
|
|
81
|
-
isMac() && navigator.maxTouchPoints > 1;
|
|
63
|
+
return testPlatform(/^iPad/) || isMac() && navigator.maxTouchPoints > 1;
|
|
82
64
|
}
|
|
83
65
|
function isIOS() {
|
|
84
|
-
|
|
66
|
+
return isIPhone() || isIPad();
|
|
85
67
|
}
|
|
86
68
|
function testPlatform(re) {
|
|
87
|
-
|
|
69
|
+
return typeof window !== "undefined" && window.navigator != null ? re.test(window.navigator.platform) : void 0;
|
|
88
70
|
}
|
|
89
71
|
|
|
90
|
-
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/use-prevent-scroll.ts
|
|
91
74
|
const KEYBOARD_BUFFER = 24;
|
|
92
|
-
const useIsomorphicLayoutEffect = typeof window !==
|
|
75
|
+
const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
93
76
|
function chain$1(...callbacks) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
callback(...args);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
};
|
|
77
|
+
return (...args) => {
|
|
78
|
+
for (const callback of callbacks) if (typeof callback === "function") callback(...args);
|
|
79
|
+
};
|
|
101
80
|
}
|
|
102
|
-
|
|
103
|
-
const visualViewport = typeof document !== 'undefined' && window.visualViewport;
|
|
81
|
+
const visualViewport = typeof document !== "undefined" && window.visualViewport;
|
|
104
82
|
function isScrollable(node) {
|
|
105
|
-
|
|
106
|
-
|
|
83
|
+
const style = window.getComputedStyle(node);
|
|
84
|
+
return /(auto|scroll)/.test(style.overflow + style.overflowX + style.overflowY);
|
|
107
85
|
}
|
|
108
86
|
function getScrollParent(node) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
while(node && !isScrollable(node)){
|
|
113
|
-
node = node.parentElement;
|
|
114
|
-
}
|
|
115
|
-
return node || document.scrollingElement || document.documentElement;
|
|
87
|
+
if (isScrollable(node)) node = node.parentElement;
|
|
88
|
+
while (node && !isScrollable(node)) node = node.parentElement;
|
|
89
|
+
return node || document.scrollingElement || document.documentElement;
|
|
116
90
|
}
|
|
117
|
-
// HTML input types that do not cause the software keyboard to appear.
|
|
118
91
|
const nonTextInputTypes = new Set([
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
92
|
+
"checkbox",
|
|
93
|
+
"radio",
|
|
94
|
+
"range",
|
|
95
|
+
"color",
|
|
96
|
+
"file",
|
|
97
|
+
"image",
|
|
98
|
+
"button",
|
|
99
|
+
"submit",
|
|
100
|
+
"reset"
|
|
128
101
|
]);
|
|
129
|
-
// The number of active usePreventScroll calls. Used to determine whether to revert back to the original page style/scroll position
|
|
130
102
|
let preventScrollCount = 0;
|
|
131
103
|
let restore;
|
|
132
104
|
/**
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (preventScrollCount === 0) {
|
|
151
|
-
restore == null ? void 0 : restore();
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
}, [
|
|
155
|
-
isDisabled
|
|
156
|
-
]);
|
|
105
|
+
* Prevents scrolling on the document body on mount, and
|
|
106
|
+
* restores it on unmount. Also ensures that content does not
|
|
107
|
+
* shift due to the scrollbars disappearing.
|
|
108
|
+
*/
|
|
109
|
+
function usePreventScroll(options = {}) {
|
|
110
|
+
const { isDisabled } = options;
|
|
111
|
+
useIsomorphicLayoutEffect(() => {
|
|
112
|
+
if (isDisabled) return;
|
|
113
|
+
preventScrollCount++;
|
|
114
|
+
if (preventScrollCount === 1) {
|
|
115
|
+
if (isIOS()) restore = preventScrollMobileSafari();
|
|
116
|
+
}
|
|
117
|
+
return () => {
|
|
118
|
+
preventScrollCount--;
|
|
119
|
+
if (preventScrollCount === 0) restore === null || restore === void 0 || restore();
|
|
120
|
+
};
|
|
121
|
+
}, [isDisabled]);
|
|
157
122
|
}
|
|
158
|
-
// Mobile Safari is a whole different beast. Even with overflow: hidden,
|
|
159
|
-
// it still scrolls the page in many situations:
|
|
160
|
-
//
|
|
161
|
-
// 1. When the bottom toolbar and address bar are collapsed, page scrolling is always allowed.
|
|
162
|
-
// 2. When the keyboard is visible, the viewport does not resize. Instead, the keyboard covers part of
|
|
163
|
-
// it, so it becomes scrollable.
|
|
164
|
-
// 3. When tapping on an input, the page always scrolls so that the input is centered in the visual viewport.
|
|
165
|
-
// This may cause even fixed position elements to scroll off the screen.
|
|
166
|
-
// 4. When using the next/previous buttons in the keyboard to navigate between inputs, the whole page always
|
|
167
|
-
// scrolls, even if the input is inside a nested scrollable element that could be scrolled instead.
|
|
168
|
-
//
|
|
169
|
-
// In order to work around these cases, and prevent scrolling without jankiness, we do a few things:
|
|
170
|
-
//
|
|
171
|
-
// 1. Prevent default on `touchmove` events that are not in a scrollable element. This prevents touch scrolling
|
|
172
|
-
// on the window.
|
|
173
|
-
// 2. Prevent default on `touchmove` events inside a scrollable element when the scroll position is at the
|
|
174
|
-
// top or bottom. This avoids the whole page scrolling instead, but does prevent overscrolling.
|
|
175
|
-
// 3. Prevent default on `touchend` events on input elements and handle focusing the element ourselves.
|
|
176
|
-
// 4. When focusing an input, apply a transform to trick Safari into thinking the input is at the top
|
|
177
|
-
// of the page, which prevents it from scrolling the page. After the input is focused, scroll the element
|
|
178
|
-
// into view ourselves, without scrolling the whole page.
|
|
179
|
-
// 5. Offset the body by the scroll position using a negative margin and scroll to the top. This should appear the
|
|
180
|
-
// same visually, but makes the actual scroll position always zero. This is required to make all of the
|
|
181
|
-
// above work or Safari will still try to scroll the page when focusing an input.
|
|
182
|
-
// 6. As a last resort, handle window scroll events, and scroll back to the top. This can happen when attempting
|
|
183
|
-
// to navigate to an input with the next/previous buttons that's outside a modal.
|
|
184
123
|
function preventScrollMobileSafari() {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
} else {
|
|
251
|
-
// Otherwise, wait for the visual viewport to resize before scrolling so we can
|
|
252
|
-
// measure the correct position to scroll to.
|
|
253
|
-
visualViewport.addEventListener('resize', ()=>scrollIntoView(target), {
|
|
254
|
-
once: true
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
};
|
|
261
|
-
let onWindowScroll = ()=>{
|
|
262
|
-
// Last resort. If the window scrolled, scroll it back to the top.
|
|
263
|
-
// It should always be at the top because the body will have a negative margin (see below).
|
|
264
|
-
window.scrollTo(0, 0);
|
|
265
|
-
};
|
|
266
|
-
// Record the original scroll position so we can restore it.
|
|
267
|
-
// Then apply a negative margin to the body to offset it by the scroll position. This will
|
|
268
|
-
// enable us to scroll the window to the top, which is required for the rest of this to work.
|
|
269
|
-
let scrollX = window.pageXOffset;
|
|
270
|
-
let scrollY = window.pageYOffset;
|
|
271
|
-
let restoreStyles = chain$1(setStyle(document.documentElement, 'paddingRight', `${window.innerWidth - document.documentElement.clientWidth}px`));
|
|
272
|
-
// Scroll to the top. The negative margin on the body will make this appear the same.
|
|
273
|
-
window.scrollTo(0, 0);
|
|
274
|
-
let removeEvents = chain$1(addEvent(document, 'touchstart', onTouchStart, {
|
|
275
|
-
passive: false,
|
|
276
|
-
capture: true
|
|
277
|
-
}), addEvent(document, 'touchmove', onTouchMove, {
|
|
278
|
-
passive: false,
|
|
279
|
-
capture: true
|
|
280
|
-
}), addEvent(document, 'touchend', onTouchEnd, {
|
|
281
|
-
passive: false,
|
|
282
|
-
capture: true
|
|
283
|
-
}), addEvent(document, 'focus', onFocus, true), addEvent(window, 'scroll', onWindowScroll));
|
|
284
|
-
return ()=>{
|
|
285
|
-
// Restore styles and scroll the page back to where it was.
|
|
286
|
-
restoreStyles();
|
|
287
|
-
removeEvents();
|
|
288
|
-
window.scrollTo(scrollX, scrollY);
|
|
289
|
-
};
|
|
124
|
+
let scrollable;
|
|
125
|
+
let lastY = 0;
|
|
126
|
+
const onTouchStart = (e) => {
|
|
127
|
+
scrollable = getScrollParent(e.target);
|
|
128
|
+
if (scrollable === document.documentElement && scrollable === document.body) return;
|
|
129
|
+
lastY = e.changedTouches[0].pageY;
|
|
130
|
+
};
|
|
131
|
+
const onTouchMove = (e) => {
|
|
132
|
+
if (!scrollable || scrollable === document.documentElement || scrollable === document.body) {
|
|
133
|
+
e.preventDefault();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const y = e.changedTouches[0].pageY;
|
|
137
|
+
const scrollTop = scrollable.scrollTop;
|
|
138
|
+
const bottom = scrollable.scrollHeight - scrollable.clientHeight;
|
|
139
|
+
if (bottom === 0) return;
|
|
140
|
+
if (scrollTop <= 0 && y > lastY || scrollTop >= bottom && y < lastY) e.preventDefault();
|
|
141
|
+
lastY = y;
|
|
142
|
+
};
|
|
143
|
+
const onTouchEnd = (e) => {
|
|
144
|
+
const target = e.target;
|
|
145
|
+
if (isInput(target) && target !== document.activeElement) {
|
|
146
|
+
e.preventDefault();
|
|
147
|
+
target.style.transform = "translateY(-2000px)";
|
|
148
|
+
target.focus();
|
|
149
|
+
requestAnimationFrame(() => {
|
|
150
|
+
target.style.transform = "";
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const onFocus = (e) => {
|
|
155
|
+
const target = e.target;
|
|
156
|
+
if (isInput(target)) {
|
|
157
|
+
target.style.transform = "translateY(-2000px)";
|
|
158
|
+
requestAnimationFrame(() => {
|
|
159
|
+
target.style.transform = "";
|
|
160
|
+
if (visualViewport) if (visualViewport.height < window.innerHeight) requestAnimationFrame(() => {
|
|
161
|
+
scrollIntoView(target);
|
|
162
|
+
});
|
|
163
|
+
else visualViewport.addEventListener("resize", () => scrollIntoView(target), { once: true });
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const onWindowScroll = () => {
|
|
168
|
+
window.scrollTo(0, 0);
|
|
169
|
+
};
|
|
170
|
+
const scrollX = window.pageXOffset;
|
|
171
|
+
const scrollY = window.pageYOffset;
|
|
172
|
+
const restoreStyles = chain$1(setStyle(document.documentElement, "paddingRight", `${window.innerWidth - document.documentElement.clientWidth}px`));
|
|
173
|
+
window.scrollTo(0, 0);
|
|
174
|
+
const removeEvents = chain$1(addEvent(document, "touchstart", onTouchStart, {
|
|
175
|
+
passive: false,
|
|
176
|
+
capture: true
|
|
177
|
+
}), addEvent(document, "touchmove", onTouchMove, {
|
|
178
|
+
passive: false,
|
|
179
|
+
capture: true
|
|
180
|
+
}), addEvent(document, "touchend", onTouchEnd, {
|
|
181
|
+
passive: false,
|
|
182
|
+
capture: true
|
|
183
|
+
}), addEvent(document, "focus", onFocus, true), addEvent(window, "scroll", onWindowScroll));
|
|
184
|
+
return () => {
|
|
185
|
+
restoreStyles();
|
|
186
|
+
removeEvents();
|
|
187
|
+
window.scrollTo(scrollX, scrollY);
|
|
188
|
+
};
|
|
290
189
|
}
|
|
291
|
-
// Sets a CSS property on an element, and returns a function to revert it to the previous value.
|
|
292
190
|
function setStyle(element, style, value) {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
return ()=>{
|
|
299
|
-
// @ts-ignore
|
|
300
|
-
element.style[style] = cur;
|
|
301
|
-
};
|
|
191
|
+
const cur = element.style[style];
|
|
192
|
+
element.style[style] = value;
|
|
193
|
+
return () => {
|
|
194
|
+
element.style[style] = cur;
|
|
195
|
+
};
|
|
302
196
|
}
|
|
303
|
-
// Adds an event listener to an element, and returns a function to remove it.
|
|
304
197
|
function addEvent(target, event, handler, options) {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
target.removeEventListener(event, handler, options);
|
|
310
|
-
};
|
|
198
|
+
target.addEventListener(event, handler, options);
|
|
199
|
+
return () => {
|
|
200
|
+
target.removeEventListener(event, handler, options);
|
|
201
|
+
};
|
|
311
202
|
}
|
|
312
203
|
function scrollIntoView(target) {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
if (targetBottom > keyboardHeight) {
|
|
324
|
-
scrollable.scrollTop += targetTop - scrollableTop;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
// @ts-ignore
|
|
328
|
-
target = scrollable.parentElement;
|
|
329
|
-
}
|
|
204
|
+
const root = document.scrollingElement || document.documentElement;
|
|
205
|
+
while (target && target !== root) {
|
|
206
|
+
const scrollable = getScrollParent(target);
|
|
207
|
+
if (scrollable !== document.documentElement && scrollable !== document.body && scrollable !== target) {
|
|
208
|
+
const scrollableTop = scrollable.getBoundingClientRect().top;
|
|
209
|
+
const targetTop = target.getBoundingClientRect().top;
|
|
210
|
+
if (target.getBoundingClientRect().bottom > scrollable.getBoundingClientRect().bottom + KEYBOARD_BUFFER) scrollable.scrollTop += targetTop - scrollableTop;
|
|
211
|
+
}
|
|
212
|
+
target = scrollable.parentElement;
|
|
213
|
+
}
|
|
330
214
|
}
|
|
331
215
|
function isInput(target) {
|
|
332
|
-
|
|
216
|
+
return target instanceof HTMLInputElement && !nonTextInputTypes.has(target.type) || target instanceof HTMLTextAreaElement || target instanceof HTMLElement && target.isContentEditable;
|
|
333
217
|
}
|
|
334
218
|
|
|
335
|
-
|
|
219
|
+
//#endregion
|
|
220
|
+
//#region src/use-composed-refs.ts
|
|
336
221
|
/**
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
ref.current = value;
|
|
344
|
-
}
|
|
222
|
+
* Set a given ref to a given value
|
|
223
|
+
* This utility takes care of different types of refs: callback refs and RefObject(s)
|
|
224
|
+
*/
|
|
225
|
+
function setRef(ref, value) {
|
|
226
|
+
if (typeof ref === "function") ref(value);
|
|
227
|
+
else if (ref !== null && ref !== void 0) ref.current = value;
|
|
345
228
|
}
|
|
346
229
|
/**
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
230
|
+
* A utility to compose multiple refs together
|
|
231
|
+
* Accepts callback refs and RefObject(s)
|
|
232
|
+
*/
|
|
233
|
+
function composeRefs(...refs) {
|
|
234
|
+
return (node) => refs.forEach((ref) => setRef(ref, node));
|
|
351
235
|
}
|
|
352
236
|
/**
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
237
|
+
* A custom hook that composes multiple refs
|
|
238
|
+
* Accepts callback refs and RefObject(s)
|
|
239
|
+
*/
|
|
240
|
+
function useComposedRefs(...refs) {
|
|
241
|
+
return React$1.useCallback(composeRefs(...refs), refs);
|
|
358
242
|
}
|
|
359
243
|
|
|
360
|
-
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region src/helpers.ts
|
|
246
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
361
247
|
function set(el, styles, ignoreCache = false) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
248
|
+
if (!el || !(el instanceof HTMLElement)) return;
|
|
249
|
+
const originalStyles = {};
|
|
250
|
+
Object.entries(styles).forEach(([key, value]) => {
|
|
251
|
+
if (key.startsWith("--")) {
|
|
252
|
+
el.style.setProperty(key, value);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
originalStyles[key] = el.style[key];
|
|
256
|
+
el.style[key] = value;
|
|
257
|
+
});
|
|
258
|
+
if (ignoreCache) return;
|
|
259
|
+
cache.set(el, originalStyles);
|
|
374
260
|
}
|
|
375
261
|
function reset(el, prop) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}
|
|
262
|
+
if (!el || !(el instanceof HTMLElement)) return;
|
|
263
|
+
const originalStyles = cache.get(el);
|
|
264
|
+
if (!originalStyles) return;
|
|
265
|
+
if (prop) el.style[prop] = originalStyles[prop];
|
|
266
|
+
else Object.entries(originalStyles).forEach(([key, value]) => {
|
|
267
|
+
el.style[key] = value;
|
|
268
|
+
});
|
|
384
269
|
}
|
|
385
|
-
const isVertical = (direction)=>{
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
default:
|
|
394
|
-
return direction;
|
|
395
|
-
}
|
|
270
|
+
const isVertical = (direction) => {
|
|
271
|
+
switch (direction) {
|
|
272
|
+
case "top":
|
|
273
|
+
case "bottom": return true;
|
|
274
|
+
case "left":
|
|
275
|
+
case "right": return false;
|
|
276
|
+
default: return direction;
|
|
277
|
+
}
|
|
396
278
|
};
|
|
397
279
|
function getTranslate(element, direction) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
if (mat) {
|
|
406
|
-
// https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix3d
|
|
407
|
-
return parseFloat(mat[1].split(', ')[isVertical(direction) ? 13 : 12]);
|
|
408
|
-
}
|
|
409
|
-
// https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix
|
|
410
|
-
mat = transform.match(/^matrix\((.+)\)$/);
|
|
411
|
-
return mat ? parseFloat(mat[1].split(', ')[isVertical(direction) ? 5 : 4]) : null;
|
|
280
|
+
if (!element) return null;
|
|
281
|
+
const style = window.getComputedStyle(element);
|
|
282
|
+
const transform = style.transform || style.webkitTransform || style.mozTransform;
|
|
283
|
+
let mat = transform.match(/^matrix3d\((.+)\)$/);
|
|
284
|
+
if (mat) return parseFloat(mat[1].split(", ")[isVertical(direction) ? 13 : 12]);
|
|
285
|
+
mat = transform.match(/^matrix\((.+)\)$/);
|
|
286
|
+
return mat ? parseFloat(mat[1].split(", ")[isVertical(direction) ? 5 : 4]) : null;
|
|
412
287
|
}
|
|
413
288
|
function dampenValue(v) {
|
|
414
|
-
|
|
289
|
+
return 8 * (Math.log(v + 1) - 2);
|
|
415
290
|
}
|
|
416
291
|
function assignStyle(element, style) {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
292
|
+
if (!element) return () => {};
|
|
293
|
+
const prevStyle = element.style.cssText;
|
|
294
|
+
Object.assign(element.style, style);
|
|
295
|
+
return () => {
|
|
296
|
+
element.style.cssText = prevStyle;
|
|
297
|
+
};
|
|
423
298
|
}
|
|
424
299
|
/**
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
fn(...args);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
};
|
|
300
|
+
* Receives functions as arguments and returns a new function that calls all.
|
|
301
|
+
*/
|
|
302
|
+
function chain(...fns) {
|
|
303
|
+
return (...args) => {
|
|
304
|
+
for (const fn of fns) if (typeof fn === "function") fn(...args);
|
|
305
|
+
};
|
|
435
306
|
}
|
|
436
307
|
|
|
308
|
+
//#endregion
|
|
309
|
+
//#region src/constants.ts
|
|
437
310
|
const TRANSITIONS = {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
311
|
+
DURATION: .5,
|
|
312
|
+
EASE: [
|
|
313
|
+
.32,
|
|
314
|
+
.72,
|
|
315
|
+
0,
|
|
316
|
+
1
|
|
317
|
+
]
|
|
445
318
|
};
|
|
446
|
-
const VELOCITY_THRESHOLD =
|
|
447
|
-
const CLOSE_THRESHOLD =
|
|
319
|
+
const VELOCITY_THRESHOLD = .4;
|
|
320
|
+
const CLOSE_THRESHOLD = .25;
|
|
448
321
|
const SCROLL_LOCK_TIMEOUT = 100;
|
|
449
322
|
const BORDER_RADIUS = 8;
|
|
450
323
|
const NESTED_DISPLACEMENT = 16;
|
|
451
324
|
const WINDOW_TOP_OFFSET = 26;
|
|
452
|
-
const DRAG_CLASS =
|
|
325
|
+
const DRAG_CLASS = "vaul-dragging";
|
|
453
326
|
|
|
454
|
-
|
|
327
|
+
//#endregion
|
|
328
|
+
//#region src/use-controllable-state.ts
|
|
455
329
|
function useCallbackRef(callback) {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
330
|
+
const callbackRef = React.useRef(callback);
|
|
331
|
+
React.useEffect(() => {
|
|
332
|
+
callbackRef.current = callback;
|
|
333
|
+
});
|
|
334
|
+
return React.useMemo(() => ((...args) => {
|
|
335
|
+
var _callbackRef$current;
|
|
336
|
+
return (_callbackRef$current = callbackRef.current) === null || _callbackRef$current === void 0 ? void 0 : _callbackRef$current.call(callbackRef, ...args);
|
|
337
|
+
}), []);
|
|
462
338
|
}
|
|
463
339
|
function useUncontrolledState({ defaultProp, onChange }) {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
340
|
+
const uncontrolledState = React.useState(defaultProp);
|
|
341
|
+
const [value] = uncontrolledState;
|
|
342
|
+
const prevValueRef = React.useRef(value);
|
|
343
|
+
const handleChange = useCallbackRef(onChange);
|
|
344
|
+
React.useEffect(() => {
|
|
345
|
+
if (prevValueRef.current !== value) {
|
|
346
|
+
handleChange(value);
|
|
347
|
+
prevValueRef.current = value;
|
|
348
|
+
}
|
|
349
|
+
}, [
|
|
350
|
+
value,
|
|
351
|
+
prevValueRef,
|
|
352
|
+
handleChange
|
|
353
|
+
]);
|
|
354
|
+
return uncontrolledState;
|
|
479
355
|
}
|
|
480
|
-
function useControllableState({ prop, defaultProp, onChange = ()=>{} }) {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
setUncontrolledProp,
|
|
500
|
-
handleChange
|
|
501
|
-
]);
|
|
502
|
-
return [
|
|
503
|
-
value,
|
|
504
|
-
setValue
|
|
505
|
-
];
|
|
356
|
+
function useControllableState({ prop, defaultProp, onChange = () => {} }) {
|
|
357
|
+
const [uncontrolledProp, setUncontrolledProp] = useUncontrolledState({
|
|
358
|
+
defaultProp,
|
|
359
|
+
onChange
|
|
360
|
+
});
|
|
361
|
+
const isControlled = prop !== void 0;
|
|
362
|
+
const value = isControlled ? prop : uncontrolledProp;
|
|
363
|
+
const handleChange = useCallbackRef(onChange);
|
|
364
|
+
return [value, React.useCallback((nextValue) => {
|
|
365
|
+
if (isControlled) {
|
|
366
|
+
const value$1 = typeof nextValue === "function" ? nextValue(prop) : nextValue;
|
|
367
|
+
if (value$1 !== prop) handleChange(value$1);
|
|
368
|
+
} else setUncontrolledProp(nextValue);
|
|
369
|
+
}, [
|
|
370
|
+
isControlled,
|
|
371
|
+
prop,
|
|
372
|
+
setUncontrolledProp,
|
|
373
|
+
handleChange
|
|
374
|
+
])];
|
|
506
375
|
}
|
|
507
376
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
snapToPoint(closestSnapPoint);
|
|
664
|
-
}
|
|
665
|
-
function onDrag({ draggedDistance }) {
|
|
666
|
-
if (activeSnapPointOffset === null) return;
|
|
667
|
-
const newValue = direction === 'bottom' || direction === 'right' ? activeSnapPointOffset - draggedDistance : activeSnapPointOffset + draggedDistance;
|
|
668
|
-
// Don't do anything if we exceed the last(biggest) snap point
|
|
669
|
-
if ((direction === 'bottom' || direction === 'right') && newValue < snapPointsOffset[snapPointsOffset.length - 1]) {
|
|
670
|
-
return;
|
|
671
|
-
}
|
|
672
|
-
if ((direction === 'top' || direction === 'left') && newValue > snapPointsOffset[snapPointsOffset.length - 1]) {
|
|
673
|
-
return;
|
|
674
|
-
}
|
|
675
|
-
set(drawerRef.current, {
|
|
676
|
-
transform: isVertical(direction) ? `translate3d(0, ${newValue}px, 0)` : `translate3d(${newValue}px, 0, 0)`
|
|
677
|
-
});
|
|
678
|
-
}
|
|
679
|
-
function getPercentageDragged(absDraggedDistance, isDraggingDown) {
|
|
680
|
-
if (!snapPoints || typeof activeSnapPointIndex !== 'number' || !snapPointsOffset || fadeFromIndex === undefined) return null;
|
|
681
|
-
// If this is true we are dragging to a snap point that is supposed to have an overlay
|
|
682
|
-
const isOverlaySnapPoint = activeSnapPointIndex === fadeFromIndex - 1;
|
|
683
|
-
const isOverlaySnapPointOrHigher = activeSnapPointIndex >= fadeFromIndex;
|
|
684
|
-
if (isOverlaySnapPointOrHigher && isDraggingDown) {
|
|
685
|
-
return 0;
|
|
686
|
-
}
|
|
687
|
-
// Don't animate, but still use this one if we are dragging away from the overlaySnapPoint
|
|
688
|
-
if (isOverlaySnapPoint && !isDraggingDown) return 1;
|
|
689
|
-
if (!shouldFade && !isOverlaySnapPoint) return null;
|
|
690
|
-
// Either fadeFrom index or the one before
|
|
691
|
-
const targetSnapPointIndex = isOverlaySnapPoint ? activeSnapPointIndex + 1 : activeSnapPointIndex - 1;
|
|
692
|
-
// Get the distance from overlaySnapPoint to the one before or vice-versa to calculate the opacity percentage accordingly
|
|
693
|
-
const snapPointDistance = isOverlaySnapPoint ? snapPointsOffset[targetSnapPointIndex] - snapPointsOffset[targetSnapPointIndex - 1] : snapPointsOffset[targetSnapPointIndex + 1] - snapPointsOffset[targetSnapPointIndex];
|
|
694
|
-
const percentageDragged = absDraggedDistance / Math.abs(snapPointDistance);
|
|
695
|
-
if (isOverlaySnapPoint) {
|
|
696
|
-
return 1 - percentageDragged;
|
|
697
|
-
} else {
|
|
698
|
-
return percentageDragged;
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
return {
|
|
702
|
-
isLastSnapPoint,
|
|
703
|
-
activeSnapPoint,
|
|
704
|
-
shouldFade,
|
|
705
|
-
getPercentageDragged,
|
|
706
|
-
setActiveSnapPoint,
|
|
707
|
-
activeSnapPointIndex,
|
|
708
|
-
onRelease,
|
|
709
|
-
onDrag,
|
|
710
|
-
snapPointsOffset
|
|
711
|
-
};
|
|
377
|
+
//#endregion
|
|
378
|
+
//#region src/use-snap-points.ts
|
|
379
|
+
function useSnapPoints({ activeSnapPointProp, setActiveSnapPointProp, snapPoints, drawerRef, overlayRef, fadeFromIndex, onSnapPointChange, direction = "bottom", container, snapToSequentialPoint }) {
|
|
380
|
+
const [activeSnapPoint, setActiveSnapPoint] = useControllableState({
|
|
381
|
+
prop: activeSnapPointProp,
|
|
382
|
+
defaultProp: snapPoints === null || snapPoints === void 0 ? void 0 : snapPoints[0],
|
|
383
|
+
onChange: setActiveSnapPointProp
|
|
384
|
+
});
|
|
385
|
+
const [windowDimensions, setWindowDimensions] = React.useState(typeof window !== "undefined" ? {
|
|
386
|
+
innerWidth: window.innerWidth,
|
|
387
|
+
innerHeight: window.innerHeight
|
|
388
|
+
} : void 0);
|
|
389
|
+
React.useEffect(() => {
|
|
390
|
+
function onResize() {
|
|
391
|
+
setWindowDimensions({
|
|
392
|
+
innerWidth: window.innerWidth,
|
|
393
|
+
innerHeight: window.innerHeight
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
window.addEventListener("resize", onResize);
|
|
397
|
+
return () => window.removeEventListener("resize", onResize);
|
|
398
|
+
}, []);
|
|
399
|
+
const isLastSnapPoint = React.useMemo(() => activeSnapPoint === (snapPoints === null || snapPoints === void 0 ? void 0 : snapPoints[snapPoints.length - 1]) || null, [snapPoints, activeSnapPoint]);
|
|
400
|
+
const activeSnapPointIndex = React.useMemo(() => (snapPoints === null || snapPoints === void 0 ? void 0 : snapPoints.findIndex((snapPoint) => snapPoint === activeSnapPoint)) ?? null, [snapPoints, activeSnapPoint]);
|
|
401
|
+
const shouldFade = snapPoints && snapPoints.length > 0 && (fadeFromIndex || fadeFromIndex === 0) && !Number.isNaN(fadeFromIndex) && snapPoints[fadeFromIndex] === activeSnapPoint || !snapPoints;
|
|
402
|
+
const snapPointsOffset = React.useMemo(() => {
|
|
403
|
+
const containerSize = container ? {
|
|
404
|
+
width: container.getBoundingClientRect().width,
|
|
405
|
+
height: container.getBoundingClientRect().height
|
|
406
|
+
} : typeof window !== "undefined" ? {
|
|
407
|
+
width: window.innerWidth,
|
|
408
|
+
height: window.innerHeight
|
|
409
|
+
} : {
|
|
410
|
+
width: 0,
|
|
411
|
+
height: 0
|
|
412
|
+
};
|
|
413
|
+
return (snapPoints === null || snapPoints === void 0 ? void 0 : snapPoints.map((snapPoint) => {
|
|
414
|
+
const isPx = typeof snapPoint === "string";
|
|
415
|
+
let snapPointAsNumber = 0;
|
|
416
|
+
if (isPx) snapPointAsNumber = parseInt(snapPoint, 10);
|
|
417
|
+
if (isVertical(direction)) {
|
|
418
|
+
const height = isPx ? snapPointAsNumber : windowDimensions ? snapPoint * containerSize.height : 0;
|
|
419
|
+
if (windowDimensions) return direction === "bottom" ? containerSize.height - height : -containerSize.height + height;
|
|
420
|
+
return height;
|
|
421
|
+
}
|
|
422
|
+
const width = isPx ? snapPointAsNumber : windowDimensions ? snapPoint * containerSize.width : 0;
|
|
423
|
+
if (windowDimensions) return direction === "right" ? containerSize.width - width : -containerSize.width + width;
|
|
424
|
+
return width;
|
|
425
|
+
})) ?? [];
|
|
426
|
+
}, [
|
|
427
|
+
snapPoints,
|
|
428
|
+
windowDimensions,
|
|
429
|
+
container
|
|
430
|
+
]);
|
|
431
|
+
const activeSnapPointOffset = React.useMemo(() => activeSnapPointIndex !== null ? snapPointsOffset === null || snapPointsOffset === void 0 ? void 0 : snapPointsOffset[activeSnapPointIndex] : null, [snapPointsOffset, activeSnapPointIndex]);
|
|
432
|
+
const snapToPoint = React.useCallback((dimension) => {
|
|
433
|
+
const newSnapPointIndex = (snapPointsOffset === null || snapPointsOffset === void 0 ? void 0 : snapPointsOffset.findIndex((snapPointDim) => snapPointDim === dimension)) ?? null;
|
|
434
|
+
onSnapPointChange(newSnapPointIndex);
|
|
435
|
+
set(drawerRef.current, {
|
|
436
|
+
transition: `transform ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(",")})`,
|
|
437
|
+
transform: isVertical(direction) ? `translate3d(0, ${dimension}px, 0)` : `translate3d(${dimension}px, 0, 0)`
|
|
438
|
+
});
|
|
439
|
+
if (snapPointsOffset && newSnapPointIndex !== snapPointsOffset.length - 1 && fadeFromIndex !== void 0 && newSnapPointIndex !== fadeFromIndex && newSnapPointIndex < fadeFromIndex) set(overlayRef.current, {
|
|
440
|
+
transition: `opacity ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(",")})`,
|
|
441
|
+
opacity: "0"
|
|
442
|
+
});
|
|
443
|
+
else set(overlayRef.current, {
|
|
444
|
+
transition: `opacity ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(",")})`,
|
|
445
|
+
opacity: "1"
|
|
446
|
+
});
|
|
447
|
+
setActiveSnapPoint(snapPoints === null || snapPoints === void 0 ? void 0 : snapPoints[Math.max(newSnapPointIndex, 0)]);
|
|
448
|
+
}, [
|
|
449
|
+
drawerRef.current,
|
|
450
|
+
snapPoints,
|
|
451
|
+
snapPointsOffset,
|
|
452
|
+
fadeFromIndex,
|
|
453
|
+
overlayRef,
|
|
454
|
+
setActiveSnapPoint
|
|
455
|
+
]);
|
|
456
|
+
React.useEffect(() => {
|
|
457
|
+
if (activeSnapPoint || activeSnapPointProp) {
|
|
458
|
+
const newIndex = (snapPoints === null || snapPoints === void 0 ? void 0 : snapPoints.findIndex((snapPoint) => snapPoint === activeSnapPointProp || snapPoint === activeSnapPoint)) ?? -1;
|
|
459
|
+
if (snapPointsOffset && newIndex !== -1 && typeof snapPointsOffset[newIndex] === "number") snapToPoint(snapPointsOffset[newIndex]);
|
|
460
|
+
}
|
|
461
|
+
}, [
|
|
462
|
+
activeSnapPoint,
|
|
463
|
+
activeSnapPointProp,
|
|
464
|
+
snapPoints,
|
|
465
|
+
snapPointsOffset,
|
|
466
|
+
snapToPoint
|
|
467
|
+
]);
|
|
468
|
+
function onRelease({ draggedDistance, closeDrawer, velocity, dismissible }) {
|
|
469
|
+
if (fadeFromIndex === void 0) return;
|
|
470
|
+
const currentPosition = direction === "bottom" || direction === "right" ? (activeSnapPointOffset ?? 0) - draggedDistance : (activeSnapPointOffset ?? 0) + draggedDistance;
|
|
471
|
+
const isOverlaySnapPoint = activeSnapPointIndex === fadeFromIndex - 1;
|
|
472
|
+
const isFirst = activeSnapPointIndex === 0;
|
|
473
|
+
const hasDraggedUp = draggedDistance > 0;
|
|
474
|
+
if (isOverlaySnapPoint) set(overlayRef.current, { transition: `opacity ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(",")})` });
|
|
475
|
+
if (!snapToSequentialPoint && velocity > 2 && !hasDraggedUp) {
|
|
476
|
+
if (dismissible) closeDrawer();
|
|
477
|
+
else snapToPoint(snapPointsOffset[0]);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (!snapToSequentialPoint && velocity > 2 && hasDraggedUp && snapPointsOffset && snapPoints) {
|
|
481
|
+
snapToPoint(snapPointsOffset[snapPoints.length - 1]);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const closestSnapPoint = snapPointsOffset === null || snapPointsOffset === void 0 ? void 0 : snapPointsOffset.reduce((prev, curr) => {
|
|
485
|
+
if (typeof prev !== "number" || typeof curr !== "number") return prev;
|
|
486
|
+
return Math.abs(curr - currentPosition) < Math.abs(prev - currentPosition) ? curr : prev;
|
|
487
|
+
});
|
|
488
|
+
const dim = isVertical(direction) ? window.innerHeight : window.innerWidth;
|
|
489
|
+
if (velocity > VELOCITY_THRESHOLD && Math.abs(draggedDistance) < dim * .4) {
|
|
490
|
+
const dragDirection = hasDraggedUp ? 1 : -1;
|
|
491
|
+
if (dragDirection > 0 && isLastSnapPoint && snapPoints) {
|
|
492
|
+
snapToPoint(snapPointsOffset[snapPoints.length - 1]);
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
if (isFirst && dragDirection < 0 && dismissible) closeDrawer();
|
|
496
|
+
if (activeSnapPointIndex === null) return;
|
|
497
|
+
snapToPoint(snapPointsOffset[activeSnapPointIndex + dragDirection]);
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
snapToPoint(closestSnapPoint);
|
|
501
|
+
}
|
|
502
|
+
function onDrag({ draggedDistance }) {
|
|
503
|
+
if (activeSnapPointOffset === null) return;
|
|
504
|
+
const newValue = direction === "bottom" || direction === "right" ? activeSnapPointOffset - draggedDistance : activeSnapPointOffset + draggedDistance;
|
|
505
|
+
if ((direction === "bottom" || direction === "right") && newValue < snapPointsOffset[snapPointsOffset.length - 1]) return;
|
|
506
|
+
if ((direction === "top" || direction === "left") && newValue > snapPointsOffset[snapPointsOffset.length - 1]) return;
|
|
507
|
+
set(drawerRef.current, { transform: isVertical(direction) ? `translate3d(0, ${newValue}px, 0)` : `translate3d(${newValue}px, 0, 0)` });
|
|
508
|
+
}
|
|
509
|
+
function getPercentageDragged(absDraggedDistance, isDraggingDown) {
|
|
510
|
+
if (!snapPoints || typeof activeSnapPointIndex !== "number" || !snapPointsOffset || fadeFromIndex === void 0) return null;
|
|
511
|
+
const isOverlaySnapPoint = activeSnapPointIndex === fadeFromIndex - 1;
|
|
512
|
+
if (activeSnapPointIndex >= fadeFromIndex && isDraggingDown) return 0;
|
|
513
|
+
if (isOverlaySnapPoint && !isDraggingDown) return 1;
|
|
514
|
+
if (!shouldFade && !isOverlaySnapPoint) return null;
|
|
515
|
+
const targetSnapPointIndex = isOverlaySnapPoint ? activeSnapPointIndex + 1 : activeSnapPointIndex - 1;
|
|
516
|
+
const snapPointDistance = isOverlaySnapPoint ? snapPointsOffset[targetSnapPointIndex] - snapPointsOffset[targetSnapPointIndex - 1] : snapPointsOffset[targetSnapPointIndex + 1] - snapPointsOffset[targetSnapPointIndex];
|
|
517
|
+
const percentageDragged = absDraggedDistance / Math.abs(snapPointDistance);
|
|
518
|
+
if (isOverlaySnapPoint) return 1 - percentageDragged;
|
|
519
|
+
else return percentageDragged;
|
|
520
|
+
}
|
|
521
|
+
return {
|
|
522
|
+
isLastSnapPoint,
|
|
523
|
+
activeSnapPoint,
|
|
524
|
+
shouldFade,
|
|
525
|
+
getPercentageDragged,
|
|
526
|
+
setActiveSnapPoint,
|
|
527
|
+
activeSnapPointIndex,
|
|
528
|
+
onRelease,
|
|
529
|
+
onDrag,
|
|
530
|
+
snapPointsOffset
|
|
531
|
+
};
|
|
712
532
|
}
|
|
713
533
|
|
|
714
|
-
|
|
534
|
+
//#endregion
|
|
535
|
+
//#region src/use-scale-background.ts
|
|
536
|
+
const noop = () => () => {};
|
|
715
537
|
function useScaleBackground() {
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
}
|
|
752
|
-
}, TRANSITIONS.DURATION * 1000);
|
|
753
|
-
};
|
|
754
|
-
}
|
|
755
|
-
}, [
|
|
756
|
-
isOpen,
|
|
757
|
-
shouldScaleBackground,
|
|
758
|
-
initialBackgroundColor
|
|
759
|
-
]);
|
|
538
|
+
const { direction, isOpen, shouldScaleBackground, setBackgroundColorOnScale, noBodyStyles } = useDrawerContext();
|
|
539
|
+
const timeoutIdRef = React.useRef(null);
|
|
540
|
+
const initialBackgroundColor = useMemo(() => document.body.style.backgroundColor, []);
|
|
541
|
+
function getScale() {
|
|
542
|
+
return (window.innerWidth - WINDOW_TOP_OFFSET) / window.innerWidth;
|
|
543
|
+
}
|
|
544
|
+
React.useEffect(() => {
|
|
545
|
+
if (isOpen && shouldScaleBackground) {
|
|
546
|
+
if (timeoutIdRef.current) clearTimeout(timeoutIdRef.current);
|
|
547
|
+
const wrapper = document.querySelector("[data-vaul-drawer-wrapper]") || document.querySelector("[vaul-drawer-wrapper]");
|
|
548
|
+
if (!wrapper) return;
|
|
549
|
+
chain(setBackgroundColorOnScale && !noBodyStyles ? assignStyle(document.body, { background: "black" }) : noop, assignStyle(wrapper, {
|
|
550
|
+
transformOrigin: isVertical(direction) ? "top" : "left",
|
|
551
|
+
transitionProperty: "transform, border-radius",
|
|
552
|
+
transitionDuration: `${TRANSITIONS.DURATION}s`,
|
|
553
|
+
transitionTimingFunction: `cubic-bezier(${TRANSITIONS.EASE.join(",")})`
|
|
554
|
+
}));
|
|
555
|
+
const wrapperStylesCleanup = assignStyle(wrapper, {
|
|
556
|
+
borderRadius: `${BORDER_RADIUS}px`,
|
|
557
|
+
overflow: "hidden",
|
|
558
|
+
...isVertical(direction) ? { transform: `scale(${getScale()}) translate3d(0, calc(env(safe-area-inset-top) + 14px), 0)` } : { transform: `scale(${getScale()}) translate3d(calc(env(safe-area-inset-top) + 14px), 0, 0)` }
|
|
559
|
+
});
|
|
560
|
+
return () => {
|
|
561
|
+
wrapperStylesCleanup();
|
|
562
|
+
timeoutIdRef.current = window.setTimeout(() => {
|
|
563
|
+
if (initialBackgroundColor) document.body.style.background = initialBackgroundColor;
|
|
564
|
+
else document.body.style.removeProperty("background");
|
|
565
|
+
}, TRANSITIONS.DURATION * 1e3);
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
}, [
|
|
569
|
+
isOpen,
|
|
570
|
+
shouldScaleBackground,
|
|
571
|
+
initialBackgroundColor
|
|
572
|
+
]);
|
|
760
573
|
}
|
|
761
574
|
|
|
575
|
+
//#endregion
|
|
576
|
+
//#region src/use-position-fixed.ts
|
|
762
577
|
let previousBodyPosition = null;
|
|
763
578
|
/**
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
React__default.useEffect(()=>{
|
|
851
|
-
if (nested || !hasBeenOpened) return;
|
|
852
|
-
// This is needed to force Safari toolbar to show **before** the drawer starts animating to prevent a gnarly shift from happening
|
|
853
|
-
if (isOpen) {
|
|
854
|
-
// avoid for standalone mode (PWA)
|
|
855
|
-
const isStandalone = window.matchMedia('(display-mode: standalone)').matches;
|
|
856
|
-
!isStandalone && setPositionFixed();
|
|
857
|
-
if (!modal) {
|
|
858
|
-
window.setTimeout(()=>{
|
|
859
|
-
restorePositionSetting();
|
|
860
|
-
}, 500);
|
|
861
|
-
}
|
|
862
|
-
} else {
|
|
863
|
-
restorePositionSetting();
|
|
864
|
-
}
|
|
865
|
-
}, [
|
|
866
|
-
isOpen,
|
|
867
|
-
hasBeenOpened,
|
|
868
|
-
activeUrl,
|
|
869
|
-
modal,
|
|
870
|
-
nested,
|
|
871
|
-
setPositionFixed,
|
|
872
|
-
restorePositionSetting
|
|
873
|
-
]);
|
|
874
|
-
return {
|
|
875
|
-
restorePositionSetting
|
|
876
|
-
};
|
|
579
|
+
* This hook is necessary to prevent buggy behavior on iOS devices (need to test on Android).
|
|
580
|
+
* 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.
|
|
581
|
+
* Issues that this hook solves:
|
|
582
|
+
* https://github.com/emilkowalski/vaul/issues/435
|
|
583
|
+
* https://github.com/emilkowalski/vaul/issues/433
|
|
584
|
+
* And more that I discovered, but were just not reported.
|
|
585
|
+
*/
|
|
586
|
+
function usePositionFixed({ isOpen, modal, nested, hasBeenOpened, preventScrollRestoration, noBodyStyles }) {
|
|
587
|
+
const [activeUrl, setActiveUrl] = React.useState(() => typeof window !== "undefined" ? window.location.href : "");
|
|
588
|
+
const scrollPos = React.useRef(0);
|
|
589
|
+
const setPositionFixed = React.useCallback(() => {
|
|
590
|
+
if (!isSafari()) return;
|
|
591
|
+
if (previousBodyPosition === null && isOpen && !noBodyStyles) {
|
|
592
|
+
previousBodyPosition = {
|
|
593
|
+
position: document.body.style.position,
|
|
594
|
+
top: document.body.style.top,
|
|
595
|
+
left: document.body.style.left,
|
|
596
|
+
height: document.body.style.height,
|
|
597
|
+
right: "unset"
|
|
598
|
+
};
|
|
599
|
+
const { scrollX, innerHeight } = window;
|
|
600
|
+
document.body.style.setProperty("position", "fixed", "important");
|
|
601
|
+
Object.assign(document.body.style, {
|
|
602
|
+
top: `${-scrollPos.current}px`,
|
|
603
|
+
left: `${-scrollX}px`,
|
|
604
|
+
right: "0px",
|
|
605
|
+
height: "auto"
|
|
606
|
+
});
|
|
607
|
+
window.setTimeout(() => window.requestAnimationFrame(() => {
|
|
608
|
+
const bottomBarHeight = innerHeight - window.innerHeight;
|
|
609
|
+
if (bottomBarHeight && scrollPos.current >= innerHeight) document.body.style.top = `${-(scrollPos.current + bottomBarHeight)}px`;
|
|
610
|
+
}), 300);
|
|
611
|
+
}
|
|
612
|
+
}, [isOpen]);
|
|
613
|
+
const restorePositionSetting = React.useCallback(() => {
|
|
614
|
+
if (!isSafari()) return;
|
|
615
|
+
if (previousBodyPosition !== null && !noBodyStyles) {
|
|
616
|
+
const y = -parseInt(document.body.style.top, 10);
|
|
617
|
+
const x = -parseInt(document.body.style.left, 10);
|
|
618
|
+
Object.assign(document.body.style, previousBodyPosition);
|
|
619
|
+
window.requestAnimationFrame(() => {
|
|
620
|
+
if (preventScrollRestoration && activeUrl !== window.location.href) {
|
|
621
|
+
setActiveUrl(window.location.href);
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
window.scrollTo(x, y);
|
|
625
|
+
});
|
|
626
|
+
previousBodyPosition = null;
|
|
627
|
+
}
|
|
628
|
+
}, [activeUrl]);
|
|
629
|
+
React.useEffect(() => {
|
|
630
|
+
function onScroll() {
|
|
631
|
+
scrollPos.current = window.scrollY;
|
|
632
|
+
}
|
|
633
|
+
onScroll();
|
|
634
|
+
window.addEventListener("scroll", onScroll);
|
|
635
|
+
return () => {
|
|
636
|
+
window.removeEventListener("scroll", onScroll);
|
|
637
|
+
};
|
|
638
|
+
}, []);
|
|
639
|
+
React.useEffect(() => {
|
|
640
|
+
if (!modal) return;
|
|
641
|
+
return () => {
|
|
642
|
+
if (typeof document === "undefined") return;
|
|
643
|
+
if (!!document.querySelector("[data-vaul-drawer]")) return;
|
|
644
|
+
restorePositionSetting();
|
|
645
|
+
};
|
|
646
|
+
}, [modal, restorePositionSetting]);
|
|
647
|
+
React.useEffect(() => {
|
|
648
|
+
if (nested || !hasBeenOpened) return;
|
|
649
|
+
if (isOpen) {
|
|
650
|
+
!window.matchMedia("(display-mode: standalone)").matches && setPositionFixed();
|
|
651
|
+
if (!modal) window.setTimeout(() => {
|
|
652
|
+
restorePositionSetting();
|
|
653
|
+
}, 500);
|
|
654
|
+
} else restorePositionSetting();
|
|
655
|
+
}, [
|
|
656
|
+
isOpen,
|
|
657
|
+
hasBeenOpened,
|
|
658
|
+
activeUrl,
|
|
659
|
+
modal,
|
|
660
|
+
nested,
|
|
661
|
+
setPositionFixed,
|
|
662
|
+
restorePositionSetting
|
|
663
|
+
]);
|
|
664
|
+
return { restorePositionSetting };
|
|
877
665
|
}
|
|
878
666
|
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
return;
|
|
1272
|
-
}
|
|
1273
|
-
onReleaseProp == null ? void 0 : onReleaseProp(event, true);
|
|
1274
|
-
resetDrawer();
|
|
1275
|
-
}
|
|
1276
|
-
React__default.useEffect(()=>{
|
|
1277
|
-
// Trigger enter animation without using CSS animation
|
|
1278
|
-
if (isOpen) {
|
|
1279
|
-
set(document.documentElement, {
|
|
1280
|
-
scrollBehavior: 'auto'
|
|
1281
|
-
});
|
|
1282
|
-
openTime.current = new Date();
|
|
1283
|
-
}
|
|
1284
|
-
return ()=>{
|
|
1285
|
-
reset(document.documentElement, 'scrollBehavior');
|
|
1286
|
-
};
|
|
1287
|
-
}, [
|
|
1288
|
-
isOpen
|
|
1289
|
-
]);
|
|
1290
|
-
function onNestedOpenChange(o) {
|
|
1291
|
-
const scale = o ? (window.innerWidth - NESTED_DISPLACEMENT) / window.innerWidth : 1;
|
|
1292
|
-
const initialTranslate = o ? -NESTED_DISPLACEMENT : 0;
|
|
1293
|
-
if (nestedOpenChangeTimer.current) {
|
|
1294
|
-
window.clearTimeout(nestedOpenChangeTimer.current);
|
|
1295
|
-
}
|
|
1296
|
-
set(drawerRef.current, {
|
|
1297
|
-
transition: `transform ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(',')})`,
|
|
1298
|
-
transform: isVertical(direction) ? `scale(${scale}) translate3d(0, ${initialTranslate}px, 0)` : `scale(${scale}) translate3d(${initialTranslate}px, 0, 0)`
|
|
1299
|
-
});
|
|
1300
|
-
if (!o && drawerRef.current) {
|
|
1301
|
-
nestedOpenChangeTimer.current = setTimeout(()=>{
|
|
1302
|
-
const translateValue = getTranslate(drawerRef.current, direction);
|
|
1303
|
-
set(drawerRef.current, {
|
|
1304
|
-
transition: 'none',
|
|
1305
|
-
transform: isVertical(direction) ? `translate3d(0, ${translateValue}px, 0)` : `translate3d(${translateValue}px, 0, 0)`
|
|
1306
|
-
});
|
|
1307
|
-
}, 500);
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
function onNestedDrag(_event, percentageDragged) {
|
|
1311
|
-
if (percentageDragged < 0) return;
|
|
1312
|
-
const initialScale = (window.innerWidth - NESTED_DISPLACEMENT) / window.innerWidth;
|
|
1313
|
-
const newScale = initialScale + percentageDragged * (1 - initialScale);
|
|
1314
|
-
const newTranslate = -NESTED_DISPLACEMENT + percentageDragged * NESTED_DISPLACEMENT;
|
|
1315
|
-
set(drawerRef.current, {
|
|
1316
|
-
transform: isVertical(direction) ? `scale(${newScale}) translate3d(0, ${newTranslate}px, 0)` : `scale(${newScale}) translate3d(${newTranslate}px, 0, 0)`,
|
|
1317
|
-
transition: 'none'
|
|
1318
|
-
});
|
|
1319
|
-
}
|
|
1320
|
-
function onNestedRelease(_event, o) {
|
|
1321
|
-
const dim = isVertical(direction) ? window.innerHeight : window.innerWidth;
|
|
1322
|
-
const scale = o ? (dim - NESTED_DISPLACEMENT) / dim : 1;
|
|
1323
|
-
const translate = o ? -NESTED_DISPLACEMENT : 0;
|
|
1324
|
-
if (o) {
|
|
1325
|
-
set(drawerRef.current, {
|
|
1326
|
-
transition: `transform ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(',')})`,
|
|
1327
|
-
transform: isVertical(direction) ? `scale(${scale}) translate3d(0, ${translate}px, 0)` : `scale(${scale}) translate3d(${translate}px, 0, 0)`
|
|
1328
|
-
});
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
React__default.useEffect(()=>{
|
|
1332
|
-
if (!modal) {
|
|
1333
|
-
// Need to do this manually unfortunately
|
|
1334
|
-
window.requestAnimationFrame(()=>{
|
|
1335
|
-
document.body.style.pointerEvents = 'auto';
|
|
1336
|
-
});
|
|
1337
|
-
}
|
|
1338
|
-
}, [
|
|
1339
|
-
modal
|
|
1340
|
-
]);
|
|
1341
|
-
return /*#__PURE__*/ React__default.createElement(Dialog.Root, {
|
|
1342
|
-
defaultOpen: defaultOpen,
|
|
1343
|
-
onOpenChange: (open)=>{
|
|
1344
|
-
if (!dismissible && !open) return;
|
|
1345
|
-
if (open) {
|
|
1346
|
-
setHasBeenOpened(true);
|
|
1347
|
-
} else {
|
|
1348
|
-
closeDrawer(true);
|
|
1349
|
-
}
|
|
1350
|
-
setIsOpen(open);
|
|
1351
|
-
},
|
|
1352
|
-
open: isOpen,
|
|
1353
|
-
modal: modal
|
|
1354
|
-
}, /*#__PURE__*/ React__default.createElement(DrawerContext.Provider, {
|
|
1355
|
-
value: {
|
|
1356
|
-
activeSnapPoint,
|
|
1357
|
-
snapPoints,
|
|
1358
|
-
setActiveSnapPoint,
|
|
1359
|
-
drawerRef,
|
|
1360
|
-
overlayRef,
|
|
1361
|
-
onOpenChange,
|
|
1362
|
-
onPress,
|
|
1363
|
-
onRelease,
|
|
1364
|
-
onDrag,
|
|
1365
|
-
dismissible,
|
|
1366
|
-
shouldAnimate,
|
|
1367
|
-
handleOnly,
|
|
1368
|
-
isOpen,
|
|
1369
|
-
isDragging,
|
|
1370
|
-
shouldFade,
|
|
1371
|
-
closeDrawer,
|
|
1372
|
-
onNestedDrag,
|
|
1373
|
-
onNestedOpenChange,
|
|
1374
|
-
onNestedRelease,
|
|
1375
|
-
keyboardIsOpen,
|
|
1376
|
-
modal,
|
|
1377
|
-
snapPointsOffset,
|
|
1378
|
-
activeSnapPointIndex,
|
|
1379
|
-
direction,
|
|
1380
|
-
shouldScaleBackground,
|
|
1381
|
-
setBackgroundColorOnScale,
|
|
1382
|
-
noBodyStyles,
|
|
1383
|
-
container,
|
|
1384
|
-
autoFocus
|
|
1385
|
-
}
|
|
1386
|
-
}, children));
|
|
667
|
+
//#endregion
|
|
668
|
+
//#region src/index.tsx
|
|
669
|
+
function Root({ open: openProp, onOpenChange, children, onDrag: onDragProp, onRelease: onReleaseProp, snapPoints, shouldScaleBackground = false, setBackgroundColorOnScale = true, closeThreshold = CLOSE_THRESHOLD, scrollLockTimeout = SCROLL_LOCK_TIMEOUT, dismissible = true, handleOnly = false, fadeFromIndex = snapPoints && snapPoints.length - 1, activeSnapPoint: activeSnapPointProp, setActiveSnapPoint: setActiveSnapPointProp, fixed, modal = true, onClose, nested, noBodyStyles = false, direction = "bottom", defaultOpen = false, disablePreventScroll = true, snapToSequentialPoint = false, preventScrollRestoration = false, repositionInputs = true, onAnimationEnd, container, autoFocus = false }) {
|
|
670
|
+
var _drawerRef$current, _drawerRef$current2;
|
|
671
|
+
const [isOpen = false, setIsOpen] = useControllableState({
|
|
672
|
+
defaultProp: defaultOpen,
|
|
673
|
+
prop: openProp,
|
|
674
|
+
onChange: (o) => {
|
|
675
|
+
onOpenChange === null || onOpenChange === void 0 || onOpenChange(o);
|
|
676
|
+
if (!o && !nested) restorePositionSetting();
|
|
677
|
+
setTimeout(() => {
|
|
678
|
+
onAnimationEnd === null || onAnimationEnd === void 0 || onAnimationEnd(o);
|
|
679
|
+
}, TRANSITIONS.DURATION * 1e3);
|
|
680
|
+
if (o && !modal) {
|
|
681
|
+
if (typeof window !== "undefined") window.requestAnimationFrame(() => {
|
|
682
|
+
document.body.style.pointerEvents = "auto";
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
if (!o) document.body.style.pointerEvents = "auto";
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
const [hasBeenOpened, setHasBeenOpened] = React.useState(false);
|
|
689
|
+
const [isDragging, setIsDragging] = React.useState(false);
|
|
690
|
+
const [justReleased, setJustReleased] = React.useState(false);
|
|
691
|
+
const overlayRef = React.useRef(null);
|
|
692
|
+
const openTime = React.useRef(null);
|
|
693
|
+
const dragStartTime = React.useRef(null);
|
|
694
|
+
const dragEndTime = React.useRef(null);
|
|
695
|
+
const lastTimeDragPrevented = React.useRef(null);
|
|
696
|
+
const isAllowedToDrag = React.useRef(false);
|
|
697
|
+
const nestedOpenChangeTimer = React.useRef(null);
|
|
698
|
+
const pointerStart = React.useRef(0);
|
|
699
|
+
const keyboardIsOpen = React.useRef(false);
|
|
700
|
+
const shouldAnimate = React.useRef(!defaultOpen);
|
|
701
|
+
const previousDiffFromInitial = React.useRef(0);
|
|
702
|
+
const drawerRef = React.useRef(null);
|
|
703
|
+
const drawerHeightRef = React.useRef(((_drawerRef$current = drawerRef.current) === null || _drawerRef$current === void 0 ? void 0 : _drawerRef$current.getBoundingClientRect().height) || 0);
|
|
704
|
+
const drawerWidthRef = React.useRef(((_drawerRef$current2 = drawerRef.current) === null || _drawerRef$current2 === void 0 ? void 0 : _drawerRef$current2.getBoundingClientRect().width) || 0);
|
|
705
|
+
const initialDrawerHeight = React.useRef(0);
|
|
706
|
+
const { activeSnapPoint, activeSnapPointIndex, setActiveSnapPoint, onRelease: onReleaseSnapPoints, snapPointsOffset, onDrag: onDragSnapPoints, shouldFade, getPercentageDragged: getSnapPointsPercentageDragged } = useSnapPoints({
|
|
707
|
+
snapPoints,
|
|
708
|
+
activeSnapPointProp,
|
|
709
|
+
setActiveSnapPointProp,
|
|
710
|
+
drawerRef,
|
|
711
|
+
fadeFromIndex,
|
|
712
|
+
overlayRef,
|
|
713
|
+
onSnapPointChange: React.useCallback((activeSnapPointIndex$1) => {
|
|
714
|
+
if (snapPoints && activeSnapPointIndex$1 === snapPointsOffset.length - 1) openTime.current = /* @__PURE__ */ new Date();
|
|
715
|
+
}, []),
|
|
716
|
+
direction,
|
|
717
|
+
container,
|
|
718
|
+
snapToSequentialPoint
|
|
719
|
+
});
|
|
720
|
+
usePreventScroll({ isDisabled: !isOpen || isDragging || !modal || justReleased || !hasBeenOpened || !repositionInputs || !disablePreventScroll });
|
|
721
|
+
const { restorePositionSetting } = usePositionFixed({
|
|
722
|
+
isOpen,
|
|
723
|
+
modal,
|
|
724
|
+
nested: nested ?? false,
|
|
725
|
+
hasBeenOpened,
|
|
726
|
+
preventScrollRestoration,
|
|
727
|
+
noBodyStyles
|
|
728
|
+
});
|
|
729
|
+
function getScale() {
|
|
730
|
+
return (window.innerWidth - WINDOW_TOP_OFFSET) / window.innerWidth;
|
|
731
|
+
}
|
|
732
|
+
function onPress(event) {
|
|
733
|
+
var _drawerRef$current3, _drawerRef$current4;
|
|
734
|
+
if (!dismissible && !snapPoints) return;
|
|
735
|
+
if (drawerRef.current && !drawerRef.current.contains(event.target)) return;
|
|
736
|
+
drawerHeightRef.current = ((_drawerRef$current3 = drawerRef.current) === null || _drawerRef$current3 === void 0 ? void 0 : _drawerRef$current3.getBoundingClientRect().height) || 0;
|
|
737
|
+
drawerWidthRef.current = ((_drawerRef$current4 = drawerRef.current) === null || _drawerRef$current4 === void 0 ? void 0 : _drawerRef$current4.getBoundingClientRect().width) || 0;
|
|
738
|
+
setIsDragging(true);
|
|
739
|
+
dragStartTime.current = /* @__PURE__ */ new Date();
|
|
740
|
+
if (isIOS()) window.addEventListener("touchend", () => isAllowedToDrag.current = false, { once: true });
|
|
741
|
+
event.target.setPointerCapture(event.pointerId);
|
|
742
|
+
pointerStart.current = isVertical(direction) ? event.pageY : event.pageX;
|
|
743
|
+
}
|
|
744
|
+
function shouldDrag(el, isDraggingInDirection) {
|
|
745
|
+
var _window$getSelection;
|
|
746
|
+
let element = el;
|
|
747
|
+
const highlightedText = (_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.toString();
|
|
748
|
+
const swipeAmount = drawerRef.current ? getTranslate(drawerRef.current, direction) : null;
|
|
749
|
+
const date = /* @__PURE__ */ new Date();
|
|
750
|
+
if (element.tagName === "SELECT") return false;
|
|
751
|
+
if (element.hasAttribute("data-vaul-no-drag") || element.closest("[data-vaul-no-drag]")) return false;
|
|
752
|
+
if (direction === "right" || direction === "left") return true;
|
|
753
|
+
if (openTime.current && date.getTime() - openTime.current.getTime() < 500) return false;
|
|
754
|
+
if (swipeAmount !== null) {
|
|
755
|
+
if (direction === "bottom" ? swipeAmount > 0 : swipeAmount < 0) return true;
|
|
756
|
+
}
|
|
757
|
+
if (highlightedText && highlightedText.length > 0) return false;
|
|
758
|
+
if (lastTimeDragPrevented.current && date.getTime() - lastTimeDragPrevented.current.getTime() < scrollLockTimeout && swipeAmount === 0) {
|
|
759
|
+
lastTimeDragPrevented.current = date;
|
|
760
|
+
return false;
|
|
761
|
+
}
|
|
762
|
+
if (isDraggingInDirection) {
|
|
763
|
+
lastTimeDragPrevented.current = date;
|
|
764
|
+
return false;
|
|
765
|
+
}
|
|
766
|
+
while (element) {
|
|
767
|
+
if (element.scrollHeight > element.clientHeight) {
|
|
768
|
+
if (element.scrollTop !== 0) {
|
|
769
|
+
lastTimeDragPrevented.current = /* @__PURE__ */ new Date();
|
|
770
|
+
return false;
|
|
771
|
+
}
|
|
772
|
+
if (element.getAttribute("role") === "dialog") return true;
|
|
773
|
+
}
|
|
774
|
+
element = element.parentNode;
|
|
775
|
+
}
|
|
776
|
+
return true;
|
|
777
|
+
}
|
|
778
|
+
function onDrag(event) {
|
|
779
|
+
if (!drawerRef.current) return;
|
|
780
|
+
if (isDragging) {
|
|
781
|
+
const directionMultiplier = direction === "bottom" || direction === "right" ? 1 : -1;
|
|
782
|
+
const draggedDistance = (pointerStart.current - (isVertical(direction) ? event.pageY : event.pageX)) * directionMultiplier;
|
|
783
|
+
const isDraggingInDirection = draggedDistance > 0;
|
|
784
|
+
const noCloseSnapPointsPreCondition = snapPoints && !dismissible && !isDraggingInDirection;
|
|
785
|
+
if (noCloseSnapPointsPreCondition && activeSnapPointIndex === 0) return;
|
|
786
|
+
const absDraggedDistance = Math.abs(draggedDistance);
|
|
787
|
+
const wrapper = document.querySelector("[data-vaul-drawer-wrapper]");
|
|
788
|
+
let percentageDragged = absDraggedDistance / (direction === "bottom" || direction === "top" ? drawerHeightRef.current : drawerWidthRef.current);
|
|
789
|
+
const snapPointPercentageDragged = getSnapPointsPercentageDragged(absDraggedDistance, isDraggingInDirection);
|
|
790
|
+
if (snapPointPercentageDragged !== null) percentageDragged = snapPointPercentageDragged;
|
|
791
|
+
if (noCloseSnapPointsPreCondition && percentageDragged >= 1) return;
|
|
792
|
+
if (!isAllowedToDrag.current && !shouldDrag(event.target, isDraggingInDirection)) return;
|
|
793
|
+
drawerRef.current.classList.add(DRAG_CLASS);
|
|
794
|
+
isAllowedToDrag.current = true;
|
|
795
|
+
set(drawerRef.current, { transition: "none" });
|
|
796
|
+
set(overlayRef.current, { transition: "none" });
|
|
797
|
+
if (snapPoints) onDragSnapPoints({ draggedDistance });
|
|
798
|
+
if (isDraggingInDirection && !snapPoints) {
|
|
799
|
+
const dampenedDraggedDistance = dampenValue(draggedDistance);
|
|
800
|
+
const translateValue = Math.min(dampenedDraggedDistance * -1, 0) * directionMultiplier;
|
|
801
|
+
set(drawerRef.current, { transform: isVertical(direction) ? `translate3d(0, ${translateValue}px, 0)` : `translate3d(${translateValue}px, 0, 0)` });
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
const opacityValue = 1 - percentageDragged;
|
|
805
|
+
if (shouldFade || fadeFromIndex && activeSnapPointIndex === fadeFromIndex - 1) {
|
|
806
|
+
onDragProp === null || onDragProp === void 0 || onDragProp(event, percentageDragged);
|
|
807
|
+
set(overlayRef.current, {
|
|
808
|
+
opacity: `${opacityValue}`,
|
|
809
|
+
transition: "none"
|
|
810
|
+
}, true);
|
|
811
|
+
}
|
|
812
|
+
if (wrapper && overlayRef.current && shouldScaleBackground) {
|
|
813
|
+
const scaleValue = Math.min(getScale() + percentageDragged * (1 - getScale()), 1);
|
|
814
|
+
const borderRadiusValue = 8 - percentageDragged * 8;
|
|
815
|
+
const translateValue = Math.max(0, 14 - percentageDragged * 14);
|
|
816
|
+
set(wrapper, {
|
|
817
|
+
borderRadius: `${borderRadiusValue}px`,
|
|
818
|
+
transform: isVertical(direction) ? `scale(${scaleValue}) translate3d(0, ${translateValue}px, 0)` : `scale(${scaleValue}) translate3d(${translateValue}px, 0, 0)`,
|
|
819
|
+
transition: "none"
|
|
820
|
+
}, true);
|
|
821
|
+
}
|
|
822
|
+
if (!snapPoints) {
|
|
823
|
+
const translateValue = absDraggedDistance * directionMultiplier;
|
|
824
|
+
set(drawerRef.current, { transform: isVertical(direction) ? `translate3d(0, ${translateValue}px, 0)` : `translate3d(${translateValue}px, 0, 0)` });
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
React.useEffect(() => {
|
|
829
|
+
window.requestAnimationFrame(() => {
|
|
830
|
+
shouldAnimate.current = true;
|
|
831
|
+
});
|
|
832
|
+
}, []);
|
|
833
|
+
React.useEffect(() => {
|
|
834
|
+
var _window$visualViewpor2;
|
|
835
|
+
function onVisualViewportChange() {
|
|
836
|
+
if (!drawerRef.current || !repositionInputs) return;
|
|
837
|
+
const focusedElement = document.activeElement;
|
|
838
|
+
if (isInput(focusedElement) || keyboardIsOpen.current) {
|
|
839
|
+
var _window$visualViewpor;
|
|
840
|
+
const visualViewportHeight = ((_window$visualViewpor = window.visualViewport) === null || _window$visualViewpor === void 0 ? void 0 : _window$visualViewpor.height) || 0;
|
|
841
|
+
const totalHeight = window.innerHeight;
|
|
842
|
+
let diffFromInitial = totalHeight - visualViewportHeight;
|
|
843
|
+
const drawerHeight = drawerRef.current.getBoundingClientRect().height || 0;
|
|
844
|
+
const isTallEnough = drawerHeight > totalHeight * .8;
|
|
845
|
+
if (!initialDrawerHeight.current) initialDrawerHeight.current = drawerHeight;
|
|
846
|
+
const offsetFromTop = drawerRef.current.getBoundingClientRect().top;
|
|
847
|
+
if (Math.abs(previousDiffFromInitial.current - diffFromInitial) > 60) keyboardIsOpen.current = !keyboardIsOpen.current;
|
|
848
|
+
if (snapPoints && snapPoints.length > 0 && snapPointsOffset && activeSnapPointIndex) {
|
|
849
|
+
const activeSnapPointHeight = snapPointsOffset[activeSnapPointIndex] || 0;
|
|
850
|
+
diffFromInitial += activeSnapPointHeight;
|
|
851
|
+
}
|
|
852
|
+
previousDiffFromInitial.current = diffFromInitial;
|
|
853
|
+
if (drawerHeight > visualViewportHeight || keyboardIsOpen.current) {
|
|
854
|
+
const height = drawerRef.current.getBoundingClientRect().height;
|
|
855
|
+
let newDrawerHeight = height;
|
|
856
|
+
if (height > visualViewportHeight) newDrawerHeight = visualViewportHeight - (isTallEnough ? offsetFromTop : WINDOW_TOP_OFFSET);
|
|
857
|
+
if (fixed) drawerRef.current.style.height = `${height - Math.max(diffFromInitial, 0)}px`;
|
|
858
|
+
else drawerRef.current.style.height = `${Math.max(newDrawerHeight, visualViewportHeight - offsetFromTop)}px`;
|
|
859
|
+
} else if (!isMobileFirefox()) drawerRef.current.style.height = `${initialDrawerHeight.current}px`;
|
|
860
|
+
if (snapPoints && snapPoints.length > 0 && !keyboardIsOpen.current) drawerRef.current.style.bottom = `0px`;
|
|
861
|
+
else drawerRef.current.style.bottom = `${Math.max(diffFromInitial, 0)}px`;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
(_window$visualViewpor2 = window.visualViewport) === null || _window$visualViewpor2 === void 0 || _window$visualViewpor2.addEventListener("resize", onVisualViewportChange);
|
|
865
|
+
return () => {
|
|
866
|
+
var _window$visualViewpor3;
|
|
867
|
+
return (_window$visualViewpor3 = window.visualViewport) === null || _window$visualViewpor3 === void 0 ? void 0 : _window$visualViewpor3.removeEventListener("resize", onVisualViewportChange);
|
|
868
|
+
};
|
|
869
|
+
}, [
|
|
870
|
+
activeSnapPointIndex,
|
|
871
|
+
snapPoints,
|
|
872
|
+
snapPointsOffset
|
|
873
|
+
]);
|
|
874
|
+
function closeDrawer(fromWithin) {
|
|
875
|
+
cancelDrag();
|
|
876
|
+
onClose === null || onClose === void 0 || onClose();
|
|
877
|
+
if (!fromWithin) setIsOpen(false);
|
|
878
|
+
setTimeout(() => {
|
|
879
|
+
if (snapPoints) setActiveSnapPoint(snapPoints[0]);
|
|
880
|
+
}, TRANSITIONS.DURATION * 1e3);
|
|
881
|
+
}
|
|
882
|
+
function resetDrawer() {
|
|
883
|
+
if (!drawerRef.current) return;
|
|
884
|
+
const wrapper = document.querySelector("[data-vaul-drawer-wrapper]");
|
|
885
|
+
const currentSwipeAmount = getTranslate(drawerRef.current, direction);
|
|
886
|
+
set(drawerRef.current, {
|
|
887
|
+
transform: "translate3d(0, 0, 0)",
|
|
888
|
+
transition: `transform ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(",")})`
|
|
889
|
+
});
|
|
890
|
+
set(overlayRef.current, {
|
|
891
|
+
transition: `opacity ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(",")})`,
|
|
892
|
+
opacity: "1"
|
|
893
|
+
});
|
|
894
|
+
if (shouldScaleBackground && currentSwipeAmount && currentSwipeAmount > 0 && isOpen) set(wrapper, {
|
|
895
|
+
borderRadius: `${BORDER_RADIUS}px`,
|
|
896
|
+
overflow: "hidden",
|
|
897
|
+
...isVertical(direction) ? {
|
|
898
|
+
transform: `scale(${getScale()}) translate3d(0, calc(env(safe-area-inset-top) + 14px), 0)`,
|
|
899
|
+
transformOrigin: "top"
|
|
900
|
+
} : {
|
|
901
|
+
transform: `scale(${getScale()}) translate3d(calc(env(safe-area-inset-top) + 14px), 0, 0)`,
|
|
902
|
+
transformOrigin: "left"
|
|
903
|
+
},
|
|
904
|
+
transitionProperty: "transform, border-radius",
|
|
905
|
+
transitionDuration: `${TRANSITIONS.DURATION}s`,
|
|
906
|
+
transitionTimingFunction: `cubic-bezier(${TRANSITIONS.EASE.join(",")})`
|
|
907
|
+
}, true);
|
|
908
|
+
}
|
|
909
|
+
function cancelDrag() {
|
|
910
|
+
if (!isDragging || !drawerRef.current) return;
|
|
911
|
+
drawerRef.current.classList.remove(DRAG_CLASS);
|
|
912
|
+
isAllowedToDrag.current = false;
|
|
913
|
+
setIsDragging(false);
|
|
914
|
+
dragEndTime.current = /* @__PURE__ */ new Date();
|
|
915
|
+
}
|
|
916
|
+
function onRelease(event) {
|
|
917
|
+
if (!isDragging || !drawerRef.current) return;
|
|
918
|
+
drawerRef.current.classList.remove(DRAG_CLASS);
|
|
919
|
+
isAllowedToDrag.current = false;
|
|
920
|
+
setIsDragging(false);
|
|
921
|
+
dragEndTime.current = /* @__PURE__ */ new Date();
|
|
922
|
+
const swipeAmount = getTranslate(drawerRef.current, direction);
|
|
923
|
+
if (!event || !shouldDrag(event.target, false) || !swipeAmount || Number.isNaN(swipeAmount)) return;
|
|
924
|
+
if (dragStartTime.current === null) return;
|
|
925
|
+
const timeTaken = dragEndTime.current.getTime() - dragStartTime.current.getTime();
|
|
926
|
+
const distMoved = pointerStart.current - (isVertical(direction) ? event.pageY : event.pageX);
|
|
927
|
+
const velocity = Math.abs(distMoved) / timeTaken;
|
|
928
|
+
if (velocity > .05) {
|
|
929
|
+
setJustReleased(true);
|
|
930
|
+
setTimeout(() => {
|
|
931
|
+
setJustReleased(false);
|
|
932
|
+
}, 200);
|
|
933
|
+
}
|
|
934
|
+
if (snapPoints) {
|
|
935
|
+
onReleaseSnapPoints({
|
|
936
|
+
draggedDistance: distMoved * (direction === "bottom" || direction === "right" ? 1 : -1),
|
|
937
|
+
closeDrawer,
|
|
938
|
+
velocity,
|
|
939
|
+
dismissible
|
|
940
|
+
});
|
|
941
|
+
onReleaseProp === null || onReleaseProp === void 0 || onReleaseProp(event, true);
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
if (direction === "bottom" || direction === "right" ? distMoved > 0 : distMoved < 0) {
|
|
945
|
+
resetDrawer();
|
|
946
|
+
onReleaseProp === null || onReleaseProp === void 0 || onReleaseProp(event, true);
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
if (velocity > VELOCITY_THRESHOLD) {
|
|
950
|
+
closeDrawer();
|
|
951
|
+
onReleaseProp === null || onReleaseProp === void 0 || onReleaseProp(event, false);
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
const visibleDrawerHeight = Math.min(drawerRef.current.getBoundingClientRect().height ?? 0, window.innerHeight);
|
|
955
|
+
const visibleDrawerWidth = Math.min(drawerRef.current.getBoundingClientRect().width ?? 0, window.innerWidth);
|
|
956
|
+
const isHorizontalSwipe = direction === "left" || direction === "right";
|
|
957
|
+
if (Math.abs(swipeAmount) >= (isHorizontalSwipe ? visibleDrawerWidth : visibleDrawerHeight) * closeThreshold) {
|
|
958
|
+
closeDrawer();
|
|
959
|
+
onReleaseProp === null || onReleaseProp === void 0 || onReleaseProp(event, false);
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
onReleaseProp === null || onReleaseProp === void 0 || onReleaseProp(event, true);
|
|
963
|
+
resetDrawer();
|
|
964
|
+
}
|
|
965
|
+
React.useEffect(() => {
|
|
966
|
+
if (isOpen) {
|
|
967
|
+
set(document.documentElement, { scrollBehavior: "auto" });
|
|
968
|
+
openTime.current = /* @__PURE__ */ new Date();
|
|
969
|
+
}
|
|
970
|
+
return () => {
|
|
971
|
+
reset(document.documentElement, "scrollBehavior");
|
|
972
|
+
};
|
|
973
|
+
}, [isOpen]);
|
|
974
|
+
function onNestedOpenChange(o) {
|
|
975
|
+
const scale = o ? (window.innerWidth - NESTED_DISPLACEMENT) / window.innerWidth : 1;
|
|
976
|
+
const initialTranslate = o ? -NESTED_DISPLACEMENT : 0;
|
|
977
|
+
if (nestedOpenChangeTimer.current) window.clearTimeout(nestedOpenChangeTimer.current);
|
|
978
|
+
set(drawerRef.current, {
|
|
979
|
+
transition: `transform ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(",")})`,
|
|
980
|
+
transform: isVertical(direction) ? `scale(${scale}) translate3d(0, ${initialTranslate}px, 0)` : `scale(${scale}) translate3d(${initialTranslate}px, 0, 0)`
|
|
981
|
+
});
|
|
982
|
+
if (!o && drawerRef.current) nestedOpenChangeTimer.current = setTimeout(() => {
|
|
983
|
+
const translateValue = getTranslate(drawerRef.current, direction);
|
|
984
|
+
set(drawerRef.current, {
|
|
985
|
+
transition: "none",
|
|
986
|
+
transform: isVertical(direction) ? `translate3d(0, ${translateValue}px, 0)` : `translate3d(${translateValue}px, 0, 0)`
|
|
987
|
+
});
|
|
988
|
+
}, 500);
|
|
989
|
+
}
|
|
990
|
+
function onNestedDrag(_event, percentageDragged) {
|
|
991
|
+
if (percentageDragged < 0) return;
|
|
992
|
+
const initialScale = (window.innerWidth - NESTED_DISPLACEMENT) / window.innerWidth;
|
|
993
|
+
const newScale = initialScale + percentageDragged * (1 - initialScale);
|
|
994
|
+
const newTranslate = -NESTED_DISPLACEMENT + percentageDragged * NESTED_DISPLACEMENT;
|
|
995
|
+
set(drawerRef.current, {
|
|
996
|
+
transform: isVertical(direction) ? `scale(${newScale}) translate3d(0, ${newTranslate}px, 0)` : `scale(${newScale}) translate3d(${newTranslate}px, 0, 0)`,
|
|
997
|
+
transition: "none"
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
function onNestedRelease(_event, o) {
|
|
1001
|
+
const dim = isVertical(direction) ? window.innerHeight : window.innerWidth;
|
|
1002
|
+
const scale = o ? (dim - NESTED_DISPLACEMENT) / dim : 1;
|
|
1003
|
+
const translate = o ? -NESTED_DISPLACEMENT : 0;
|
|
1004
|
+
if (o) set(drawerRef.current, {
|
|
1005
|
+
transition: `transform ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(",")})`,
|
|
1006
|
+
transform: isVertical(direction) ? `scale(${scale}) translate3d(0, ${translate}px, 0)` : `scale(${scale}) translate3d(${translate}px, 0, 0)`
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
React.useEffect(() => {
|
|
1010
|
+
if (!modal) window.requestAnimationFrame(() => {
|
|
1011
|
+
document.body.style.pointerEvents = "auto";
|
|
1012
|
+
});
|
|
1013
|
+
}, [modal]);
|
|
1014
|
+
return /* @__PURE__ */ jsx(Dialog.Root, {
|
|
1015
|
+
defaultOpen,
|
|
1016
|
+
onOpenChange: (open) => {
|
|
1017
|
+
if (!dismissible && !open) return;
|
|
1018
|
+
if (open) setHasBeenOpened(true);
|
|
1019
|
+
else closeDrawer(true);
|
|
1020
|
+
setIsOpen(open);
|
|
1021
|
+
},
|
|
1022
|
+
open: isOpen,
|
|
1023
|
+
modal,
|
|
1024
|
+
children: /* @__PURE__ */ jsx(DrawerContext.Provider, {
|
|
1025
|
+
value: {
|
|
1026
|
+
activeSnapPoint,
|
|
1027
|
+
snapPoints,
|
|
1028
|
+
setActiveSnapPoint,
|
|
1029
|
+
drawerRef,
|
|
1030
|
+
overlayRef,
|
|
1031
|
+
onOpenChange,
|
|
1032
|
+
onPress,
|
|
1033
|
+
onRelease,
|
|
1034
|
+
onDrag,
|
|
1035
|
+
dismissible,
|
|
1036
|
+
shouldAnimate,
|
|
1037
|
+
handleOnly,
|
|
1038
|
+
isOpen,
|
|
1039
|
+
isDragging,
|
|
1040
|
+
shouldFade,
|
|
1041
|
+
closeDrawer,
|
|
1042
|
+
onNestedDrag,
|
|
1043
|
+
onNestedOpenChange,
|
|
1044
|
+
onNestedRelease,
|
|
1045
|
+
keyboardIsOpen,
|
|
1046
|
+
modal,
|
|
1047
|
+
snapPointsOffset,
|
|
1048
|
+
activeSnapPointIndex,
|
|
1049
|
+
direction,
|
|
1050
|
+
shouldScaleBackground,
|
|
1051
|
+
setBackgroundColorOnScale,
|
|
1052
|
+
noBodyStyles,
|
|
1053
|
+
container,
|
|
1054
|
+
autoFocus
|
|
1055
|
+
},
|
|
1056
|
+
children
|
|
1057
|
+
})
|
|
1058
|
+
});
|
|
1387
1059
|
}
|
|
1388
|
-
const Overlay =
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
"data-vaul-snap-points": isOpen && hasSnapPoints ? 'true' : 'false',
|
|
1404
|
-
"data-vaul-snap-points-overlay": isOpen && shouldFade ? 'true' : 'false',
|
|
1405
|
-
"data-vaul-animate": (shouldAnimate == null ? void 0 : shouldAnimate.current) ? 'true' : 'false',
|
|
1406
|
-
...rest
|
|
1407
|
-
});
|
|
1060
|
+
const Overlay = React.forwardRef(function({ ...rest }, ref) {
|
|
1061
|
+
const { overlayRef, snapPoints, onRelease, shouldFade, isOpen, modal, shouldAnimate } = useDrawerContext();
|
|
1062
|
+
const composedRef = useComposedRefs(ref, overlayRef);
|
|
1063
|
+
const hasSnapPoints = snapPoints && snapPoints.length > 0;
|
|
1064
|
+
const onMouseUp = React.useCallback((event) => onRelease(event), [onRelease]);
|
|
1065
|
+
if (!modal) return null;
|
|
1066
|
+
return /* @__PURE__ */ jsx(Dialog.Backdrop, {
|
|
1067
|
+
onMouseUp,
|
|
1068
|
+
ref: composedRef,
|
|
1069
|
+
"data-vaul-overlay": "",
|
|
1070
|
+
"data-vaul-snap-points": isOpen && hasSnapPoints ? "true" : "false",
|
|
1071
|
+
"data-vaul-snap-points-overlay": isOpen && shouldFade ? "true" : "false",
|
|
1072
|
+
"data-vaul-animate": (shouldAnimate === null || shouldAnimate === void 0 ? void 0 : shouldAnimate.current) ? "true" : "false",
|
|
1073
|
+
...rest
|
|
1074
|
+
});
|
|
1408
1075
|
});
|
|
1409
|
-
Overlay.displayName =
|
|
1410
|
-
const Content =
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
rest.onPointerUp == null ? void 0 : rest.onPointerUp.call(rest, event);
|
|
1498
|
-
pointerStartRef.current = null;
|
|
1499
|
-
wasBeyondThePointRef.current = false;
|
|
1500
|
-
onRelease(event);
|
|
1501
|
-
},
|
|
1502
|
-
onPointerOut: (event)=>{
|
|
1503
|
-
rest.onPointerOut == null ? void 0 : rest.onPointerOut.call(rest, event);
|
|
1504
|
-
handleOnPointerUp(lastKnownPointerEventRef.current);
|
|
1505
|
-
},
|
|
1506
|
-
onContextMenu: (event)=>{
|
|
1507
|
-
rest.onContextMenu == null ? void 0 : rest.onContextMenu.call(rest, event);
|
|
1508
|
-
if (lastKnownPointerEventRef.current) {
|
|
1509
|
-
handleOnPointerUp(lastKnownPointerEventRef.current);
|
|
1510
|
-
}
|
|
1511
|
-
}
|
|
1512
|
-
}));
|
|
1076
|
+
Overlay.displayName = "Drawer.Overlay";
|
|
1077
|
+
const Content = React.forwardRef(function({ style, ...rest }, ref) {
|
|
1078
|
+
const { drawerRef, onPress, onRelease, onDrag, keyboardIsOpen, snapPointsOffset, activeSnapPointIndex, modal, isOpen, direction, snapPoints, container, handleOnly, shouldAnimate, autoFocus } = useDrawerContext();
|
|
1079
|
+
const [delayedSnapPoints, setDelayedSnapPoints] = React.useState(false);
|
|
1080
|
+
const composedRef = useComposedRefs(ref, drawerRef);
|
|
1081
|
+
const pointerStartRef = React.useRef(null);
|
|
1082
|
+
const lastKnownPointerEventRef = React.useRef(null);
|
|
1083
|
+
const wasBeyondThePointRef = React.useRef(false);
|
|
1084
|
+
const hasSnapPoints = snapPoints && snapPoints.length > 0;
|
|
1085
|
+
useScaleBackground();
|
|
1086
|
+
const isDeltaInDirection = (delta, direction$1, threshold = 0) => {
|
|
1087
|
+
if (wasBeyondThePointRef.current) return true;
|
|
1088
|
+
const deltaY = Math.abs(delta.y);
|
|
1089
|
+
const deltaX = Math.abs(delta.x);
|
|
1090
|
+
const isDeltaX = deltaX > deltaY;
|
|
1091
|
+
const dFactor = ["bottom", "right"].includes(direction$1) ? 1 : -1;
|
|
1092
|
+
if (direction$1 === "left" || direction$1 === "right") {
|
|
1093
|
+
if (!(delta.x * dFactor < 0) && deltaX >= 0 && deltaX <= threshold) return isDeltaX;
|
|
1094
|
+
} else if (!(delta.y * dFactor < 0) && deltaY >= 0 && deltaY <= threshold) return !isDeltaX;
|
|
1095
|
+
wasBeyondThePointRef.current = true;
|
|
1096
|
+
return true;
|
|
1097
|
+
};
|
|
1098
|
+
React.useEffect(() => {
|
|
1099
|
+
if (hasSnapPoints) window.requestAnimationFrame(() => {
|
|
1100
|
+
setDelayedSnapPoints(true);
|
|
1101
|
+
});
|
|
1102
|
+
}, []);
|
|
1103
|
+
function handleOnPointerUp(event) {
|
|
1104
|
+
pointerStartRef.current = null;
|
|
1105
|
+
wasBeyondThePointRef.current = false;
|
|
1106
|
+
onRelease(event);
|
|
1107
|
+
}
|
|
1108
|
+
return /* @__PURE__ */ jsx(Dialog.Viewport, { children: /* @__PURE__ */ jsx(Dialog.Popup, {
|
|
1109
|
+
"data-vaul-drawer-direction": direction,
|
|
1110
|
+
"data-vaul-drawer": "",
|
|
1111
|
+
"data-vaul-delayed-snap-points": delayedSnapPoints ? "true" : "false",
|
|
1112
|
+
"data-vaul-snap-points": isOpen && hasSnapPoints ? "true" : "false",
|
|
1113
|
+
"data-vaul-custom-container": container ? "true" : "false",
|
|
1114
|
+
"data-vaul-animate": (shouldAnimate === null || shouldAnimate === void 0 ? void 0 : shouldAnimate.current) ? "true" : "false",
|
|
1115
|
+
...rest,
|
|
1116
|
+
ref: composedRef,
|
|
1117
|
+
style: snapPointsOffset && snapPointsOffset.length > 0 ? {
|
|
1118
|
+
"--snap-point-height": `${snapPointsOffset[activeSnapPointIndex ?? 0]}px`,
|
|
1119
|
+
...style
|
|
1120
|
+
} : style,
|
|
1121
|
+
onPointerDown: (event) => {
|
|
1122
|
+
var _rest$onPointerDown;
|
|
1123
|
+
if (handleOnly) return;
|
|
1124
|
+
(_rest$onPointerDown = rest.onPointerDown) === null || _rest$onPointerDown === void 0 || _rest$onPointerDown.call(rest, event);
|
|
1125
|
+
pointerStartRef.current = {
|
|
1126
|
+
x: event.pageX,
|
|
1127
|
+
y: event.pageY
|
|
1128
|
+
};
|
|
1129
|
+
onPress(event);
|
|
1130
|
+
},
|
|
1131
|
+
onPointerMove: (event) => {
|
|
1132
|
+
var _rest$onPointerMove;
|
|
1133
|
+
lastKnownPointerEventRef.current = event;
|
|
1134
|
+
if (handleOnly) return;
|
|
1135
|
+
(_rest$onPointerMove = rest.onPointerMove) === null || _rest$onPointerMove === void 0 || _rest$onPointerMove.call(rest, event);
|
|
1136
|
+
if (!pointerStartRef.current) return;
|
|
1137
|
+
const yPosition = event.pageY - pointerStartRef.current.y;
|
|
1138
|
+
const xPosition = event.pageX - pointerStartRef.current.x;
|
|
1139
|
+
const swipeStartThreshold = event.pointerType === "touch" ? 10 : 2;
|
|
1140
|
+
if (isDeltaInDirection({
|
|
1141
|
+
x: xPosition,
|
|
1142
|
+
y: yPosition
|
|
1143
|
+
}, direction, swipeStartThreshold)) onDrag(event);
|
|
1144
|
+
else if (Math.abs(xPosition) > swipeStartThreshold || Math.abs(yPosition) > swipeStartThreshold) pointerStartRef.current = null;
|
|
1145
|
+
},
|
|
1146
|
+
onPointerUp: (event) => {
|
|
1147
|
+
var _rest$onPointerUp;
|
|
1148
|
+
(_rest$onPointerUp = rest.onPointerUp) === null || _rest$onPointerUp === void 0 || _rest$onPointerUp.call(rest, event);
|
|
1149
|
+
pointerStartRef.current = null;
|
|
1150
|
+
wasBeyondThePointRef.current = false;
|
|
1151
|
+
onRelease(event);
|
|
1152
|
+
},
|
|
1153
|
+
onPointerOut: (event) => {
|
|
1154
|
+
var _rest$onPointerOut;
|
|
1155
|
+
(_rest$onPointerOut = rest.onPointerOut) === null || _rest$onPointerOut === void 0 || _rest$onPointerOut.call(rest, event);
|
|
1156
|
+
handleOnPointerUp(lastKnownPointerEventRef.current);
|
|
1157
|
+
},
|
|
1158
|
+
onContextMenu: (event) => {
|
|
1159
|
+
var _rest$onContextMenu;
|
|
1160
|
+
(_rest$onContextMenu = rest.onContextMenu) === null || _rest$onContextMenu === void 0 || _rest$onContextMenu.call(rest, event);
|
|
1161
|
+
if (lastKnownPointerEventRef.current) handleOnPointerUp(lastKnownPointerEventRef.current);
|
|
1162
|
+
}
|
|
1163
|
+
}) });
|
|
1513
1164
|
});
|
|
1514
|
-
Content.displayName =
|
|
1165
|
+
Content.displayName = "Drawer.Content";
|
|
1515
1166
|
const LONG_HANDLE_PRESS_TIMEOUT = 250;
|
|
1516
1167
|
const DOUBLE_TAP_TIMEOUT = 120;
|
|
1517
|
-
const Handle =
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
"data-vaul-drawer-visible": isOpen ? 'true' : 'false',
|
|
1586
|
-
"data-vaul-handle": "",
|
|
1587
|
-
"aria-hidden": "true",
|
|
1588
|
-
...rest
|
|
1589
|
-
}, /*#__PURE__*/ React__default.createElement("span", {
|
|
1590
|
-
"data-vaul-handle-hitarea": "",
|
|
1591
|
-
"aria-hidden": "true"
|
|
1592
|
-
}, children));
|
|
1168
|
+
const Handle = React.forwardRef(function({ preventCycle = false, children, ...rest }, ref) {
|
|
1169
|
+
const { closeDrawer, isDragging, snapPoints, activeSnapPoint, setActiveSnapPoint, dismissible, handleOnly, isOpen, onPress, onDrag } = useDrawerContext();
|
|
1170
|
+
const closeTimeoutIdRef = React.useRef(null);
|
|
1171
|
+
const shouldCancelInteractionRef = React.useRef(false);
|
|
1172
|
+
function handleStartCycle() {
|
|
1173
|
+
if (shouldCancelInteractionRef.current) {
|
|
1174
|
+
handleCancelInteraction();
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
window.setTimeout(() => {
|
|
1178
|
+
handleCycleSnapPoints();
|
|
1179
|
+
}, DOUBLE_TAP_TIMEOUT);
|
|
1180
|
+
}
|
|
1181
|
+
function handleCycleSnapPoints() {
|
|
1182
|
+
if (isDragging || preventCycle || shouldCancelInteractionRef.current) {
|
|
1183
|
+
handleCancelInteraction();
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
handleCancelInteraction();
|
|
1187
|
+
if (!snapPoints || snapPoints.length === 0) {
|
|
1188
|
+
if (!dismissible) closeDrawer();
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
if (activeSnapPoint === snapPoints[snapPoints.length - 1] && dismissible) {
|
|
1192
|
+
closeDrawer();
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
const currentSnapIndex = snapPoints.findIndex((point) => point === activeSnapPoint);
|
|
1196
|
+
if (currentSnapIndex === -1) return;
|
|
1197
|
+
const nextSnapPoint = snapPoints[currentSnapIndex + 1];
|
|
1198
|
+
setActiveSnapPoint(nextSnapPoint);
|
|
1199
|
+
}
|
|
1200
|
+
function handleStartInteraction() {
|
|
1201
|
+
closeTimeoutIdRef.current = window.setTimeout(() => {
|
|
1202
|
+
shouldCancelInteractionRef.current = true;
|
|
1203
|
+
}, LONG_HANDLE_PRESS_TIMEOUT);
|
|
1204
|
+
}
|
|
1205
|
+
function handleCancelInteraction() {
|
|
1206
|
+
if (closeTimeoutIdRef.current) window.clearTimeout(closeTimeoutIdRef.current);
|
|
1207
|
+
shouldCancelInteractionRef.current = false;
|
|
1208
|
+
}
|
|
1209
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1210
|
+
onClick: handleStartCycle,
|
|
1211
|
+
onPointerCancel: handleCancelInteraction,
|
|
1212
|
+
onPointerDown: (e) => {
|
|
1213
|
+
if (handleOnly) onPress({
|
|
1214
|
+
...e,
|
|
1215
|
+
preventBaseUIHandler: () => {}
|
|
1216
|
+
});
|
|
1217
|
+
handleStartInteraction();
|
|
1218
|
+
},
|
|
1219
|
+
onPointerMove: (e) => {
|
|
1220
|
+
if (handleOnly) onDrag({
|
|
1221
|
+
...e,
|
|
1222
|
+
preventBaseUIHandler: () => {}
|
|
1223
|
+
});
|
|
1224
|
+
},
|
|
1225
|
+
ref,
|
|
1226
|
+
"data-vaul-drawer-visible": isOpen ? "true" : "false",
|
|
1227
|
+
"data-vaul-handle": "",
|
|
1228
|
+
"aria-hidden": "true",
|
|
1229
|
+
...rest,
|
|
1230
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
1231
|
+
"data-vaul-handle-hitarea": "",
|
|
1232
|
+
"aria-hidden": "true",
|
|
1233
|
+
children
|
|
1234
|
+
})
|
|
1235
|
+
});
|
|
1593
1236
|
});
|
|
1594
|
-
Handle.displayName =
|
|
1237
|
+
Handle.displayName = "Drawer.Handle";
|
|
1595
1238
|
function NestedRoot({ onDrag, onOpenChange, open: nestedIsOpen, ...rest }) {
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
},
|
|
1616
|
-
onRelease: onNestedRelease,
|
|
1617
|
-
...rest
|
|
1618
|
-
});
|
|
1239
|
+
const { onNestedDrag, onNestedOpenChange, onNestedRelease } = useDrawerContext();
|
|
1240
|
+
if (!onNestedDrag) throw new Error("Drawer.NestedRoot must be placed in another drawer");
|
|
1241
|
+
return /* @__PURE__ */ jsx(Root, {
|
|
1242
|
+
nested: true,
|
|
1243
|
+
open: nestedIsOpen,
|
|
1244
|
+
onClose: () => {
|
|
1245
|
+
onNestedOpenChange(false);
|
|
1246
|
+
},
|
|
1247
|
+
onDrag: (e, p) => {
|
|
1248
|
+
onNestedDrag(e, p);
|
|
1249
|
+
onDrag === null || onDrag === void 0 || onDrag(e, p);
|
|
1250
|
+
},
|
|
1251
|
+
onOpenChange: (o) => {
|
|
1252
|
+
if (o) onNestedOpenChange(o);
|
|
1253
|
+
onOpenChange === null || onOpenChange === void 0 || onOpenChange(o);
|
|
1254
|
+
},
|
|
1255
|
+
onRelease: onNestedRelease,
|
|
1256
|
+
...rest
|
|
1257
|
+
});
|
|
1619
1258
|
}
|
|
1620
1259
|
function Portal(props) {
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1260
|
+
const context = useDrawerContext();
|
|
1261
|
+
const { container = context.container, ...portalProps } = props;
|
|
1262
|
+
return /* @__PURE__ */ jsx(Dialog.Portal, {
|
|
1263
|
+
container,
|
|
1264
|
+
...portalProps
|
|
1265
|
+
});
|
|
1627
1266
|
}
|
|
1628
1267
|
const Drawer = {
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1268
|
+
Root,
|
|
1269
|
+
NestedRoot,
|
|
1270
|
+
Content,
|
|
1271
|
+
Overlay,
|
|
1272
|
+
Trigger: Dialog.Trigger,
|
|
1273
|
+
Portal,
|
|
1274
|
+
Handle,
|
|
1275
|
+
Close: Dialog.Close,
|
|
1276
|
+
Title: Dialog.Title,
|
|
1277
|
+
Description: Dialog.Description
|
|
1639
1278
|
};
|
|
1640
1279
|
|
|
1280
|
+
//#endregion
|
|
1641
1281
|
export { Content, Drawer, Handle, NestedRoot, Overlay, Portal, Root };
|
|
1282
|
+
//# sourceMappingURL=index.mjs.map
|