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