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