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