react-modal-sheet 4.4.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +332 -188
- package/dist/index.d.mts +51 -39
- package/dist/index.d.ts +51 -39
- package/dist/index.js +854 -585
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +847 -579
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -3
- package/src/SheetBackdrop.tsx +19 -6
- package/src/SheetContainer.tsx +34 -25
- package/src/SheetContent.tsx +77 -14
- package/src/SheetDragIndicator.tsx +52 -0
- package/src/SheetHeader.tsx +30 -30
- package/src/constants.ts +5 -3
- package/src/context.tsx +2 -42
- package/src/hooks/use-dimensions.ts +4 -4
- package/src/hooks/use-drag-constraints.ts +3 -3
- package/src/hooks/use-modal-effect.ts +19 -23
- package/src/hooks/use-resize-observer.ts +31 -0
- package/src/hooks/use-scroll-position.ts +72 -0
- package/src/hooks/use-sheet-state.ts +63 -0
- package/src/hooks/use-virtual-keyboard.ts +153 -0
- package/src/index.tsx +14 -10
- package/src/sheet.tsx +247 -209
- package/src/snap.ts +226 -0
- package/src/styles.ts +94 -53
- package/src/types.tsx +83 -79
- package/src/utils.ts +8 -149
- package/src/SheetScroller.tsx +0 -96
- package/src/hooks/use-event-callbacks.ts +0 -44
package/dist/index.js
CHANGED
|
@@ -1,18 +1,132 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var reactDom = require('react-dom');
|
|
4
|
-
var React2 = require('react');
|
|
5
3
|
var react = require('motion/react');
|
|
4
|
+
var React4 = require('react');
|
|
5
|
+
var reactDom = require('react-dom');
|
|
6
|
+
var useMeasure = require('react-use-measure');
|
|
6
7
|
var motion = require('motion');
|
|
7
8
|
|
|
8
9
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
10
|
|
|
10
|
-
var
|
|
11
|
+
var React4__default = /*#__PURE__*/_interopDefault(React4);
|
|
12
|
+
var useMeasure__default = /*#__PURE__*/_interopDefault(useMeasure);
|
|
11
13
|
|
|
12
|
-
// src/
|
|
14
|
+
// src/SheetBackdrop.tsx
|
|
15
|
+
var SheetContext = React4.createContext(
|
|
16
|
+
void 0
|
|
17
|
+
);
|
|
18
|
+
function useSheetContext() {
|
|
19
|
+
const context = React4.useContext(SheetContext);
|
|
20
|
+
if (!context) throw new Error("Sheet context error");
|
|
21
|
+
return context;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/styles.ts
|
|
25
|
+
var styles = {
|
|
26
|
+
root: {
|
|
27
|
+
base: {
|
|
28
|
+
position: "fixed",
|
|
29
|
+
top: 0,
|
|
30
|
+
bottom: 0,
|
|
31
|
+
left: 0,
|
|
32
|
+
right: 0,
|
|
33
|
+
overflow: "hidden",
|
|
34
|
+
pointerEvents: "none"
|
|
35
|
+
},
|
|
36
|
+
decorative: {}
|
|
37
|
+
},
|
|
38
|
+
backdrop: {
|
|
39
|
+
base: {
|
|
40
|
+
zIndex: 1,
|
|
41
|
+
position: "fixed",
|
|
42
|
+
top: 0,
|
|
43
|
+
left: 0,
|
|
44
|
+
width: "100%",
|
|
45
|
+
height: "100%",
|
|
46
|
+
touchAction: "none",
|
|
47
|
+
userSelect: "none"
|
|
48
|
+
},
|
|
49
|
+
decorative: {
|
|
50
|
+
backgroundColor: "rgba(0, 0, 0, 0.2)",
|
|
51
|
+
border: "none",
|
|
52
|
+
WebkitTapHighlightColor: "transparent"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
container: {
|
|
56
|
+
base: {
|
|
57
|
+
zIndex: 2,
|
|
58
|
+
position: "absolute",
|
|
59
|
+
left: 0,
|
|
60
|
+
bottom: 0,
|
|
61
|
+
width: "100%",
|
|
62
|
+
pointerEvents: "auto",
|
|
63
|
+
display: "flex",
|
|
64
|
+
flexDirection: "column"
|
|
65
|
+
},
|
|
66
|
+
decorative: {
|
|
67
|
+
backgroundColor: "#fff",
|
|
68
|
+
borderTopRightRadius: "8px",
|
|
69
|
+
borderTopLeftRadius: "8px",
|
|
70
|
+
boxShadow: "0px -2px 16px rgba(0, 0, 0, 0.3)"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
headerWrapper: {
|
|
74
|
+
base: {
|
|
75
|
+
width: "100%"
|
|
76
|
+
},
|
|
77
|
+
decorative: {}
|
|
78
|
+
},
|
|
79
|
+
header: {
|
|
80
|
+
base: {
|
|
81
|
+
width: "100%",
|
|
82
|
+
position: "relative"
|
|
83
|
+
},
|
|
84
|
+
decorative: {
|
|
85
|
+
height: "40px",
|
|
86
|
+
display: "flex",
|
|
87
|
+
alignItems: "center",
|
|
88
|
+
justifyContent: "center"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
indicatorWrapper: {
|
|
92
|
+
base: {
|
|
93
|
+
display: "flex"
|
|
94
|
+
},
|
|
95
|
+
decorative: {}
|
|
96
|
+
},
|
|
97
|
+
indicator: {
|
|
98
|
+
base: {
|
|
99
|
+
display: "inline-block"
|
|
100
|
+
},
|
|
101
|
+
decorative: {
|
|
102
|
+
width: "18px",
|
|
103
|
+
height: "4px",
|
|
104
|
+
borderRadius: "99px",
|
|
105
|
+
backgroundColor: "#ddd"
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
content: {
|
|
109
|
+
base: {
|
|
110
|
+
minHeight: "0px",
|
|
111
|
+
position: "relative",
|
|
112
|
+
flexGrow: 1,
|
|
113
|
+
display: "flex",
|
|
114
|
+
flexDirection: "column"
|
|
115
|
+
},
|
|
116
|
+
decorative: {}
|
|
117
|
+
},
|
|
118
|
+
scroller: {
|
|
119
|
+
base: {
|
|
120
|
+
height: "100%",
|
|
121
|
+
overflowY: "auto",
|
|
122
|
+
overscrollBehaviorY: "none"
|
|
123
|
+
},
|
|
124
|
+
decorative: {}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
13
127
|
|
|
14
128
|
// src/constants.ts
|
|
15
|
-
var
|
|
129
|
+
var DEFAULT_HEIGHT = "calc(100% - env(safe-area-inset-top) - 34px)";
|
|
16
130
|
var IS_SSR = typeof window === "undefined";
|
|
17
131
|
var DEFAULT_TWEEN_CONFIG = {
|
|
18
132
|
ease: "easeOut",
|
|
@@ -26,96 +140,15 @@ var DEFAULT_DRAG_CLOSE_THRESHOLD = 0.6;
|
|
|
26
140
|
var DEFAULT_DRAG_VELOCITY_THRESHOLD = 500;
|
|
27
141
|
|
|
28
142
|
// src/utils.ts
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
if (!sheetEl) {
|
|
32
|
-
console.warn(
|
|
33
|
-
"Sheet height is not available because the sheet element is not mounted yet."
|
|
34
|
-
);
|
|
35
|
-
return 0;
|
|
36
|
-
}
|
|
37
|
-
return Math.round(sheetEl.getBoundingClientRect().height);
|
|
38
|
-
}
|
|
39
|
-
function getSnapPoints({
|
|
40
|
-
snapPointsProp,
|
|
41
|
-
sheetHeight
|
|
42
|
-
}) {
|
|
43
|
-
const snapPointValues = snapPointsProp.map((point) => {
|
|
44
|
-
if (point > 0 && point <= 1) {
|
|
45
|
-
return Math.round(point * sheetHeight);
|
|
46
|
-
}
|
|
47
|
-
return point < 0 ? sheetHeight + point : point;
|
|
48
|
-
});
|
|
49
|
-
console.assert(
|
|
50
|
-
inDescendingOrder(snapPointValues) || sheetHeight === 0,
|
|
51
|
-
`Snap points need to be in descending order got: [${snapPointsProp.join(", ")}]`
|
|
52
|
-
);
|
|
53
|
-
return snapPointValues;
|
|
54
|
-
}
|
|
55
|
-
function getClosestSnapPoint({
|
|
56
|
-
snapPoints,
|
|
57
|
-
currentY,
|
|
58
|
-
sheetHeight,
|
|
59
|
-
detent
|
|
60
|
-
}) {
|
|
61
|
-
const snapInverse = snapPoints.map(
|
|
62
|
-
(p) => sheetHeight - Math.min(p, sheetHeight)
|
|
63
|
-
);
|
|
64
|
-
if (detent === "content-height" && !snapInverse.includes(0)) {
|
|
65
|
-
snapInverse.unshift(0);
|
|
66
|
-
}
|
|
67
|
-
const snapTo = getClosest(snapInverse, currentY);
|
|
68
|
-
const snapIndex = snapInverse.indexOf(snapTo);
|
|
69
|
-
const snapY = validateSnapTo({
|
|
70
|
-
snapTo: getClosest(snapInverse, currentY),
|
|
71
|
-
sheetHeight
|
|
72
|
-
});
|
|
73
|
-
return { snapY, snapIndex };
|
|
74
|
-
}
|
|
75
|
-
function getClosest(nums, goal) {
|
|
76
|
-
let closest = nums[0];
|
|
77
|
-
let minDifference = Math.abs(nums[0] - goal);
|
|
78
|
-
for (let i = 1; i < nums.length; i++) {
|
|
79
|
-
const difference = Math.abs(nums[i] - goal);
|
|
80
|
-
if (difference < minDifference) {
|
|
81
|
-
closest = nums[i];
|
|
82
|
-
minDifference = difference;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return closest;
|
|
143
|
+
function applyStyles(styles2, unstyled) {
|
|
144
|
+
return unstyled ? styles2.base : { ...styles2.base, ...styles2.decorative };
|
|
86
145
|
}
|
|
87
|
-
function
|
|
146
|
+
function isAscendingOrder(arr) {
|
|
88
147
|
for (let i = 0; i < arr.length; i++) {
|
|
89
|
-
if (arr[i + 1]
|
|
148
|
+
if (arr[i + 1] < arr[i]) return false;
|
|
90
149
|
}
|
|
91
150
|
return true;
|
|
92
151
|
}
|
|
93
|
-
function getSnapY({
|
|
94
|
-
sheetHeight,
|
|
95
|
-
snapPoints,
|
|
96
|
-
snapIndex
|
|
97
|
-
}) {
|
|
98
|
-
const snapPoint = snapPoints[snapIndex];
|
|
99
|
-
if (snapPoint === void 0) {
|
|
100
|
-
console.warn(
|
|
101
|
-
`Invalid snap index ${snapIndex}. Snap points are: [${snapPoints.join(", ")}]`
|
|
102
|
-
);
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
const y = validateSnapTo({ snapTo: sheetHeight - snapPoint, sheetHeight });
|
|
106
|
-
return y;
|
|
107
|
-
}
|
|
108
|
-
function validateSnapTo({
|
|
109
|
-
snapTo,
|
|
110
|
-
sheetHeight
|
|
111
|
-
}) {
|
|
112
|
-
if (snapTo < 0) {
|
|
113
|
-
console.warn(
|
|
114
|
-
`Snap point is out of bounds. Sheet height is ${sheetHeight} but snap point is ${sheetHeight + Math.abs(snapTo)}.`
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
return Math.max(Math.round(snapTo), 0);
|
|
118
|
-
}
|
|
119
152
|
function mergeRefs(refs) {
|
|
120
153
|
return (value) => {
|
|
121
154
|
refs.forEach((ref) => {
|
|
@@ -127,10 +160,6 @@ function mergeRefs(refs) {
|
|
|
127
160
|
});
|
|
128
161
|
};
|
|
129
162
|
}
|
|
130
|
-
function isTouchDevice() {
|
|
131
|
-
if (IS_SSR) return false;
|
|
132
|
-
return "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
133
|
-
}
|
|
134
163
|
function testPlatform(re) {
|
|
135
164
|
var _a;
|
|
136
165
|
return typeof window !== "undefined" && window.navigator != null ? re.test(
|
|
@@ -159,111 +188,289 @@ var isIPad = cached(function() {
|
|
|
159
188
|
var isIOS = cached(function() {
|
|
160
189
|
return isIPhone() || isIPad();
|
|
161
190
|
});
|
|
162
|
-
|
|
163
|
-
|
|
191
|
+
|
|
192
|
+
// src/SheetBackdrop.tsx
|
|
193
|
+
var isClickable = (props) => !!props.onClick || !!props.onTap;
|
|
194
|
+
var SheetBackdrop = React4.forwardRef(
|
|
195
|
+
({ style, className = "", unstyled, ...rest }, ref) => {
|
|
196
|
+
const sheetContext = useSheetContext();
|
|
197
|
+
const clickable = isClickable(rest);
|
|
198
|
+
const Comp = clickable ? react.motion.button : react.motion.div;
|
|
199
|
+
const pointerEvents = clickable ? "auto" : "none";
|
|
200
|
+
const isUnstyled = unstyled ?? sheetContext.unstyled;
|
|
201
|
+
const backdropStyle = {
|
|
202
|
+
...applyStyles(styles.backdrop, isUnstyled),
|
|
203
|
+
...style,
|
|
204
|
+
pointerEvents
|
|
205
|
+
};
|
|
206
|
+
return /* @__PURE__ */ React4__default.default.createElement(
|
|
207
|
+
Comp,
|
|
208
|
+
{
|
|
209
|
+
...rest,
|
|
210
|
+
ref,
|
|
211
|
+
className: `react-modal-sheet-backdrop ${className}`,
|
|
212
|
+
style: backdropStyle,
|
|
213
|
+
initial: { opacity: 0 },
|
|
214
|
+
animate: { opacity: 1 },
|
|
215
|
+
exit: { opacity: 0 },
|
|
216
|
+
transition: { duration: 1 }
|
|
217
|
+
}
|
|
218
|
+
);
|
|
219
|
+
}
|
|
164
220
|
);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
221
|
+
SheetBackdrop.displayName = "SheetBackdrop";
|
|
222
|
+
var SheetContainer = React4.forwardRef(
|
|
223
|
+
({ children, style, className = "", unstyled, ...rest }, ref) => {
|
|
224
|
+
const sheetContext = useSheetContext();
|
|
225
|
+
const isUnstyled = unstyled ?? sheetContext.unstyled;
|
|
226
|
+
const containerStyle = {
|
|
227
|
+
...applyStyles(styles.container, isUnstyled),
|
|
228
|
+
...style,
|
|
229
|
+
y: sheetContext.y
|
|
230
|
+
};
|
|
231
|
+
if (sheetContext.detent === "default") {
|
|
232
|
+
containerStyle.height = DEFAULT_HEIGHT;
|
|
233
|
+
}
|
|
234
|
+
if (sheetContext.detent === "full") {
|
|
235
|
+
containerStyle.height = "100%";
|
|
236
|
+
containerStyle.maxHeight = "100%";
|
|
237
|
+
}
|
|
238
|
+
if (sheetContext.detent === "content") {
|
|
239
|
+
containerStyle.height = "auto";
|
|
240
|
+
containerStyle.maxHeight = DEFAULT_HEIGHT;
|
|
241
|
+
}
|
|
242
|
+
return /* @__PURE__ */ React4__default.default.createElement(
|
|
243
|
+
react.motion.div,
|
|
244
|
+
{
|
|
245
|
+
...rest,
|
|
246
|
+
ref: mergeRefs([
|
|
247
|
+
ref,
|
|
248
|
+
sheetContext.sheetRef,
|
|
249
|
+
sheetContext.sheetBoundsRef
|
|
250
|
+
]),
|
|
251
|
+
className: `react-modal-sheet-container ${className}`,
|
|
252
|
+
style: containerStyle
|
|
253
|
+
},
|
|
254
|
+
children
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
);
|
|
258
|
+
SheetContainer.displayName = "SheetContainer";
|
|
259
|
+
var constraints = { bottom: 0, top: 0, left: 0, right: 0 };
|
|
260
|
+
function useDragConstraints() {
|
|
261
|
+
const ref = React4.useRef(null);
|
|
262
|
+
const onMeasure = React4.useCallback(() => constraints, []);
|
|
263
|
+
return { ref, onMeasure };
|
|
264
|
+
}
|
|
265
|
+
function useScrollPosition() {
|
|
266
|
+
const ref = React4.useRef(null);
|
|
267
|
+
const [scrollPosition, setScrollPosition] = React4.useState(void 0);
|
|
268
|
+
React4.useEffect(() => {
|
|
269
|
+
const element = ref.current;
|
|
270
|
+
if (!element) return;
|
|
271
|
+
let scrollTimeout = null;
|
|
272
|
+
function determineScrollPosition(element2) {
|
|
273
|
+
const { scrollTop, scrollHeight, clientHeight } = element2;
|
|
274
|
+
const isScrollable2 = scrollHeight > clientHeight;
|
|
275
|
+
if (!isScrollable2) {
|
|
276
|
+
if (scrollPosition) setScrollPosition(void 0);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const isAtTop = scrollTop <= 0;
|
|
280
|
+
const isAtBottom = Math.ceil(scrollHeight) - Math.ceil(scrollTop) === Math.ceil(clientHeight);
|
|
281
|
+
let position;
|
|
282
|
+
if (isAtTop) {
|
|
283
|
+
position = "top";
|
|
284
|
+
} else if (isAtBottom) {
|
|
285
|
+
position = "bottom";
|
|
286
|
+
} else {
|
|
287
|
+
position = "middle";
|
|
288
|
+
}
|
|
289
|
+
if (position === scrollPosition) return;
|
|
290
|
+
setScrollPosition(position);
|
|
291
|
+
}
|
|
292
|
+
function onScroll(event) {
|
|
293
|
+
if (event.currentTarget instanceof HTMLDivElement) {
|
|
294
|
+
const el = event.currentTarget;
|
|
295
|
+
if (scrollTimeout) clearTimeout(scrollTimeout);
|
|
296
|
+
scrollTimeout = setTimeout(() => determineScrollPosition(el), 32);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function onTouchStart(event) {
|
|
300
|
+
if (event.currentTarget instanceof HTMLDivElement) {
|
|
301
|
+
determineScrollPosition(event.currentTarget);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
determineScrollPosition(element);
|
|
305
|
+
element.addEventListener("scroll", onScroll);
|
|
306
|
+
element.addEventListener("touchstart", onTouchStart);
|
|
307
|
+
return () => {
|
|
308
|
+
if (scrollTimeout) clearTimeout(scrollTimeout);
|
|
309
|
+
element.removeEventListener("scroll", onScroll);
|
|
310
|
+
element.removeEventListener("touchstart", onTouchStart);
|
|
311
|
+
};
|
|
312
|
+
}, []);
|
|
313
|
+
return { ref, scrollPosition };
|
|
169
314
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
315
|
+
|
|
316
|
+
// src/SheetContent.tsx
|
|
317
|
+
var SheetContent = React4.forwardRef(
|
|
318
|
+
({
|
|
319
|
+
disableScroll: disableScrollProp,
|
|
320
|
+
disableDrag: disableDragProp,
|
|
321
|
+
children,
|
|
322
|
+
style: styleProp,
|
|
323
|
+
className = "",
|
|
324
|
+
scrollRef: scrollRefProp = null,
|
|
325
|
+
unstyled,
|
|
326
|
+
...rest
|
|
327
|
+
}, ref) => {
|
|
328
|
+
const sheetContext = useSheetContext();
|
|
329
|
+
const dragConstraints = useDragConstraints();
|
|
330
|
+
const scroll = useScrollPosition();
|
|
331
|
+
const disableScroll = typeof disableScrollProp === "function" ? disableScrollProp({
|
|
332
|
+
scrollPosition: scroll.scrollPosition,
|
|
333
|
+
currentSnap: sheetContext.currentSnap
|
|
334
|
+
}) : Boolean(disableScrollProp);
|
|
335
|
+
const disableDragDueToScroll = !disableScroll && scroll.scrollPosition && scroll.scrollPosition !== "top";
|
|
336
|
+
const disableDragDueToProp = typeof disableDragProp === "function" ? disableDragProp({
|
|
337
|
+
scrollPosition: scroll.scrollPosition,
|
|
338
|
+
currentSnap: sheetContext.currentSnap
|
|
339
|
+
}) : Boolean(disableDragProp);
|
|
340
|
+
const disableDrag = disableDragDueToProp || disableDragDueToScroll || sheetContext.disableDrag;
|
|
341
|
+
const dragProps = disableDrag || sheetContext.disableDrag ? void 0 : sheetContext.dragProps;
|
|
342
|
+
const isUnstyled = unstyled ?? sheetContext.unstyled;
|
|
343
|
+
const contentStyle = {
|
|
344
|
+
...applyStyles(styles.content, isUnstyled),
|
|
345
|
+
...styleProp
|
|
346
|
+
};
|
|
347
|
+
const scrollStyle = applyStyles(styles.scroller, isUnstyled);
|
|
348
|
+
if (sheetContext.avoidKeyboard) {
|
|
349
|
+
scrollStyle.paddingBottom = "env(keyboard-inset-height, var(--keyboard-inset-height, 0px))";
|
|
350
|
+
}
|
|
351
|
+
if (disableScroll) {
|
|
352
|
+
scrollStyle.overflowY = "hidden";
|
|
353
|
+
}
|
|
354
|
+
return /* @__PURE__ */ React4__default.default.createElement(
|
|
355
|
+
react.motion.div,
|
|
356
|
+
{
|
|
357
|
+
...rest,
|
|
358
|
+
ref: mergeRefs([ref, dragConstraints.ref]),
|
|
359
|
+
className: `react-modal-sheet-content ${className}`,
|
|
360
|
+
style: contentStyle,
|
|
361
|
+
...dragProps,
|
|
362
|
+
dragConstraints: dragConstraints.ref,
|
|
363
|
+
onMeasureDragConstraints: dragConstraints.onMeasure
|
|
364
|
+
},
|
|
365
|
+
/* @__PURE__ */ React4__default.default.createElement(
|
|
366
|
+
react.motion.div,
|
|
367
|
+
{
|
|
368
|
+
ref: mergeRefs([scroll.ref, scrollRefProp]),
|
|
369
|
+
style: scrollStyle,
|
|
370
|
+
className: "react-modal-sheet-content-scroller"
|
|
371
|
+
},
|
|
372
|
+
children
|
|
373
|
+
)
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
);
|
|
377
|
+
SheetContent.displayName = "SheetContent";
|
|
378
|
+
function SheetDragIndicator({
|
|
379
|
+
style,
|
|
380
|
+
className = "",
|
|
381
|
+
unstyled,
|
|
382
|
+
...rest
|
|
173
383
|
}) {
|
|
174
384
|
const sheetContext = useSheetContext();
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
385
|
+
const indicator1Transform = react.useTransform(
|
|
386
|
+
sheetContext.indicatorRotation,
|
|
387
|
+
(r) => `translateX(2px) rotate(${r}deg)`
|
|
388
|
+
);
|
|
389
|
+
const indicator2Transform = react.useTransform(
|
|
390
|
+
sheetContext.indicatorRotation,
|
|
391
|
+
(r) => `translateX(-2px) rotate(${ -1 * r}deg)`
|
|
392
|
+
);
|
|
393
|
+
const isUnstyled = unstyled ?? sheetContext.unstyled;
|
|
394
|
+
const indicatorWrapperStyle = {
|
|
395
|
+
...applyStyles(styles.indicatorWrapper, isUnstyled),
|
|
396
|
+
...style
|
|
397
|
+
};
|
|
398
|
+
const indicatorStyle = applyStyles(styles.indicator, isUnstyled);
|
|
399
|
+
return /* @__PURE__ */ React4__default.default.createElement(
|
|
400
|
+
"div",
|
|
184
401
|
{
|
|
185
|
-
|
|
402
|
+
className: `react-modal-sheet-drag-indicator-container ${className}`,
|
|
403
|
+
style: indicatorWrapperStyle,
|
|
404
|
+
...rest
|
|
186
405
|
},
|
|
187
|
-
|
|
406
|
+
/* @__PURE__ */ React4__default.default.createElement(
|
|
407
|
+
react.motion.span,
|
|
408
|
+
{
|
|
409
|
+
className: "react-modal-sheet-drag-indicator",
|
|
410
|
+
style: { ...indicatorStyle, transform: indicator1Transform }
|
|
411
|
+
}
|
|
412
|
+
),
|
|
413
|
+
/* @__PURE__ */ React4__default.default.createElement(
|
|
414
|
+
react.motion.span,
|
|
415
|
+
{
|
|
416
|
+
className: "react-modal-sheet-drag-indicator",
|
|
417
|
+
style: { ...indicatorStyle, transform: indicator2Transform }
|
|
418
|
+
}
|
|
419
|
+
)
|
|
188
420
|
);
|
|
189
421
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
backgroundColor: "rgba(0, 0, 0, 0.2)",
|
|
215
|
-
touchAction: "none",
|
|
216
|
-
border: "none",
|
|
217
|
-
userSelect: "none",
|
|
218
|
-
WebkitTapHighlightColor: "transparent"
|
|
219
|
-
},
|
|
220
|
-
container: {
|
|
221
|
-
zIndex: 2,
|
|
222
|
-
position: "absolute",
|
|
223
|
-
left: 0,
|
|
224
|
-
bottom: 0,
|
|
225
|
-
width: "100%",
|
|
226
|
-
backgroundColor: "#fff",
|
|
227
|
-
borderTopRightRadius: "8px",
|
|
228
|
-
borderTopLeftRadius: "8px",
|
|
229
|
-
boxShadow: "0px -2px 16px rgba(0, 0, 0, 0.3)",
|
|
230
|
-
display: "flex",
|
|
231
|
-
flexDirection: "column",
|
|
232
|
-
pointerEvents: "auto"
|
|
233
|
-
},
|
|
234
|
-
headerWrapper: {
|
|
235
|
-
width: "100%"
|
|
236
|
-
},
|
|
237
|
-
header: {
|
|
238
|
-
height: "40px",
|
|
239
|
-
width: "100%",
|
|
240
|
-
position: "relative",
|
|
241
|
-
display: "flex",
|
|
242
|
-
alignItems: "center",
|
|
243
|
-
justifyContent: "center"
|
|
244
|
-
},
|
|
245
|
-
indicator: {
|
|
246
|
-
width: "18px",
|
|
247
|
-
height: "4px",
|
|
248
|
-
borderRadius: "99px",
|
|
249
|
-
backgroundColor: "#ddd"
|
|
250
|
-
},
|
|
251
|
-
content: {
|
|
252
|
-
flexGrow: 1,
|
|
253
|
-
display: "flex",
|
|
254
|
-
flexDirection: "column",
|
|
255
|
-
minHeight: "0px",
|
|
256
|
-
position: "relative"
|
|
257
|
-
},
|
|
258
|
-
scroller: {
|
|
259
|
-
height: "100%",
|
|
260
|
-
overflowY: "auto",
|
|
261
|
-
overscrollBehaviorY: "none"
|
|
422
|
+
var SheetHeader = React4.forwardRef(
|
|
423
|
+
({ children, style, disableDrag, unstyled, className = "", ...rest }, ref) => {
|
|
424
|
+
const sheetContext = useSheetContext();
|
|
425
|
+
const dragConstraints = useDragConstraints();
|
|
426
|
+
const dragProps = disableDrag || sheetContext.disableDrag ? void 0 : sheetContext.dragProps;
|
|
427
|
+
const isUnstyled = unstyled ?? sheetContext.unstyled;
|
|
428
|
+
const headerWrapperStyle = {
|
|
429
|
+
...applyStyles(styles.headerWrapper, isUnstyled),
|
|
430
|
+
...style
|
|
431
|
+
};
|
|
432
|
+
const headerStyle = applyStyles(styles.header, isUnstyled);
|
|
433
|
+
return /* @__PURE__ */ React4__default.default.createElement(
|
|
434
|
+
react.motion.div,
|
|
435
|
+
{
|
|
436
|
+
...rest,
|
|
437
|
+
ref: mergeRefs([ref, dragConstraints.ref]),
|
|
438
|
+
style: headerWrapperStyle,
|
|
439
|
+
className: `react-modal-sheet-header-container ${className}`,
|
|
440
|
+
...dragProps,
|
|
441
|
+
dragConstraints: dragConstraints.ref,
|
|
442
|
+
onMeasureDragConstraints: dragConstraints.onMeasure
|
|
443
|
+
},
|
|
444
|
+
children || /* @__PURE__ */ React4__default.default.createElement("div", { className: "react-modal-sheet-header", style: headerStyle }, /* @__PURE__ */ React4__default.default.createElement(SheetDragIndicator, null))
|
|
445
|
+
);
|
|
262
446
|
}
|
|
263
|
-
|
|
264
|
-
|
|
447
|
+
);
|
|
448
|
+
SheetHeader.displayName = "SheetHeader";
|
|
449
|
+
var useIsomorphicLayoutEffect = IS_SSR ? React4.useEffect : React4.useLayoutEffect;
|
|
450
|
+
|
|
451
|
+
// src/hooks/use-dimensions.ts
|
|
452
|
+
function useDimensions() {
|
|
453
|
+
const [dimensions, setDimensions] = React4.useState(() => ({
|
|
454
|
+
windowHeight: !IS_SSR ? window.innerHeight : 0,
|
|
455
|
+
windowWidth: !IS_SSR ? window.innerWidth : 0
|
|
456
|
+
}));
|
|
457
|
+
useIsomorphicLayoutEffect(() => {
|
|
458
|
+
function handler() {
|
|
459
|
+
setDimensions({
|
|
460
|
+
windowHeight: window.innerHeight,
|
|
461
|
+
windowWidth: window.innerWidth
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
handler();
|
|
465
|
+
window.addEventListener("resize", handler);
|
|
466
|
+
return () => {
|
|
467
|
+
window.removeEventListener("resize", handler);
|
|
468
|
+
};
|
|
469
|
+
}, []);
|
|
470
|
+
return dimensions;
|
|
471
|
+
}
|
|
265
472
|
function useSafeAreaInsets() {
|
|
266
|
-
const [insets] =
|
|
473
|
+
const [insets] = React4.useState(() => {
|
|
267
474
|
const fallback = { top: 0, left: 0, right: 0, bottom: 0 };
|
|
268
475
|
if (IS_SSR) return fallback;
|
|
269
476
|
const root = document.querySelector(":root");
|
|
@@ -293,12 +500,18 @@ function getComputedValue(computed, property) {
|
|
|
293
500
|
// src/hooks/use-modal-effect.ts
|
|
294
501
|
function useModalEffect({
|
|
295
502
|
y,
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
503
|
+
detent,
|
|
504
|
+
rootId: _rootId,
|
|
505
|
+
sheetHeight,
|
|
506
|
+
snapPoints,
|
|
299
507
|
startThreshold
|
|
300
508
|
}) {
|
|
301
509
|
const insetTop = useSafeAreaInsets().top;
|
|
510
|
+
let rootId = _rootId;
|
|
511
|
+
if (rootId && detent === "full") {
|
|
512
|
+
console.warn('Using "full" detent with modal effect is not supported.');
|
|
513
|
+
rootId = void 0;
|
|
514
|
+
}
|
|
302
515
|
useIsomorphicLayoutEffect(() => {
|
|
303
516
|
return () => {
|
|
304
517
|
if (rootId) cleanupModalEffect(rootId);
|
|
@@ -308,18 +521,15 @@ function useModalEffect({
|
|
|
308
521
|
if (!rootId) return;
|
|
309
522
|
const root = document.querySelector(`#${rootId}`);
|
|
310
523
|
if (!root) return;
|
|
311
|
-
let sheetHeight = 0;
|
|
312
524
|
const removeStartListener = y.on("animationStart", () => {
|
|
313
|
-
sheetHeight = getSheetHeight(sheetRef);
|
|
314
525
|
setupModalEffect(rootId);
|
|
315
526
|
});
|
|
316
527
|
const removeChangeListener = y.on("change", (yValue) => {
|
|
317
528
|
if (!root) return;
|
|
318
529
|
let progress = Math.max(0, 1 - yValue / sheetHeight);
|
|
319
|
-
const
|
|
320
|
-
const snapThresholdPoint = snapPoints && snapPoints.length > 1 ? snapPoints[1] : void 0;
|
|
530
|
+
const snapThresholdPoint = snapPoints.length > 1 ? snapPoints[snapPoints.length - 2] : void 0;
|
|
321
531
|
if (snapThresholdPoint !== void 0) {
|
|
322
|
-
const snapThresholdValue =
|
|
532
|
+
const snapThresholdValue = snapThresholdPoint.snapValueY;
|
|
323
533
|
if (yValue <= snapThresholdValue) {
|
|
324
534
|
progress = (snapThresholdValue - yValue) / snapThresholdValue;
|
|
325
535
|
} else {
|
|
@@ -356,7 +566,7 @@ function useModalEffect({
|
|
|
356
566
|
removeCompleteListener();
|
|
357
567
|
removeCancelListener();
|
|
358
568
|
};
|
|
359
|
-
}, [y, rootId, insetTop, startThreshold,
|
|
569
|
+
}, [y, rootId, insetTop, startThreshold, sheetHeight]);
|
|
360
570
|
}
|
|
361
571
|
function setupModalEffect(rootId) {
|
|
362
572
|
const root = document.querySelector(`#${rootId}`);
|
|
@@ -383,36 +593,6 @@ function cleanupModalEffect(rootId) {
|
|
|
383
593
|
root.style.removeProperty("border-top-right-radius");
|
|
384
594
|
root.style.removeProperty("border-top-left-radius");
|
|
385
595
|
}
|
|
386
|
-
function useDimensions() {
|
|
387
|
-
const [dimensions, setDimensions] = React2.useState(() => ({
|
|
388
|
-
height: !IS_SSR ? window.innerHeight : 0,
|
|
389
|
-
width: !IS_SSR ? window.innerWidth : 0
|
|
390
|
-
}));
|
|
391
|
-
useIsomorphicLayoutEffect(() => {
|
|
392
|
-
function handler() {
|
|
393
|
-
setDimensions({
|
|
394
|
-
height: window.innerHeight,
|
|
395
|
-
width: window.innerWidth
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
handler();
|
|
399
|
-
window.addEventListener("resize", handler);
|
|
400
|
-
return () => {
|
|
401
|
-
window.removeEventListener("resize", handler);
|
|
402
|
-
};
|
|
403
|
-
}, []);
|
|
404
|
-
return dimensions;
|
|
405
|
-
}
|
|
406
|
-
function useStableCallback(handler) {
|
|
407
|
-
const handlerRef = React2.useRef(void 0);
|
|
408
|
-
useIsomorphicLayoutEffect(() => {
|
|
409
|
-
handlerRef.current = handler;
|
|
410
|
-
});
|
|
411
|
-
return React2.useCallback((...args) => {
|
|
412
|
-
const fn = handlerRef.current;
|
|
413
|
-
return fn == null ? void 0 : fn(...args);
|
|
414
|
-
}, []);
|
|
415
|
-
}
|
|
416
596
|
|
|
417
597
|
// src/hooks/use-prevent-scroll.ts
|
|
418
598
|
var KEYBOARD_BUFFER = 24;
|
|
@@ -629,83 +809,370 @@ function scrollIntoView(target) {
|
|
|
629
809
|
function willOpenKeyboard(target) {
|
|
630
810
|
return target instanceof HTMLInputElement && !nonTextInputTypes.has(target.type) || target instanceof HTMLTextAreaElement || target instanceof HTMLElement && target.isContentEditable;
|
|
631
811
|
}
|
|
812
|
+
function useStableCallback(handler) {
|
|
813
|
+
const handlerRef = React4.useRef(void 0);
|
|
814
|
+
useIsomorphicLayoutEffect(() => {
|
|
815
|
+
handlerRef.current = handler;
|
|
816
|
+
});
|
|
817
|
+
return React4.useCallback((...args) => {
|
|
818
|
+
const fn = handlerRef.current;
|
|
819
|
+
return fn == null ? void 0 : fn(...args);
|
|
820
|
+
}, []);
|
|
821
|
+
}
|
|
632
822
|
|
|
633
|
-
// src/sheet.
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
823
|
+
// src/hooks/use-sheet-state.ts
|
|
824
|
+
function useSheetState({
|
|
825
|
+
isOpen,
|
|
826
|
+
onClosed: _onClosed,
|
|
827
|
+
onOpening: _onOpening,
|
|
828
|
+
onOpen: _onOpen,
|
|
829
|
+
onClosing: _onClosing
|
|
830
|
+
}) {
|
|
831
|
+
const [state, setState] = React4.useState(isOpen ? "opening" : "closed");
|
|
832
|
+
const onClosed = useStableCallback(() => _onClosed == null ? void 0 : _onClosed());
|
|
833
|
+
const onOpening = useStableCallback(() => _onOpening == null ? void 0 : _onOpening());
|
|
834
|
+
const onOpen = useStableCallback(() => _onOpen == null ? void 0 : _onOpen());
|
|
835
|
+
const onClosing = useStableCallback(() => _onClosing == null ? void 0 : _onClosing());
|
|
836
|
+
React4.useEffect(() => {
|
|
837
|
+
if (isOpen && state === "closed") {
|
|
838
|
+
setState("opening");
|
|
839
|
+
} else if (!isOpen && (state === "open" || state === "opening")) {
|
|
840
|
+
setState("closing");
|
|
841
|
+
}
|
|
842
|
+
}, [isOpen, state]);
|
|
843
|
+
React4.useEffect(() => {
|
|
844
|
+
async function handle() {
|
|
845
|
+
switch (state) {
|
|
846
|
+
case "closed":
|
|
847
|
+
await (onClosed == null ? void 0 : onClosed());
|
|
848
|
+
break;
|
|
849
|
+
case "opening":
|
|
850
|
+
await (onOpening == null ? void 0 : onOpening());
|
|
851
|
+
setState("open");
|
|
852
|
+
break;
|
|
853
|
+
case "open":
|
|
854
|
+
await (onOpen == null ? void 0 : onOpen());
|
|
855
|
+
break;
|
|
856
|
+
case "closing":
|
|
857
|
+
await (onClosing == null ? void 0 : onClosing());
|
|
858
|
+
setState("closed");
|
|
859
|
+
break;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
handle().catch((error) => {
|
|
863
|
+
console.error("Internal sheet state error:", error);
|
|
864
|
+
});
|
|
865
|
+
}, [state]);
|
|
866
|
+
return state;
|
|
867
|
+
}
|
|
868
|
+
function useVirtualKeyboard({
|
|
869
|
+
containerRef,
|
|
870
|
+
isEnabled = true,
|
|
871
|
+
debounceDelay = 100,
|
|
872
|
+
includeContentEditable = true,
|
|
873
|
+
visualViewportThreshold = 100
|
|
874
|
+
}) {
|
|
875
|
+
const [state, setState] = React4.useState({
|
|
876
|
+
isVisible: false,
|
|
877
|
+
height: 0
|
|
878
|
+
});
|
|
879
|
+
const focusedElementRef = React4.useRef(null);
|
|
880
|
+
const debounceTimer = React4.useRef(null);
|
|
881
|
+
const isTextInput = useStableCallback((el) => {
|
|
882
|
+
return (el == null ? void 0 : el.tagName) === "INPUT" || (el == null ? void 0 : el.tagName) === "TEXTAREA" || includeContentEditable && el instanceof HTMLElement && el.isContentEditable;
|
|
883
|
+
});
|
|
884
|
+
React4.useEffect(() => {
|
|
885
|
+
if (!isEnabled) return;
|
|
886
|
+
const vv = window.visualViewport;
|
|
887
|
+
const vk = navigator.virtualKeyboard;
|
|
888
|
+
function setKeyboardInsetHeightEnv(height) {
|
|
889
|
+
var _a;
|
|
890
|
+
(_a = containerRef.current) == null ? void 0 : _a.style.setProperty(
|
|
891
|
+
"--keyboard-inset-height",
|
|
892
|
+
`${height}px`
|
|
893
|
+
);
|
|
894
|
+
}
|
|
895
|
+
function handleFocusIn(e) {
|
|
896
|
+
if (e.target instanceof HTMLElement && isTextInput(e.target)) {
|
|
897
|
+
focusedElementRef.current = e.target;
|
|
898
|
+
updateKeyboardState();
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
function handleFocusOut() {
|
|
902
|
+
focusedElementRef.current = null;
|
|
903
|
+
updateKeyboardState();
|
|
904
|
+
}
|
|
905
|
+
function updateKeyboardState() {
|
|
906
|
+
if (debounceTimer.current) {
|
|
907
|
+
clearTimeout(debounceTimer.current);
|
|
908
|
+
}
|
|
909
|
+
debounceTimer.current = setTimeout(() => {
|
|
910
|
+
const active = focusedElementRef.current;
|
|
911
|
+
const inputIsFocused = isTextInput(active);
|
|
912
|
+
if (!inputIsFocused) {
|
|
913
|
+
setKeyboardInsetHeightEnv(0);
|
|
914
|
+
setState({ isVisible: false, height: 0 });
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
if (vv) {
|
|
918
|
+
const heightDiff = window.innerHeight - vv.height;
|
|
919
|
+
if (heightDiff > visualViewportThreshold) {
|
|
920
|
+
setKeyboardInsetHeightEnv(heightDiff);
|
|
921
|
+
setState({ isVisible: true, height: heightDiff });
|
|
922
|
+
} else {
|
|
923
|
+
setKeyboardInsetHeightEnv(0);
|
|
924
|
+
setState({ isVisible: false, height: 0 });
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}, debounceDelay);
|
|
928
|
+
}
|
|
929
|
+
window.addEventListener("focusin", handleFocusIn);
|
|
930
|
+
window.addEventListener("focusout", handleFocusOut);
|
|
931
|
+
if (vv) {
|
|
932
|
+
vv.addEventListener("resize", updateKeyboardState);
|
|
933
|
+
vv.addEventListener("scroll", updateKeyboardState);
|
|
934
|
+
}
|
|
935
|
+
let currentOverlaysContent = false;
|
|
936
|
+
if (vk) {
|
|
937
|
+
currentOverlaysContent = vk.overlaysContent;
|
|
938
|
+
vk.overlaysContent = true;
|
|
939
|
+
}
|
|
940
|
+
return () => {
|
|
941
|
+
window.removeEventListener("focusin", handleFocusIn);
|
|
942
|
+
window.removeEventListener("focusout", handleFocusOut);
|
|
943
|
+
if (vv) {
|
|
944
|
+
vv.removeEventListener("resize", updateKeyboardState);
|
|
945
|
+
vv.removeEventListener("scroll", updateKeyboardState);
|
|
946
|
+
}
|
|
947
|
+
if (vk) {
|
|
948
|
+
vk.overlaysContent = currentOverlaysContent;
|
|
949
|
+
}
|
|
950
|
+
if (debounceTimer.current) {
|
|
951
|
+
clearTimeout(debounceTimer.current);
|
|
952
|
+
}
|
|
953
|
+
};
|
|
954
|
+
}, [
|
|
955
|
+
debounceDelay,
|
|
956
|
+
includeContentEditable,
|
|
957
|
+
isEnabled,
|
|
958
|
+
visualViewportThreshold
|
|
959
|
+
]);
|
|
960
|
+
return {
|
|
961
|
+
keyboardHeight: state.height,
|
|
962
|
+
isKeyboardOpen: state.isVisible
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// src/snap.ts
|
|
967
|
+
function computeSnapPoints({
|
|
968
|
+
snapPointsProp,
|
|
969
|
+
sheetHeight
|
|
970
|
+
}) {
|
|
971
|
+
if (sheetHeight <= 0) {
|
|
972
|
+
console.warn(
|
|
973
|
+
`Sheet height is ${sheetHeight}, cannot compute snap points. Make sure the sheet is mounted and has a valid height.`
|
|
974
|
+
);
|
|
975
|
+
return [];
|
|
976
|
+
}
|
|
977
|
+
const snapPointValues = snapPointsProp.map((point) => {
|
|
978
|
+
if (point > 0 && point <= 1) {
|
|
979
|
+
return Math.round(point * sheetHeight);
|
|
980
|
+
}
|
|
981
|
+
return point < 0 ? sheetHeight + point : point;
|
|
982
|
+
});
|
|
983
|
+
console.assert(
|
|
984
|
+
isAscendingOrder(snapPointValues),
|
|
985
|
+
`Snap points need to be in ascending order got: [${snapPointsProp.join(", ")}]`
|
|
986
|
+
);
|
|
987
|
+
snapPointValues.forEach((snap) => {
|
|
988
|
+
if (snap < 0 || snap > sheetHeight) {
|
|
989
|
+
console.warn(
|
|
990
|
+
`Snap point ${snap} is outside of the sheet height ${sheetHeight}. This can cause unexpected behavior. Consider adjusting your snap points.`
|
|
991
|
+
);
|
|
992
|
+
}
|
|
993
|
+
});
|
|
994
|
+
if (!snapPointValues.includes(sheetHeight)) {
|
|
995
|
+
console.warn(
|
|
996
|
+
"Snap points do not include the sheet height.Please include `1` as the last snap point or it will be included automatically.This is to ensure the sheet can be fully opened."
|
|
997
|
+
);
|
|
998
|
+
snapPointValues.push(sheetHeight);
|
|
999
|
+
}
|
|
1000
|
+
return snapPointValues.map((snap, index) => ({
|
|
1001
|
+
snapIndex: index,
|
|
1002
|
+
snapValue: snap,
|
|
1003
|
+
// Absolute value from the bottom of the sheet
|
|
1004
|
+
snapValueY: sheetHeight - snap
|
|
1005
|
+
// Y value is inverted as `y = 0` means sheet is at the top
|
|
1006
|
+
}));
|
|
1007
|
+
}
|
|
1008
|
+
function findClosestSnapPoint({
|
|
1009
|
+
snapPoints,
|
|
1010
|
+
currentY
|
|
1011
|
+
}) {
|
|
1012
|
+
return snapPoints.reduce(
|
|
1013
|
+
(closest, snap) => Math.abs(snap.snapValueY - currentY) < Math.abs(closest.snapValueY - currentY) ? snap : closest
|
|
1014
|
+
);
|
|
1015
|
+
}
|
|
1016
|
+
function findNextSnapPointInDirection({
|
|
1017
|
+
y,
|
|
1018
|
+
snapPoints,
|
|
1019
|
+
dragDirection
|
|
1020
|
+
}) {
|
|
1021
|
+
if (dragDirection === "down") {
|
|
1022
|
+
return snapPoints.slice().reverse().find((s) => s.snapValueY > y);
|
|
1023
|
+
} else {
|
|
1024
|
+
return snapPoints.find((s) => s.snapValueY < y);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
function handleHighVelocityDrag({
|
|
1028
|
+
dragDirection,
|
|
1029
|
+
snapPoints
|
|
1030
|
+
}) {
|
|
1031
|
+
const bottomSnapPoint = snapPoints[0];
|
|
1032
|
+
const topSnapPoint = snapPoints[snapPoints.length - 1];
|
|
1033
|
+
if (dragDirection === "down") {
|
|
1034
|
+
return {
|
|
1035
|
+
yTo: bottomSnapPoint.snapValueY,
|
|
1036
|
+
snapIndex: bottomSnapPoint.snapIndex
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
return {
|
|
1040
|
+
yTo: topSnapPoint.snapValueY,
|
|
1041
|
+
snapIndex: topSnapPoint.snapIndex
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
function handleLowVelocityDrag({
|
|
1045
|
+
currentSnapPoint,
|
|
1046
|
+
currentY,
|
|
1047
|
+
dragDirection,
|
|
1048
|
+
snapPoints,
|
|
1049
|
+
velocity
|
|
1050
|
+
}) {
|
|
1051
|
+
const closestSnapRelativeToCurrentY = findClosestSnapPoint({
|
|
1052
|
+
snapPoints,
|
|
1053
|
+
currentY
|
|
1054
|
+
});
|
|
1055
|
+
if (Math.abs(velocity) < 20) {
|
|
1056
|
+
return {
|
|
1057
|
+
yTo: closestSnapRelativeToCurrentY.snapValueY,
|
|
1058
|
+
snapIndex: closestSnapRelativeToCurrentY.snapIndex
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
const nextSnapInDirectionRelativeToCurrentY = findNextSnapPointInDirection({
|
|
1062
|
+
y: currentY,
|
|
1063
|
+
snapPoints,
|
|
1064
|
+
dragDirection
|
|
1065
|
+
});
|
|
1066
|
+
if (nextSnapInDirectionRelativeToCurrentY) {
|
|
1067
|
+
return {
|
|
1068
|
+
yTo: nextSnapInDirectionRelativeToCurrentY.snapValueY,
|
|
1069
|
+
snapIndex: nextSnapInDirectionRelativeToCurrentY.snapIndex
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
return {
|
|
1073
|
+
yTo: currentSnapPoint.snapValueY,
|
|
1074
|
+
snapIndex: currentSnapPoint.snapIndex
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
// src/sheet.tsx
|
|
1079
|
+
var Sheet = React4.forwardRef(
|
|
1080
|
+
({
|
|
1081
|
+
avoidKeyboard = true,
|
|
642
1082
|
children,
|
|
1083
|
+
className = "",
|
|
1084
|
+
detent = "default",
|
|
1085
|
+
disableDismiss = false,
|
|
1086
|
+
disableDrag: disableDragProp = false,
|
|
643
1087
|
disableScrollLocking = false,
|
|
1088
|
+
dragCloseThreshold = DEFAULT_DRAG_CLOSE_THRESHOLD,
|
|
1089
|
+
dragVelocityThreshold = DEFAULT_DRAG_VELOCITY_THRESHOLD,
|
|
1090
|
+
initialSnap,
|
|
644
1091
|
isOpen,
|
|
645
|
-
snapPoints: snapPointsProp,
|
|
646
|
-
rootId,
|
|
647
1092
|
modalEffectRootId,
|
|
1093
|
+
modalEffectThreshold,
|
|
648
1094
|
mountPoint,
|
|
649
|
-
style,
|
|
650
|
-
detent = "full-height",
|
|
651
|
-
initialSnap = 0,
|
|
652
|
-
disableDrag = false,
|
|
653
1095
|
prefersReducedMotion = false,
|
|
1096
|
+
snapPoints: snapPointsProp,
|
|
1097
|
+
style,
|
|
654
1098
|
tweenConfig = DEFAULT_TWEEN_CONFIG,
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
1099
|
+
unstyled = false,
|
|
1100
|
+
onOpenStart,
|
|
1101
|
+
onOpenEnd,
|
|
1102
|
+
onClose,
|
|
1103
|
+
onCloseStart,
|
|
1104
|
+
onCloseEnd,
|
|
1105
|
+
onSnap,
|
|
1106
|
+
onDrag: onDragProp,
|
|
1107
|
+
onDragStart: onDragStartProp,
|
|
1108
|
+
onDragEnd: onDragEndProp,
|
|
658
1109
|
...rest
|
|
659
1110
|
}, ref) => {
|
|
660
|
-
const
|
|
1111
|
+
const [sheetBoundsRef, sheetBounds] = useMeasure__default.default();
|
|
1112
|
+
const sheetRef = React4.useRef(null);
|
|
1113
|
+
const sheetHeight = Math.round(sheetBounds.height);
|
|
1114
|
+
const [currentSnap, setCurrentSnap] = React4.useState(initialSnap);
|
|
1115
|
+
const snapPoints = snapPointsProp && sheetHeight > 0 ? computeSnapPoints({ sheetHeight, snapPointsProp }) : [];
|
|
1116
|
+
const { windowHeight } = useDimensions();
|
|
1117
|
+
const closedY = sheetHeight > 0 ? sheetHeight : windowHeight;
|
|
1118
|
+
const y = react.useMotionValue(closedY);
|
|
1119
|
+
const yInverted = react.useTransform(y, (val) => Math.max(sheetHeight - val, 0));
|
|
661
1120
|
const indicatorRotation = react.useMotionValue(0);
|
|
662
|
-
const { height: windowHeight } = useDimensions();
|
|
663
1121
|
const shouldReduceMotion = react.useReducedMotion();
|
|
664
1122
|
const reduceMotion = Boolean(prefersReducedMotion || shouldReduceMotion);
|
|
665
1123
|
const animationOptions = {
|
|
666
1124
|
type: "tween",
|
|
667
1125
|
...reduceMotion ? REDUCED_MOTION_TWEEN_CONFIG : tweenConfig
|
|
668
1126
|
};
|
|
669
|
-
const
|
|
1127
|
+
const keyboard = useVirtualKeyboard({
|
|
1128
|
+
isEnabled: isOpen && avoidKeyboard,
|
|
1129
|
+
containerRef: sheetRef
|
|
1130
|
+
});
|
|
1131
|
+
const disableDrag = keyboard.isKeyboardOpen || disableDragProp;
|
|
670
1132
|
const zIndex = react.useTransform(
|
|
671
1133
|
y,
|
|
672
|
-
(
|
|
1134
|
+
(val) => val + 2 >= closedY ? -1 : (style == null ? void 0 : style.zIndex) ?? 9999
|
|
673
1135
|
);
|
|
674
1136
|
const visibility = react.useTransform(
|
|
675
1137
|
y,
|
|
676
|
-
(
|
|
1138
|
+
(val) => val + 2 >= closedY ? "hidden" : "visible"
|
|
677
1139
|
);
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
onCloseStart,
|
|
682
|
-
onCloseEnd
|
|
1140
|
+
const updateSnap = useStableCallback((snapIndex) => {
|
|
1141
|
+
setCurrentSnap(snapIndex);
|
|
1142
|
+
onSnap == null ? void 0 : onSnap(snapIndex);
|
|
683
1143
|
});
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
});
|
|
692
|
-
const onDrag = useStableCallback((_, info) => {
|
|
693
|
-
const currentY = y.get();
|
|
694
|
-
if (snapPointsProp) {
|
|
695
|
-
const sheetHeight = getSheetHeight(sheetRef);
|
|
696
|
-
const snapPoints = getSnapPoints({ snapPointsProp, sheetHeight });
|
|
697
|
-
const topSnapPoint = sheetHeight - snapPoints[0];
|
|
698
|
-
if (info.delta.y < 0 && currentY <= topSnapPoint) {
|
|
699
|
-
y.set(topSnapPoint);
|
|
700
|
-
return;
|
|
1144
|
+
const getSnapPoint = useStableCallback((snapIndex) => {
|
|
1145
|
+
if (snapPointsProp && snapPoints) {
|
|
1146
|
+
if (snapIndex < 0 || snapIndex >= snapPoints.length) {
|
|
1147
|
+
console.warn(
|
|
1148
|
+
`Invalid snap index ${snapIndex}. Snap points are: [${snapPointsProp.join(", ")}] and their computed values are: [${snapPoints.map((point) => point.snapValue).join(", ")}]`
|
|
1149
|
+
);
|
|
1150
|
+
return null;
|
|
701
1151
|
}
|
|
1152
|
+
return snapPoints[snapIndex];
|
|
702
1153
|
}
|
|
703
|
-
|
|
704
|
-
if (velocity > 0) indicatorRotation.set(10);
|
|
705
|
-
if (velocity < 0) indicatorRotation.set(-10);
|
|
706
|
-
y.set(Math.max(currentY + info.delta.y, 0));
|
|
1154
|
+
return null;
|
|
707
1155
|
});
|
|
708
|
-
const
|
|
1156
|
+
const snapTo = useStableCallback(async (snapIndex) => {
|
|
1157
|
+
if (!snapPointsProp) {
|
|
1158
|
+
console.warn("Snapping is not possible without `snapPoints` prop.");
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
const snapPoint = getSnapPoint(snapIndex);
|
|
1162
|
+
if (snapPoint === null) {
|
|
1163
|
+
console.warn(`Invalid snap index ${snapIndex}.`);
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
if (snapIndex === 0) {
|
|
1167
|
+
onClose();
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
await react.animate(y, snapPoint.snapValueY, {
|
|
1171
|
+
...animationOptions,
|
|
1172
|
+
onComplete: () => updateSnap(snapIndex)
|
|
1173
|
+
});
|
|
1174
|
+
});
|
|
1175
|
+
const blurActiveInput = useStableCallback(() => {
|
|
709
1176
|
const focusedElement = document.activeElement;
|
|
710
1177
|
if (!focusedElement || !sheetRef.current) return;
|
|
711
1178
|
const isInput = focusedElement.tagName === "INPUT" || focusedElement.tagName === "TEXTAREA";
|
|
@@ -713,351 +1180,153 @@ var Sheet = React2.forwardRef(
|
|
|
713
1180
|
focusedElement.blur();
|
|
714
1181
|
}
|
|
715
1182
|
});
|
|
716
|
-
const
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
1183
|
+
const onDrag = useStableCallback((event, info) => {
|
|
1184
|
+
onDragProp == null ? void 0 : onDragProp(event, info);
|
|
1185
|
+
const currentY = y.get();
|
|
1186
|
+
const velocity = y.getVelocity();
|
|
1187
|
+
if (velocity > 0) indicatorRotation.set(10);
|
|
1188
|
+
if (velocity < 0) indicatorRotation.set(-10);
|
|
1189
|
+
y.set(Math.max(currentY + info.delta.y, 0));
|
|
1190
|
+
});
|
|
1191
|
+
const onDragStart = useStableCallback((event, info) => {
|
|
1192
|
+
blurActiveInput();
|
|
1193
|
+
onDragStartProp == null ? void 0 : onDragStartProp(event, info);
|
|
1194
|
+
});
|
|
1195
|
+
const onDragEnd = useStableCallback((event, info) => {
|
|
1196
|
+
blurActiveInput();
|
|
1197
|
+
onDragEndProp == null ? void 0 : onDragEndProp(event, info);
|
|
1198
|
+
const currentY = y.get();
|
|
1199
|
+
let yTo = 0;
|
|
1200
|
+
const currentSnapPoint = currentSnap !== void 0 ? getSnapPoint(currentSnap) : null;
|
|
1201
|
+
if (currentSnapPoint) {
|
|
1202
|
+
const dragOffsetDirection = info.offset.y > 0 ? "down" : "up";
|
|
1203
|
+
const dragVelocityDirection = info.velocity.y > 0 ? "down" : "up";
|
|
1204
|
+
const isHighVelocity = Math.abs(info.velocity.y) > dragVelocityThreshold;
|
|
1205
|
+
let result;
|
|
1206
|
+
if (isHighVelocity) {
|
|
1207
|
+
result = handleHighVelocityDrag({
|
|
726
1208
|
snapPoints,
|
|
1209
|
+
dragDirection: dragVelocityDirection
|
|
1210
|
+
});
|
|
1211
|
+
} else {
|
|
1212
|
+
result = handleLowVelocityDrag({
|
|
1213
|
+
currentSnapPoint,
|
|
727
1214
|
currentY,
|
|
728
|
-
|
|
729
|
-
|
|
1215
|
+
dragDirection: dragOffsetDirection,
|
|
1216
|
+
snapPoints,
|
|
1217
|
+
velocity: info.velocity.y
|
|
730
1218
|
});
|
|
731
|
-
yTo = snapY;
|
|
732
|
-
onSnap == null ? void 0 : onSnap(snapIndex);
|
|
733
|
-
} else if (currentY / sheetHeight > dragCloseThreshold) {
|
|
734
|
-
yTo = sheetHeight;
|
|
735
1219
|
}
|
|
736
|
-
|
|
737
|
-
if (yTo + 1 >= sheetHeight) {
|
|
738
|
-
|
|
1220
|
+
yTo = result.yTo;
|
|
1221
|
+
if (disableDismiss && yTo + 1 >= sheetHeight) {
|
|
1222
|
+
const bottomSnapPoint = snapPoints.find((s) => s.snapValue > 0);
|
|
1223
|
+
if (bottomSnapPoint) {
|
|
1224
|
+
yTo = bottomSnapPoint.snapValueY;
|
|
1225
|
+
updateSnap(bottomSnapPoint.snapIndex);
|
|
1226
|
+
} else {
|
|
1227
|
+
yTo = currentY;
|
|
1228
|
+
}
|
|
1229
|
+
} else if (result.snapIndex !== void 0) {
|
|
1230
|
+
updateSnap(result.snapIndex);
|
|
739
1231
|
}
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
onSnap(isOpen ? initialSnap : snapPointsProp.length - 1);
|
|
746
|
-
}
|
|
747
|
-
}, [isOpen]);
|
|
748
|
-
React2.useEffect(() => {
|
|
749
|
-
if (!isOpen) return;
|
|
750
|
-
let yTo = 0;
|
|
751
|
-
if (snapPointsProp) {
|
|
752
|
-
const snapIndex = initialSnap;
|
|
753
|
-
const sheetHeight = getSheetHeight(sheetRef);
|
|
754
|
-
const snapPoints = getSnapPoints({ snapPointsProp, sheetHeight });
|
|
755
|
-
const snapY = getSnapY({ sheetHeight, snapPoints, snapIndex });
|
|
756
|
-
if (snapY !== null) {
|
|
757
|
-
yTo = snapY;
|
|
1232
|
+
} else if (info.velocity.y > dragVelocityThreshold || currentY > sheetHeight * dragCloseThreshold) {
|
|
1233
|
+
if (disableDismiss) {
|
|
1234
|
+
yTo = 0;
|
|
1235
|
+
} else {
|
|
1236
|
+
yTo = closedY;
|
|
758
1237
|
}
|
|
759
1238
|
}
|
|
760
1239
|
react.animate(y, yTo, animationOptions);
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
y,
|
|
764
|
-
snapTo: (snapIndex) => {
|
|
765
|
-
if (!snapPointsProp) {
|
|
766
|
-
console.warn("Snapping is not possible without `snapPoints` prop.");
|
|
767
|
-
return;
|
|
768
|
-
}
|
|
769
|
-
const sheetHeight = getSheetHeight(sheetRef);
|
|
770
|
-
const snapPoints = getSnapPoints({ snapPointsProp, sheetHeight });
|
|
771
|
-
const snapY = getSnapY({ sheetHeight, snapPoints, snapIndex });
|
|
772
|
-
if (snapY !== null) {
|
|
773
|
-
react.animate(y, snapY, animationOptions);
|
|
774
|
-
onSnap == null ? void 0 : onSnap(snapIndex);
|
|
775
|
-
if (snapY + 1 >= sheetHeight) {
|
|
776
|
-
onClose();
|
|
777
|
-
}
|
|
778
|
-
}
|
|
1240
|
+
if (yTo + 1 >= sheetHeight && !disableDismiss) {
|
|
1241
|
+
onClose();
|
|
779
1242
|
}
|
|
1243
|
+
indicatorRotation.set(0);
|
|
1244
|
+
});
|
|
1245
|
+
React4.useImperativeHandle(ref, () => ({
|
|
1246
|
+
y,
|
|
1247
|
+
yInverted,
|
|
1248
|
+
height: sheetHeight,
|
|
1249
|
+
snapTo
|
|
780
1250
|
}));
|
|
781
|
-
if (rootId) {
|
|
782
|
-
console.warn(
|
|
783
|
-
"The `rootId` prop is deprecated and will be removed in the next major version. Use `modalEffectRootId` instead."
|
|
784
|
-
);
|
|
785
|
-
}
|
|
786
1251
|
useModalEffect({
|
|
787
1252
|
y,
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
1253
|
+
detent,
|
|
1254
|
+
sheetHeight,
|
|
1255
|
+
snapPoints,
|
|
1256
|
+
rootId: modalEffectRootId,
|
|
791
1257
|
startThreshold: modalEffectThreshold
|
|
792
1258
|
});
|
|
793
1259
|
usePreventScroll({
|
|
794
1260
|
isDisabled: disableScrollLocking || !isOpen
|
|
795
1261
|
});
|
|
796
|
-
const
|
|
797
|
-
const dragProps2 = {
|
|
798
|
-
drag: "y",
|
|
799
|
-
dragElastic: 0,
|
|
800
|
-
dragMomentum: false,
|
|
801
|
-
dragPropagation: false,
|
|
802
|
-
onDrag,
|
|
803
|
-
onDragStart,
|
|
804
|
-
onDragEnd
|
|
805
|
-
};
|
|
806
|
-
return disableDrag ? void 0 : dragProps2;
|
|
807
|
-
}, [disableDrag, windowHeight]);
|
|
808
|
-
const context = {
|
|
809
|
-
y,
|
|
810
|
-
sheetRef,
|
|
1262
|
+
const state = useSheetState({
|
|
811
1263
|
isOpen,
|
|
812
|
-
|
|
1264
|
+
onOpen: async () => {
|
|
1265
|
+
onOpenStart == null ? void 0 : onOpenStart();
|
|
1266
|
+
const initialSnapPoint = initialSnap !== void 0 ? getSnapPoint(initialSnap) : null;
|
|
1267
|
+
const yTo = (initialSnapPoint == null ? void 0 : initialSnapPoint.snapValueY) ?? 0;
|
|
1268
|
+
await react.animate(y, yTo, animationOptions);
|
|
1269
|
+
if (initialSnap !== void 0) {
|
|
1270
|
+
updateSnap(initialSnap);
|
|
1271
|
+
}
|
|
1272
|
+
onOpenEnd == null ? void 0 : onOpenEnd();
|
|
1273
|
+
},
|
|
1274
|
+
onClosing: async () => {
|
|
1275
|
+
onCloseStart == null ? void 0 : onCloseStart();
|
|
1276
|
+
await react.animate(y, closedY, animationOptions);
|
|
1277
|
+
onCloseEnd == null ? void 0 : onCloseEnd();
|
|
1278
|
+
}
|
|
1279
|
+
});
|
|
1280
|
+
const dragProps = {
|
|
1281
|
+
drag: "y",
|
|
1282
|
+
dragElastic: 0,
|
|
1283
|
+
dragMomentum: false,
|
|
1284
|
+
dragPropagation: false,
|
|
1285
|
+
onDrag,
|
|
1286
|
+
onDragStart,
|
|
1287
|
+
onDragEnd
|
|
1288
|
+
};
|
|
1289
|
+
const context = {
|
|
1290
|
+
currentSnap,
|
|
813
1291
|
detent,
|
|
814
|
-
|
|
815
|
-
callbacks,
|
|
1292
|
+
disableDrag,
|
|
816
1293
|
dragProps,
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
1294
|
+
indicatorRotation,
|
|
1295
|
+
avoidKeyboard,
|
|
1296
|
+
sheetBoundsRef,
|
|
1297
|
+
sheetRef,
|
|
1298
|
+
unstyled,
|
|
1299
|
+
y
|
|
821
1300
|
};
|
|
822
|
-
const sheet = /* @__PURE__ */
|
|
1301
|
+
const sheet = /* @__PURE__ */ React4__default.default.createElement(SheetContext.Provider, { value: context }, /* @__PURE__ */ React4__default.default.createElement(
|
|
823
1302
|
react.motion.div,
|
|
824
1303
|
{
|
|
825
1304
|
...rest,
|
|
826
1305
|
ref,
|
|
827
|
-
|
|
1306
|
+
"data-sheet-state": state,
|
|
1307
|
+
className: `react-modal-sheet-root ${className}`,
|
|
1308
|
+
style: {
|
|
1309
|
+
...applyStyles(styles.root, unstyled),
|
|
1310
|
+
zIndex,
|
|
1311
|
+
visibility,
|
|
1312
|
+
...style
|
|
1313
|
+
}
|
|
828
1314
|
},
|
|
829
|
-
|
|
830
|
-
children,
|
|
831
|
-
(child, i) => React2.cloneElement(child, { key: `sheet-child-${i}` })
|
|
832
|
-
)) : null)
|
|
1315
|
+
state !== "closed" ? children : null
|
|
833
1316
|
));
|
|
834
1317
|
if (IS_SSR) return sheet;
|
|
835
1318
|
return reactDom.createPortal(sheet, mountPoint ?? document.body);
|
|
836
1319
|
}
|
|
837
1320
|
);
|
|
838
1321
|
Sheet.displayName = "Sheet";
|
|
839
|
-
function useEventCallbacks(isOpen, callbacks) {
|
|
840
|
-
const prevOpen = usePrevious(isOpen);
|
|
841
|
-
const didOpen = React2.useRef(false);
|
|
842
|
-
const handleAnimationComplete = React2.useCallback(() => {
|
|
843
|
-
var _a, _b, _c, _d;
|
|
844
|
-
if (!didOpen.current) {
|
|
845
|
-
(_b = (_a = callbacks.current).onOpenEnd) == null ? void 0 : _b.call(_a);
|
|
846
|
-
didOpen.current = true;
|
|
847
|
-
} else {
|
|
848
|
-
(_d = (_c = callbacks.current).onCloseEnd) == null ? void 0 : _d.call(_c);
|
|
849
|
-
didOpen.current = false;
|
|
850
|
-
}
|
|
851
|
-
}, [isOpen, prevOpen]);
|
|
852
|
-
React2.useEffect(() => {
|
|
853
|
-
var _a, _b, _c, _d;
|
|
854
|
-
if (!prevOpen && isOpen) {
|
|
855
|
-
(_b = (_a = callbacks.current).onOpenStart) == null ? void 0 : _b.call(_a);
|
|
856
|
-
} else if (!isOpen && prevOpen) {
|
|
857
|
-
(_d = (_c = callbacks.current).onCloseStart) == null ? void 0 : _d.call(_c);
|
|
858
|
-
}
|
|
859
|
-
}, [isOpen, prevOpen]);
|
|
860
|
-
return { handleAnimationComplete };
|
|
861
|
-
}
|
|
862
|
-
function usePrevious(state) {
|
|
863
|
-
const ref = React2.useRef(void 0);
|
|
864
|
-
React2.useEffect(() => {
|
|
865
|
-
ref.current = state;
|
|
866
|
-
});
|
|
867
|
-
return ref.current;
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
// src/SheetContainer.tsx
|
|
871
|
-
var SheetContainer = React2.forwardRef(
|
|
872
|
-
({ children, style, className = "", ...rest }, ref) => {
|
|
873
|
-
const {
|
|
874
|
-
y,
|
|
875
|
-
isOpen,
|
|
876
|
-
callbacks,
|
|
877
|
-
sheetRef,
|
|
878
|
-
windowHeight,
|
|
879
|
-
detent,
|
|
880
|
-
animationOptions
|
|
881
|
-
} = useSheetContext();
|
|
882
|
-
const { handleAnimationComplete } = useEventCallbacks(isOpen, callbacks);
|
|
883
|
-
const height = detent === "full-height" ? MAX_HEIGHT : void 0;
|
|
884
|
-
const maxHeight = detent === "content-height" ? MAX_HEIGHT : void 0;
|
|
885
|
-
return /* @__PURE__ */ React2__default.default.createElement(
|
|
886
|
-
react.motion.div,
|
|
887
|
-
{
|
|
888
|
-
...rest,
|
|
889
|
-
ref: mergeRefs([sheetRef, ref]),
|
|
890
|
-
className: `react-modal-sheet-container ${className}`,
|
|
891
|
-
style: { ...styles.container, height, maxHeight, ...style, y },
|
|
892
|
-
initial: { y: windowHeight },
|
|
893
|
-
exit: { y: windowHeight, transition: animationOptions },
|
|
894
|
-
onAnimationComplete: handleAnimationComplete
|
|
895
|
-
},
|
|
896
|
-
children
|
|
897
|
-
);
|
|
898
|
-
}
|
|
899
|
-
);
|
|
900
|
-
SheetContainer.displayName = "SheetContainer";
|
|
901
|
-
var constraints = { bottom: 0, top: 0, left: 0, right: 0 };
|
|
902
|
-
function useDragConstraints() {
|
|
903
|
-
const constraintsRef = React2.useRef(null);
|
|
904
|
-
const onMeasureDragConstraints = React2.useCallback(() => constraints, []);
|
|
905
|
-
return { constraintsRef, onMeasureDragConstraints };
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
// src/SheetContent.tsx
|
|
909
|
-
var SheetContent = React2.forwardRef(
|
|
910
|
-
({ children, style, disableDrag, className = "", ...rest }, ref) => {
|
|
911
|
-
const sheetContext = useSheetContext();
|
|
912
|
-
const sheetScrollerContext = useSheetScrollerContext();
|
|
913
|
-
const { constraintsRef, onMeasureDragConstraints } = useDragConstraints();
|
|
914
|
-
const dragProps = disableDrag || sheetScrollerContext.disableDrag ? void 0 : sheetContext.dragProps;
|
|
915
|
-
return /* @__PURE__ */ React2__default.default.createElement(
|
|
916
|
-
react.motion.div,
|
|
917
|
-
{
|
|
918
|
-
...rest,
|
|
919
|
-
ref: mergeRefs([ref, constraintsRef]),
|
|
920
|
-
className: `react-modal-sheet-content ${className}`,
|
|
921
|
-
style: { ...styles.content, ...style },
|
|
922
|
-
...dragProps,
|
|
923
|
-
dragConstraints: constraintsRef,
|
|
924
|
-
onMeasureDragConstraints
|
|
925
|
-
},
|
|
926
|
-
children
|
|
927
|
-
);
|
|
928
|
-
}
|
|
929
|
-
);
|
|
930
|
-
SheetContent.displayName = "SheetContent";
|
|
931
|
-
var SheetHeader = React2.forwardRef(
|
|
932
|
-
({ children, style, disableDrag, ...rest }, ref) => {
|
|
933
|
-
const { indicatorRotation, dragProps } = useSheetContext();
|
|
934
|
-
const { constraintsRef, onMeasureDragConstraints } = useDragConstraints();
|
|
935
|
-
const _dragProps = disableDrag ? void 0 : dragProps;
|
|
936
|
-
const indicator1Transform = react.useTransform(
|
|
937
|
-
indicatorRotation,
|
|
938
|
-
(r) => `translateX(2px) rotate(${r}deg)`
|
|
939
|
-
);
|
|
940
|
-
const indicator2Transform = react.useTransform(
|
|
941
|
-
indicatorRotation,
|
|
942
|
-
(r) => `translateX(-2px) rotate(${ -1 * r}deg)`
|
|
943
|
-
);
|
|
944
|
-
return /* @__PURE__ */ React2__default.default.createElement(
|
|
945
|
-
react.motion.div,
|
|
946
|
-
{
|
|
947
|
-
...rest,
|
|
948
|
-
ref: mergeRefs([ref, constraintsRef]),
|
|
949
|
-
style: { ...styles.headerWrapper, ...style },
|
|
950
|
-
..._dragProps,
|
|
951
|
-
dragConstraints: constraintsRef,
|
|
952
|
-
onMeasureDragConstraints
|
|
953
|
-
},
|
|
954
|
-
children || /* @__PURE__ */ React2__default.default.createElement("div", { className: "react-modal-sheet-header", style: styles.header }, /* @__PURE__ */ React2__default.default.createElement(
|
|
955
|
-
react.motion.span,
|
|
956
|
-
{
|
|
957
|
-
className: "react-modal-sheet-drag-indicator",
|
|
958
|
-
style: { ...styles.indicator, transform: indicator1Transform }
|
|
959
|
-
}
|
|
960
|
-
), /* @__PURE__ */ React2__default.default.createElement(
|
|
961
|
-
react.motion.span,
|
|
962
|
-
{
|
|
963
|
-
className: "react-modal-sheet-drag-indicator",
|
|
964
|
-
style: { ...styles.indicator, transform: indicator2Transform }
|
|
965
|
-
}
|
|
966
|
-
))
|
|
967
|
-
);
|
|
968
|
-
}
|
|
969
|
-
);
|
|
970
|
-
SheetHeader.displayName = "SheetHeader";
|
|
971
|
-
var isClickable = (props) => !!props.onClick || !!props.onTap;
|
|
972
|
-
var SheetBackdrop = React2.forwardRef(
|
|
973
|
-
({ style = {}, className = "", ...rest }, ref) => {
|
|
974
|
-
const Comp = isClickable(rest) ? react.motion.button : react.motion.div;
|
|
975
|
-
const pointerEvents = isClickable(rest) ? "auto" : "none";
|
|
976
|
-
return /* @__PURE__ */ React2__default.default.createElement(
|
|
977
|
-
Comp,
|
|
978
|
-
{
|
|
979
|
-
...rest,
|
|
980
|
-
ref,
|
|
981
|
-
className: `react-modal-sheet-backdrop ${className}`,
|
|
982
|
-
style: { ...styles.backdrop, ...style, pointerEvents },
|
|
983
|
-
initial: { opacity: 0 },
|
|
984
|
-
animate: { opacity: 1 },
|
|
985
|
-
exit: { opacity: 0 }
|
|
986
|
-
}
|
|
987
|
-
);
|
|
988
|
-
}
|
|
989
|
-
);
|
|
990
|
-
SheetBackdrop.displayName = "SheetBackdrop";
|
|
991
|
-
var SheetScroller = React2.forwardRef(
|
|
992
|
-
({
|
|
993
|
-
autoPadding = true,
|
|
994
|
-
disableScroll = false,
|
|
995
|
-
draggableAt = "top",
|
|
996
|
-
children,
|
|
997
|
-
style: styleProp,
|
|
998
|
-
className = "",
|
|
999
|
-
...rest
|
|
1000
|
-
}, ref) => {
|
|
1001
|
-
const { y } = useSheetContext();
|
|
1002
|
-
const { setDragEnabled, setDragDisabled } = useSheetScrollerContext();
|
|
1003
|
-
function determineDragState(element) {
|
|
1004
|
-
if (disableScroll) {
|
|
1005
|
-
setDragEnabled();
|
|
1006
|
-
return;
|
|
1007
|
-
}
|
|
1008
|
-
const { scrollTop, scrollHeight, clientHeight } = element;
|
|
1009
|
-
const isScrollable2 = scrollHeight > clientHeight;
|
|
1010
|
-
if (!isScrollable2) return;
|
|
1011
|
-
const isAtTop = scrollTop <= 0;
|
|
1012
|
-
const isAtBottom = scrollHeight - scrollTop === clientHeight;
|
|
1013
|
-
const shouldEnable = draggableAt === "top" && isAtTop || draggableAt === "bottom" && isAtBottom || draggableAt === "both" && (isAtTop || isAtBottom);
|
|
1014
|
-
if (shouldEnable) {
|
|
1015
|
-
setDragEnabled();
|
|
1016
|
-
} else {
|
|
1017
|
-
setDragDisabled();
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
function onScroll(event) {
|
|
1021
|
-
determineDragState(event.currentTarget);
|
|
1022
|
-
if (rest.onScroll) rest.onScroll(event);
|
|
1023
|
-
}
|
|
1024
|
-
function onTouchStart(event) {
|
|
1025
|
-
determineDragState(event.currentTarget);
|
|
1026
|
-
if (rest.onTouchStart) rest.onTouchStart(event);
|
|
1027
|
-
}
|
|
1028
|
-
const scrollProps = isTouchDevice() ? { onScroll, onTouchStart } : void 0;
|
|
1029
|
-
const style = {
|
|
1030
|
-
...styles.scroller,
|
|
1031
|
-
...styleProp
|
|
1032
|
-
};
|
|
1033
|
-
if (autoPadding) {
|
|
1034
|
-
style.paddingBottom = y;
|
|
1035
|
-
}
|
|
1036
|
-
if (disableScroll) {
|
|
1037
|
-
style.overflowY = "hidden";
|
|
1038
|
-
}
|
|
1039
|
-
return /* @__PURE__ */ React2__default.default.createElement(
|
|
1040
|
-
react.motion.div,
|
|
1041
|
-
{
|
|
1042
|
-
...rest,
|
|
1043
|
-
ref,
|
|
1044
|
-
className: `react-modal-sheet-scroller ${className}`,
|
|
1045
|
-
style,
|
|
1046
|
-
...scrollProps
|
|
1047
|
-
},
|
|
1048
|
-
children
|
|
1049
|
-
);
|
|
1050
|
-
}
|
|
1051
|
-
);
|
|
1052
|
-
SheetScroller.displayName = "SheetScroller";
|
|
1053
1322
|
|
|
1054
1323
|
// src/index.tsx
|
|
1055
1324
|
var Sheet2 = Object.assign(Sheet, {
|
|
1056
1325
|
Container: SheetContainer,
|
|
1057
1326
|
Header: SheetHeader,
|
|
1327
|
+
DragIndicator: SheetDragIndicator,
|
|
1058
1328
|
Content: SheetContent,
|
|
1059
|
-
Backdrop: SheetBackdrop
|
|
1060
|
-
Scroller: SheetScroller
|
|
1329
|
+
Backdrop: SheetBackdrop
|
|
1061
1330
|
});
|
|
1062
1331
|
|
|
1063
1332
|
exports.Sheet = Sheet2;
|