react-modal-sheet 2.0.0 → 2.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/README.md +19 -18
- package/dist/react-modal-sheet.cjs.development.js +137 -211
- package/dist/react-modal-sheet.cjs.development.js.map +1 -1
- package/dist/react-modal-sheet.cjs.production.min.js +1 -1
- package/dist/react-modal-sheet.cjs.production.min.js.map +1 -1
- package/dist/react-modal-sheet.esm.js +137 -211
- package/dist/react-modal-sheet.esm.js.map +1 -1
- package/dist/sheet.d.ts +1 -0
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/sheet.tsx +2 -1
- package/src/types.tsx +1 -0
|
@@ -4,35 +4,29 @@ import { useMotionValue, useReducedMotion, useTransform, animate, motion, Animat
|
|
|
4
4
|
import { useLayoutEffect as useLayoutEffect$1, isIOS, chain, getScrollParent } from '@react-aria/utils';
|
|
5
5
|
|
|
6
6
|
function _extends() {
|
|
7
|
-
_extends = Object.assign
|
|
7
|
+
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
8
8
|
for (var i = 1; i < arguments.length; i++) {
|
|
9
9
|
var source = arguments[i];
|
|
10
|
-
|
|
11
10
|
for (var key in source) {
|
|
12
11
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
13
12
|
target[key] = source[key];
|
|
14
13
|
}
|
|
15
14
|
}
|
|
16
15
|
}
|
|
17
|
-
|
|
18
16
|
return target;
|
|
19
17
|
};
|
|
20
|
-
|
|
21
18
|
return _extends.apply(this, arguments);
|
|
22
19
|
}
|
|
23
|
-
|
|
24
20
|
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
25
21
|
if (source == null) return {};
|
|
26
22
|
var target = {};
|
|
27
23
|
var sourceKeys = Object.keys(source);
|
|
28
24
|
var key, i;
|
|
29
|
-
|
|
30
25
|
for (i = 0; i < sourceKeys.length; i++) {
|
|
31
26
|
key = sourceKeys[i];
|
|
32
27
|
if (excluded.indexOf(key) >= 0) continue;
|
|
33
28
|
target[key] = source[key];
|
|
34
29
|
}
|
|
35
|
-
|
|
36
30
|
return target;
|
|
37
31
|
}
|
|
38
32
|
|
|
@@ -52,22 +46,18 @@ var DRAG_VELOCITY_THRESHOLD = 500;
|
|
|
52
46
|
function getClosest(nums, goal) {
|
|
53
47
|
var closest = nums[0];
|
|
54
48
|
var minDifference = Math.abs(nums[0] - goal);
|
|
55
|
-
|
|
56
49
|
for (var i = 1; i < nums.length; i++) {
|
|
57
50
|
var difference = Math.abs(nums[i] - goal);
|
|
58
|
-
|
|
59
51
|
if (difference < minDifference) {
|
|
60
52
|
closest = nums[i];
|
|
61
53
|
minDifference = difference;
|
|
62
54
|
}
|
|
63
55
|
}
|
|
64
|
-
|
|
65
56
|
return closest;
|
|
66
57
|
}
|
|
67
58
|
function applyRootStyles(rootId) {
|
|
68
59
|
var body = document.querySelector('body');
|
|
69
60
|
var root = document.querySelector("#" + rootId);
|
|
70
|
-
|
|
71
61
|
if (root) {
|
|
72
62
|
var p = 24;
|
|
73
63
|
var h = window.innerHeight;
|
|
@@ -77,7 +67,6 @@ function applyRootStyles(rootId) {
|
|
|
77
67
|
root.style.willChange = 'transform';
|
|
78
68
|
root.style.transition = 'transform 200ms ease-in-out, border-radius 200ms linear';
|
|
79
69
|
root.style.transform = "translateY(calc(env(safe-area-inset-top) + " + p / 2 + "px)) scale(" + s + ")"; // prettier-ignore
|
|
80
|
-
|
|
81
70
|
root.style.borderTopRightRadius = '10px';
|
|
82
71
|
root.style.borderTopLeftRadius = '10px';
|
|
83
72
|
}
|
|
@@ -85,7 +74,6 @@ function applyRootStyles(rootId) {
|
|
|
85
74
|
function cleanupRootStyles(rootId) {
|
|
86
75
|
var body = document.querySelector('body');
|
|
87
76
|
var root = document.getElementById(rootId);
|
|
88
|
-
|
|
89
77
|
function onTransitionEnd() {
|
|
90
78
|
root.style.removeProperty('overflow');
|
|
91
79
|
root.style.removeProperty('will-change');
|
|
@@ -93,13 +81,12 @@ function cleanupRootStyles(rootId) {
|
|
|
93
81
|
body.style.removeProperty('background-color');
|
|
94
82
|
root.removeEventListener('transitionend', onTransitionEnd);
|
|
95
83
|
}
|
|
96
|
-
|
|
97
84
|
if (root) {
|
|
98
85
|
// Start animating back
|
|
99
86
|
root.style.removeProperty('border-top-right-radius');
|
|
100
87
|
root.style.removeProperty('border-top-left-radius');
|
|
101
|
-
root.style.removeProperty('transform');
|
|
102
|
-
|
|
88
|
+
root.style.removeProperty('transform');
|
|
89
|
+
// Remove temp properties after animation is finished
|
|
103
90
|
root.addEventListener('transitionend', onTransitionEnd);
|
|
104
91
|
}
|
|
105
92
|
}
|
|
@@ -107,17 +94,14 @@ function inDescendingOrder(arr) {
|
|
|
107
94
|
for (var i = 0; i < arr.length; i++) {
|
|
108
95
|
if (arr[i + 1] > arr[i]) return false;
|
|
109
96
|
}
|
|
110
|
-
|
|
111
97
|
return true;
|
|
112
98
|
}
|
|
113
99
|
function validateSnapTo(_ref) {
|
|
114
100
|
var snapTo = _ref.snapTo,
|
|
115
|
-
|
|
116
|
-
|
|
101
|
+
sheetHeight = _ref.sheetHeight;
|
|
117
102
|
if (snapTo < 0) {
|
|
118
103
|
console.warn("Snap point is out of bounds. Sheet height is " + sheetHeight + " but snap point is " + (sheetHeight + Math.abs(snapTo)) + ".");
|
|
119
104
|
}
|
|
120
|
-
|
|
121
105
|
return Math.max(Math.round(snapTo), 0);
|
|
122
106
|
}
|
|
123
107
|
function mergeRefs(refs) {
|
|
@@ -138,8 +122,8 @@ function isTouchDevice() {
|
|
|
138
122
|
|
|
139
123
|
var useIsomorphicLayoutEffect = IS_SSR ? useEffect : useLayoutEffect;
|
|
140
124
|
function useModalEffect(isOpen, rootId) {
|
|
141
|
-
var prevOpen = usePrevious(isOpen);
|
|
142
|
-
|
|
125
|
+
var prevOpen = usePrevious(isOpen);
|
|
126
|
+
// Automatically apply the iOS modal effect to the body when sheet opens/closes
|
|
143
127
|
useEffect(function () {
|
|
144
128
|
if (rootId && !prevOpen && isOpen) {
|
|
145
129
|
applyRootStyles(rootId);
|
|
@@ -148,51 +132,47 @@ function useModalEffect(isOpen, rootId) {
|
|
|
148
132
|
}
|
|
149
133
|
}, [isOpen, prevOpen]); // eslint-disable-line
|
|
150
134
|
// Make sure to cleanup modal styles on unmount
|
|
151
|
-
|
|
152
135
|
useEffect(function () {
|
|
153
136
|
return function () {
|
|
154
137
|
if (rootId && isOpen) cleanupRootStyles(rootId);
|
|
155
138
|
};
|
|
156
139
|
}, [isOpen]); // eslint-disable-line
|
|
157
140
|
}
|
|
141
|
+
|
|
158
142
|
function useEventCallbacks(isOpen, callbacks) {
|
|
159
143
|
var prevOpen = usePrevious(isOpen);
|
|
160
|
-
var didOpen = useRef(false);
|
|
144
|
+
var didOpen = useRef(false);
|
|
145
|
+
// Because of AnimatePrecence we don't have access to latest isOpen value
|
|
161
146
|
// so we need to read and write to a ref to determine if we are
|
|
162
147
|
// opening or closing the sheet
|
|
163
|
-
|
|
164
148
|
var handleAnimationComplete = useCallback(function () {
|
|
165
149
|
if (!didOpen.current) {
|
|
166
|
-
callbacks.current.onOpenEnd == null
|
|
150
|
+
callbacks.current.onOpenEnd == null || callbacks.current.onOpenEnd();
|
|
167
151
|
didOpen.current = true;
|
|
168
152
|
} else {
|
|
169
|
-
callbacks.current.onCloseEnd == null
|
|
153
|
+
callbacks.current.onCloseEnd == null || callbacks.current.onCloseEnd();
|
|
170
154
|
didOpen.current = false;
|
|
171
155
|
}
|
|
172
156
|
}, [isOpen, prevOpen]); // eslint-disable-line
|
|
173
|
-
|
|
174
157
|
useEffect(function () {
|
|
175
158
|
if (!prevOpen && isOpen) {
|
|
176
|
-
callbacks.current.onOpenStart == null
|
|
159
|
+
callbacks.current.onOpenStart == null || callbacks.current.onOpenStart();
|
|
177
160
|
} else if (!isOpen && prevOpen) {
|
|
178
|
-
callbacks.current.onCloseStart == null
|
|
161
|
+
callbacks.current.onCloseStart == null || callbacks.current.onCloseStart();
|
|
179
162
|
}
|
|
180
163
|
}, [isOpen, prevOpen]); // eslint-disable-line
|
|
181
|
-
|
|
182
164
|
return {
|
|
183
165
|
handleAnimationComplete: handleAnimationComplete
|
|
184
166
|
};
|
|
185
167
|
}
|
|
186
168
|
function useWindowHeight() {
|
|
187
169
|
var _React$useState = useState(0),
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
170
|
+
windowHeight = _React$useState[0],
|
|
171
|
+
setWindowHeight = _React$useState[1];
|
|
191
172
|
useIsomorphicLayoutEffect(function () {
|
|
192
173
|
var updateHeight = function updateHeight() {
|
|
193
174
|
return setWindowHeight(window.innerHeight);
|
|
194
175
|
};
|
|
195
|
-
|
|
196
176
|
window.addEventListener('resize', updateHeight);
|
|
197
177
|
updateHeight();
|
|
198
178
|
return function () {
|
|
@@ -207,9 +187,9 @@ function usePrevious(state) {
|
|
|
207
187
|
ref.current = state;
|
|
208
188
|
});
|
|
209
189
|
return ref.current;
|
|
210
|
-
}
|
|
190
|
+
}
|
|
191
|
+
// Userland version of the `useEvent` React hook:
|
|
211
192
|
// RFC: https://github.com/reactjs/rfcs/blob/useevent/text/0000-useevent.md
|
|
212
|
-
|
|
213
193
|
function useEvent(handler) {
|
|
214
194
|
var handlerRef = useRef();
|
|
215
195
|
useIsomorphicLayoutEffect(function () {
|
|
@@ -217,11 +197,9 @@ function useEvent(handler) {
|
|
|
217
197
|
});
|
|
218
198
|
return useCallback(function () {
|
|
219
199
|
var fn = handlerRef.current;
|
|
220
|
-
|
|
221
200
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
222
201
|
args[_key] = arguments[_key];
|
|
223
202
|
}
|
|
224
|
-
|
|
225
203
|
return fn == null ? void 0 : fn.apply(void 0, args);
|
|
226
204
|
}, []);
|
|
227
205
|
}
|
|
@@ -236,19 +214,15 @@ var SheetScrollerContext = /*#__PURE__*/createContext(undefined);
|
|
|
236
214
|
function SheetScrollerContextProvider(_ref) {
|
|
237
215
|
var children = _ref.children;
|
|
238
216
|
var sheetContext = useSheetContext();
|
|
239
|
-
|
|
240
217
|
var _React$useState = useState(!!sheetContext.disableDrag),
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
218
|
+
disableDrag = _React$useState[0],
|
|
219
|
+
setDisableDrag = _React$useState[1];
|
|
244
220
|
function setDragEnabled() {
|
|
245
221
|
if (!sheetContext.disableDrag) setDisableDrag(false);
|
|
246
222
|
}
|
|
247
|
-
|
|
248
223
|
function setDragDisabled() {
|
|
249
224
|
if (!disableDrag) setDisableDrag(true);
|
|
250
225
|
}
|
|
251
|
-
|
|
252
226
|
return createElement(SheetScrollerContext.Provider, {
|
|
253
227
|
value: {
|
|
254
228
|
disableDrag: disableDrag,
|
|
@@ -264,11 +238,11 @@ var useSheetScrollerContext = function useSheetScrollerContext() {
|
|
|
264
238
|
};
|
|
265
239
|
|
|
266
240
|
// Source: https://github.com/adobe/react-spectrum/blob/main/packages/@react-aria/overlays/src/usePreventScroll.ts
|
|
267
|
-
|
|
268
|
-
var visualViewport = typeof window !== 'undefined' && window.visualViewport;
|
|
269
|
-
|
|
270
|
-
var nonTextInputTypes = /*#__PURE__*/new Set(['checkbox', 'radio', 'range', 'color', 'file', 'image', 'button', 'submit', 'reset']);
|
|
271
|
-
|
|
241
|
+
// @ts-ignore
|
|
242
|
+
var visualViewport = typeof window !== 'undefined' && window.visualViewport;
|
|
243
|
+
// HTML input types that do not cause the software keyboard to appear.
|
|
244
|
+
var nonTextInputTypes = /*#__PURE__*/new Set(['checkbox', 'radio', 'range', 'color', 'file', 'image', 'button', 'submit', 'reset']);
|
|
245
|
+
// The number of active usePreventScroll calls. Used to determine whether to revert back to the original page style/scroll position
|
|
272
246
|
var preventScrollCount = 0;
|
|
273
247
|
var restore;
|
|
274
248
|
/**
|
|
@@ -276,21 +250,17 @@ var restore;
|
|
|
276
250
|
* restores it on unmount. Also ensures that content does not
|
|
277
251
|
* shift due to the scrollbars disappearing.
|
|
278
252
|
*/
|
|
279
|
-
|
|
280
253
|
function usePreventScroll(options) {
|
|
281
254
|
if (options === void 0) {
|
|
282
255
|
options = {};
|
|
283
256
|
}
|
|
284
|
-
|
|
285
257
|
var _options = options,
|
|
286
|
-
|
|
258
|
+
isDisabled = _options.isDisabled;
|
|
287
259
|
useLayoutEffect$1(function () {
|
|
288
260
|
if (isDisabled) {
|
|
289
261
|
return;
|
|
290
262
|
}
|
|
291
|
-
|
|
292
263
|
preventScrollCount++;
|
|
293
|
-
|
|
294
264
|
if (preventScrollCount === 1) {
|
|
295
265
|
if (isIOS()) {
|
|
296
266
|
restore = preventScrollMobileSafari();
|
|
@@ -298,21 +268,20 @@ function usePreventScroll(options) {
|
|
|
298
268
|
restore = preventScrollStandard();
|
|
299
269
|
}
|
|
300
270
|
}
|
|
301
|
-
|
|
302
271
|
return function () {
|
|
303
272
|
preventScrollCount--;
|
|
304
|
-
|
|
305
273
|
if (preventScrollCount === 0) {
|
|
306
274
|
restore();
|
|
307
275
|
}
|
|
308
276
|
};
|
|
309
277
|
}, [isDisabled]);
|
|
310
|
-
}
|
|
278
|
+
}
|
|
279
|
+
// For most browsers, all we need to do is set `overflow: hidden` on the root element, and
|
|
311
280
|
// add some padding to prevent the page from shifting when the scrollbar is hidden.
|
|
312
|
-
|
|
313
281
|
function preventScrollStandard() {
|
|
314
282
|
return chain(setStyle(document.documentElement, 'paddingRight', window.innerWidth - document.documentElement.clientWidth + "px"), setStyle(document.documentElement, 'overflow', 'hidden'));
|
|
315
|
-
}
|
|
283
|
+
}
|
|
284
|
+
// Mobile Safari is a whole different beast. Even with overflow: hidden,
|
|
316
285
|
// it still scrolls the page in many situations:
|
|
317
286
|
//
|
|
318
287
|
// 1. When the bottom toolbar and address bar are collapsed, page scrolling is always allowed.
|
|
@@ -338,57 +307,47 @@ function preventScrollStandard() {
|
|
|
338
307
|
// above work or Safari will still try to scroll the page when focusing an input.
|
|
339
308
|
// 6. As a last resort, handle window scroll events, and scroll back to the top. This can happen when attempting
|
|
340
309
|
// to navigate to an input with the next/previous buttons that's outside a modal.
|
|
341
|
-
|
|
342
|
-
|
|
343
310
|
function preventScrollMobileSafari() {
|
|
344
311
|
var scrollable;
|
|
345
312
|
var lastY = 0;
|
|
346
|
-
|
|
347
313
|
var onTouchStart = function onTouchStart(e) {
|
|
348
314
|
// Store the nearest scrollable parent element from the element that the user touched.
|
|
349
315
|
scrollable = getScrollParent(e.target);
|
|
350
|
-
|
|
351
316
|
if (scrollable === document.documentElement && scrollable === document.body) {
|
|
352
317
|
return;
|
|
353
318
|
}
|
|
354
|
-
|
|
355
319
|
lastY = e.changedTouches[0].pageY;
|
|
356
320
|
};
|
|
357
|
-
|
|
358
321
|
var onTouchMove = function onTouchMove(e) {
|
|
359
322
|
// Prevent scrolling the window.
|
|
360
323
|
if (scrollable === document.documentElement || scrollable === document.body) {
|
|
361
324
|
e.preventDefault();
|
|
362
325
|
return;
|
|
363
|
-
}
|
|
326
|
+
}
|
|
327
|
+
// Prevent scrolling up when at the top and scrolling down when at the bottom
|
|
364
328
|
// of a nested scrollable area, otherwise mobile Safari will start scrolling
|
|
365
329
|
// the window instead. Unfortunately, this disables bounce scrolling when at
|
|
366
330
|
// the top but it's the best we can do.
|
|
367
|
-
|
|
368
|
-
|
|
369
331
|
var y = e.changedTouches[0].pageY;
|
|
370
332
|
var scrollTop = scrollable.scrollTop;
|
|
371
|
-
var bottom = scrollable.scrollHeight - scrollable.clientHeight;
|
|
372
|
-
|
|
333
|
+
var bottom = scrollable.scrollHeight - scrollable.clientHeight;
|
|
334
|
+
// Fix for: https://github.com/adobe/react-spectrum/pull/3780/files
|
|
373
335
|
if (bottom === 0) {
|
|
374
336
|
return;
|
|
375
337
|
}
|
|
376
|
-
|
|
377
338
|
if (scrollTop <= 0 && y > lastY || scrollTop >= bottom && y < lastY) {
|
|
378
339
|
e.preventDefault();
|
|
379
340
|
}
|
|
380
|
-
|
|
381
341
|
lastY = y;
|
|
382
342
|
};
|
|
383
|
-
|
|
384
343
|
var onTouchEnd = function onTouchEnd(e) {
|
|
385
|
-
var target = e.target;
|
|
386
|
-
|
|
344
|
+
var target = e.target;
|
|
345
|
+
// Apply this change if we're not already focused on the target element
|
|
387
346
|
if (willOpenKeyboard(target) && target !== document.activeElement) {
|
|
388
|
-
e.preventDefault();
|
|
347
|
+
e.preventDefault();
|
|
348
|
+
// Apply a transform to trick Safari into thinking the input is at the top of the page
|
|
389
349
|
// so it doesn't try to scroll it into view. When tapping on an input, this needs to
|
|
390
350
|
// be done before the "focus" event, so we have to focus the element ourselves.
|
|
391
|
-
|
|
392
351
|
target.style.transform = 'translateY(-2000px)';
|
|
393
352
|
target.focus();
|
|
394
353
|
requestAnimationFrame(function () {
|
|
@@ -396,10 +355,8 @@ function preventScrollMobileSafari() {
|
|
|
396
355
|
});
|
|
397
356
|
}
|
|
398
357
|
};
|
|
399
|
-
|
|
400
358
|
var onFocus = function onFocus(e) {
|
|
401
359
|
var target = e.target;
|
|
402
|
-
|
|
403
360
|
if (willOpenKeyboard(target)) {
|
|
404
361
|
// Transform also needs to be applied in the focus event in cases where focus moves
|
|
405
362
|
// other than tapping on an input directly, e.g. the next/previous buttons in the
|
|
@@ -407,9 +364,9 @@ function preventScrollMobileSafari() {
|
|
|
407
364
|
// is good enough, whereas when tapping an input, it must be done before the focus event. 🤷♂️
|
|
408
365
|
target.style.transform = 'translateY(-2000px)';
|
|
409
366
|
requestAnimationFrame(function () {
|
|
410
|
-
target.style.transform = '';
|
|
367
|
+
target.style.transform = '';
|
|
368
|
+
// This will have prevented the browser from scrolling the focused element into view,
|
|
411
369
|
// so we need to do this ourselves in a way that doesn't cause the whole page to scroll.
|
|
412
|
-
|
|
413
370
|
if (visualViewport) {
|
|
414
371
|
if (visualViewport.height < window.innerHeight) {
|
|
415
372
|
// If the keyboard is already visible, do this after one additional frame
|
|
@@ -430,20 +387,18 @@ function preventScrollMobileSafari() {
|
|
|
430
387
|
});
|
|
431
388
|
}
|
|
432
389
|
};
|
|
433
|
-
|
|
434
390
|
var onWindowScroll = function onWindowScroll() {
|
|
435
391
|
// Last resort. If the window scrolled, scroll it back to the top.
|
|
436
392
|
// It should always be at the top because the body will have a negative margin (see below).
|
|
437
393
|
window.scrollTo(0, 0);
|
|
438
|
-
};
|
|
394
|
+
};
|
|
395
|
+
// Record the original scroll position so we can restore it.
|
|
439
396
|
// Then apply a negative margin to the body to offset it by the scroll position. This will
|
|
440
397
|
// enable us to scroll the window to the top, which is required for the rest of this to work.
|
|
441
|
-
|
|
442
|
-
|
|
443
398
|
var scrollX = window.pageXOffset;
|
|
444
399
|
var scrollY = window.pageYOffset;
|
|
445
|
-
var restoreStyles = chain(setStyle(document.documentElement, 'paddingRight', window.innerWidth - document.documentElement.clientWidth + "px"), setStyle(document.documentElement, 'overflow', 'hidden'), setStyle(document.body, 'marginTop', "-" + scrollY + "px"));
|
|
446
|
-
|
|
400
|
+
var restoreStyles = chain(setStyle(document.documentElement, 'paddingRight', window.innerWidth - document.documentElement.clientWidth + "px"), setStyle(document.documentElement, 'overflow', 'hidden'), setStyle(document.body, 'marginTop', "-" + scrollY + "px"));
|
|
401
|
+
// Scroll to the top. The negative margin on the body will make this appear the same.
|
|
447
402
|
window.scrollTo(0, 0);
|
|
448
403
|
var removeEvents = chain(addEvent(document, 'touchstart', onTouchStart, {
|
|
449
404
|
passive: false,
|
|
@@ -461,45 +416,37 @@ function preventScrollMobileSafari() {
|
|
|
461
416
|
removeEvents();
|
|
462
417
|
window.scrollTo(scrollX, scrollY);
|
|
463
418
|
};
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
|
|
419
|
+
}
|
|
420
|
+
// Sets a CSS property on an element, and returns a function to revert it to the previous value.
|
|
467
421
|
function setStyle(element, style, value) {
|
|
468
422
|
var cur = element.style[style];
|
|
469
423
|
element.style[style] = value;
|
|
470
424
|
return function () {
|
|
471
425
|
element.style[style] = cur;
|
|
472
426
|
};
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
|
|
427
|
+
}
|
|
428
|
+
// Adds an event listener to an element, and returns a function to remove it.
|
|
476
429
|
function addEvent(target, event, handler, options) {
|
|
477
430
|
target.addEventListener(event, handler, options);
|
|
478
431
|
return function () {
|
|
479
432
|
target.removeEventListener(event, handler, options);
|
|
480
433
|
};
|
|
481
434
|
}
|
|
482
|
-
|
|
483
435
|
function scrollIntoView(target) {
|
|
484
436
|
var root = document.scrollingElement || document.documentElement;
|
|
485
|
-
|
|
486
437
|
while (target && target !== root) {
|
|
487
438
|
// Find the parent scrollable element and adjust the scroll position if the target is not already in view.
|
|
488
439
|
var scrollable = getScrollParent(target);
|
|
489
|
-
|
|
490
440
|
if (scrollable !== document.documentElement && scrollable !== document.body && scrollable !== target) {
|
|
491
441
|
var scrollableTop = scrollable.getBoundingClientRect().top;
|
|
492
442
|
var targetTop = target.getBoundingClientRect().top;
|
|
493
|
-
|
|
494
443
|
if (targetTop > scrollableTop + target.clientHeight) {
|
|
495
444
|
scrollable.scrollTop += targetTop - scrollableTop;
|
|
496
445
|
}
|
|
497
446
|
}
|
|
498
|
-
|
|
499
447
|
target = scrollable.parentElement;
|
|
500
448
|
}
|
|
501
449
|
}
|
|
502
|
-
|
|
503
450
|
function willOpenKeyboard(target) {
|
|
504
451
|
return target instanceof HTMLInputElement && !nonTextInputTypes.has(target.type) || target instanceof HTMLTextAreaElement || target instanceof HTMLElement && target.isContentEditable;
|
|
505
452
|
}
|
|
@@ -569,53 +516,53 @@ var styles = {
|
|
|
569
516
|
}
|
|
570
517
|
};
|
|
571
518
|
|
|
519
|
+
var _excluded = ["onOpenStart", "onOpenEnd", "onClose", "onCloseStart", "onCloseEnd", "onSnap", "children", "disableScrollLocking", "isOpen", "snapPoints", "rootId", "mountPoint", "style", "detent", "initialSnap", "disableDrag", "prefersReducedMotion", "tweenConfig"];
|
|
572
520
|
var Sheet = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
573
521
|
var onOpenStart = _ref.onOpenStart,
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
522
|
+
onOpenEnd = _ref.onOpenEnd,
|
|
523
|
+
onClose = _ref.onClose,
|
|
524
|
+
onCloseStart = _ref.onCloseStart,
|
|
525
|
+
onCloseEnd = _ref.onCloseEnd,
|
|
526
|
+
onSnap = _ref.onSnap,
|
|
527
|
+
children = _ref.children,
|
|
528
|
+
_ref$disableScrollLoc = _ref.disableScrollLocking,
|
|
529
|
+
disableScrollLocking = _ref$disableScrollLoc === void 0 ? false : _ref$disableScrollLoc,
|
|
530
|
+
isOpen = _ref.isOpen,
|
|
531
|
+
snapPoints = _ref.snapPoints,
|
|
532
|
+
rootId = _ref.rootId,
|
|
533
|
+
mountPoint = _ref.mountPoint,
|
|
534
|
+
style = _ref.style,
|
|
535
|
+
_ref$detent = _ref.detent,
|
|
536
|
+
detent = _ref$detent === void 0 ? 'full-height' : _ref$detent,
|
|
537
|
+
_ref$initialSnap = _ref.initialSnap,
|
|
538
|
+
initialSnap = _ref$initialSnap === void 0 ? 0 : _ref$initialSnap,
|
|
539
|
+
_ref$disableDrag = _ref.disableDrag,
|
|
540
|
+
disableDrag = _ref$disableDrag === void 0 ? false : _ref$disableDrag,
|
|
541
|
+
_ref$prefersReducedMo = _ref.prefersReducedMotion,
|
|
542
|
+
prefersReducedMotion = _ref$prefersReducedMo === void 0 ? false : _ref$prefersReducedMo,
|
|
543
|
+
_ref$tweenConfig = _ref.tweenConfig,
|
|
544
|
+
tweenConfig = _ref$tweenConfig === void 0 ? DEFAULT_TWEEN_CONFIG : _ref$tweenConfig,
|
|
545
|
+
rest = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
597
546
|
var sheetRef = useRef(null);
|
|
598
547
|
var indicatorRotation = useMotionValue(0);
|
|
599
548
|
var windowHeight = useWindowHeight();
|
|
600
549
|
var shouldReduceMotion = useReducedMotion();
|
|
601
550
|
var reduceMotion = Boolean(prefersReducedMotion || shouldReduceMotion);
|
|
602
|
-
|
|
603
551
|
var animationOptions = _extends({
|
|
604
552
|
type: 'tween'
|
|
605
|
-
}, reduceMotion ? REDUCED_MOTION_TWEEN_CONFIG : tweenConfig);
|
|
553
|
+
}, reduceMotion ? REDUCED_MOTION_TWEEN_CONFIG : tweenConfig);
|
|
554
|
+
// NOTE: the inital value for `y` doesn't matter since it is overwritten by
|
|
606
555
|
// the value driven by the `AnimatePresence` component when the sheet is opened
|
|
607
556
|
// and after that it is driven by the gestures and/or snapping
|
|
608
|
-
|
|
609
|
-
|
|
610
557
|
var y = useMotionValue(0);
|
|
611
558
|
var zIndex = useTransform(y, function (value) {
|
|
612
559
|
return value >= windowHeight ? -1 : 9999999;
|
|
613
560
|
});
|
|
614
561
|
var visibility = useTransform(y, function (value) {
|
|
615
562
|
return value >= windowHeight ? 'hidden' : 'visible';
|
|
616
|
-
});
|
|
563
|
+
});
|
|
564
|
+
// Keep the callback fns up-to-date so that they can be accessed inside
|
|
617
565
|
// the effect without including them to the dependencies array
|
|
618
|
-
|
|
619
566
|
var callbacks = useRef({
|
|
620
567
|
onOpenStart: onOpenStart,
|
|
621
568
|
onOpenEnd: onOpenEnd,
|
|
@@ -630,7 +577,6 @@ var Sheet = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
630
577
|
onCloseEnd: onCloseEnd
|
|
631
578
|
};
|
|
632
579
|
});
|
|
633
|
-
|
|
634
580
|
if (snapPoints) {
|
|
635
581
|
// Convert negative / percentage snap points to absolute values
|
|
636
582
|
snapPoints = snapPoints.map(function (point) {
|
|
@@ -638,21 +584,20 @@ var Sheet = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
638
584
|
if (point > 0 && point <= 1) return Math.round(point * windowHeight);
|
|
639
585
|
return point < 0 ? windowHeight + point : point; // negative values
|
|
640
586
|
});
|
|
587
|
+
|
|
641
588
|
console.assert(inDescendingOrder(snapPoints) || windowHeight === 0, "Snap points need to be in descending order got: [" + snapPoints + "]");
|
|
642
589
|
}
|
|
643
|
-
|
|
644
590
|
var onDrag = useEvent(function (_, _ref2) {
|
|
645
591
|
var delta = _ref2.delta;
|
|
646
592
|
// Update drag indicator rotation based on drag velocity
|
|
647
593
|
var velocity = y.getVelocity();
|
|
648
594
|
if (velocity > 0) indicatorRotation.set(10);
|
|
649
|
-
if (velocity < 0) indicatorRotation.set(-10);
|
|
650
|
-
|
|
595
|
+
if (velocity < 0) indicatorRotation.set(-10);
|
|
596
|
+
// Make sure user cannot drag beyond the top of the sheet
|
|
651
597
|
y.set(Math.max(y.get() + delta.y, 0));
|
|
652
598
|
});
|
|
653
599
|
var onDragEnd = useEvent(function (_, _ref3) {
|
|
654
600
|
var velocity = _ref3.velocity;
|
|
655
|
-
|
|
656
601
|
if (velocity.y > DRAG_VELOCITY_THRESHOLD) {
|
|
657
602
|
// User flicked the sheet down
|
|
658
603
|
onClose();
|
|
@@ -661,58 +606,49 @@ var Sheet = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
661
606
|
var sheetHeight = sheetEl.getBoundingClientRect().height;
|
|
662
607
|
var currentY = y.get();
|
|
663
608
|
var snapTo = 0;
|
|
664
|
-
|
|
665
609
|
if (snapPoints) {
|
|
666
610
|
var snapToValues = snapPoints.map(function (p) {
|
|
667
611
|
return sheetHeight - Math.min(p, sheetHeight);
|
|
668
|
-
});
|
|
669
|
-
|
|
612
|
+
});
|
|
613
|
+
// Allow snapping to the top of the sheet if detent is set to `content-height`
|
|
670
614
|
if (detent === 'content-height' && !snapToValues.includes(0)) {
|
|
671
615
|
snapToValues.unshift(0);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
|
|
616
|
+
}
|
|
617
|
+
// Get the closest snap point
|
|
675
618
|
snapTo = getClosest(snapToValues, currentY);
|
|
676
619
|
} else if (currentY / sheetHeight > DRAG_CLOSE_THRESHOLD) {
|
|
677
620
|
// Close if dragged over enough far
|
|
678
621
|
snapTo = sheetHeight;
|
|
679
622
|
}
|
|
680
|
-
|
|
681
623
|
snapTo = validateSnapTo({
|
|
682
624
|
snapTo: snapTo,
|
|
683
625
|
sheetHeight: sheetHeight
|
|
684
|
-
});
|
|
685
|
-
|
|
626
|
+
});
|
|
627
|
+
// Update the spring value so that the sheet is animated to the snap point
|
|
686
628
|
animate(y, snapTo, animationOptions);
|
|
687
|
-
|
|
688
629
|
if (snapPoints && onSnap) {
|
|
689
630
|
var snapValue = Math.abs(Math.round(snapPoints[0] - snapTo));
|
|
690
631
|
var snapIndex = snapPoints.indexOf(getClosest(snapPoints, snapValue)); // prettier-ignore
|
|
691
|
-
|
|
692
632
|
onSnap(snapIndex);
|
|
693
633
|
}
|
|
694
|
-
|
|
695
634
|
var roundedSheetHeight = Math.round(sheetHeight);
|
|
696
635
|
var shouldClose = snapTo >= roundedSheetHeight;
|
|
697
636
|
if (shouldClose) onClose();
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
|
|
637
|
+
}
|
|
638
|
+
// Reset indicator rotation after dragging
|
|
701
639
|
indicatorRotation.set(0);
|
|
702
|
-
});
|
|
703
|
-
|
|
640
|
+
});
|
|
641
|
+
// Trigger onSnap callback when sheet is opened or closed
|
|
704
642
|
useEffect(function () {
|
|
705
643
|
if (!snapPoints || !onSnap) return;
|
|
706
644
|
var snapIndex = isOpen ? initialSnap : snapPoints.length - 1;
|
|
707
645
|
onSnap(snapIndex);
|
|
708
646
|
}, [isOpen]); // eslint-disable-line
|
|
709
|
-
|
|
710
647
|
useImperativeHandle(ref, function () {
|
|
711
648
|
return {
|
|
712
649
|
y: y,
|
|
713
650
|
snapTo: function snapTo(snapIndex) {
|
|
714
651
|
var sheetEl = sheetRef.current;
|
|
715
|
-
|
|
716
652
|
if (snapPoints && snapPoints[snapIndex] !== undefined && sheetEl !== null) {
|
|
717
653
|
var sheetHeight = sheetEl.getBoundingClientRect().height;
|
|
718
654
|
var snapPoint = snapPoints[snapIndex];
|
|
@@ -727,11 +663,11 @@ var Sheet = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
727
663
|
}
|
|
728
664
|
};
|
|
729
665
|
});
|
|
730
|
-
useModalEffect(isOpen, rootId);
|
|
666
|
+
useModalEffect(isOpen, rootId);
|
|
667
|
+
// Framer Motion should handle body scroll locking but it's not working
|
|
731
668
|
// properly on iOS. Scroll locking from React Aria seems to work much better.
|
|
732
|
-
|
|
733
669
|
usePreventScroll({
|
|
734
|
-
isDisabled: !isOpen
|
|
670
|
+
isDisabled: disableScrollLocking === true || !isOpen
|
|
735
671
|
});
|
|
736
672
|
var dragProps = useMemo(function () {
|
|
737
673
|
var dragProps = {
|
|
@@ -748,7 +684,6 @@ var Sheet = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
748
684
|
};
|
|
749
685
|
return disableDrag ? undefined : dragProps;
|
|
750
686
|
}, [disableDrag]); // eslint-disable-line
|
|
751
|
-
|
|
752
687
|
var context = {
|
|
753
688
|
y: y,
|
|
754
689
|
sheetRef: sheetRef,
|
|
@@ -781,30 +716,28 @@ var Sheet = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
781
716
|
return createPortal(sheet, mountPoint != null ? mountPoint : document.body);
|
|
782
717
|
});
|
|
783
718
|
|
|
719
|
+
var _excluded$1 = ["children", "style", "className"];
|
|
784
720
|
var SheetContainer = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
785
721
|
var children = _ref.children,
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
722
|
+
_ref$style = _ref.style,
|
|
723
|
+
style = _ref$style === void 0 ? {} : _ref$style,
|
|
724
|
+
_ref$className = _ref.className,
|
|
725
|
+
className = _ref$className === void 0 ? '' : _ref$className,
|
|
726
|
+
rest = _objectWithoutPropertiesLoose(_ref, _excluded$1);
|
|
792
727
|
var _useSheetContext = useSheetContext(),
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
728
|
+
y = _useSheetContext.y,
|
|
729
|
+
isOpen = _useSheetContext.isOpen,
|
|
730
|
+
callbacks = _useSheetContext.callbacks,
|
|
731
|
+
snapPoints = _useSheetContext.snapPoints,
|
|
732
|
+
_useSheetContext$init = _useSheetContext.initialSnap,
|
|
733
|
+
initialSnap = _useSheetContext$init === void 0 ? 0 : _useSheetContext$init,
|
|
734
|
+
sheetRef = _useSheetContext.sheetRef,
|
|
735
|
+
windowHeight = _useSheetContext.windowHeight,
|
|
736
|
+
detent = _useSheetContext.detent,
|
|
737
|
+
animationOptions = _useSheetContext.animationOptions,
|
|
738
|
+
reduceMotion = _useSheetContext.reduceMotion;
|
|
805
739
|
var _useEventCallbacks = useEventCallbacks(isOpen, callbacks),
|
|
806
|
-
|
|
807
|
-
|
|
740
|
+
handleAnimationComplete = _useEventCallbacks.handleAnimationComplete;
|
|
808
741
|
var initialY = snapPoints ? snapPoints[0] - snapPoints[initialSnap] : 0;
|
|
809
742
|
var maxSnapHeight = snapPoints ? snapPoints[0] : null;
|
|
810
743
|
var height = maxSnapHeight !== null ? "min(" + maxSnapHeight + "px, " + MAX_HEIGHT + ")" : MAX_HEIGHT;
|
|
@@ -833,14 +766,14 @@ var SheetContainer = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
833
766
|
}), children);
|
|
834
767
|
});
|
|
835
768
|
|
|
769
|
+
var _excluded$2 = ["children", "style", "disableDrag", "className"];
|
|
836
770
|
var SheetContent = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
837
771
|
var children = _ref.children,
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
772
|
+
style = _ref.style,
|
|
773
|
+
disableDrag = _ref.disableDrag,
|
|
774
|
+
_ref$className = _ref.className,
|
|
775
|
+
className = _ref$className === void 0 ? '' : _ref$className,
|
|
776
|
+
rest = _objectWithoutPropertiesLoose(_ref, _excluded$2);
|
|
844
777
|
var sheetContext = useSheetContext();
|
|
845
778
|
var sheetScrollerContext = useSheetScrollerContext();
|
|
846
779
|
var dragProps = disableDrag || sheetScrollerContext.disableDrag ? undefined : sheetContext.dragProps;
|
|
@@ -851,18 +784,16 @@ var SheetContent = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
851
784
|
}, dragProps), children);
|
|
852
785
|
});
|
|
853
786
|
|
|
787
|
+
var _excluded$3 = ["children", "style", "disableDrag"];
|
|
854
788
|
var SheetHeader = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
855
789
|
var children = _ref.children,
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
790
|
+
style = _ref.style,
|
|
791
|
+
disableDrag = _ref.disableDrag,
|
|
792
|
+
rest = _objectWithoutPropertiesLoose(_ref, _excluded$3);
|
|
860
793
|
var _useSheetContext = useSheetContext(),
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
794
|
+
indicatorRotation = _useSheetContext.indicatorRotation,
|
|
795
|
+
dragProps = _useSheetContext.dragProps;
|
|
864
796
|
var _dragProps = disableDrag ? undefined : dragProps;
|
|
865
|
-
|
|
866
797
|
var indicator1Transform = useTransform(indicatorRotation, function (r) {
|
|
867
798
|
return "translateX(2px) rotate(" + r + "deg)";
|
|
868
799
|
});
|
|
@@ -888,17 +819,16 @@ var SheetHeader = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
888
819
|
})));
|
|
889
820
|
});
|
|
890
821
|
|
|
822
|
+
var _excluded$4 = ["style", "className"];
|
|
891
823
|
var isClickable = function isClickable(props) {
|
|
892
824
|
return !!props.onClick || !!props.onTap;
|
|
893
825
|
};
|
|
894
|
-
|
|
895
826
|
var SheetBackdrop = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
896
827
|
var _ref$style = _ref.style,
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
828
|
+
style = _ref$style === void 0 ? {} : _ref$style,
|
|
829
|
+
_ref$className = _ref.className,
|
|
830
|
+
className = _ref$className === void 0 ? '' : _ref$className,
|
|
831
|
+
rest = _objectWithoutPropertiesLoose(_ref, _excluded$4);
|
|
902
832
|
var Comp = isClickable(rest) ? motion.button : motion.div;
|
|
903
833
|
var pointerEvents = isClickable(rest) ? 'auto' : 'none';
|
|
904
834
|
return createElement(Comp, Object.assign({}, rest, {
|
|
@@ -919,42 +849,37 @@ var SheetBackdrop = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
919
849
|
}));
|
|
920
850
|
});
|
|
921
851
|
|
|
852
|
+
var _excluded$5 = ["draggableAt", "children", "style", "className"];
|
|
922
853
|
var SheetScroller = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
923
854
|
var _ref$draggableAt = _ref.draggableAt,
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
855
|
+
draggableAt = _ref$draggableAt === void 0 ? 'top' : _ref$draggableAt,
|
|
856
|
+
children = _ref.children,
|
|
857
|
+
style = _ref.style,
|
|
858
|
+
_ref$className = _ref.className,
|
|
859
|
+
className = _ref$className === void 0 ? '' : _ref$className,
|
|
860
|
+
rest = _objectWithoutPropertiesLoose(_ref, _excluded$5);
|
|
931
861
|
var sheetScrollerContext = useSheetScrollerContext();
|
|
932
|
-
|
|
933
862
|
function determineDragState(element) {
|
|
934
863
|
var scrollTop = element.scrollTop,
|
|
935
|
-
|
|
936
|
-
|
|
864
|
+
scrollHeight = element.scrollHeight,
|
|
865
|
+
clientHeight = element.clientHeight;
|
|
937
866
|
var isScrollable = scrollHeight > clientHeight;
|
|
938
867
|
if (!isScrollable) return;
|
|
939
868
|
var isAtTop = scrollTop <= 0;
|
|
940
869
|
var isAtBottom = scrollHeight - scrollTop === clientHeight;
|
|
941
870
|
var shouldEnable = draggableAt === 'top' && isAtTop || draggableAt === 'bottom' && isAtBottom || draggableAt === 'both' && (isAtTop || isAtBottom);
|
|
942
|
-
|
|
943
871
|
if (shouldEnable) {
|
|
944
872
|
sheetScrollerContext.setDragEnabled();
|
|
945
873
|
} else {
|
|
946
874
|
sheetScrollerContext.setDragDisabled();
|
|
947
875
|
}
|
|
948
876
|
}
|
|
949
|
-
|
|
950
877
|
function onScroll(e) {
|
|
951
878
|
determineDragState(e.currentTarget);
|
|
952
879
|
}
|
|
953
|
-
|
|
954
880
|
function onTouchStart(e) {
|
|
955
881
|
determineDragState(e.currentTarget);
|
|
956
882
|
}
|
|
957
|
-
|
|
958
883
|
var scrollProps = isTouchDevice() ? {
|
|
959
884
|
onScroll: onScroll,
|
|
960
885
|
onTouchStart: onTouchStart
|
|
@@ -966,6 +891,7 @@ var SheetScroller = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
966
891
|
}, scrollProps), children);
|
|
967
892
|
});
|
|
968
893
|
|
|
894
|
+
// HACK: this is needed to get the typing to work properly...
|
|
969
895
|
var _SheetCompound = Sheet;
|
|
970
896
|
_SheetCompound.Container = SheetContainer;
|
|
971
897
|
_SheetCompound.Header = SheetHeader;
|