react-modal-sheet 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +207 -110
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +203 -106
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -4
- package/src/hooks.tsx +85 -16
- package/src/sheet.tsx +5 -1
- package/src/use-prevent-scroll.ts +80 -21
- package/src/utils.ts +41 -42
package/dist/index.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
var React2 = require('react');
|
|
4
4
|
var reactDom = require('react-dom');
|
|
5
5
|
var framerMotion = require('framer-motion');
|
|
6
|
-
var utils = require('@react-aria/utils');
|
|
7
6
|
|
|
8
7
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
8
|
|
|
@@ -25,104 +24,85 @@ var REDUCED_MOTION_TWEEN_CONFIG = {
|
|
|
25
24
|
var DEFAULT_DRAG_CLOSE_THRESHOLD = 0.6;
|
|
26
25
|
var DEFAULT_DRAG_VELOCITY_THRESHOLD = 500;
|
|
27
26
|
|
|
28
|
-
// src/
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
function applyRootStyles(rootId) {
|
|
42
|
-
const body = document.querySelector("body");
|
|
43
|
-
const root = document.querySelector(`#${rootId}`);
|
|
44
|
-
if (root) {
|
|
45
|
-
const p = 24;
|
|
46
|
-
const h = window.innerHeight;
|
|
47
|
-
const s = (h - p) / h;
|
|
27
|
+
// src/hooks.tsx
|
|
28
|
+
var useIsomorphicLayoutEffect = IS_SSR ? React2.useEffect : React2.useLayoutEffect;
|
|
29
|
+
function useModalEffect({
|
|
30
|
+
y,
|
|
31
|
+
rootId,
|
|
32
|
+
sheetRef
|
|
33
|
+
}) {
|
|
34
|
+
const heightRef = React2.useRef(IS_SSR ? 0 : window.innerHeight);
|
|
35
|
+
function setup() {
|
|
36
|
+
const root = document.querySelector(`#${rootId}`);
|
|
37
|
+
const body = document.querySelector("body");
|
|
38
|
+
if (!root)
|
|
39
|
+
return;
|
|
48
40
|
body.style.backgroundColor = "#000";
|
|
49
41
|
root.style.overflow = "hidden";
|
|
50
|
-
root.style.
|
|
51
|
-
root.style.
|
|
52
|
-
root.style.
|
|
53
|
-
root.style.
|
|
54
|
-
root.style.borderTopLeftRadius = "10px";
|
|
42
|
+
root.style.transitionTimingFunction = "cubic-bezier(0.32, 0.72, 0, 1)";
|
|
43
|
+
root.style.transitionProperty = "transform, border-radius";
|
|
44
|
+
root.style.transitionDuration = "0.5s";
|
|
45
|
+
root.style.transformOrigin = "center top";
|
|
55
46
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function inDescendingOrder(arr) {
|
|
75
|
-
for (let i = 0; i < arr.length; i++) {
|
|
76
|
-
if (arr[i + 1] > arr[i])
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
function validateSnapTo({
|
|
82
|
-
snapTo,
|
|
83
|
-
sheetHeight
|
|
84
|
-
}) {
|
|
85
|
-
if (snapTo < 0) {
|
|
86
|
-
console.warn(
|
|
87
|
-
`Snap point is out of bounds. Sheet height is ${sheetHeight} but snap point is ${sheetHeight + Math.abs(snapTo)}.`
|
|
88
|
-
);
|
|
47
|
+
function cleanup() {
|
|
48
|
+
const root = document.querySelector(`#${rootId}`);
|
|
49
|
+
const body = document.querySelector("body");
|
|
50
|
+
if (!root)
|
|
51
|
+
return;
|
|
52
|
+
setTimeout(() => {
|
|
53
|
+
body.style.removeProperty("background-color");
|
|
54
|
+
root.style.removeProperty("overflow");
|
|
55
|
+
root.style.removeProperty("transition-timing-function");
|
|
56
|
+
root.style.removeProperty("transition-property");
|
|
57
|
+
root.style.removeProperty("transition-duration");
|
|
58
|
+
root.style.removeProperty("transform-origin");
|
|
59
|
+
root.style.removeProperty("transform");
|
|
60
|
+
root.style.removeProperty("border-top-right-radius");
|
|
61
|
+
root.style.removeProperty("border-top-left-radius");
|
|
62
|
+
}, 100);
|
|
89
63
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
ref(value);
|
|
97
|
-
} else if (ref) {
|
|
98
|
-
ref.current = value;
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
function isTouchDevice() {
|
|
104
|
-
if (typeof window === "undefined")
|
|
105
|
-
return false;
|
|
106
|
-
return "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// src/hooks.tsx
|
|
110
|
-
var useIsomorphicLayoutEffect = IS_SSR ? React2.useEffect : React2.useLayoutEffect;
|
|
111
|
-
function useModalEffect(isOpen, rootId) {
|
|
112
|
-
const prevOpen = usePrevious(isOpen);
|
|
64
|
+
useIsomorphicLayoutEffect(() => {
|
|
65
|
+
return () => {
|
|
66
|
+
if (rootId)
|
|
67
|
+
cleanup();
|
|
68
|
+
};
|
|
69
|
+
}, []);
|
|
113
70
|
React2.useEffect(() => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
71
|
+
const root = document.querySelector(`#${rootId}`);
|
|
72
|
+
if (!root)
|
|
73
|
+
return;
|
|
74
|
+
function onCompleted() {
|
|
75
|
+
if (y.get() - 10 >= heightRef.current)
|
|
76
|
+
cleanup();
|
|
118
77
|
}
|
|
119
|
-
|
|
120
|
-
|
|
78
|
+
const removeStartListener = y.on("animationStart", () => {
|
|
79
|
+
var _a;
|
|
80
|
+
heightRef.current = ((_a = sheetRef.current) == null ? void 0 : _a.offsetHeight) || window.innerHeight;
|
|
81
|
+
setup();
|
|
82
|
+
});
|
|
83
|
+
const removeChangeListener = y.on("change", (value) => {
|
|
84
|
+
if (root) {
|
|
85
|
+
const progress = Math.max(0, 1 - value / heightRef.current);
|
|
86
|
+
const pageWidth = window.innerWidth;
|
|
87
|
+
const scale = (pageWidth - 16) / pageWidth;
|
|
88
|
+
const ty = framerMotion.transform(progress, [0, 1], [0, 24]);
|
|
89
|
+
const s = framerMotion.transform(progress, [0, 1], [1, scale]);
|
|
90
|
+
const borderRadius = framerMotion.transform(progress, [0, 1], [0, 10]);
|
|
91
|
+
const inset = "env(safe-area-inset-top)";
|
|
92
|
+
root.style.transform = `scale(${s}) translate3d(0, calc(${inset} + ${ty}px), 0)`;
|
|
93
|
+
root.style.borderTopRightRadius = `${borderRadius}px`;
|
|
94
|
+
root.style.borderTopLeftRadius = `${borderRadius}px`;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
const removeCompleteListener = y.on("animationComplete", onCompleted);
|
|
98
|
+
const removeCancelListener = y.on("animationCancel", onCompleted);
|
|
121
99
|
return () => {
|
|
122
|
-
|
|
123
|
-
|
|
100
|
+
removeStartListener();
|
|
101
|
+
removeChangeListener();
|
|
102
|
+
removeCompleteListener();
|
|
103
|
+
removeCancelListener();
|
|
124
104
|
};
|
|
125
|
-
}, [
|
|
105
|
+
}, [y, rootId]);
|
|
126
106
|
}
|
|
127
107
|
function useEventCallbacks(isOpen, callbacks) {
|
|
128
108
|
const prevOpen = usePrevious(isOpen);
|
|
@@ -149,8 +129,8 @@ function useEventCallbacks(isOpen, callbacks) {
|
|
|
149
129
|
}
|
|
150
130
|
function useDimensions() {
|
|
151
131
|
const [dimensions, setDimensions] = React2.useState({
|
|
152
|
-
height:
|
|
153
|
-
width:
|
|
132
|
+
height: !IS_SSR ? window.innerHeight : 0,
|
|
133
|
+
width: !IS_SSR ? window.innerWidth : 0
|
|
154
134
|
});
|
|
155
135
|
useIsomorphicLayoutEffect(() => {
|
|
156
136
|
function handler() {
|
|
@@ -227,7 +207,120 @@ var useSheetScrollerContext = () => {
|
|
|
227
207
|
throw Error("Sheet scroller context error");
|
|
228
208
|
return context;
|
|
229
209
|
};
|
|
230
|
-
|
|
210
|
+
|
|
211
|
+
// src/utils.ts
|
|
212
|
+
function getClosest(nums, goal) {
|
|
213
|
+
let closest = nums[0];
|
|
214
|
+
let minDifference = Math.abs(nums[0] - goal);
|
|
215
|
+
for (let i = 1; i < nums.length; i++) {
|
|
216
|
+
const difference = Math.abs(nums[i] - goal);
|
|
217
|
+
if (difference < minDifference) {
|
|
218
|
+
closest = nums[i];
|
|
219
|
+
minDifference = difference;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return closest;
|
|
223
|
+
}
|
|
224
|
+
function inDescendingOrder(arr) {
|
|
225
|
+
for (let i = 0; i < arr.length; i++) {
|
|
226
|
+
if (arr[i + 1] > arr[i])
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
function validateSnapTo({
|
|
232
|
+
snapTo,
|
|
233
|
+
sheetHeight
|
|
234
|
+
}) {
|
|
235
|
+
if (snapTo < 0) {
|
|
236
|
+
console.warn(
|
|
237
|
+
`Snap point is out of bounds. Sheet height is ${sheetHeight} but snap point is ${sheetHeight + Math.abs(snapTo)}.`
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
return Math.max(Math.round(snapTo), 0);
|
|
241
|
+
}
|
|
242
|
+
function mergeRefs(refs) {
|
|
243
|
+
return (value) => {
|
|
244
|
+
refs.forEach((ref) => {
|
|
245
|
+
if (typeof ref === "function") {
|
|
246
|
+
ref(value);
|
|
247
|
+
} else if (ref) {
|
|
248
|
+
ref.current = value;
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
function isTouchDevice() {
|
|
254
|
+
if (typeof window === "undefined")
|
|
255
|
+
return false;
|
|
256
|
+
return "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
257
|
+
}
|
|
258
|
+
function testPlatform(re) {
|
|
259
|
+
var _a;
|
|
260
|
+
return typeof window !== "undefined" && window.navigator != null ? re.test(
|
|
261
|
+
// @ts-expect-error
|
|
262
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
263
|
+
((_a = window.navigator["userAgentData"]) == null ? void 0 : _a.platform) || window.navigator.platform
|
|
264
|
+
) : false;
|
|
265
|
+
}
|
|
266
|
+
function cached(fn) {
|
|
267
|
+
let res = null;
|
|
268
|
+
return () => {
|
|
269
|
+
if (res == null) {
|
|
270
|
+
res = fn();
|
|
271
|
+
}
|
|
272
|
+
return res;
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
var isMac = cached(function() {
|
|
276
|
+
return testPlatform(/^Mac/i);
|
|
277
|
+
});
|
|
278
|
+
var isIPhone = cached(function() {
|
|
279
|
+
return testPlatform(/^iPhone/i);
|
|
280
|
+
});
|
|
281
|
+
var isIPad = cached(function() {
|
|
282
|
+
return testPlatform(/^iPad/i) || // iPadOS 13 lies and says it's a Mac, but we can distinguish by detecting touch support.
|
|
283
|
+
isMac() && navigator.maxTouchPoints > 1;
|
|
284
|
+
});
|
|
285
|
+
var isIOS = cached(function() {
|
|
286
|
+
return isIPhone() || isIPad();
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// src/use-prevent-scroll.ts
|
|
290
|
+
var KEYBOARD_BUFFER = 24;
|
|
291
|
+
function chain(...callbacks) {
|
|
292
|
+
return (...args) => {
|
|
293
|
+
for (const callback of callbacks) {
|
|
294
|
+
if (typeof callback === "function") {
|
|
295
|
+
callback(...args);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
var visualViewport = typeof document !== "undefined" && window.visualViewport;
|
|
301
|
+
function isScrollable(node, checkForOverflow) {
|
|
302
|
+
if (!node) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
const style = window.getComputedStyle(node);
|
|
306
|
+
let isScrollable2 = /(auto|scroll)/.test(
|
|
307
|
+
style.overflow + style.overflowX + style.overflowY
|
|
308
|
+
);
|
|
309
|
+
if (isScrollable2 && checkForOverflow) {
|
|
310
|
+
isScrollable2 = node.scrollHeight !== node.clientHeight || node.scrollWidth !== node.clientWidth;
|
|
311
|
+
}
|
|
312
|
+
return isScrollable2;
|
|
313
|
+
}
|
|
314
|
+
function getScrollParent(node, checkForOverflow) {
|
|
315
|
+
let scrollableNode = node;
|
|
316
|
+
if (isScrollable(scrollableNode, checkForOverflow)) {
|
|
317
|
+
scrollableNode = scrollableNode.parentElement;
|
|
318
|
+
}
|
|
319
|
+
while (scrollableNode && !isScrollable(scrollableNode, checkForOverflow)) {
|
|
320
|
+
scrollableNode = scrollableNode.parentElement;
|
|
321
|
+
}
|
|
322
|
+
return scrollableNode || document.scrollingElement || document.documentElement;
|
|
323
|
+
}
|
|
231
324
|
var nonTextInputTypes = /* @__PURE__ */ new Set([
|
|
232
325
|
"checkbox",
|
|
233
326
|
"radio",
|
|
@@ -243,13 +336,13 @@ var preventScrollCount = 0;
|
|
|
243
336
|
var restore;
|
|
244
337
|
function usePreventScroll(options = {}) {
|
|
245
338
|
const { isDisabled } = options;
|
|
246
|
-
|
|
339
|
+
useIsomorphicLayoutEffect(() => {
|
|
247
340
|
if (isDisabled) {
|
|
248
341
|
return;
|
|
249
342
|
}
|
|
250
343
|
preventScrollCount++;
|
|
251
344
|
if (preventScrollCount === 1) {
|
|
252
|
-
if (
|
|
345
|
+
if (isIOS()) {
|
|
253
346
|
restore = preventScrollMobileSafari();
|
|
254
347
|
} else {
|
|
255
348
|
restore = preventScrollStandard();
|
|
@@ -258,13 +351,13 @@ function usePreventScroll(options = {}) {
|
|
|
258
351
|
return () => {
|
|
259
352
|
preventScrollCount--;
|
|
260
353
|
if (preventScrollCount === 0) {
|
|
261
|
-
restore();
|
|
354
|
+
restore == null ? void 0 : restore();
|
|
262
355
|
}
|
|
263
356
|
};
|
|
264
357
|
}, [isDisabled]);
|
|
265
358
|
}
|
|
266
359
|
function preventScrollStandard() {
|
|
267
|
-
return
|
|
360
|
+
return chain(
|
|
268
361
|
setStyle(
|
|
269
362
|
document.documentElement,
|
|
270
363
|
"paddingRight",
|
|
@@ -277,7 +370,7 @@ function preventScrollMobileSafari() {
|
|
|
277
370
|
let scrollable;
|
|
278
371
|
let lastY = 0;
|
|
279
372
|
const onTouchStart = (e) => {
|
|
280
|
-
scrollable =
|
|
373
|
+
scrollable = getScrollParent(e.target, true);
|
|
281
374
|
if (scrollable === document.documentElement && scrollable === document.body) {
|
|
282
375
|
return;
|
|
283
376
|
}
|
|
@@ -287,7 +380,7 @@ function preventScrollMobileSafari() {
|
|
|
287
380
|
if (scrollable === void 0) {
|
|
288
381
|
return;
|
|
289
382
|
}
|
|
290
|
-
if (scrollable === document.documentElement || scrollable === document.body) {
|
|
383
|
+
if (!scrollable || scrollable === document.documentElement || scrollable === document.body) {
|
|
291
384
|
e.preventDefault();
|
|
292
385
|
return;
|
|
293
386
|
}
|
|
@@ -327,9 +420,7 @@ function preventScrollMobileSafari() {
|
|
|
327
420
|
} else {
|
|
328
421
|
visualViewport.addEventListener(
|
|
329
422
|
"resize",
|
|
330
|
-
() =>
|
|
331
|
-
scrollIntoView(target);
|
|
332
|
-
},
|
|
423
|
+
() => scrollIntoView(target),
|
|
333
424
|
{ once: true }
|
|
334
425
|
);
|
|
335
426
|
}
|
|
@@ -342,7 +433,7 @@ function preventScrollMobileSafari() {
|
|
|
342
433
|
};
|
|
343
434
|
const scrollX = window.pageXOffset;
|
|
344
435
|
const scrollY = window.pageYOffset;
|
|
345
|
-
const restoreStyles =
|
|
436
|
+
const restoreStyles = chain(
|
|
346
437
|
setStyle(
|
|
347
438
|
document.documentElement,
|
|
348
439
|
"paddingRight",
|
|
@@ -352,7 +443,7 @@ function preventScrollMobileSafari() {
|
|
|
352
443
|
setStyle(document.body, "marginTop", `-${scrollY}px`)
|
|
353
444
|
);
|
|
354
445
|
window.scrollTo(0, 0);
|
|
355
|
-
const removeEvents =
|
|
446
|
+
const removeEvents = chain(
|
|
356
447
|
addEvent(document, "touchstart", onTouchStart, {
|
|
357
448
|
passive: false,
|
|
358
449
|
capture: true
|
|
@@ -390,11 +481,13 @@ function addEvent(target, event, handler, options) {
|
|
|
390
481
|
function scrollIntoView(target) {
|
|
391
482
|
const root = document.scrollingElement || document.documentElement;
|
|
392
483
|
while (target && target !== root) {
|
|
393
|
-
const scrollable =
|
|
484
|
+
const scrollable = getScrollParent(target);
|
|
394
485
|
if (scrollable !== document.documentElement && scrollable !== document.body && scrollable !== target) {
|
|
395
486
|
const scrollableTop = scrollable.getBoundingClientRect().top;
|
|
396
487
|
const targetTop = target.getBoundingClientRect().top;
|
|
397
|
-
|
|
488
|
+
const targetBottom = target.getBoundingClientRect().bottom;
|
|
489
|
+
const keyboardHeight = scrollable.getBoundingClientRect().bottom + KEYBOARD_BUFFER;
|
|
490
|
+
if (targetBottom > keyboardHeight) {
|
|
398
491
|
scrollable.scrollTop += targetTop - scrollableTop;
|
|
399
492
|
}
|
|
400
493
|
}
|
|
@@ -618,7 +711,11 @@ var Sheet = React2.forwardRef(
|
|
|
618
711
|
}
|
|
619
712
|
}
|
|
620
713
|
}));
|
|
621
|
-
useModalEffect(
|
|
714
|
+
useModalEffect({
|
|
715
|
+
y,
|
|
716
|
+
rootId,
|
|
717
|
+
sheetRef
|
|
718
|
+
});
|
|
622
719
|
usePreventScroll({ isDisabled: disableScrollLocking || !isOpen });
|
|
623
720
|
const dragProps = React2.useMemo(() => {
|
|
624
721
|
const dragProps2 = {
|
|
@@ -798,8 +895,8 @@ var SheetScroller = React2.forwardRef(
|
|
|
798
895
|
const sheetScrollerContext = useSheetScrollerContext();
|
|
799
896
|
function determineDragState(element) {
|
|
800
897
|
const { scrollTop, scrollHeight, clientHeight } = element;
|
|
801
|
-
const
|
|
802
|
-
if (!
|
|
898
|
+
const isScrollable2 = scrollHeight > clientHeight;
|
|
899
|
+
if (!isScrollable2)
|
|
803
900
|
return;
|
|
804
901
|
const isAtTop = scrollTop <= 0;
|
|
805
902
|
const isAtBottom = scrollHeight - scrollTop === clientHeight;
|