react-modal-sheet 1.11.0 → 2.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/README.md +81 -51
- package/dist/SheetBackdrop.d.ts +1 -1
- package/dist/SheetContainer.d.ts +1 -1
- package/dist/SheetContent.d.ts +1 -1
- package/dist/SheetHeader.d.ts +1 -1
- package/dist/SheetScroller.d.ts +5 -0
- package/dist/constants.d.ts +7 -4
- package/dist/context.d.ts +6 -1
- package/dist/hooks.d.ts +2 -2
- package/dist/react-modal-sheet.cjs.development.js +137 -63
- 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 +138 -64
- package/dist/react-modal-sheet.esm.js.map +1 -1
- package/dist/sheet.d.ts +1 -1
- package/dist/types.d.ts +17 -2
- package/dist/utils.d.ts +1 -0
- package/package.json +2 -3
- package/src/SheetContent.tsx +9 -4
- package/src/SheetScroller.tsx +59 -0
- package/src/constants.ts +8 -4
- package/src/context.tsx +38 -1
- package/src/hooks.tsx +5 -5
- package/src/index.tsx +2 -0
- package/src/sheet.tsx +19 -13
- package/src/styles.ts +9 -3
- package/src/types.tsx +24 -3
- package/src/utils.ts +20 -26
|
@@ -42,20 +42,32 @@ function _objectWithoutPropertiesLoose(source, excluded) {
|
|
|
42
42
|
|
|
43
43
|
var MAX_HEIGHT = 'calc(100% - env(safe-area-inset-top) - 34px)';
|
|
44
44
|
var IS_SSR = typeof window === 'undefined';
|
|
45
|
-
var
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
var DEFAULT_TWEEN_CONFIG = {
|
|
46
|
+
ease: 'easeOut',
|
|
47
|
+
duration: 0.2
|
|
48
|
+
};
|
|
49
|
+
var REDUCED_MOTION_TWEEN_CONFIG = {
|
|
50
|
+
ease: 'linear',
|
|
51
|
+
duration: 0.01
|
|
49
52
|
};
|
|
50
53
|
var DRAG_CLOSE_THRESHOLD = 0.6;
|
|
51
54
|
var DRAG_VELOCITY_THRESHOLD = 500;
|
|
52
55
|
|
|
53
56
|
function getClosest(nums, goal) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
var closest = nums[0];
|
|
58
|
+
var minDifference = Math.abs(nums[0] - goal);
|
|
59
|
+
|
|
60
|
+
for (var i = 1; i < nums.length; i++) {
|
|
61
|
+
var difference = Math.abs(nums[i] - goal);
|
|
62
|
+
|
|
63
|
+
if (difference < minDifference) {
|
|
64
|
+
closest = nums[i];
|
|
65
|
+
minDifference = difference;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return closest;
|
|
57
70
|
}
|
|
58
|
-
var highlightId = 'react-modal-sheet-highlight';
|
|
59
71
|
function applyRootStyles(rootId) {
|
|
60
72
|
var body = document.querySelector('body');
|
|
61
73
|
var root = document.querySelector("#" + rootId);
|
|
@@ -67,51 +79,30 @@ function applyRootStyles(rootId) {
|
|
|
67
79
|
body.style.backgroundColor = '#000';
|
|
68
80
|
root.style.overflow = 'hidden';
|
|
69
81
|
root.style.willChange = 'transform';
|
|
70
|
-
root.style.transition = 'transform 200ms linear';
|
|
82
|
+
root.style.transition = 'transform 200ms ease-in-out, border-radius 200ms linear';
|
|
71
83
|
root.style.transform = "translateY(calc(env(safe-area-inset-top) + " + p / 2 + "px)) scale(" + s + ")"; // prettier-ignore
|
|
72
84
|
|
|
73
85
|
root.style.borderTopRightRadius = '10px';
|
|
74
|
-
root.style.borderTopLeftRadius = '10px';
|
|
75
|
-
|
|
76
|
-
var highlight = document.createElement('div');
|
|
77
|
-
highlight.setAttribute('aria-hidden', 'true');
|
|
78
|
-
highlight.id = highlightId;
|
|
79
|
-
highlight.style.position = 'absolute';
|
|
80
|
-
highlight.style.top = '0px';
|
|
81
|
-
highlight.style.left = '0px';
|
|
82
|
-
highlight.style.bottom = '0px';
|
|
83
|
-
highlight.style.right = '0px';
|
|
84
|
-
highlight.style.opacity = '0';
|
|
85
|
-
highlight.style.transition = 'opacity 200ms linear';
|
|
86
|
-
highlight.style.backgroundColor = 'rgba(150, 150, 150, 0.1)';
|
|
87
|
-
root.appendChild(highlight);
|
|
88
|
-
requestAnimationFrame(function () {
|
|
89
|
-
return highlight.style.opacity = '1';
|
|
90
|
-
});
|
|
86
|
+
root.style.borderTopLeftRadius = '10px';
|
|
91
87
|
}
|
|
92
88
|
}
|
|
93
89
|
function cleanupRootStyles(rootId) {
|
|
94
90
|
var body = document.querySelector('body');
|
|
95
91
|
var root = document.getElementById(rootId);
|
|
96
|
-
var highlight = document.getElementById(highlightId);
|
|
97
92
|
|
|
98
93
|
function onTransitionEnd() {
|
|
99
|
-
var _highlight$parentNode;
|
|
100
|
-
|
|
101
94
|
root.style.removeProperty('overflow');
|
|
102
95
|
root.style.removeProperty('will-change');
|
|
103
96
|
root.style.removeProperty('transition');
|
|
104
97
|
body.style.removeProperty('background-color');
|
|
105
98
|
root.removeEventListener('transitionend', onTransitionEnd);
|
|
106
|
-
(_highlight$parentNode = highlight.parentNode) == null ? void 0 : _highlight$parentNode.removeChild(highlight);
|
|
107
99
|
}
|
|
108
100
|
|
|
109
|
-
if (root
|
|
101
|
+
if (root) {
|
|
110
102
|
// Start animating back
|
|
111
103
|
root.style.removeProperty('border-top-right-radius');
|
|
112
104
|
root.style.removeProperty('border-top-left-radius');
|
|
113
|
-
root.style.removeProperty('transform');
|
|
114
|
-
highlight.style.opacity = '0'; // Remove temp properties after animation is finished
|
|
105
|
+
root.style.removeProperty('transform'); // Remove temp properties after animation is finished
|
|
115
106
|
|
|
116
107
|
root.addEventListener('transitionend', onTransitionEnd);
|
|
117
108
|
}
|
|
@@ -144,9 +135,13 @@ function mergeRefs(refs) {
|
|
|
144
135
|
});
|
|
145
136
|
};
|
|
146
137
|
}
|
|
138
|
+
function isTouchDevice() {
|
|
139
|
+
if (typeof window === 'undefined') return false;
|
|
140
|
+
return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
|
141
|
+
}
|
|
147
142
|
|
|
148
143
|
var useIsomorphicLayoutEffect = IS_SSR ? React.useEffect : React.useLayoutEffect;
|
|
149
|
-
|
|
144
|
+
function useModalEffect(isOpen, rootId) {
|
|
150
145
|
var prevOpen = usePrevious(isOpen); // Automatically apply the iOS modal effect to the body when sheet opens/closes
|
|
151
146
|
|
|
152
147
|
React.useEffect(function () {
|
|
@@ -163,8 +158,8 @@ var useModalEffect = function useModalEffect(isOpen, rootId) {
|
|
|
163
158
|
if (rootId && isOpen) cleanupRootStyles(rootId);
|
|
164
159
|
};
|
|
165
160
|
}, [isOpen]); // eslint-disable-line
|
|
166
|
-
}
|
|
167
|
-
|
|
161
|
+
}
|
|
162
|
+
function useEventCallbacks(isOpen, callbacks) {
|
|
168
163
|
var prevOpen = usePrevious(isOpen);
|
|
169
164
|
var didOpen = React.useRef(false); // Because of AnimatePrecence we don't have access to latest isOpen value
|
|
170
165
|
// so we need to read and write to a ref to determine if we are
|
|
@@ -191,7 +186,7 @@ var useEventCallbacks = function useEventCallbacks(isOpen, callbacks) {
|
|
|
191
186
|
return {
|
|
192
187
|
handleAnimationComplete: handleAnimationComplete
|
|
193
188
|
};
|
|
194
|
-
}
|
|
189
|
+
}
|
|
195
190
|
function useWindowHeight() {
|
|
196
191
|
var _React$useState = React.useState(0),
|
|
197
192
|
windowHeight = _React$useState[0],
|
|
@@ -241,6 +236,36 @@ var useSheetContext = function useSheetContext() {
|
|
|
241
236
|
if (!context) throw Error('Sheet context error');
|
|
242
237
|
return context;
|
|
243
238
|
};
|
|
239
|
+
var SheetScrollerContext = /*#__PURE__*/React.createContext(undefined);
|
|
240
|
+
function SheetScrollerContextProvider(_ref) {
|
|
241
|
+
var children = _ref.children;
|
|
242
|
+
var sheetContext = useSheetContext();
|
|
243
|
+
|
|
244
|
+
var _React$useState = React.useState(!!sheetContext.disableDrag),
|
|
245
|
+
disableDrag = _React$useState[0],
|
|
246
|
+
setDisableDrag = _React$useState[1];
|
|
247
|
+
|
|
248
|
+
function setDragEnabled() {
|
|
249
|
+
if (!sheetContext.disableDrag) setDisableDrag(false);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function setDragDisabled() {
|
|
253
|
+
if (!disableDrag) setDisableDrag(true);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return React.createElement(SheetScrollerContext.Provider, {
|
|
257
|
+
value: {
|
|
258
|
+
disableDrag: disableDrag,
|
|
259
|
+
setDragEnabled: setDragEnabled,
|
|
260
|
+
setDragDisabled: setDragDisabled
|
|
261
|
+
}
|
|
262
|
+
}, children);
|
|
263
|
+
}
|
|
264
|
+
var useSheetScrollerContext = function useSheetScrollerContext() {
|
|
265
|
+
var context = React.useContext(SheetScrollerContext);
|
|
266
|
+
if (!context) throw Error('Sheet scroller context error');
|
|
267
|
+
return context;
|
|
268
|
+
};
|
|
244
269
|
|
|
245
270
|
// Source: https://github.com/adobe/react-spectrum/blob/main/packages/@react-aria/overlays/src/usePreventScroll.ts
|
|
246
271
|
|
|
@@ -500,7 +525,7 @@ var styles = {
|
|
|
500
525
|
left: 0,
|
|
501
526
|
width: '100%',
|
|
502
527
|
height: '100%',
|
|
503
|
-
backgroundColor: 'rgba(
|
|
528
|
+
backgroundColor: 'rgba(0, 0, 0, 0.2)',
|
|
504
529
|
touchAction: 'none',
|
|
505
530
|
border: 'none'
|
|
506
531
|
},
|
|
@@ -536,9 +561,15 @@ var styles = {
|
|
|
536
561
|
backgroundColor: '#ddd'
|
|
537
562
|
},
|
|
538
563
|
content: {
|
|
539
|
-
|
|
540
|
-
|
|
564
|
+
flexGrow: 1,
|
|
565
|
+
display: 'flex',
|
|
566
|
+
flexDirection: 'column',
|
|
567
|
+
minHeight: '0px',
|
|
541
568
|
position: 'relative'
|
|
569
|
+
},
|
|
570
|
+
scroller: {
|
|
571
|
+
height: '100%',
|
|
572
|
+
overflowY: 'auto'
|
|
542
573
|
}
|
|
543
574
|
};
|
|
544
575
|
|
|
@@ -559,28 +590,27 @@ var Sheet = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
559
590
|
detent = _ref$detent === void 0 ? 'full-height' : _ref$detent,
|
|
560
591
|
_ref$initialSnap = _ref.initialSnap,
|
|
561
592
|
initialSnap = _ref$initialSnap === void 0 ? 0 : _ref$initialSnap,
|
|
562
|
-
_ref$springConfig = _ref.springConfig,
|
|
563
|
-
springConfig = _ref$springConfig === void 0 ? DEFAULT_SPRING_CONFIG : _ref$springConfig,
|
|
564
593
|
_ref$disableDrag = _ref.disableDrag,
|
|
565
594
|
disableDrag = _ref$disableDrag === void 0 ? false : _ref$disableDrag,
|
|
566
595
|
_ref$prefersReducedMo = _ref.prefersReducedMotion,
|
|
567
596
|
prefersReducedMotion = _ref$prefersReducedMo === void 0 ? false : _ref$prefersReducedMo,
|
|
568
|
-
|
|
597
|
+
_ref$tweenConfig = _ref.tweenConfig,
|
|
598
|
+
tweenConfig = _ref$tweenConfig === void 0 ? DEFAULT_TWEEN_CONFIG : _ref$tweenConfig,
|
|
599
|
+
rest = _objectWithoutPropertiesLoose(_ref, ["onOpenStart", "onOpenEnd", "onClose", "onCloseStart", "onCloseEnd", "onSnap", "children", "isOpen", "snapPoints", "rootId", "mountPoint", "style", "detent", "initialSnap", "disableDrag", "prefersReducedMotion", "tweenConfig"]);
|
|
569
600
|
|
|
570
601
|
var sheetRef = React.useRef(null);
|
|
571
602
|
var indicatorRotation = framerMotion.useMotionValue(0);
|
|
572
603
|
var windowHeight = useWindowHeight();
|
|
573
604
|
var shouldReduceMotion = framerMotion.useReducedMotion();
|
|
574
605
|
var reduceMotion = Boolean(prefersReducedMotion || shouldReduceMotion);
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
} :
|
|
579
|
-
type: 'spring'
|
|
580
|
-
}, springConfig); // NOTE: the inital value for `y` doesn't matter since it is overwritten by
|
|
606
|
+
|
|
607
|
+
var animationOptions = _extends({
|
|
608
|
+
type: 'tween'
|
|
609
|
+
}, reduceMotion ? REDUCED_MOTION_TWEEN_CONFIG : tweenConfig); // NOTE: the inital value for `y` doesn't matter since it is overwritten by
|
|
581
610
|
// the value driven by the `AnimatePresence` component when the sheet is opened
|
|
582
611
|
// and after that it is driven by the gestures and/or snapping
|
|
583
612
|
|
|
613
|
+
|
|
584
614
|
var y = framerMotion.useMotionValue(0);
|
|
585
615
|
var zIndex = framerMotion.useTransform(y, function (value) {
|
|
586
616
|
return value >= windowHeight ? -1 : 9999999;
|
|
@@ -638,11 +668,8 @@ var Sheet = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
638
668
|
|
|
639
669
|
if (snapPoints) {
|
|
640
670
|
var snapToValues = snapPoints.map(function (p) {
|
|
641
|
-
return sheetHeight - p;
|
|
642
|
-
})
|
|
643
|
-
return p >= 0;
|
|
644
|
-
}); // negative values can occur with `content-height` detent
|
|
645
|
-
// Allow snapping to the top of the sheet if detent is set to `content-height`
|
|
671
|
+
return sheetHeight - Math.min(p, sheetHeight);
|
|
672
|
+
}); // Allow snapping to the top of the sheet if detent is set to `content-height`
|
|
646
673
|
|
|
647
674
|
if (detent === 'content-height' && !snapToValues.includes(0)) {
|
|
648
675
|
snapToValues.unshift(0);
|
|
@@ -738,7 +765,8 @@ var Sheet = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
738
765
|
dragProps: dragProps,
|
|
739
766
|
windowHeight: windowHeight,
|
|
740
767
|
animationOptions: animationOptions,
|
|
741
|
-
reduceMotion: reduceMotion
|
|
768
|
+
reduceMotion: reduceMotion,
|
|
769
|
+
disableDrag: disableDrag
|
|
742
770
|
};
|
|
743
771
|
var sheet = React.createElement(SheetContext.Provider, {
|
|
744
772
|
value: context
|
|
@@ -748,11 +776,11 @@ var Sheet = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
748
776
|
zIndex: zIndex,
|
|
749
777
|
visibility: visibility
|
|
750
778
|
}, style)
|
|
751
|
-
}), React.createElement(framerMotion.AnimatePresence, null, isOpen ? React.Children.map(children, function (child, i) {
|
|
779
|
+
}), React.createElement(framerMotion.AnimatePresence, null, isOpen ? React.createElement(SheetScrollerContextProvider, null, React.Children.map(children, function (child, i) {
|
|
752
780
|
return React.cloneElement(child, {
|
|
753
781
|
key: "sheet-child-" + i
|
|
754
782
|
});
|
|
755
|
-
}) : null)));
|
|
783
|
+
})) : null)));
|
|
756
784
|
if (IS_SSR) return sheet;
|
|
757
785
|
return ReactDOM.createPortal(sheet, mountPoint != null ? mountPoint : document.body);
|
|
758
786
|
});
|
|
@@ -817,16 +845,14 @@ var SheetContent = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
817
845
|
className = _ref$className === void 0 ? '' : _ref$className,
|
|
818
846
|
rest = _objectWithoutPropertiesLoose(_ref, ["children", "style", "disableDrag", "className"]);
|
|
819
847
|
|
|
820
|
-
var
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
var _dragProps = disableDrag ? undefined : dragProps;
|
|
824
|
-
|
|
848
|
+
var sheetContext = useSheetContext();
|
|
849
|
+
var sheetScrollerContext = useSheetScrollerContext();
|
|
850
|
+
var dragProps = disableDrag || sheetScrollerContext.disableDrag ? undefined : sheetContext.dragProps;
|
|
825
851
|
return React.createElement(framerMotion.motion.div, Object.assign({}, rest, {
|
|
826
852
|
ref: ref,
|
|
827
853
|
className: "react-modal-sheet-content " + className,
|
|
828
854
|
style: _extends({}, styles.content, style)
|
|
829
|
-
},
|
|
855
|
+
}, dragProps), children);
|
|
830
856
|
});
|
|
831
857
|
|
|
832
858
|
var SheetHeader = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
@@ -897,11 +923,59 @@ var SheetBackdrop = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
897
923
|
}));
|
|
898
924
|
});
|
|
899
925
|
|
|
926
|
+
var SheetScroller = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
927
|
+
var _ref$draggableAt = _ref.draggableAt,
|
|
928
|
+
draggableAt = _ref$draggableAt === void 0 ? 'top' : _ref$draggableAt,
|
|
929
|
+
children = _ref.children,
|
|
930
|
+
style = _ref.style,
|
|
931
|
+
_ref$className = _ref.className,
|
|
932
|
+
className = _ref$className === void 0 ? '' : _ref$className,
|
|
933
|
+
rest = _objectWithoutPropertiesLoose(_ref, ["draggableAt", "children", "style", "className"]);
|
|
934
|
+
|
|
935
|
+
var sheetScrollerContext = useSheetScrollerContext();
|
|
936
|
+
|
|
937
|
+
function determineDragState(element) {
|
|
938
|
+
var scrollTop = element.scrollTop,
|
|
939
|
+
scrollHeight = element.scrollHeight,
|
|
940
|
+
clientHeight = element.clientHeight;
|
|
941
|
+
var isScrollable = scrollHeight > clientHeight;
|
|
942
|
+
if (!isScrollable) return;
|
|
943
|
+
var isAtTop = scrollTop <= 0;
|
|
944
|
+
var isAtBottom = scrollHeight - scrollTop === clientHeight;
|
|
945
|
+
var shouldEnable = draggableAt === 'top' && isAtTop || draggableAt === 'bottom' && isAtBottom || draggableAt === 'both' && (isAtTop || isAtBottom);
|
|
946
|
+
|
|
947
|
+
if (shouldEnable) {
|
|
948
|
+
sheetScrollerContext.setDragEnabled();
|
|
949
|
+
} else {
|
|
950
|
+
sheetScrollerContext.setDragDisabled();
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
function onScroll(e) {
|
|
955
|
+
determineDragState(e.currentTarget);
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
function onTouchStart(e) {
|
|
959
|
+
determineDragState(e.currentTarget);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
var scrollProps = isTouchDevice() ? {
|
|
963
|
+
onScroll: onScroll,
|
|
964
|
+
onTouchStart: onTouchStart
|
|
965
|
+
} : undefined;
|
|
966
|
+
return React.createElement("div", Object.assign({}, rest, {
|
|
967
|
+
ref: ref,
|
|
968
|
+
className: "react-modal-sheet-scroller " + className,
|
|
969
|
+
style: _extends({}, styles.scroller, style)
|
|
970
|
+
}, scrollProps), children);
|
|
971
|
+
});
|
|
972
|
+
|
|
900
973
|
var _SheetCompound = Sheet;
|
|
901
974
|
_SheetCompound.Container = SheetContainer;
|
|
902
975
|
_SheetCompound.Header = SheetHeader;
|
|
903
976
|
_SheetCompound.Content = SheetContent;
|
|
904
977
|
_SheetCompound.Backdrop = SheetBackdrop;
|
|
978
|
+
_SheetCompound.Scroller = SheetScroller;
|
|
905
979
|
|
|
906
980
|
exports.default = _SheetCompound;
|
|
907
981
|
//# sourceMappingURL=react-modal-sheet.cjs.development.js.map
|