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