react-modal-sheet 4.0.2 → 4.2.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 +46 -26
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +401 -309
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +402 -310
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/SheetContainer.tsx +5 -18
- package/src/SheetContent.tsx +1 -1
- package/src/SheetHeader.tsx +1 -1
- package/src/context.tsx +4 -4
- package/src/hooks/use-dimensions.ts +30 -0
- package/src/hooks/use-drag-constraints.ts +14 -0
- package/src/hooks/use-event-callbacks.ts +44 -0
- package/src/hooks/use-isomorphic-layout-effect.ts +5 -0
- package/src/hooks/use-modal-effect.ts +165 -0
- package/src/{use-prevent-scroll.ts → hooks/use-prevent-scroll.ts} +2 -2
- package/src/hooks/use-safe-area-insets.ts +40 -0
- package/src/hooks/use-stable-callback.ts +18 -0
- package/src/sheet.tsx +96 -72
- package/src/styles.ts +1 -1
- package/src/types.tsx +6 -3
- package/src/utils.ts +88 -10
- package/src/hooks.tsx +0 -197
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var React2 = require('react');
|
|
4
3
|
var reactDom = require('react-dom');
|
|
4
|
+
var React2 = require('react');
|
|
5
5
|
var react = require('motion/react');
|
|
6
|
+
var motion = require('motion');
|
|
6
7
|
|
|
7
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
9
|
|
|
@@ -24,182 +25,33 @@ var REDUCED_MOTION_TWEEN_CONFIG = {
|
|
|
24
25
|
var DEFAULT_DRAG_CLOSE_THRESHOLD = 0.6;
|
|
25
26
|
var DEFAULT_DRAG_VELOCITY_THRESHOLD = 500;
|
|
26
27
|
|
|
27
|
-
// src/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
function setup() {
|
|
36
|
-
const root = document.querySelector(`#${rootId}`);
|
|
37
|
-
const body = document.querySelector("body");
|
|
38
|
-
if (!root) return;
|
|
39
|
-
body.style.backgroundColor = "#000";
|
|
40
|
-
root.style.overflow = "hidden";
|
|
41
|
-
root.style.transitionTimingFunction = "cubic-bezier(0.32, 0.72, 0, 1)";
|
|
42
|
-
root.style.transitionProperty = "transform, border-radius";
|
|
43
|
-
root.style.transitionDuration = "0.5s";
|
|
44
|
-
root.style.transformOrigin = "center top";
|
|
45
|
-
}
|
|
46
|
-
function cleanup() {
|
|
47
|
-
const root = document.querySelector(`#${rootId}`);
|
|
48
|
-
const body = document.querySelector("body");
|
|
49
|
-
if (!root) return;
|
|
50
|
-
setTimeout(() => {
|
|
51
|
-
body.style.removeProperty("background-color");
|
|
52
|
-
root.style.removeProperty("overflow");
|
|
53
|
-
root.style.removeProperty("transition-timing-function");
|
|
54
|
-
root.style.removeProperty("transition-property");
|
|
55
|
-
root.style.removeProperty("transition-duration");
|
|
56
|
-
root.style.removeProperty("transform-origin");
|
|
57
|
-
root.style.removeProperty("transform");
|
|
58
|
-
root.style.removeProperty("border-top-right-radius");
|
|
59
|
-
root.style.removeProperty("border-top-left-radius");
|
|
60
|
-
}, 100);
|
|
28
|
+
// src/utils.ts
|
|
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;
|
|
61
36
|
}
|
|
62
|
-
|
|
63
|
-
return () => {
|
|
64
|
-
if (rootId) cleanup();
|
|
65
|
-
};
|
|
66
|
-
}, []);
|
|
67
|
-
React2.useEffect(() => {
|
|
68
|
-
const root = document.querySelector(`#${rootId}`);
|
|
69
|
-
if (!root) return;
|
|
70
|
-
function onCompleted() {
|
|
71
|
-
if (y.get() - 10 >= heightRef.current) cleanup();
|
|
72
|
-
}
|
|
73
|
-
const removeStartListener = y.on("animationStart", () => {
|
|
74
|
-
var _a;
|
|
75
|
-
heightRef.current = ((_a = sheetRef.current) == null ? void 0 : _a.offsetHeight) || window.innerHeight;
|
|
76
|
-
setup();
|
|
77
|
-
});
|
|
78
|
-
const removeChangeListener = y.on("change", (value) => {
|
|
79
|
-
if (root) {
|
|
80
|
-
const progress = Math.max(0, 1 - value / heightRef.current);
|
|
81
|
-
const pageWidth = window.innerWidth;
|
|
82
|
-
const scale = (pageWidth - 16) / pageWidth;
|
|
83
|
-
const ty = react.transform(progress, [0, 1], [0, 24]);
|
|
84
|
-
const s = react.transform(progress, [0, 1], [1, scale]);
|
|
85
|
-
const borderRadius = react.transform(progress, [0, 1], [0, 10]);
|
|
86
|
-
const inset = "env(safe-area-inset-top)";
|
|
87
|
-
root.style.transform = `scale(${s}) translate3d(0, calc(${inset} + ${ty}px), 0)`;
|
|
88
|
-
root.style.borderTopRightRadius = `${borderRadius}px`;
|
|
89
|
-
root.style.borderTopLeftRadius = `${borderRadius}px`;
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
const removeCompleteListener = y.on("animationComplete", onCompleted);
|
|
93
|
-
const removeCancelListener = y.on("animationCancel", onCompleted);
|
|
94
|
-
return () => {
|
|
95
|
-
removeStartListener();
|
|
96
|
-
removeChangeListener();
|
|
97
|
-
removeCompleteListener();
|
|
98
|
-
removeCancelListener();
|
|
99
|
-
};
|
|
100
|
-
}, [y, rootId]);
|
|
101
|
-
}
|
|
102
|
-
function useEventCallbacks(isOpen, callbacks) {
|
|
103
|
-
const prevOpen = usePrevious(isOpen);
|
|
104
|
-
const didOpen = React2.useRef(false);
|
|
105
|
-
const handleAnimationComplete = React2.useCallback(() => {
|
|
106
|
-
var _a, _b, _c, _d;
|
|
107
|
-
if (!didOpen.current) {
|
|
108
|
-
(_b = (_a = callbacks.current).onOpenEnd) == null ? void 0 : _b.call(_a);
|
|
109
|
-
didOpen.current = true;
|
|
110
|
-
} else {
|
|
111
|
-
(_d = (_c = callbacks.current).onCloseEnd) == null ? void 0 : _d.call(_c);
|
|
112
|
-
didOpen.current = false;
|
|
113
|
-
}
|
|
114
|
-
}, [isOpen, prevOpen]);
|
|
115
|
-
React2.useEffect(() => {
|
|
116
|
-
var _a, _b, _c, _d;
|
|
117
|
-
if (!prevOpen && isOpen) {
|
|
118
|
-
(_b = (_a = callbacks.current).onOpenStart) == null ? void 0 : _b.call(_a);
|
|
119
|
-
} else if (!isOpen && prevOpen) {
|
|
120
|
-
(_d = (_c = callbacks.current).onCloseStart) == null ? void 0 : _d.call(_c);
|
|
121
|
-
}
|
|
122
|
-
}, [isOpen, prevOpen]);
|
|
123
|
-
return { handleAnimationComplete };
|
|
37
|
+
return Math.round(sheetEl.getBoundingClientRect().height);
|
|
124
38
|
}
|
|
125
|
-
function
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
setDimensions({
|
|
133
|
-
height: window.innerHeight,
|
|
134
|
-
width: window.innerWidth
|
|
135
|
-
});
|
|
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);
|
|
136
46
|
}
|
|
137
|
-
|
|
138
|
-
window.addEventListener("resize", handler);
|
|
139
|
-
return () => {
|
|
140
|
-
window.removeEventListener("resize", handler);
|
|
141
|
-
};
|
|
142
|
-
}, []);
|
|
143
|
-
return dimensions;
|
|
144
|
-
}
|
|
145
|
-
function usePrevious(state) {
|
|
146
|
-
const ref = React2.useRef(void 0);
|
|
147
|
-
React2.useEffect(() => {
|
|
148
|
-
ref.current = state;
|
|
47
|
+
return point < 0 ? sheetHeight + point : point;
|
|
149
48
|
});
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const handlerRef = React2.useRef(void 0);
|
|
154
|
-
useIsomorphicLayoutEffect(() => {
|
|
155
|
-
handlerRef.current = handler;
|
|
156
|
-
});
|
|
157
|
-
return React2.useCallback((...args) => {
|
|
158
|
-
const fn = handlerRef.current;
|
|
159
|
-
return fn == null ? void 0 : fn(...args);
|
|
160
|
-
}, []);
|
|
161
|
-
}
|
|
162
|
-
var constraints = { bottom: 0, top: 0, left: 0, right: 0 };
|
|
163
|
-
function useDragConstraints() {
|
|
164
|
-
const constraintsRef = React2.useRef(null);
|
|
165
|
-
const onMeasureDragConstraints = React2.useCallback(() => constraints, []);
|
|
166
|
-
return { constraintsRef, onMeasureDragConstraints };
|
|
167
|
-
}
|
|
168
|
-
var SheetContext = React2.createContext(
|
|
169
|
-
void 0
|
|
170
|
-
);
|
|
171
|
-
var useSheetContext = () => {
|
|
172
|
-
const context = React2.useContext(SheetContext);
|
|
173
|
-
if (!context) throw new Error("Sheet context error");
|
|
174
|
-
return context;
|
|
175
|
-
};
|
|
176
|
-
var SheetScrollerContext = React2.createContext(void 0);
|
|
177
|
-
function SheetScrollerContextProvider({
|
|
178
|
-
children
|
|
179
|
-
}) {
|
|
180
|
-
const sheetContext = useSheetContext();
|
|
181
|
-
const [disableDrag, setDisableDrag] = React2.useState(!!sheetContext.disableDrag);
|
|
182
|
-
function setDragEnabled() {
|
|
183
|
-
if (!sheetContext.disableDrag) setDisableDrag(false);
|
|
184
|
-
}
|
|
185
|
-
function setDragDisabled() {
|
|
186
|
-
if (!disableDrag) setDisableDrag(true);
|
|
187
|
-
}
|
|
188
|
-
return /* @__PURE__ */ React2__default.default.createElement(
|
|
189
|
-
SheetScrollerContext.Provider,
|
|
190
|
-
{
|
|
191
|
-
value: { disableDrag, setDragEnabled, setDragDisabled }
|
|
192
|
-
},
|
|
193
|
-
children
|
|
49
|
+
console.assert(
|
|
50
|
+
inDescendingOrder(snapPointValues) || sheetHeight === 0,
|
|
51
|
+
`Snap points need to be in descending order got: [${snapPointsProp.join(", ")}]`
|
|
194
52
|
);
|
|
53
|
+
return snapPointValues;
|
|
195
54
|
}
|
|
196
|
-
var useSheetScrollerContext = () => {
|
|
197
|
-
const context = React2.useContext(SheetScrollerContext);
|
|
198
|
-
if (!context) throw new Error("Sheet scroller context error");
|
|
199
|
-
return context;
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
// src/utils.ts
|
|
203
55
|
function getClosest(nums, goal) {
|
|
204
56
|
let closest = nums[0];
|
|
205
57
|
let minDifference = Math.abs(nums[0] - goal);
|
|
@@ -218,6 +70,21 @@ function inDescendingOrder(arr) {
|
|
|
218
70
|
}
|
|
219
71
|
return true;
|
|
220
72
|
}
|
|
73
|
+
function getSnapY({
|
|
74
|
+
sheetHeight,
|
|
75
|
+
snapPoints,
|
|
76
|
+
snapIndex
|
|
77
|
+
}) {
|
|
78
|
+
const snapPoint = snapPoints[snapIndex];
|
|
79
|
+
if (snapPoint === void 0) {
|
|
80
|
+
console.warn(
|
|
81
|
+
`Invalid snap index ${snapIndex}. Snap points are: [${snapPoints.join(", ")}]`
|
|
82
|
+
);
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
const y = validateSnapTo({ snapTo: sheetHeight - snapPoint, sheetHeight });
|
|
86
|
+
return y;
|
|
87
|
+
}
|
|
221
88
|
function validateSnapTo({
|
|
222
89
|
snapTo,
|
|
223
90
|
sheetHeight
|
|
@@ -241,7 +108,7 @@ function mergeRefs(refs) {
|
|
|
241
108
|
};
|
|
242
109
|
}
|
|
243
110
|
function isTouchDevice() {
|
|
244
|
-
if (
|
|
111
|
+
if (IS_SSR) return false;
|
|
245
112
|
return "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
246
113
|
}
|
|
247
114
|
function testPlatform(re) {
|
|
@@ -267,14 +134,265 @@ var isIPhone = cached(function() {
|
|
|
267
134
|
return testPlatform(/^iPhone/i);
|
|
268
135
|
});
|
|
269
136
|
var isIPad = cached(function() {
|
|
270
|
-
return testPlatform(/^iPad/i) ||
|
|
271
|
-
isMac() && navigator.maxTouchPoints > 1;
|
|
137
|
+
return testPlatform(/^iPad/i) || isMac() && navigator.maxTouchPoints > 1;
|
|
272
138
|
});
|
|
273
139
|
var isIOS = cached(function() {
|
|
274
140
|
return isIPhone() || isIPad();
|
|
275
141
|
});
|
|
142
|
+
var SheetContext = React2.createContext(
|
|
143
|
+
void 0
|
|
144
|
+
);
|
|
145
|
+
function useSheetContext() {
|
|
146
|
+
const context = React2.useContext(SheetContext);
|
|
147
|
+
if (!context) throw new Error("Sheet context error");
|
|
148
|
+
return context;
|
|
149
|
+
}
|
|
150
|
+
var SheetScrollerContext = React2.createContext(void 0);
|
|
151
|
+
function SheetScrollerContextProvider({
|
|
152
|
+
children
|
|
153
|
+
}) {
|
|
154
|
+
const sheetContext = useSheetContext();
|
|
155
|
+
const [disableDrag, setDisableDrag] = React2.useState(!!sheetContext.disableDrag);
|
|
156
|
+
function setDragEnabled() {
|
|
157
|
+
if (!sheetContext.disableDrag) setDisableDrag(false);
|
|
158
|
+
}
|
|
159
|
+
function setDragDisabled() {
|
|
160
|
+
if (!disableDrag) setDisableDrag(true);
|
|
161
|
+
}
|
|
162
|
+
return /* @__PURE__ */ React2__default.default.createElement(
|
|
163
|
+
SheetScrollerContext.Provider,
|
|
164
|
+
{
|
|
165
|
+
value: { disableDrag, setDragEnabled, setDragDisabled }
|
|
166
|
+
},
|
|
167
|
+
children
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
function useSheetScrollerContext() {
|
|
171
|
+
const context = React2.useContext(SheetScrollerContext);
|
|
172
|
+
if (!context) throw new Error("Sheet scroller context error");
|
|
173
|
+
return context;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/styles.ts
|
|
177
|
+
var styles = {
|
|
178
|
+
wrapper: {
|
|
179
|
+
position: "fixed",
|
|
180
|
+
top: 0,
|
|
181
|
+
bottom: 0,
|
|
182
|
+
left: 0,
|
|
183
|
+
right: 0,
|
|
184
|
+
overflow: "hidden",
|
|
185
|
+
pointerEvents: "none"
|
|
186
|
+
},
|
|
187
|
+
backdrop: {
|
|
188
|
+
zIndex: 1,
|
|
189
|
+
position: "fixed",
|
|
190
|
+
top: 0,
|
|
191
|
+
left: 0,
|
|
192
|
+
width: "100%",
|
|
193
|
+
height: "100%",
|
|
194
|
+
backgroundColor: "rgba(0, 0, 0, 0.2)",
|
|
195
|
+
touchAction: "none",
|
|
196
|
+
border: "none",
|
|
197
|
+
WebkitTapHighlightColor: "transparent"
|
|
198
|
+
},
|
|
199
|
+
container: {
|
|
200
|
+
zIndex: 2,
|
|
201
|
+
position: "absolute",
|
|
202
|
+
left: 0,
|
|
203
|
+
bottom: 0,
|
|
204
|
+
width: "100%",
|
|
205
|
+
backgroundColor: "#fff",
|
|
206
|
+
borderTopRightRadius: "8px",
|
|
207
|
+
borderTopLeftRadius: "8px",
|
|
208
|
+
boxShadow: "0px -2px 16px rgba(0, 0, 0, 0.3)",
|
|
209
|
+
display: "flex",
|
|
210
|
+
flexDirection: "column",
|
|
211
|
+
pointerEvents: "auto"
|
|
212
|
+
},
|
|
213
|
+
headerWrapper: {
|
|
214
|
+
width: "100%"
|
|
215
|
+
},
|
|
216
|
+
header: {
|
|
217
|
+
height: "40px",
|
|
218
|
+
width: "100%",
|
|
219
|
+
position: "relative",
|
|
220
|
+
display: "flex",
|
|
221
|
+
alignItems: "center",
|
|
222
|
+
justifyContent: "center"
|
|
223
|
+
},
|
|
224
|
+
indicator: {
|
|
225
|
+
width: "18px",
|
|
226
|
+
height: "4px",
|
|
227
|
+
borderRadius: "99px",
|
|
228
|
+
backgroundColor: "#ddd"
|
|
229
|
+
},
|
|
230
|
+
content: {
|
|
231
|
+
flexGrow: 1,
|
|
232
|
+
display: "flex",
|
|
233
|
+
flexDirection: "column",
|
|
234
|
+
minHeight: "0px",
|
|
235
|
+
position: "relative"
|
|
236
|
+
},
|
|
237
|
+
scroller: {
|
|
238
|
+
height: "100%",
|
|
239
|
+
overflowY: "auto"
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
var useIsomorphicLayoutEffect = IS_SSR ? React2.useEffect : React2.useLayoutEffect;
|
|
243
|
+
function useSafeAreaInsets() {
|
|
244
|
+
const [insets] = React2.useState(() => {
|
|
245
|
+
const fallback = { top: 0, left: 0, right: 0, bottom: 0 };
|
|
246
|
+
if (IS_SSR) return fallback;
|
|
247
|
+
const root = document.querySelector(":root");
|
|
248
|
+
if (!root) return fallback;
|
|
249
|
+
root.style.setProperty("--rms-sat", "env(safe-area-inset-top)");
|
|
250
|
+
root.style.setProperty("--rms-sal", "env(safe-area-inset-left)");
|
|
251
|
+
root.style.setProperty("--rms-sar", "env(safe-area-inset-right)");
|
|
252
|
+
root.style.setProperty("--rms-sab", "env(safe-area-inset-bottom)");
|
|
253
|
+
const computedStyle = getComputedStyle(root);
|
|
254
|
+
const sat = getComputedValue(computedStyle, "--rms-sat");
|
|
255
|
+
const sal = getComputedValue(computedStyle, "--rms-sal");
|
|
256
|
+
const sar = getComputedValue(computedStyle, "--rms-sar");
|
|
257
|
+
const sab = getComputedValue(computedStyle, "--rms-sab");
|
|
258
|
+
root.style.removeProperty("--rms-sat");
|
|
259
|
+
root.style.removeProperty("--rms-sal");
|
|
260
|
+
root.style.removeProperty("--rms-sar");
|
|
261
|
+
root.style.removeProperty("--rms-sab");
|
|
262
|
+
return { top: sat, left: sal, right: sar, bottom: sab };
|
|
263
|
+
});
|
|
264
|
+
return insets;
|
|
265
|
+
}
|
|
266
|
+
function getComputedValue(computed, property) {
|
|
267
|
+
const strValue = computed.getPropertyValue(property).replace("px", "").trim();
|
|
268
|
+
return parseInt(strValue, 10) || 0;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// src/hooks/use-modal-effect.ts
|
|
272
|
+
function useModalEffect({
|
|
273
|
+
y,
|
|
274
|
+
rootId,
|
|
275
|
+
sheetRef,
|
|
276
|
+
snapPointsProp,
|
|
277
|
+
startThreshold
|
|
278
|
+
}) {
|
|
279
|
+
const insetTop = useSafeAreaInsets().top;
|
|
280
|
+
useIsomorphicLayoutEffect(() => {
|
|
281
|
+
return () => {
|
|
282
|
+
if (rootId) cleanupModalEffect(rootId);
|
|
283
|
+
};
|
|
284
|
+
}, []);
|
|
285
|
+
useIsomorphicLayoutEffect(() => {
|
|
286
|
+
if (!rootId) return;
|
|
287
|
+
const root = document.querySelector(`#${rootId}`);
|
|
288
|
+
if (!root) return;
|
|
289
|
+
let sheetHeight = 0;
|
|
290
|
+
const removeStartListener = y.on("animationStart", () => {
|
|
291
|
+
sheetHeight = getSheetHeight(sheetRef);
|
|
292
|
+
setupModalEffect(rootId);
|
|
293
|
+
});
|
|
294
|
+
const removeChangeListener = y.on("change", (yValue) => {
|
|
295
|
+
if (!root) return;
|
|
296
|
+
let progress = Math.max(0, 1 - yValue / sheetHeight);
|
|
297
|
+
const snapPoints = snapPointsProp ? getSnapPoints({ snapPointsProp, sheetHeight }) : void 0;
|
|
298
|
+
const snapThresholdPoint = snapPoints && snapPoints.length > 1 ? snapPoints[1] : void 0;
|
|
299
|
+
if (snapThresholdPoint !== void 0) {
|
|
300
|
+
const snapThresholdValue = sheetHeight - Math.min(snapThresholdPoint, sheetHeight);
|
|
301
|
+
if (yValue <= snapThresholdValue) {
|
|
302
|
+
progress = (snapThresholdValue - yValue) / snapThresholdValue;
|
|
303
|
+
} else {
|
|
304
|
+
progress = 0;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (startThreshold !== void 0) {
|
|
308
|
+
const startThresholdValue = sheetHeight - Math.min(Math.floor(startThreshold * sheetHeight), sheetHeight);
|
|
309
|
+
if (yValue <= startThresholdValue) {
|
|
310
|
+
progress = (startThresholdValue - yValue) / startThresholdValue;
|
|
311
|
+
} else {
|
|
312
|
+
progress = 0;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
progress = Math.max(0, Math.min(1, progress));
|
|
316
|
+
const pageWidth = window.innerWidth;
|
|
317
|
+
const ty = motion.transform(progress, [0, 1], [0, 24 + insetTop]);
|
|
318
|
+
const s = motion.transform(progress, [0, 1], [1, (pageWidth - 16) / pageWidth]);
|
|
319
|
+
const borderRadius = motion.transform(progress, [0, 1], [0, 10]);
|
|
320
|
+
root.style.transform = `scale(${s}) translate3d(0, ${ty}px, 0)`;
|
|
321
|
+
root.style.borderTopRightRadius = `${borderRadius}px`;
|
|
322
|
+
root.style.borderTopLeftRadius = `${borderRadius}px`;
|
|
323
|
+
});
|
|
324
|
+
function onCompleted() {
|
|
325
|
+
if (y.get() - 5 >= sheetHeight) {
|
|
326
|
+
cleanupModalEffect(rootId);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const removeCompleteListener = y.on("animationComplete", onCompleted);
|
|
330
|
+
const removeCancelListener = y.on("animationCancel", onCompleted);
|
|
331
|
+
return () => {
|
|
332
|
+
removeStartListener();
|
|
333
|
+
removeChangeListener();
|
|
334
|
+
removeCompleteListener();
|
|
335
|
+
removeCancelListener();
|
|
336
|
+
};
|
|
337
|
+
}, [y, rootId, insetTop, startThreshold, snapPointsProp]);
|
|
338
|
+
}
|
|
339
|
+
function setupModalEffect(rootId) {
|
|
340
|
+
const root = document.querySelector(`#${rootId}`);
|
|
341
|
+
const body = document.querySelector("body");
|
|
342
|
+
if (!root) return;
|
|
343
|
+
body.style.backgroundColor = "#000";
|
|
344
|
+
root.style.overflow = "hidden";
|
|
345
|
+
root.style.transitionTimingFunction = "cubic-bezier(0.32, 0.72, 0, 1)";
|
|
346
|
+
root.style.transitionProperty = "transform, border-radius";
|
|
347
|
+
root.style.transitionDuration = "0.5s";
|
|
348
|
+
root.style.transformOrigin = "center top";
|
|
349
|
+
}
|
|
350
|
+
function cleanupModalEffect(rootId) {
|
|
351
|
+
const root = document.querySelector(`#${rootId}`);
|
|
352
|
+
const body = document.querySelector("body");
|
|
353
|
+
if (!root) return;
|
|
354
|
+
body.style.removeProperty("background-color");
|
|
355
|
+
root.style.removeProperty("overflow");
|
|
356
|
+
root.style.removeProperty("transition-timing-function");
|
|
357
|
+
root.style.removeProperty("transition-property");
|
|
358
|
+
root.style.removeProperty("transition-duration");
|
|
359
|
+
root.style.removeProperty("transform-origin");
|
|
360
|
+
root.style.removeProperty("transform");
|
|
361
|
+
root.style.removeProperty("border-top-right-radius");
|
|
362
|
+
root.style.removeProperty("border-top-left-radius");
|
|
363
|
+
}
|
|
364
|
+
function useDimensions() {
|
|
365
|
+
const [dimensions, setDimensions] = React2.useState(() => ({
|
|
366
|
+
height: !IS_SSR ? window.innerHeight : 0,
|
|
367
|
+
width: !IS_SSR ? window.innerWidth : 0
|
|
368
|
+
}));
|
|
369
|
+
useIsomorphicLayoutEffect(() => {
|
|
370
|
+
function handler() {
|
|
371
|
+
setDimensions({
|
|
372
|
+
height: window.innerHeight,
|
|
373
|
+
width: window.innerWidth
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
handler();
|
|
377
|
+
window.addEventListener("resize", handler);
|
|
378
|
+
return () => {
|
|
379
|
+
window.removeEventListener("resize", handler);
|
|
380
|
+
};
|
|
381
|
+
}, []);
|
|
382
|
+
return dimensions;
|
|
383
|
+
}
|
|
384
|
+
function useStableCallback(handler) {
|
|
385
|
+
const handlerRef = React2.useRef(void 0);
|
|
386
|
+
useIsomorphicLayoutEffect(() => {
|
|
387
|
+
handlerRef.current = handler;
|
|
388
|
+
});
|
|
389
|
+
return React2.useCallback((...args) => {
|
|
390
|
+
const fn = handlerRef.current;
|
|
391
|
+
return fn == null ? void 0 : fn(...args);
|
|
392
|
+
}, []);
|
|
393
|
+
}
|
|
276
394
|
|
|
277
|
-
// src/use-prevent-scroll.ts
|
|
395
|
+
// src/hooks/use-prevent-scroll.ts
|
|
278
396
|
var KEYBOARD_BUFFER = 24;
|
|
279
397
|
function chain(...callbacks) {
|
|
280
398
|
return (...args) => {
|
|
@@ -490,74 +608,6 @@ function willOpenKeyboard(target) {
|
|
|
490
608
|
return target instanceof HTMLInputElement && !nonTextInputTypes.has(target.type) || target instanceof HTMLTextAreaElement || target instanceof HTMLElement && target.isContentEditable;
|
|
491
609
|
}
|
|
492
610
|
|
|
493
|
-
// src/styles.ts
|
|
494
|
-
var styles = {
|
|
495
|
-
wrapper: {
|
|
496
|
-
position: "fixed",
|
|
497
|
-
top: 0,
|
|
498
|
-
bottom: 0,
|
|
499
|
-
left: 0,
|
|
500
|
-
right: 0,
|
|
501
|
-
overflow: "hidden",
|
|
502
|
-
pointerEvents: "none"
|
|
503
|
-
},
|
|
504
|
-
backdrop: {
|
|
505
|
-
zIndex: 1,
|
|
506
|
-
position: "fixed",
|
|
507
|
-
top: 0,
|
|
508
|
-
left: 0,
|
|
509
|
-
width: "100%",
|
|
510
|
-
height: "100%",
|
|
511
|
-
backgroundColor: "rgba(0, 0, 0, 0.2)",
|
|
512
|
-
touchAction: "none",
|
|
513
|
-
// Disable iOS body scrolling
|
|
514
|
-
border: "none",
|
|
515
|
-
WebkitTapHighlightColor: "transparent"
|
|
516
|
-
},
|
|
517
|
-
container: {
|
|
518
|
-
zIndex: 2,
|
|
519
|
-
position: "absolute",
|
|
520
|
-
left: 0,
|
|
521
|
-
bottom: 0,
|
|
522
|
-
width: "100%",
|
|
523
|
-
backgroundColor: "#fff",
|
|
524
|
-
borderTopRightRadius: "8px",
|
|
525
|
-
borderTopLeftRadius: "8px",
|
|
526
|
-
boxShadow: "0px -2px 16px rgba(0, 0, 0, 0.3)",
|
|
527
|
-
display: "flex",
|
|
528
|
-
flexDirection: "column",
|
|
529
|
-
pointerEvents: "auto"
|
|
530
|
-
},
|
|
531
|
-
headerWrapper: {
|
|
532
|
-
width: "100%"
|
|
533
|
-
},
|
|
534
|
-
header: {
|
|
535
|
-
height: "40px",
|
|
536
|
-
width: "100%",
|
|
537
|
-
position: "relative",
|
|
538
|
-
display: "flex",
|
|
539
|
-
alignItems: "center",
|
|
540
|
-
justifyContent: "center"
|
|
541
|
-
},
|
|
542
|
-
indicator: {
|
|
543
|
-
width: "18px",
|
|
544
|
-
height: "4px",
|
|
545
|
-
borderRadius: "99px",
|
|
546
|
-
backgroundColor: "#ddd"
|
|
547
|
-
},
|
|
548
|
-
content: {
|
|
549
|
-
flexGrow: 1,
|
|
550
|
-
display: "flex",
|
|
551
|
-
flexDirection: "column",
|
|
552
|
-
minHeight: "0px",
|
|
553
|
-
position: "relative"
|
|
554
|
-
},
|
|
555
|
-
scroller: {
|
|
556
|
-
height: "100%",
|
|
557
|
-
overflowY: "auto"
|
|
558
|
-
}
|
|
559
|
-
};
|
|
560
|
-
|
|
561
611
|
// src/sheet.tsx
|
|
562
612
|
var Sheet = React2.forwardRef(
|
|
563
613
|
({
|
|
@@ -572,6 +622,7 @@ var Sheet = React2.forwardRef(
|
|
|
572
622
|
isOpen,
|
|
573
623
|
snapPoints: snapPointsProp,
|
|
574
624
|
rootId,
|
|
625
|
+
modalEffectRootId,
|
|
575
626
|
mountPoint,
|
|
576
627
|
style,
|
|
577
628
|
detent = "full-height",
|
|
@@ -581,6 +632,7 @@ var Sheet = React2.forwardRef(
|
|
|
581
632
|
tweenConfig = DEFAULT_TWEEN_CONFIG,
|
|
582
633
|
dragVelocityThreshold = DEFAULT_DRAG_VELOCITY_THRESHOLD,
|
|
583
634
|
dragCloseThreshold = DEFAULT_DRAG_CLOSE_THRESHOLD,
|
|
635
|
+
modalEffectThreshold,
|
|
584
636
|
...rest
|
|
585
637
|
}, ref) => {
|
|
586
638
|
const sheetRef = React2.useRef(null);
|
|
@@ -615,26 +667,13 @@ var Sheet = React2.forwardRef(
|
|
|
615
667
|
onCloseEnd
|
|
616
668
|
};
|
|
617
669
|
});
|
|
618
|
-
|
|
619
|
-
if (snapPoints) {
|
|
620
|
-
snapPoints = snapPoints.map((point) => {
|
|
621
|
-
if (point > 0 && point <= 1) return Math.round(point * windowHeight);
|
|
622
|
-
return point < 0 ? windowHeight + point : point;
|
|
623
|
-
});
|
|
624
|
-
console.assert(
|
|
625
|
-
inDescendingOrder(snapPoints) || windowHeight === 0,
|
|
626
|
-
`Snap points need to be in descending order got: [${snapPoints.join(
|
|
627
|
-
", "
|
|
628
|
-
)}]`
|
|
629
|
-
);
|
|
630
|
-
}
|
|
631
|
-
const onDrag = useEffectEvent((_, { delta }) => {
|
|
670
|
+
const onDrag = useStableCallback((_, { delta }) => {
|
|
632
671
|
const velocity = y.getVelocity();
|
|
633
672
|
if (velocity > 0) indicatorRotation.set(10);
|
|
634
673
|
if (velocity < 0) indicatorRotation.set(-10);
|
|
635
674
|
y.set(Math.max(y.get() + delta.y, 0));
|
|
636
675
|
});
|
|
637
|
-
const onDragStart =
|
|
676
|
+
const onDragStart = useStableCallback(() => {
|
|
638
677
|
const focusedElement = document.activeElement;
|
|
639
678
|
if (!focusedElement || !sheetRef.current) return;
|
|
640
679
|
const isInput = focusedElement.tagName === "INPUT" || focusedElement.tagName === "TEXTAREA";
|
|
@@ -642,67 +681,91 @@ var Sheet = React2.forwardRef(
|
|
|
642
681
|
focusedElement.blur();
|
|
643
682
|
}
|
|
644
683
|
});
|
|
645
|
-
const onDragEnd =
|
|
684
|
+
const onDragEnd = useStableCallback((_, { velocity }) => {
|
|
646
685
|
if (velocity.y > dragVelocityThreshold) {
|
|
647
686
|
onClose();
|
|
648
687
|
} else {
|
|
649
|
-
const sheetHeight = sheetRef
|
|
688
|
+
const sheetHeight = getSheetHeight(sheetRef);
|
|
650
689
|
const currentY = y.get();
|
|
651
|
-
let
|
|
690
|
+
let yTo = 0;
|
|
691
|
+
const snapPoints = snapPointsProp ? getSnapPoints({ snapPointsProp, sheetHeight }) : void 0;
|
|
652
692
|
if (snapPoints) {
|
|
653
|
-
const
|
|
693
|
+
const snapInverse = snapPoints.map(
|
|
654
694
|
(p) => sheetHeight - Math.min(p, sheetHeight)
|
|
655
695
|
);
|
|
656
|
-
if (detent === "content-height" && !
|
|
657
|
-
|
|
696
|
+
if (detent === "content-height" && !snapInverse.includes(0)) {
|
|
697
|
+
snapInverse.unshift(0);
|
|
658
698
|
}
|
|
659
|
-
snapTo = getClosest(
|
|
699
|
+
const snapTo = getClosest(snapInverse, currentY);
|
|
700
|
+
const snapIndex = snapInverse.indexOf(snapTo);
|
|
701
|
+
yTo = validateSnapTo({
|
|
702
|
+
snapTo: getClosest(snapInverse, currentY),
|
|
703
|
+
sheetHeight
|
|
704
|
+
});
|
|
705
|
+
onSnap == null ? void 0 : onSnap(snapIndex);
|
|
660
706
|
} else if (currentY / sheetHeight > dragCloseThreshold) {
|
|
661
|
-
|
|
707
|
+
yTo = sheetHeight;
|
|
662
708
|
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
const snapValue = Math.abs(Math.round(snapPoints[0] - snapTo));
|
|
667
|
-
const snapIndex = snapPoints.indexOf(
|
|
668
|
-
getClosest(snapPoints, snapValue)
|
|
669
|
-
);
|
|
670
|
-
onSnap(snapIndex);
|
|
709
|
+
react.animate(y, yTo, animationOptions);
|
|
710
|
+
if (yTo + 1 >= sheetHeight) {
|
|
711
|
+
onClose();
|
|
671
712
|
}
|
|
672
|
-
const roundedSheetHeight = Math.round(sheetHeight);
|
|
673
|
-
const shouldClose = snapTo + 2 >= roundedSheetHeight;
|
|
674
|
-
if (shouldClose) onClose();
|
|
675
713
|
}
|
|
676
714
|
indicatorRotation.set(0);
|
|
677
715
|
});
|
|
678
716
|
React2.useEffect(() => {
|
|
679
|
-
if (
|
|
680
|
-
|
|
681
|
-
|
|
717
|
+
if (snapPointsProp && onSnap) {
|
|
718
|
+
onSnap(isOpen ? initialSnap : snapPointsProp.length - 1);
|
|
719
|
+
}
|
|
720
|
+
}, [isOpen]);
|
|
721
|
+
React2.useEffect(() => {
|
|
722
|
+
if (!isOpen) return;
|
|
723
|
+
let yTo = 0;
|
|
724
|
+
if (snapPointsProp) {
|
|
725
|
+
const snapIndex = initialSnap;
|
|
726
|
+
const sheetHeight = getSheetHeight(sheetRef);
|
|
727
|
+
const snapPoints = getSnapPoints({ snapPointsProp, sheetHeight });
|
|
728
|
+
const ySnap = getSnapY({ sheetHeight, snapPoints, snapIndex });
|
|
729
|
+
if (ySnap !== null) {
|
|
730
|
+
yTo = ySnap;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
react.animate(y, yTo, animationOptions);
|
|
682
734
|
}, [isOpen]);
|
|
683
735
|
React2.useImperativeHandle(ref, () => ({
|
|
684
736
|
y,
|
|
685
737
|
snapTo: (snapIndex) => {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
react.animate(y,
|
|
695
|
-
|
|
696
|
-
if (
|
|
738
|
+
if (!snapPointsProp) {
|
|
739
|
+
console.warn("Snapping is not possible without `snapPoints` prop.");
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
const sheetHeight = getSheetHeight(sheetRef);
|
|
743
|
+
const snapPoints = getSnapPoints({ snapPointsProp, sheetHeight });
|
|
744
|
+
const ySnap = getSnapY({ sheetHeight, snapPoints, snapIndex });
|
|
745
|
+
if (ySnap !== null) {
|
|
746
|
+
react.animate(y, ySnap, animationOptions);
|
|
747
|
+
onSnap == null ? void 0 : onSnap(snapIndex);
|
|
748
|
+
if (ySnap + 1 >= sheetHeight) {
|
|
749
|
+
onClose();
|
|
750
|
+
}
|
|
697
751
|
}
|
|
698
752
|
}
|
|
699
753
|
}));
|
|
754
|
+
if (rootId) {
|
|
755
|
+
console.warn(
|
|
756
|
+
"The `rootId` prop is deprecated and will be removed in the next major version. Use `modalEffectRootId` instead."
|
|
757
|
+
);
|
|
758
|
+
}
|
|
700
759
|
useModalEffect({
|
|
701
760
|
y,
|
|
702
|
-
|
|
703
|
-
|
|
761
|
+
sheetRef,
|
|
762
|
+
snapPointsProp,
|
|
763
|
+
rootId: rootId || modalEffectRootId,
|
|
764
|
+
startThreshold: modalEffectThreshold
|
|
765
|
+
});
|
|
766
|
+
usePreventScroll({
|
|
767
|
+
isDisabled: disableScrollLocking || !isOpen
|
|
704
768
|
});
|
|
705
|
-
usePreventScroll({ isDisabled: disableScrollLocking || !isOpen });
|
|
706
769
|
const dragProps = React2.useMemo(() => {
|
|
707
770
|
const dragProps2 = {
|
|
708
771
|
drag: "y",
|
|
@@ -720,7 +783,6 @@ var Sheet = React2.forwardRef(
|
|
|
720
783
|
sheetRef,
|
|
721
784
|
isOpen,
|
|
722
785
|
initialSnap,
|
|
723
|
-
snapPoints,
|
|
724
786
|
detent,
|
|
725
787
|
indicatorRotation,
|
|
726
788
|
callbacks,
|
|
@@ -747,38 +809,60 @@ var Sheet = React2.forwardRef(
|
|
|
747
809
|
}
|
|
748
810
|
);
|
|
749
811
|
Sheet.displayName = "Sheet";
|
|
812
|
+
function useEventCallbacks(isOpen, callbacks) {
|
|
813
|
+
const prevOpen = usePrevious(isOpen);
|
|
814
|
+
const didOpen = React2.useRef(false);
|
|
815
|
+
const handleAnimationComplete = React2.useCallback(() => {
|
|
816
|
+
var _a, _b, _c, _d;
|
|
817
|
+
if (!didOpen.current) {
|
|
818
|
+
(_b = (_a = callbacks.current).onOpenEnd) == null ? void 0 : _b.call(_a);
|
|
819
|
+
didOpen.current = true;
|
|
820
|
+
} else {
|
|
821
|
+
(_d = (_c = callbacks.current).onCloseEnd) == null ? void 0 : _d.call(_c);
|
|
822
|
+
didOpen.current = false;
|
|
823
|
+
}
|
|
824
|
+
}, [isOpen, prevOpen]);
|
|
825
|
+
React2.useEffect(() => {
|
|
826
|
+
var _a, _b, _c, _d;
|
|
827
|
+
if (!prevOpen && isOpen) {
|
|
828
|
+
(_b = (_a = callbacks.current).onOpenStart) == null ? void 0 : _b.call(_a);
|
|
829
|
+
} else if (!isOpen && prevOpen) {
|
|
830
|
+
(_d = (_c = callbacks.current).onCloseStart) == null ? void 0 : _d.call(_c);
|
|
831
|
+
}
|
|
832
|
+
}, [isOpen, prevOpen]);
|
|
833
|
+
return { handleAnimationComplete };
|
|
834
|
+
}
|
|
835
|
+
function usePrevious(state) {
|
|
836
|
+
const ref = React2.useRef(void 0);
|
|
837
|
+
React2.useEffect(() => {
|
|
838
|
+
ref.current = state;
|
|
839
|
+
});
|
|
840
|
+
return ref.current;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// src/SheetContainer.tsx
|
|
750
844
|
var SheetContainer = React2.forwardRef(
|
|
751
|
-
({ children, style
|
|
845
|
+
({ children, style, className = "", ...rest }, ref) => {
|
|
752
846
|
const {
|
|
753
847
|
y,
|
|
754
848
|
isOpen,
|
|
755
849
|
callbacks,
|
|
756
|
-
snapPoints,
|
|
757
|
-
initialSnap = 0,
|
|
758
850
|
sheetRef,
|
|
759
851
|
windowHeight,
|
|
760
852
|
detent,
|
|
761
853
|
animationOptions
|
|
762
854
|
} = useSheetContext();
|
|
763
855
|
const { handleAnimationComplete } = useEventCallbacks(isOpen, callbacks);
|
|
764
|
-
const
|
|
765
|
-
const
|
|
766
|
-
const height = maxSnapHeight !== null ? `min(${maxSnapHeight}px, ${MAX_HEIGHT})` : MAX_HEIGHT;
|
|
856
|
+
const height = detent === "full-height" ? MAX_HEIGHT : void 0;
|
|
857
|
+
const maxHeight = detent === "content-height" ? MAX_HEIGHT : void 0;
|
|
767
858
|
return /* @__PURE__ */ React2__default.default.createElement(
|
|
768
859
|
react.motion.div,
|
|
769
860
|
{
|
|
770
861
|
...rest,
|
|
771
862
|
ref: mergeRefs([sheetRef, ref]),
|
|
772
863
|
className: `react-modal-sheet-container ${className}`,
|
|
773
|
-
style: {
|
|
774
|
-
...styles.container,
|
|
775
|
-
...style,
|
|
776
|
-
...detent === "full-height" && { height },
|
|
777
|
-
...detent === "content-height" && { maxHeight: height },
|
|
778
|
-
y
|
|
779
|
-
},
|
|
864
|
+
style: { ...styles.container, height, maxHeight, ...style, y },
|
|
780
865
|
initial: { y: windowHeight },
|
|
781
|
-
animate: { y: initialY, transition: animationOptions },
|
|
782
866
|
exit: { y: windowHeight, transition: animationOptions },
|
|
783
867
|
onAnimationComplete: handleAnimationComplete
|
|
784
868
|
},
|
|
@@ -787,6 +871,14 @@ var SheetContainer = React2.forwardRef(
|
|
|
787
871
|
}
|
|
788
872
|
);
|
|
789
873
|
SheetContainer.displayName = "SheetContainer";
|
|
874
|
+
var constraints = { bottom: 0, top: 0, left: 0, right: 0 };
|
|
875
|
+
function useDragConstraints() {
|
|
876
|
+
const constraintsRef = React2.useRef(null);
|
|
877
|
+
const onMeasureDragConstraints = React2.useCallback(() => constraints, []);
|
|
878
|
+
return { constraintsRef, onMeasureDragConstraints };
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// src/SheetContent.tsx
|
|
790
882
|
var SheetContent = React2.forwardRef(
|
|
791
883
|
({ children, style, disableDrag, className = "", ...rest }, ref) => {
|
|
792
884
|
const sheetContext = useSheetContext();
|