react-modal-sheet 2.2.1 → 3.0.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 CHANGED
@@ -1,8 +1,830 @@
1
+ 'use strict';
1
2
 
2
- 'use strict'
3
+ var React2 = require('react');
4
+ var reactDom = require('react-dom');
5
+ var framerMotion = require('framer-motion');
6
+ var utils = require('@react-aria/utils');
3
7
 
4
- if (process.env.NODE_ENV === 'production') {
5
- module.exports = require('./react-modal-sheet.cjs.production.min.js')
6
- } else {
7
- module.exports = require('./react-modal-sheet.cjs.development.js')
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var React2__default = /*#__PURE__*/_interopDefault(React2);
11
+
12
+ // src/sheet.tsx
13
+
14
+ // src/constants.ts
15
+ var MAX_HEIGHT = "calc(100% - env(safe-area-inset-top) - 34px)";
16
+ var IS_SSR = typeof window === "undefined";
17
+ var DEFAULT_TWEEN_CONFIG = {
18
+ ease: "easeOut",
19
+ duration: 0.2
20
+ };
21
+ var REDUCED_MOTION_TWEEN_CONFIG = {
22
+ ease: "linear",
23
+ duration: 0.01
24
+ };
25
+ var DRAG_CLOSE_THRESHOLD = 0.6;
26
+ var DRAG_VELOCITY_THRESHOLD = 500;
27
+
28
+ // src/utils.ts
29
+ function getClosest(nums, goal) {
30
+ let closest = nums[0];
31
+ let minDifference = Math.abs(nums[0] - goal);
32
+ for (let i = 1; i < nums.length; i++) {
33
+ const difference = Math.abs(nums[i] - goal);
34
+ if (difference < minDifference) {
35
+ closest = nums[i];
36
+ minDifference = difference;
37
+ }
38
+ }
39
+ return closest;
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;
48
+ body.style.backgroundColor = "#000";
49
+ root.style.overflow = "hidden";
50
+ root.style.willChange = "transform";
51
+ root.style.transition = "transform 200ms ease-in-out, border-radius 200ms linear";
52
+ root.style.transform = `translateY(calc(env(safe-area-inset-top) + ${p / 2}px)) scale(${s})`;
53
+ root.style.borderTopRightRadius = "10px";
54
+ root.style.borderTopLeftRadius = "10px";
55
+ }
56
+ }
57
+ function cleanupRootStyles(rootId) {
58
+ const body = document.querySelector("body");
59
+ const root = document.getElementById(rootId);
60
+ function onTransitionEnd() {
61
+ root.style.removeProperty("overflow");
62
+ root.style.removeProperty("will-change");
63
+ root.style.removeProperty("transition");
64
+ body.style.removeProperty("background-color");
65
+ root.removeEventListener("transitionend", onTransitionEnd);
66
+ }
67
+ if (root) {
68
+ root.style.removeProperty("border-top-right-radius");
69
+ root.style.removeProperty("border-top-left-radius");
70
+ root.style.removeProperty("transform");
71
+ root.addEventListener("transitionend", onTransitionEnd);
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
+ );
89
+ }
90
+ return Math.max(Math.round(snapTo), 0);
91
+ }
92
+ function mergeRefs(refs) {
93
+ return (value) => {
94
+ refs.forEach((ref) => {
95
+ if (typeof ref === "function") {
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);
113
+ React2.useEffect(() => {
114
+ if (rootId && !prevOpen && isOpen) {
115
+ applyRootStyles(rootId);
116
+ } else if (rootId && !isOpen && prevOpen) {
117
+ cleanupRootStyles(rootId);
118
+ }
119
+ }, [isOpen, prevOpen]);
120
+ React2.useEffect(() => {
121
+ return () => {
122
+ if (rootId && isOpen)
123
+ cleanupRootStyles(rootId);
124
+ };
125
+ }, [isOpen]);
126
+ }
127
+ function useEventCallbacks(isOpen, callbacks) {
128
+ const prevOpen = usePrevious(isOpen);
129
+ const didOpen = React2.useRef(false);
130
+ const handleAnimationComplete = React2.useCallback(() => {
131
+ var _a, _b, _c, _d;
132
+ if (!didOpen.current) {
133
+ (_b = (_a = callbacks.current).onOpenEnd) == null ? void 0 : _b.call(_a);
134
+ didOpen.current = true;
135
+ } else {
136
+ (_d = (_c = callbacks.current).onCloseEnd) == null ? void 0 : _d.call(_c);
137
+ didOpen.current = false;
138
+ }
139
+ }, [isOpen, prevOpen]);
140
+ React2.useEffect(() => {
141
+ var _a, _b, _c, _d;
142
+ if (!prevOpen && isOpen) {
143
+ (_b = (_a = callbacks.current).onOpenStart) == null ? void 0 : _b.call(_a);
144
+ } else if (!isOpen && prevOpen) {
145
+ (_d = (_c = callbacks.current).onCloseStart) == null ? void 0 : _d.call(_c);
146
+ }
147
+ }, [isOpen, prevOpen]);
148
+ return { handleAnimationComplete };
149
+ }
150
+ function useDimensions() {
151
+ const [dimensions, setDimensions] = React2.useState({ height: 0, width: 0 });
152
+ useIsomorphicLayoutEffect(() => {
153
+ const updateHeight = () => {
154
+ setDimensions({ height: window.innerHeight, width: window.innerWidth });
155
+ };
156
+ window.addEventListener("resize", updateHeight);
157
+ updateHeight();
158
+ return () => {
159
+ window.removeEventListener("resize", updateHeight);
160
+ };
161
+ }, []);
162
+ return dimensions;
163
+ }
164
+ function usePrevious(state) {
165
+ const ref = React2.useRef();
166
+ React2.useEffect(() => {
167
+ ref.current = state;
168
+ });
169
+ return ref.current;
8
170
  }
171
+ function useEvent(handler) {
172
+ const handlerRef = React2.useRef();
173
+ useIsomorphicLayoutEffect(() => {
174
+ handlerRef.current = handler;
175
+ });
176
+ return React2.useCallback((...args) => {
177
+ const fn = handlerRef.current;
178
+ return fn == null ? void 0 : fn(...args);
179
+ }, []);
180
+ }
181
+ var constraints = { bottom: 0, top: 0, left: 0, right: 0 };
182
+ function useDragConstraints() {
183
+ const constraintsRef = React2.useRef(null);
184
+ const onMeasureDragConstraints = React2.useCallback(() => constraints, []);
185
+ return { constraintsRef, onMeasureDragConstraints };
186
+ }
187
+ var SheetContext = React2.createContext(
188
+ void 0
189
+ );
190
+ var useSheetContext = () => {
191
+ const context = React2.useContext(SheetContext);
192
+ if (!context)
193
+ throw Error("Sheet context error");
194
+ return context;
195
+ };
196
+ var SheetScrollerContext = React2.createContext(void 0);
197
+ function SheetScrollerContextProvider({
198
+ children
199
+ }) {
200
+ const sheetContext = useSheetContext();
201
+ const [disableDrag, setDisableDrag] = React2.useState(!!sheetContext.disableDrag);
202
+ function setDragEnabled() {
203
+ if (!sheetContext.disableDrag)
204
+ setDisableDrag(false);
205
+ }
206
+ function setDragDisabled() {
207
+ if (!disableDrag)
208
+ setDisableDrag(true);
209
+ }
210
+ return /* @__PURE__ */ React2__default.default.createElement(
211
+ SheetScrollerContext.Provider,
212
+ {
213
+ value: { disableDrag, setDragEnabled, setDragDisabled }
214
+ },
215
+ children
216
+ );
217
+ }
218
+ var useSheetScrollerContext = () => {
219
+ const context = React2.useContext(SheetScrollerContext);
220
+ if (!context)
221
+ throw Error("Sheet scroller context error");
222
+ return context;
223
+ };
224
+ var visualViewport = typeof window !== "undefined" ? window.visualViewport : void 0;
225
+ var nonTextInputTypes = /* @__PURE__ */ new Set([
226
+ "checkbox",
227
+ "radio",
228
+ "range",
229
+ "color",
230
+ "file",
231
+ "image",
232
+ "button",
233
+ "submit",
234
+ "reset"
235
+ ]);
236
+ var preventScrollCount = 0;
237
+ var restore;
238
+ function usePreventScroll(options = {}) {
239
+ const { isDisabled } = options;
240
+ utils.useLayoutEffect(() => {
241
+ if (isDisabled) {
242
+ return;
243
+ }
244
+ preventScrollCount++;
245
+ if (preventScrollCount === 1) {
246
+ if (utils.isIOS()) {
247
+ restore = preventScrollMobileSafari();
248
+ } else {
249
+ restore = preventScrollStandard();
250
+ }
251
+ }
252
+ return () => {
253
+ preventScrollCount--;
254
+ if (preventScrollCount === 0) {
255
+ restore();
256
+ }
257
+ };
258
+ }, [isDisabled]);
259
+ }
260
+ function preventScrollStandard() {
261
+ return utils.chain(
262
+ setStyle(
263
+ document.documentElement,
264
+ "paddingRight",
265
+ `${window.innerWidth - document.documentElement.clientWidth}px`
266
+ ),
267
+ setStyle(document.documentElement, "overflow", "hidden")
268
+ );
269
+ }
270
+ function preventScrollMobileSafari() {
271
+ let scrollable;
272
+ let lastY = 0;
273
+ const onTouchStart = (e) => {
274
+ scrollable = utils.getScrollParent(e.target);
275
+ if (scrollable === document.documentElement && scrollable === document.body) {
276
+ return;
277
+ }
278
+ lastY = e.changedTouches[0].pageY;
279
+ };
280
+ const onTouchMove = (e) => {
281
+ if (scrollable === void 0) {
282
+ return;
283
+ }
284
+ if (scrollable === document.documentElement || scrollable === document.body) {
285
+ e.preventDefault();
286
+ return;
287
+ }
288
+ const y = e.changedTouches[0].pageY;
289
+ const scrollTop = scrollable.scrollTop;
290
+ const bottom = scrollable.scrollHeight - scrollable.clientHeight;
291
+ if (bottom === 0) {
292
+ return;
293
+ }
294
+ if (scrollTop <= 0 && y > lastY || scrollTop >= bottom && y < lastY) {
295
+ e.preventDefault();
296
+ }
297
+ lastY = y;
298
+ };
299
+ const onTouchEnd = (e) => {
300
+ const target = e.target;
301
+ if (willOpenKeyboard(target) && target !== document.activeElement) {
302
+ e.preventDefault();
303
+ target.style.transform = "translateY(-2000px)";
304
+ target.focus();
305
+ requestAnimationFrame(() => {
306
+ target.style.transform = "";
307
+ });
308
+ }
309
+ };
310
+ const onFocus = (e) => {
311
+ const target = e.target;
312
+ if (willOpenKeyboard(target)) {
313
+ target.style.transform = "translateY(-2000px)";
314
+ requestAnimationFrame(() => {
315
+ target.style.transform = "";
316
+ if (visualViewport) {
317
+ if (visualViewport.height < window.innerHeight) {
318
+ requestAnimationFrame(() => {
319
+ scrollIntoView(target);
320
+ });
321
+ } else {
322
+ visualViewport.addEventListener(
323
+ "resize",
324
+ () => {
325
+ scrollIntoView(target);
326
+ },
327
+ { once: true }
328
+ );
329
+ }
330
+ }
331
+ });
332
+ }
333
+ };
334
+ const onWindowScroll = () => {
335
+ window.scrollTo(0, 0);
336
+ };
337
+ const scrollX = window.pageXOffset;
338
+ const scrollY = window.pageYOffset;
339
+ const restoreStyles = utils.chain(
340
+ setStyle(
341
+ document.documentElement,
342
+ "paddingRight",
343
+ `${window.innerWidth - document.documentElement.clientWidth}px`
344
+ ),
345
+ setStyle(document.documentElement, "overflow", "hidden"),
346
+ setStyle(document.body, "marginTop", `-${scrollY}px`)
347
+ );
348
+ window.scrollTo(0, 0);
349
+ const removeEvents = utils.chain(
350
+ addEvent(document, "touchstart", onTouchStart, {
351
+ passive: false,
352
+ capture: true
353
+ }),
354
+ addEvent(document, "touchmove", onTouchMove, {
355
+ passive: false,
356
+ capture: true
357
+ }),
358
+ addEvent(document, "touchend", onTouchEnd, {
359
+ passive: false,
360
+ capture: true
361
+ }),
362
+ addEvent(document, "focus", onFocus, true),
363
+ addEvent(window, "scroll", onWindowScroll)
364
+ );
365
+ return () => {
366
+ restoreStyles();
367
+ removeEvents();
368
+ window.scrollTo(scrollX, scrollY);
369
+ };
370
+ }
371
+ function setStyle(element, style, value) {
372
+ const cur = element.style[style];
373
+ element.style[style] = value;
374
+ return () => {
375
+ element.style[style] = cur;
376
+ };
377
+ }
378
+ function addEvent(target, event, handler, options) {
379
+ target.addEventListener(event, handler, options);
380
+ return () => {
381
+ target.removeEventListener(event, handler, options);
382
+ };
383
+ }
384
+ function scrollIntoView(target) {
385
+ const root = document.scrollingElement || document.documentElement;
386
+ while (target && target !== root) {
387
+ const scrollable = utils.getScrollParent(target);
388
+ if (scrollable !== document.documentElement && scrollable !== document.body && scrollable !== target) {
389
+ const scrollableTop = scrollable.getBoundingClientRect().top;
390
+ const targetTop = target.getBoundingClientRect().top;
391
+ if (targetTop > scrollableTop + target.clientHeight) {
392
+ scrollable.scrollTop += targetTop - scrollableTop;
393
+ }
394
+ }
395
+ target = scrollable.parentElement;
396
+ }
397
+ }
398
+ function willOpenKeyboard(target) {
399
+ return target instanceof HTMLInputElement && !nonTextInputTypes.has(target.type) || target instanceof HTMLTextAreaElement || target instanceof HTMLElement && target.isContentEditable;
400
+ }
401
+
402
+ // src/styles.ts
403
+ var styles = {
404
+ wrapper: {
405
+ position: "fixed",
406
+ top: 0,
407
+ bottom: 0,
408
+ left: 0,
409
+ right: 0,
410
+ overflow: "hidden",
411
+ pointerEvents: "none"
412
+ },
413
+ backdrop: {
414
+ zIndex: 1,
415
+ position: "fixed",
416
+ top: 0,
417
+ left: 0,
418
+ width: "100%",
419
+ height: "100%",
420
+ backgroundColor: "rgba(0, 0, 0, 0.2)",
421
+ touchAction: "none",
422
+ // Disable iOS body scrolling
423
+ border: "none"
424
+ },
425
+ container: {
426
+ zIndex: 2,
427
+ position: "absolute",
428
+ left: 0,
429
+ bottom: 0,
430
+ width: "100%",
431
+ backgroundColor: "#fff",
432
+ borderTopRightRadius: "8px",
433
+ borderTopLeftRadius: "8px",
434
+ boxShadow: "0px -2px 16px rgba(0, 0, 0, 0.3)",
435
+ display: "flex",
436
+ flexDirection: "column",
437
+ pointerEvents: "auto"
438
+ },
439
+ headerWrapper: {
440
+ width: "100%"
441
+ },
442
+ header: {
443
+ height: "40px",
444
+ width: "100%",
445
+ position: "relative",
446
+ display: "flex",
447
+ alignItems: "center",
448
+ justifyContent: "center"
449
+ },
450
+ indicator: {
451
+ width: "18px",
452
+ height: "4px",
453
+ borderRadius: "99px",
454
+ backgroundColor: "#ddd"
455
+ },
456
+ content: {
457
+ flexGrow: 1,
458
+ display: "flex",
459
+ flexDirection: "column",
460
+ minHeight: "0px",
461
+ position: "relative"
462
+ },
463
+ scroller: {
464
+ height: "100%",
465
+ overflowY: "auto"
466
+ }
467
+ };
468
+ var styles_default = styles;
469
+
470
+ // src/sheet.tsx
471
+ var Sheet = React2.forwardRef(
472
+ ({
473
+ onOpenStart,
474
+ onOpenEnd,
475
+ onClose,
476
+ onCloseStart,
477
+ onCloseEnd,
478
+ onSnap,
479
+ children,
480
+ disableScrollLocking = false,
481
+ isOpen,
482
+ snapPoints,
483
+ rootId,
484
+ mountPoint,
485
+ style,
486
+ detent = "full-height",
487
+ initialSnap = 0,
488
+ disableDrag = false,
489
+ prefersReducedMotion = false,
490
+ tweenConfig = DEFAULT_TWEEN_CONFIG,
491
+ ...rest
492
+ }, ref) => {
493
+ const sheetRef = React2.useRef(null);
494
+ const constraintsRef = React2.useRef(null);
495
+ const indicatorRotation = framerMotion.useMotionValue(0);
496
+ const { height: windowHeight } = useDimensions();
497
+ const shouldReduceMotion = framerMotion.useReducedMotion();
498
+ const reduceMotion = Boolean(prefersReducedMotion || shouldReduceMotion);
499
+ const animationOptions = {
500
+ type: "tween",
501
+ ...reduceMotion ? REDUCED_MOTION_TWEEN_CONFIG : tweenConfig
502
+ };
503
+ const y = framerMotion.useMotionValue(0);
504
+ const zIndex = framerMotion.useTransform(
505
+ y,
506
+ (value) => value >= windowHeight ? -1 : 9999999
507
+ );
508
+ const visibility = framerMotion.useTransform(
509
+ y,
510
+ (value) => value >= windowHeight ? "hidden" : "visible"
511
+ );
512
+ const callbacks = React2.useRef({
513
+ onOpenStart,
514
+ onOpenEnd,
515
+ onCloseStart,
516
+ onCloseEnd
517
+ });
518
+ useIsomorphicLayoutEffect(() => {
519
+ callbacks.current = {
520
+ onOpenStart,
521
+ onOpenEnd,
522
+ onCloseStart,
523
+ onCloseEnd
524
+ };
525
+ });
526
+ if (snapPoints) {
527
+ snapPoints = snapPoints.map((point) => {
528
+ if (point > 0 && point <= 1)
529
+ return Math.round(point * windowHeight);
530
+ return point < 0 ? windowHeight + point : point;
531
+ });
532
+ console.assert(
533
+ inDescendingOrder(snapPoints) || windowHeight === 0,
534
+ `Snap points need to be in descending order got: [${snapPoints.join(
535
+ ", "
536
+ )}]`
537
+ );
538
+ }
539
+ const onDrag = useEvent((_, { delta }) => {
540
+ const velocity = y.getVelocity();
541
+ if (velocity > 0)
542
+ indicatorRotation.set(10);
543
+ if (velocity < 0)
544
+ indicatorRotation.set(-10);
545
+ y.set(Math.max(y.get() + delta.y, 0));
546
+ });
547
+ const onDragEnd = useEvent((_, { velocity }) => {
548
+ if (velocity.y > DRAG_VELOCITY_THRESHOLD) {
549
+ onClose();
550
+ } else {
551
+ const sheetEl = sheetRef.current;
552
+ const sheetHeight = sheetEl.getBoundingClientRect().height;
553
+ const currentY = y.get();
554
+ let snapTo = 0;
555
+ if (snapPoints) {
556
+ const snapToValues = snapPoints.map(
557
+ (p) => sheetHeight - Math.min(p, sheetHeight)
558
+ );
559
+ if (detent === "content-height" && !snapToValues.includes(0)) {
560
+ snapToValues.unshift(0);
561
+ }
562
+ snapTo = getClosest(snapToValues, currentY);
563
+ } else if (currentY / sheetHeight > DRAG_CLOSE_THRESHOLD) {
564
+ snapTo = sheetHeight;
565
+ }
566
+ snapTo = validateSnapTo({ snapTo, sheetHeight });
567
+ void framerMotion.animate(y, snapTo, animationOptions);
568
+ if (snapPoints && onSnap) {
569
+ const snapValue = Math.abs(Math.round(snapPoints[0] - snapTo));
570
+ const snapIndex = snapPoints.indexOf(getClosest(snapPoints, snapValue));
571
+ onSnap(snapIndex);
572
+ }
573
+ const roundedSheetHeight = Math.round(sheetHeight);
574
+ const shouldClose = snapTo >= roundedSheetHeight;
575
+ if (shouldClose)
576
+ onClose();
577
+ }
578
+ indicatorRotation.set(0);
579
+ });
580
+ React2.useEffect(() => {
581
+ if (!snapPoints || !onSnap)
582
+ return;
583
+ const snapIndex = isOpen ? initialSnap : snapPoints.length - 1;
584
+ onSnap(snapIndex);
585
+ }, [isOpen]);
586
+ React2.useImperativeHandle(ref, () => ({
587
+ y,
588
+ snapTo: (snapIndex) => {
589
+ const sheetEl = sheetRef.current;
590
+ if ((snapPoints == null ? void 0 : snapPoints[snapIndex]) !== void 0 && sheetEl !== null) {
591
+ const sheetHeight = sheetEl.getBoundingClientRect().height;
592
+ const snapPoint = snapPoints[snapIndex];
593
+ const snapTo = validateSnapTo({
594
+ snapTo: sheetHeight - snapPoint,
595
+ sheetHeight
596
+ });
597
+ void framerMotion.animate(y, snapTo, animationOptions);
598
+ if (onSnap)
599
+ onSnap(snapIndex);
600
+ if (snapTo >= sheetHeight)
601
+ onClose();
602
+ }
603
+ }
604
+ }));
605
+ useModalEffect(isOpen, rootId);
606
+ usePreventScroll({ isDisabled: disableScrollLocking || !isOpen });
607
+ const dragProps = React2.useMemo(() => {
608
+ const dragProps2 = {
609
+ drag: "y",
610
+ dragElastic: 0,
611
+ dragMomentum: false,
612
+ dragPropagation: false,
613
+ onDrag,
614
+ onDragEnd
615
+ };
616
+ return disableDrag ? void 0 : dragProps2;
617
+ }, [disableDrag, windowHeight]);
618
+ const context = {
619
+ y,
620
+ sheetRef,
621
+ isOpen,
622
+ initialSnap,
623
+ snapPoints,
624
+ detent,
625
+ indicatorRotation,
626
+ callbacks,
627
+ dragProps,
628
+ windowHeight,
629
+ animationOptions,
630
+ reduceMotion,
631
+ disableDrag
632
+ };
633
+ const sheet = /* @__PURE__ */ React2__default.default.createElement(SheetContext.Provider, { value: context }, /* @__PURE__ */ React2__default.default.createElement(
634
+ framerMotion.motion.div,
635
+ {
636
+ ...rest,
637
+ ref: mergeRefs([ref, constraintsRef]),
638
+ style: { ...styles_default.wrapper, zIndex, visibility, ...style }
639
+ },
640
+ /* @__PURE__ */ React2__default.default.createElement(framerMotion.AnimatePresence, null, isOpen ? /* @__PURE__ */ React2__default.default.createElement(SheetScrollerContextProvider, null, React2.Children.map(
641
+ children,
642
+ (child, i) => React2.cloneElement(child, { key: `sheet-child-${i}` })
643
+ )) : null)
644
+ ));
645
+ if (IS_SSR)
646
+ return sheet;
647
+ return reactDom.createPortal(sheet, mountPoint ?? document.body);
648
+ }
649
+ );
650
+ Sheet.displayName = "Sheet";
651
+ var sheet_default = Sheet;
652
+ var SheetContainer = React2.forwardRef(
653
+ ({ children, style = {}, className = "", ...rest }, ref) => {
654
+ const {
655
+ y,
656
+ isOpen,
657
+ callbacks,
658
+ snapPoints,
659
+ initialSnap = 0,
660
+ sheetRef,
661
+ windowHeight,
662
+ detent,
663
+ animationOptions,
664
+ reduceMotion
665
+ } = useSheetContext();
666
+ const { handleAnimationComplete } = useEventCallbacks(isOpen, callbacks);
667
+ const initialY = snapPoints ? snapPoints[0] - snapPoints[initialSnap] : 0;
668
+ const maxSnapHeight = snapPoints ? snapPoints[0] : null;
669
+ const height = maxSnapHeight !== null ? `min(${maxSnapHeight}px, ${MAX_HEIGHT})` : MAX_HEIGHT;
670
+ return /* @__PURE__ */ React2__default.default.createElement(
671
+ framerMotion.motion.div,
672
+ {
673
+ ...rest,
674
+ ref: mergeRefs([sheetRef, ref]),
675
+ className: `react-modal-sheet-container ${className}`,
676
+ style: {
677
+ ...styles_default.container,
678
+ ...style,
679
+ ...detent === "full-height" && { height },
680
+ ...detent === "content-height" && { maxHeight: height },
681
+ y
682
+ },
683
+ initial: reduceMotion ? false : { y: windowHeight },
684
+ animate: { y: initialY, transition: animationOptions },
685
+ exit: { y: windowHeight, transition: animationOptions },
686
+ onAnimationComplete: handleAnimationComplete
687
+ },
688
+ children
689
+ );
690
+ }
691
+ );
692
+ SheetContainer.displayName = "SheetContainer";
693
+ var SheetContainer_default = SheetContainer;
694
+ var SheetContent = React2.forwardRef(
695
+ ({ children, style, disableDrag, className = "", ...rest }, ref) => {
696
+ const sheetContext = useSheetContext();
697
+ const sheetScrollerContext = useSheetScrollerContext();
698
+ const { constraintsRef, onMeasureDragConstraints } = useDragConstraints();
699
+ const dragProps = disableDrag || sheetScrollerContext.disableDrag ? void 0 : sheetContext.dragProps;
700
+ return /* @__PURE__ */ React2__default.default.createElement(
701
+ framerMotion.motion.div,
702
+ {
703
+ ...rest,
704
+ ref: mergeRefs([ref, constraintsRef]),
705
+ className: `react-modal-sheet-content ${className}`,
706
+ style: { ...styles_default.content, ...style },
707
+ ...dragProps,
708
+ dragConstraints: constraintsRef,
709
+ onMeasureDragConstraints
710
+ },
711
+ children
712
+ );
713
+ }
714
+ );
715
+ SheetContent.displayName = "SheetContent";
716
+ var SheetContent_default = SheetContent;
717
+ var SheetHeader = React2.forwardRef(
718
+ ({ children, style, disableDrag, ...rest }, ref) => {
719
+ const { indicatorRotation, dragProps } = useSheetContext();
720
+ const { constraintsRef, onMeasureDragConstraints } = useDragConstraints();
721
+ const _dragProps = disableDrag ? void 0 : dragProps;
722
+ const indicator1Transform = framerMotion.useTransform(
723
+ indicatorRotation,
724
+ (r) => `translateX(2px) rotate(${r}deg)`
725
+ );
726
+ const indicator2Transform = framerMotion.useTransform(
727
+ indicatorRotation,
728
+ (r) => `translateX(-2px) rotate(${-1 * r}deg)`
729
+ );
730
+ return /* @__PURE__ */ React2__default.default.createElement(
731
+ framerMotion.motion.div,
732
+ {
733
+ ...rest,
734
+ ref: mergeRefs([ref, constraintsRef]),
735
+ style: { ...styles_default.headerWrapper, ...style },
736
+ ..._dragProps,
737
+ dragConstraints: constraintsRef,
738
+ onMeasureDragConstraints
739
+ },
740
+ children || /* @__PURE__ */ React2__default.default.createElement("div", { className: "react-modal-sheet-header", style: styles_default.header }, /* @__PURE__ */ React2__default.default.createElement(
741
+ framerMotion.motion.span,
742
+ {
743
+ className: "react-modal-sheet-drag-indicator",
744
+ style: { ...styles_default.indicator, transform: indicator1Transform }
745
+ }
746
+ ), /* @__PURE__ */ React2__default.default.createElement(
747
+ framerMotion.motion.span,
748
+ {
749
+ className: "react-modal-sheet-drag-indicator",
750
+ style: { ...styles_default.indicator, transform: indicator2Transform }
751
+ }
752
+ ))
753
+ );
754
+ }
755
+ );
756
+ SheetHeader.displayName = "SheetHeader";
757
+ var SheetHeader_default = SheetHeader;
758
+ var isClickable = (props) => !!props.onClick || !!props.onTap;
759
+ var SheetBackdrop = React2.forwardRef(
760
+ ({ style = {}, className = "", ...rest }, ref) => {
761
+ const Comp = isClickable(rest) ? framerMotion.motion.button : framerMotion.motion.div;
762
+ const pointerEvents = isClickable(rest) ? "auto" : "none";
763
+ return /* @__PURE__ */ React2__default.default.createElement(
764
+ Comp,
765
+ {
766
+ ...rest,
767
+ ref,
768
+ className: `react-modal-sheet-backdrop ${className}`,
769
+ style: { ...styles_default.backdrop, ...style, pointerEvents },
770
+ initial: { opacity: 0 },
771
+ animate: { opacity: 1 },
772
+ exit: { opacity: 0 }
773
+ }
774
+ );
775
+ }
776
+ );
777
+ SheetBackdrop.displayName = "SheetBackdrop";
778
+ var SheetBackdrop_default = SheetBackdrop;
779
+ var SheetScroller = React2.forwardRef(
780
+ ({ draggableAt = "top", children, style, className = "", ...rest }, ref) => {
781
+ const sheetScrollerContext = useSheetScrollerContext();
782
+ function determineDragState(element) {
783
+ const { scrollTop, scrollHeight, clientHeight } = element;
784
+ const isScrollable = scrollHeight > clientHeight;
785
+ if (!isScrollable)
786
+ return;
787
+ const isAtTop = scrollTop <= 0;
788
+ const isAtBottom = scrollHeight - scrollTop === clientHeight;
789
+ const shouldEnable = draggableAt === "top" && isAtTop || draggableAt === "bottom" && isAtBottom || draggableAt === "both" && (isAtTop || isAtBottom);
790
+ if (shouldEnable) {
791
+ sheetScrollerContext.setDragEnabled();
792
+ } else {
793
+ sheetScrollerContext.setDragDisabled();
794
+ }
795
+ }
796
+ function onScroll(e) {
797
+ determineDragState(e.currentTarget);
798
+ }
799
+ function onTouchStart(e) {
800
+ determineDragState(e.currentTarget);
801
+ }
802
+ const scrollProps = isTouchDevice() ? { onScroll, onTouchStart } : void 0;
803
+ return /* @__PURE__ */ React2__default.default.createElement(
804
+ "div",
805
+ {
806
+ ...rest,
807
+ ref,
808
+ className: `react-modal-sheet-scroller ${className}`,
809
+ style: { ...styles_default.scroller, ...style },
810
+ ...scrollProps
811
+ },
812
+ children
813
+ );
814
+ }
815
+ );
816
+ SheetScroller.displayName = "SheetScroller";
817
+ var SheetScroller_default = SheetScroller;
818
+
819
+ // src/index.tsx
820
+ var _SheetCompound = sheet_default;
821
+ _SheetCompound.Container = SheetContainer_default;
822
+ _SheetCompound.Header = SheetHeader_default;
823
+ _SheetCompound.Content = SheetContent_default;
824
+ _SheetCompound.Backdrop = SheetBackdrop_default;
825
+ _SheetCompound.Scroller = SheetScroller_default;
826
+ var Sheet2 = _SheetCompound;
827
+
828
+ exports.Sheet = Sheet2;
829
+ //# sourceMappingURL=out.js.map
830
+ //# sourceMappingURL=index.js.map