react-modal-sheet 2.2.1 → 3.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 +5 -5
- package/dist/index.d.mts +64 -0
- package/dist/index.d.ts +64 -8
- package/dist/index.js +827 -5
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +824 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +59 -36
- package/src/SheetBackdrop.tsx +5 -3
- package/src/SheetContainer.tsx +5 -3
- package/src/SheetContent.tsx +5 -3
- package/src/SheetHeader.tsx +7 -5
- package/src/SheetScroller.tsx +7 -5
- package/src/context.tsx +8 -10
- package/src/hooks.tsx +30 -23
- package/src/index.tsx +7 -7
- package/src/sheet.tsx +47 -32
- package/src/styles.ts +2 -2
- package/src/types.tsx +44 -35
- package/src/use-prevent-scroll.ts +26 -23
- package/src/utils.ts +2 -4
- package/dist/SheetBackdrop.d.ts +0 -5
- package/dist/SheetContainer.d.ts +0 -7
- package/dist/SheetContent.d.ts +0 -8
- package/dist/SheetHeader.d.ts +0 -8
- package/dist/SheetScroller.d.ts +0 -5
- package/dist/constants.d.ts +0 -12
- package/dist/context.d.ts +0 -9
- package/dist/hooks.d.ts +0 -15
- package/dist/react-modal-sheet.cjs.development.js +0 -940
- package/dist/react-modal-sheet.cjs.development.js.map +0 -1
- package/dist/react-modal-sheet.cjs.production.min.js +0 -2
- package/dist/react-modal-sheet.cjs.production.min.js.map +0 -1
- package/dist/react-modal-sheet.esm.js +0 -936
- package/dist/react-modal-sheet.esm.js.map +0 -1
- package/dist/sheet.d.ts +0 -279
- package/dist/styles.d.ts +0 -5
- package/dist/types.d.ts +0 -84
- package/dist/use-prevent-scroll.d.ts +0 -11
- package/dist/utils.d.ts +0 -11
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
import React2, { createContext, forwardRef, useRef, useEffect, useImperativeHandle, useMemo, Children, cloneElement, useLayoutEffect, useCallback, useState, useContext } from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
import { useMotionValue, useReducedMotion, useTransform, animate, motion, AnimatePresence } from 'framer-motion';
|
|
4
|
+
import { useLayoutEffect as useLayoutEffect$1, isIOS, chain, getScrollParent } from '@react-aria/utils';
|
|
5
|
+
|
|
6
|
+
// src/sheet.tsx
|
|
7
|
+
|
|
8
|
+
// src/constants.ts
|
|
9
|
+
var MAX_HEIGHT = "calc(100% - env(safe-area-inset-top) - 34px)";
|
|
10
|
+
var IS_SSR = typeof window === "undefined";
|
|
11
|
+
var DEFAULT_TWEEN_CONFIG = {
|
|
12
|
+
ease: "easeOut",
|
|
13
|
+
duration: 0.2
|
|
14
|
+
};
|
|
15
|
+
var REDUCED_MOTION_TWEEN_CONFIG = {
|
|
16
|
+
ease: "linear",
|
|
17
|
+
duration: 0.01
|
|
18
|
+
};
|
|
19
|
+
var DRAG_CLOSE_THRESHOLD = 0.6;
|
|
20
|
+
var DRAG_VELOCITY_THRESHOLD = 500;
|
|
21
|
+
|
|
22
|
+
// src/utils.ts
|
|
23
|
+
function getClosest(nums, goal) {
|
|
24
|
+
let closest = nums[0];
|
|
25
|
+
let minDifference = Math.abs(nums[0] - goal);
|
|
26
|
+
for (let i = 1; i < nums.length; i++) {
|
|
27
|
+
const difference = Math.abs(nums[i] - goal);
|
|
28
|
+
if (difference < minDifference) {
|
|
29
|
+
closest = nums[i];
|
|
30
|
+
minDifference = difference;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return closest;
|
|
34
|
+
}
|
|
35
|
+
function applyRootStyles(rootId) {
|
|
36
|
+
const body = document.querySelector("body");
|
|
37
|
+
const root = document.querySelector(`#${rootId}`);
|
|
38
|
+
if (root) {
|
|
39
|
+
const p = 24;
|
|
40
|
+
const h = window.innerHeight;
|
|
41
|
+
const s = (h - p) / h;
|
|
42
|
+
body.style.backgroundColor = "#000";
|
|
43
|
+
root.style.overflow = "hidden";
|
|
44
|
+
root.style.willChange = "transform";
|
|
45
|
+
root.style.transition = "transform 200ms ease-in-out, border-radius 200ms linear";
|
|
46
|
+
root.style.transform = `translateY(calc(env(safe-area-inset-top) + ${p / 2}px)) scale(${s})`;
|
|
47
|
+
root.style.borderTopRightRadius = "10px";
|
|
48
|
+
root.style.borderTopLeftRadius = "10px";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function cleanupRootStyles(rootId) {
|
|
52
|
+
const body = document.querySelector("body");
|
|
53
|
+
const root = document.getElementById(rootId);
|
|
54
|
+
function onTransitionEnd() {
|
|
55
|
+
root.style.removeProperty("overflow");
|
|
56
|
+
root.style.removeProperty("will-change");
|
|
57
|
+
root.style.removeProperty("transition");
|
|
58
|
+
body.style.removeProperty("background-color");
|
|
59
|
+
root.removeEventListener("transitionend", onTransitionEnd);
|
|
60
|
+
}
|
|
61
|
+
if (root) {
|
|
62
|
+
root.style.removeProperty("border-top-right-radius");
|
|
63
|
+
root.style.removeProperty("border-top-left-radius");
|
|
64
|
+
root.style.removeProperty("transform");
|
|
65
|
+
root.addEventListener("transitionend", onTransitionEnd);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function inDescendingOrder(arr) {
|
|
69
|
+
for (let i = 0; i < arr.length; i++) {
|
|
70
|
+
if (arr[i + 1] > arr[i])
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
function validateSnapTo({
|
|
76
|
+
snapTo,
|
|
77
|
+
sheetHeight
|
|
78
|
+
}) {
|
|
79
|
+
if (snapTo < 0) {
|
|
80
|
+
console.warn(
|
|
81
|
+
`Snap point is out of bounds. Sheet height is ${sheetHeight} but snap point is ${sheetHeight + Math.abs(snapTo)}.`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
return Math.max(Math.round(snapTo), 0);
|
|
85
|
+
}
|
|
86
|
+
function mergeRefs(refs) {
|
|
87
|
+
return (value) => {
|
|
88
|
+
refs.forEach((ref) => {
|
|
89
|
+
if (typeof ref === "function") {
|
|
90
|
+
ref(value);
|
|
91
|
+
} else if (ref) {
|
|
92
|
+
ref.current = value;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function isTouchDevice() {
|
|
98
|
+
if (typeof window === "undefined")
|
|
99
|
+
return false;
|
|
100
|
+
return "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/hooks.tsx
|
|
104
|
+
var useIsomorphicLayoutEffect = IS_SSR ? useEffect : useLayoutEffect;
|
|
105
|
+
function useModalEffect(isOpen, rootId) {
|
|
106
|
+
const prevOpen = usePrevious(isOpen);
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
if (rootId && !prevOpen && isOpen) {
|
|
109
|
+
applyRootStyles(rootId);
|
|
110
|
+
} else if (rootId && !isOpen && prevOpen) {
|
|
111
|
+
cleanupRootStyles(rootId);
|
|
112
|
+
}
|
|
113
|
+
}, [isOpen, prevOpen]);
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
return () => {
|
|
116
|
+
if (rootId && isOpen)
|
|
117
|
+
cleanupRootStyles(rootId);
|
|
118
|
+
};
|
|
119
|
+
}, [isOpen]);
|
|
120
|
+
}
|
|
121
|
+
function useEventCallbacks(isOpen, callbacks) {
|
|
122
|
+
const prevOpen = usePrevious(isOpen);
|
|
123
|
+
const didOpen = useRef(false);
|
|
124
|
+
const handleAnimationComplete = useCallback(() => {
|
|
125
|
+
var _a, _b, _c, _d;
|
|
126
|
+
if (!didOpen.current) {
|
|
127
|
+
(_b = (_a = callbacks.current).onOpenEnd) == null ? void 0 : _b.call(_a);
|
|
128
|
+
didOpen.current = true;
|
|
129
|
+
} else {
|
|
130
|
+
(_d = (_c = callbacks.current).onCloseEnd) == null ? void 0 : _d.call(_c);
|
|
131
|
+
didOpen.current = false;
|
|
132
|
+
}
|
|
133
|
+
}, [isOpen, prevOpen]);
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
var _a, _b, _c, _d;
|
|
136
|
+
if (!prevOpen && isOpen) {
|
|
137
|
+
(_b = (_a = callbacks.current).onOpenStart) == null ? void 0 : _b.call(_a);
|
|
138
|
+
} else if (!isOpen && prevOpen) {
|
|
139
|
+
(_d = (_c = callbacks.current).onCloseStart) == null ? void 0 : _d.call(_c);
|
|
140
|
+
}
|
|
141
|
+
}, [isOpen, prevOpen]);
|
|
142
|
+
return { handleAnimationComplete };
|
|
143
|
+
}
|
|
144
|
+
function useDimensions() {
|
|
145
|
+
const [dimensions, setDimensions] = useState({ height: 0, width: 0 });
|
|
146
|
+
useIsomorphicLayoutEffect(() => {
|
|
147
|
+
const updateHeight = () => {
|
|
148
|
+
setDimensions({ height: window.innerHeight, width: window.innerWidth });
|
|
149
|
+
};
|
|
150
|
+
window.addEventListener("resize", updateHeight);
|
|
151
|
+
updateHeight();
|
|
152
|
+
return () => {
|
|
153
|
+
window.removeEventListener("resize", updateHeight);
|
|
154
|
+
};
|
|
155
|
+
}, []);
|
|
156
|
+
return dimensions;
|
|
157
|
+
}
|
|
158
|
+
function usePrevious(state) {
|
|
159
|
+
const ref = useRef();
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
ref.current = state;
|
|
162
|
+
});
|
|
163
|
+
return ref.current;
|
|
164
|
+
}
|
|
165
|
+
function useEvent(handler) {
|
|
166
|
+
const handlerRef = useRef();
|
|
167
|
+
useIsomorphicLayoutEffect(() => {
|
|
168
|
+
handlerRef.current = handler;
|
|
169
|
+
});
|
|
170
|
+
return useCallback((...args) => {
|
|
171
|
+
const fn = handlerRef.current;
|
|
172
|
+
return fn == null ? void 0 : fn(...args);
|
|
173
|
+
}, []);
|
|
174
|
+
}
|
|
175
|
+
var constraints = { bottom: 0, top: 0, left: 0, right: 0 };
|
|
176
|
+
function useDragConstraints() {
|
|
177
|
+
const constraintsRef = useRef(null);
|
|
178
|
+
const onMeasureDragConstraints = useCallback(() => constraints, []);
|
|
179
|
+
return { constraintsRef, onMeasureDragConstraints };
|
|
180
|
+
}
|
|
181
|
+
var SheetContext = createContext(
|
|
182
|
+
void 0
|
|
183
|
+
);
|
|
184
|
+
var useSheetContext = () => {
|
|
185
|
+
const context = useContext(SheetContext);
|
|
186
|
+
if (!context)
|
|
187
|
+
throw Error("Sheet context error");
|
|
188
|
+
return context;
|
|
189
|
+
};
|
|
190
|
+
var SheetScrollerContext = createContext(void 0);
|
|
191
|
+
function SheetScrollerContextProvider({
|
|
192
|
+
children
|
|
193
|
+
}) {
|
|
194
|
+
const sheetContext = useSheetContext();
|
|
195
|
+
const [disableDrag, setDisableDrag] = useState(!!sheetContext.disableDrag);
|
|
196
|
+
function setDragEnabled() {
|
|
197
|
+
if (!sheetContext.disableDrag)
|
|
198
|
+
setDisableDrag(false);
|
|
199
|
+
}
|
|
200
|
+
function setDragDisabled() {
|
|
201
|
+
if (!disableDrag)
|
|
202
|
+
setDisableDrag(true);
|
|
203
|
+
}
|
|
204
|
+
return /* @__PURE__ */ React2.createElement(
|
|
205
|
+
SheetScrollerContext.Provider,
|
|
206
|
+
{
|
|
207
|
+
value: { disableDrag, setDragEnabled, setDragDisabled }
|
|
208
|
+
},
|
|
209
|
+
children
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
var useSheetScrollerContext = () => {
|
|
213
|
+
const context = useContext(SheetScrollerContext);
|
|
214
|
+
if (!context)
|
|
215
|
+
throw Error("Sheet scroller context error");
|
|
216
|
+
return context;
|
|
217
|
+
};
|
|
218
|
+
var visualViewport = typeof window !== "undefined" ? window.visualViewport : void 0;
|
|
219
|
+
var nonTextInputTypes = /* @__PURE__ */ new Set([
|
|
220
|
+
"checkbox",
|
|
221
|
+
"radio",
|
|
222
|
+
"range",
|
|
223
|
+
"color",
|
|
224
|
+
"file",
|
|
225
|
+
"image",
|
|
226
|
+
"button",
|
|
227
|
+
"submit",
|
|
228
|
+
"reset"
|
|
229
|
+
]);
|
|
230
|
+
var preventScrollCount = 0;
|
|
231
|
+
var restore;
|
|
232
|
+
function usePreventScroll(options = {}) {
|
|
233
|
+
const { isDisabled } = options;
|
|
234
|
+
useLayoutEffect$1(() => {
|
|
235
|
+
if (isDisabled) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
preventScrollCount++;
|
|
239
|
+
if (preventScrollCount === 1) {
|
|
240
|
+
if (isIOS()) {
|
|
241
|
+
restore = preventScrollMobileSafari();
|
|
242
|
+
} else {
|
|
243
|
+
restore = preventScrollStandard();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return () => {
|
|
247
|
+
preventScrollCount--;
|
|
248
|
+
if (preventScrollCount === 0) {
|
|
249
|
+
restore();
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
}, [isDisabled]);
|
|
253
|
+
}
|
|
254
|
+
function preventScrollStandard() {
|
|
255
|
+
return chain(
|
|
256
|
+
setStyle(
|
|
257
|
+
document.documentElement,
|
|
258
|
+
"paddingRight",
|
|
259
|
+
`${window.innerWidth - document.documentElement.clientWidth}px`
|
|
260
|
+
),
|
|
261
|
+
setStyle(document.documentElement, "overflow", "hidden")
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
function preventScrollMobileSafari() {
|
|
265
|
+
let scrollable;
|
|
266
|
+
let lastY = 0;
|
|
267
|
+
const onTouchStart = (e) => {
|
|
268
|
+
scrollable = getScrollParent(e.target);
|
|
269
|
+
if (scrollable === document.documentElement && scrollable === document.body) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
lastY = e.changedTouches[0].pageY;
|
|
273
|
+
};
|
|
274
|
+
const onTouchMove = (e) => {
|
|
275
|
+
if (scrollable === void 0) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (scrollable === document.documentElement || scrollable === document.body) {
|
|
279
|
+
e.preventDefault();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const y = e.changedTouches[0].pageY;
|
|
283
|
+
const scrollTop = scrollable.scrollTop;
|
|
284
|
+
const bottom = scrollable.scrollHeight - scrollable.clientHeight;
|
|
285
|
+
if (bottom === 0) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (scrollTop <= 0 && y > lastY || scrollTop >= bottom && y < lastY) {
|
|
289
|
+
e.preventDefault();
|
|
290
|
+
}
|
|
291
|
+
lastY = y;
|
|
292
|
+
};
|
|
293
|
+
const onTouchEnd = (e) => {
|
|
294
|
+
const target = e.target;
|
|
295
|
+
if (willOpenKeyboard(target) && target !== document.activeElement) {
|
|
296
|
+
e.preventDefault();
|
|
297
|
+
target.style.transform = "translateY(-2000px)";
|
|
298
|
+
target.focus();
|
|
299
|
+
requestAnimationFrame(() => {
|
|
300
|
+
target.style.transform = "";
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
const onFocus = (e) => {
|
|
305
|
+
const target = e.target;
|
|
306
|
+
if (willOpenKeyboard(target)) {
|
|
307
|
+
target.style.transform = "translateY(-2000px)";
|
|
308
|
+
requestAnimationFrame(() => {
|
|
309
|
+
target.style.transform = "";
|
|
310
|
+
if (visualViewport) {
|
|
311
|
+
if (visualViewport.height < window.innerHeight) {
|
|
312
|
+
requestAnimationFrame(() => {
|
|
313
|
+
scrollIntoView(target);
|
|
314
|
+
});
|
|
315
|
+
} else {
|
|
316
|
+
visualViewport.addEventListener(
|
|
317
|
+
"resize",
|
|
318
|
+
() => {
|
|
319
|
+
scrollIntoView(target);
|
|
320
|
+
},
|
|
321
|
+
{ once: true }
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
const onWindowScroll = () => {
|
|
329
|
+
window.scrollTo(0, 0);
|
|
330
|
+
};
|
|
331
|
+
const scrollX = window.pageXOffset;
|
|
332
|
+
const scrollY = window.pageYOffset;
|
|
333
|
+
const restoreStyles = chain(
|
|
334
|
+
setStyle(
|
|
335
|
+
document.documentElement,
|
|
336
|
+
"paddingRight",
|
|
337
|
+
`${window.innerWidth - document.documentElement.clientWidth}px`
|
|
338
|
+
),
|
|
339
|
+
setStyle(document.documentElement, "overflow", "hidden"),
|
|
340
|
+
setStyle(document.body, "marginTop", `-${scrollY}px`)
|
|
341
|
+
);
|
|
342
|
+
window.scrollTo(0, 0);
|
|
343
|
+
const removeEvents = chain(
|
|
344
|
+
addEvent(document, "touchstart", onTouchStart, {
|
|
345
|
+
passive: false,
|
|
346
|
+
capture: true
|
|
347
|
+
}),
|
|
348
|
+
addEvent(document, "touchmove", onTouchMove, {
|
|
349
|
+
passive: false,
|
|
350
|
+
capture: true
|
|
351
|
+
}),
|
|
352
|
+
addEvent(document, "touchend", onTouchEnd, {
|
|
353
|
+
passive: false,
|
|
354
|
+
capture: true
|
|
355
|
+
}),
|
|
356
|
+
addEvent(document, "focus", onFocus, true),
|
|
357
|
+
addEvent(window, "scroll", onWindowScroll)
|
|
358
|
+
);
|
|
359
|
+
return () => {
|
|
360
|
+
restoreStyles();
|
|
361
|
+
removeEvents();
|
|
362
|
+
window.scrollTo(scrollX, scrollY);
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
function setStyle(element, style, value) {
|
|
366
|
+
const cur = element.style[style];
|
|
367
|
+
element.style[style] = value;
|
|
368
|
+
return () => {
|
|
369
|
+
element.style[style] = cur;
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
function addEvent(target, event, handler, options) {
|
|
373
|
+
target.addEventListener(event, handler, options);
|
|
374
|
+
return () => {
|
|
375
|
+
target.removeEventListener(event, handler, options);
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
function scrollIntoView(target) {
|
|
379
|
+
const root = document.scrollingElement || document.documentElement;
|
|
380
|
+
while (target && target !== root) {
|
|
381
|
+
const scrollable = getScrollParent(target);
|
|
382
|
+
if (scrollable !== document.documentElement && scrollable !== document.body && scrollable !== target) {
|
|
383
|
+
const scrollableTop = scrollable.getBoundingClientRect().top;
|
|
384
|
+
const targetTop = target.getBoundingClientRect().top;
|
|
385
|
+
if (targetTop > scrollableTop + target.clientHeight) {
|
|
386
|
+
scrollable.scrollTop += targetTop - scrollableTop;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
target = scrollable.parentElement;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
function willOpenKeyboard(target) {
|
|
393
|
+
return target instanceof HTMLInputElement && !nonTextInputTypes.has(target.type) || target instanceof HTMLTextAreaElement || target instanceof HTMLElement && target.isContentEditable;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// src/styles.ts
|
|
397
|
+
var styles = {
|
|
398
|
+
wrapper: {
|
|
399
|
+
position: "fixed",
|
|
400
|
+
top: 0,
|
|
401
|
+
bottom: 0,
|
|
402
|
+
left: 0,
|
|
403
|
+
right: 0,
|
|
404
|
+
overflow: "hidden",
|
|
405
|
+
pointerEvents: "none"
|
|
406
|
+
},
|
|
407
|
+
backdrop: {
|
|
408
|
+
zIndex: 1,
|
|
409
|
+
position: "fixed",
|
|
410
|
+
top: 0,
|
|
411
|
+
left: 0,
|
|
412
|
+
width: "100%",
|
|
413
|
+
height: "100%",
|
|
414
|
+
backgroundColor: "rgba(0, 0, 0, 0.2)",
|
|
415
|
+
touchAction: "none",
|
|
416
|
+
// Disable iOS body scrolling
|
|
417
|
+
border: "none"
|
|
418
|
+
},
|
|
419
|
+
container: {
|
|
420
|
+
zIndex: 2,
|
|
421
|
+
position: "absolute",
|
|
422
|
+
left: 0,
|
|
423
|
+
bottom: 0,
|
|
424
|
+
width: "100%",
|
|
425
|
+
backgroundColor: "#fff",
|
|
426
|
+
borderTopRightRadius: "8px",
|
|
427
|
+
borderTopLeftRadius: "8px",
|
|
428
|
+
boxShadow: "0px -2px 16px rgba(0, 0, 0, 0.3)",
|
|
429
|
+
display: "flex",
|
|
430
|
+
flexDirection: "column",
|
|
431
|
+
pointerEvents: "auto"
|
|
432
|
+
},
|
|
433
|
+
headerWrapper: {
|
|
434
|
+
width: "100%"
|
|
435
|
+
},
|
|
436
|
+
header: {
|
|
437
|
+
height: "40px",
|
|
438
|
+
width: "100%",
|
|
439
|
+
position: "relative",
|
|
440
|
+
display: "flex",
|
|
441
|
+
alignItems: "center",
|
|
442
|
+
justifyContent: "center"
|
|
443
|
+
},
|
|
444
|
+
indicator: {
|
|
445
|
+
width: "18px",
|
|
446
|
+
height: "4px",
|
|
447
|
+
borderRadius: "99px",
|
|
448
|
+
backgroundColor: "#ddd"
|
|
449
|
+
},
|
|
450
|
+
content: {
|
|
451
|
+
flexGrow: 1,
|
|
452
|
+
display: "flex",
|
|
453
|
+
flexDirection: "column",
|
|
454
|
+
minHeight: "0px",
|
|
455
|
+
position: "relative"
|
|
456
|
+
},
|
|
457
|
+
scroller: {
|
|
458
|
+
height: "100%",
|
|
459
|
+
overflowY: "auto"
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
var styles_default = styles;
|
|
463
|
+
|
|
464
|
+
// src/sheet.tsx
|
|
465
|
+
var Sheet = forwardRef(
|
|
466
|
+
({
|
|
467
|
+
onOpenStart,
|
|
468
|
+
onOpenEnd,
|
|
469
|
+
onClose,
|
|
470
|
+
onCloseStart,
|
|
471
|
+
onCloseEnd,
|
|
472
|
+
onSnap,
|
|
473
|
+
children,
|
|
474
|
+
disableScrollLocking = false,
|
|
475
|
+
isOpen,
|
|
476
|
+
snapPoints,
|
|
477
|
+
rootId,
|
|
478
|
+
mountPoint,
|
|
479
|
+
style,
|
|
480
|
+
detent = "full-height",
|
|
481
|
+
initialSnap = 0,
|
|
482
|
+
disableDrag = false,
|
|
483
|
+
prefersReducedMotion = false,
|
|
484
|
+
tweenConfig = DEFAULT_TWEEN_CONFIG,
|
|
485
|
+
...rest
|
|
486
|
+
}, ref) => {
|
|
487
|
+
const sheetRef = useRef(null);
|
|
488
|
+
const constraintsRef = useRef(null);
|
|
489
|
+
const indicatorRotation = useMotionValue(0);
|
|
490
|
+
const { height: windowHeight } = useDimensions();
|
|
491
|
+
const shouldReduceMotion = useReducedMotion();
|
|
492
|
+
const reduceMotion = Boolean(prefersReducedMotion || shouldReduceMotion);
|
|
493
|
+
const animationOptions = {
|
|
494
|
+
type: "tween",
|
|
495
|
+
...reduceMotion ? REDUCED_MOTION_TWEEN_CONFIG : tweenConfig
|
|
496
|
+
};
|
|
497
|
+
const y = useMotionValue(0);
|
|
498
|
+
const zIndex = useTransform(
|
|
499
|
+
y,
|
|
500
|
+
(value) => value >= windowHeight ? -1 : 9999999
|
|
501
|
+
);
|
|
502
|
+
const visibility = useTransform(
|
|
503
|
+
y,
|
|
504
|
+
(value) => value >= windowHeight ? "hidden" : "visible"
|
|
505
|
+
);
|
|
506
|
+
const callbacks = useRef({
|
|
507
|
+
onOpenStart,
|
|
508
|
+
onOpenEnd,
|
|
509
|
+
onCloseStart,
|
|
510
|
+
onCloseEnd
|
|
511
|
+
});
|
|
512
|
+
useIsomorphicLayoutEffect(() => {
|
|
513
|
+
callbacks.current = {
|
|
514
|
+
onOpenStart,
|
|
515
|
+
onOpenEnd,
|
|
516
|
+
onCloseStart,
|
|
517
|
+
onCloseEnd
|
|
518
|
+
};
|
|
519
|
+
});
|
|
520
|
+
if (snapPoints) {
|
|
521
|
+
snapPoints = snapPoints.map((point) => {
|
|
522
|
+
if (point > 0 && point <= 1)
|
|
523
|
+
return Math.round(point * windowHeight);
|
|
524
|
+
return point < 0 ? windowHeight + point : point;
|
|
525
|
+
});
|
|
526
|
+
console.assert(
|
|
527
|
+
inDescendingOrder(snapPoints) || windowHeight === 0,
|
|
528
|
+
`Snap points need to be in descending order got: [${snapPoints.join(
|
|
529
|
+
", "
|
|
530
|
+
)}]`
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
const onDrag = useEvent((_, { delta }) => {
|
|
534
|
+
const velocity = y.getVelocity();
|
|
535
|
+
if (velocity > 0)
|
|
536
|
+
indicatorRotation.set(10);
|
|
537
|
+
if (velocity < 0)
|
|
538
|
+
indicatorRotation.set(-10);
|
|
539
|
+
y.set(Math.max(y.get() + delta.y, 0));
|
|
540
|
+
});
|
|
541
|
+
const onDragEnd = useEvent((_, { velocity }) => {
|
|
542
|
+
if (velocity.y > DRAG_VELOCITY_THRESHOLD) {
|
|
543
|
+
onClose();
|
|
544
|
+
} else {
|
|
545
|
+
const sheetEl = sheetRef.current;
|
|
546
|
+
const sheetHeight = sheetEl.getBoundingClientRect().height;
|
|
547
|
+
const currentY = y.get();
|
|
548
|
+
let snapTo = 0;
|
|
549
|
+
if (snapPoints) {
|
|
550
|
+
const snapToValues = snapPoints.map(
|
|
551
|
+
(p) => sheetHeight - Math.min(p, sheetHeight)
|
|
552
|
+
);
|
|
553
|
+
if (detent === "content-height" && !snapToValues.includes(0)) {
|
|
554
|
+
snapToValues.unshift(0);
|
|
555
|
+
}
|
|
556
|
+
snapTo = getClosest(snapToValues, currentY);
|
|
557
|
+
} else if (currentY / sheetHeight > DRAG_CLOSE_THRESHOLD) {
|
|
558
|
+
snapTo = sheetHeight;
|
|
559
|
+
}
|
|
560
|
+
snapTo = validateSnapTo({ snapTo, sheetHeight });
|
|
561
|
+
void animate(y, snapTo, animationOptions);
|
|
562
|
+
if (snapPoints && onSnap) {
|
|
563
|
+
const snapValue = Math.abs(Math.round(snapPoints[0] - snapTo));
|
|
564
|
+
const snapIndex = snapPoints.indexOf(getClosest(snapPoints, snapValue));
|
|
565
|
+
onSnap(snapIndex);
|
|
566
|
+
}
|
|
567
|
+
const roundedSheetHeight = Math.round(sheetHeight);
|
|
568
|
+
const shouldClose = snapTo >= roundedSheetHeight;
|
|
569
|
+
if (shouldClose)
|
|
570
|
+
onClose();
|
|
571
|
+
}
|
|
572
|
+
indicatorRotation.set(0);
|
|
573
|
+
});
|
|
574
|
+
useEffect(() => {
|
|
575
|
+
if (!snapPoints || !onSnap)
|
|
576
|
+
return;
|
|
577
|
+
const snapIndex = isOpen ? initialSnap : snapPoints.length - 1;
|
|
578
|
+
onSnap(snapIndex);
|
|
579
|
+
}, [isOpen]);
|
|
580
|
+
useImperativeHandle(ref, () => ({
|
|
581
|
+
y,
|
|
582
|
+
snapTo: (snapIndex) => {
|
|
583
|
+
const sheetEl = sheetRef.current;
|
|
584
|
+
if ((snapPoints == null ? void 0 : snapPoints[snapIndex]) !== void 0 && sheetEl !== null) {
|
|
585
|
+
const sheetHeight = sheetEl.getBoundingClientRect().height;
|
|
586
|
+
const snapPoint = snapPoints[snapIndex];
|
|
587
|
+
const snapTo = validateSnapTo({
|
|
588
|
+
snapTo: sheetHeight - snapPoint,
|
|
589
|
+
sheetHeight
|
|
590
|
+
});
|
|
591
|
+
void animate(y, snapTo, animationOptions);
|
|
592
|
+
if (onSnap)
|
|
593
|
+
onSnap(snapIndex);
|
|
594
|
+
if (snapTo >= sheetHeight)
|
|
595
|
+
onClose();
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}));
|
|
599
|
+
useModalEffect(isOpen, rootId);
|
|
600
|
+
usePreventScroll({ isDisabled: disableScrollLocking || !isOpen });
|
|
601
|
+
const dragProps = useMemo(() => {
|
|
602
|
+
const dragProps2 = {
|
|
603
|
+
drag: "y",
|
|
604
|
+
dragElastic: 0,
|
|
605
|
+
dragMomentum: false,
|
|
606
|
+
dragPropagation: false,
|
|
607
|
+
onDrag,
|
|
608
|
+
onDragEnd
|
|
609
|
+
};
|
|
610
|
+
return disableDrag ? void 0 : dragProps2;
|
|
611
|
+
}, [disableDrag, windowHeight]);
|
|
612
|
+
const context = {
|
|
613
|
+
y,
|
|
614
|
+
sheetRef,
|
|
615
|
+
isOpen,
|
|
616
|
+
initialSnap,
|
|
617
|
+
snapPoints,
|
|
618
|
+
detent,
|
|
619
|
+
indicatorRotation,
|
|
620
|
+
callbacks,
|
|
621
|
+
dragProps,
|
|
622
|
+
windowHeight,
|
|
623
|
+
animationOptions,
|
|
624
|
+
reduceMotion,
|
|
625
|
+
disableDrag
|
|
626
|
+
};
|
|
627
|
+
const sheet = /* @__PURE__ */ React2.createElement(SheetContext.Provider, { value: context }, /* @__PURE__ */ React2.createElement(
|
|
628
|
+
motion.div,
|
|
629
|
+
{
|
|
630
|
+
...rest,
|
|
631
|
+
ref: mergeRefs([ref, constraintsRef]),
|
|
632
|
+
style: { ...styles_default.wrapper, zIndex, visibility, ...style }
|
|
633
|
+
},
|
|
634
|
+
/* @__PURE__ */ React2.createElement(AnimatePresence, null, isOpen ? /* @__PURE__ */ React2.createElement(SheetScrollerContextProvider, null, Children.map(
|
|
635
|
+
children,
|
|
636
|
+
(child, i) => cloneElement(child, { key: `sheet-child-${i}` })
|
|
637
|
+
)) : null)
|
|
638
|
+
));
|
|
639
|
+
if (IS_SSR)
|
|
640
|
+
return sheet;
|
|
641
|
+
return createPortal(sheet, mountPoint ?? document.body);
|
|
642
|
+
}
|
|
643
|
+
);
|
|
644
|
+
Sheet.displayName = "Sheet";
|
|
645
|
+
var sheet_default = Sheet;
|
|
646
|
+
var SheetContainer = forwardRef(
|
|
647
|
+
({ children, style = {}, className = "", ...rest }, ref) => {
|
|
648
|
+
const {
|
|
649
|
+
y,
|
|
650
|
+
isOpen,
|
|
651
|
+
callbacks,
|
|
652
|
+
snapPoints,
|
|
653
|
+
initialSnap = 0,
|
|
654
|
+
sheetRef,
|
|
655
|
+
windowHeight,
|
|
656
|
+
detent,
|
|
657
|
+
animationOptions,
|
|
658
|
+
reduceMotion
|
|
659
|
+
} = useSheetContext();
|
|
660
|
+
const { handleAnimationComplete } = useEventCallbacks(isOpen, callbacks);
|
|
661
|
+
const initialY = snapPoints ? snapPoints[0] - snapPoints[initialSnap] : 0;
|
|
662
|
+
const maxSnapHeight = snapPoints ? snapPoints[0] : null;
|
|
663
|
+
const height = maxSnapHeight !== null ? `min(${maxSnapHeight}px, ${MAX_HEIGHT})` : MAX_HEIGHT;
|
|
664
|
+
return /* @__PURE__ */ React2.createElement(
|
|
665
|
+
motion.div,
|
|
666
|
+
{
|
|
667
|
+
...rest,
|
|
668
|
+
ref: mergeRefs([sheetRef, ref]),
|
|
669
|
+
className: `react-modal-sheet-container ${className}`,
|
|
670
|
+
style: {
|
|
671
|
+
...styles_default.container,
|
|
672
|
+
...style,
|
|
673
|
+
...detent === "full-height" && { height },
|
|
674
|
+
...detent === "content-height" && { maxHeight: height },
|
|
675
|
+
y
|
|
676
|
+
},
|
|
677
|
+
initial: reduceMotion ? false : { y: windowHeight },
|
|
678
|
+
animate: { y: initialY, transition: animationOptions },
|
|
679
|
+
exit: { y: windowHeight, transition: animationOptions },
|
|
680
|
+
onAnimationComplete: handleAnimationComplete
|
|
681
|
+
},
|
|
682
|
+
children
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
);
|
|
686
|
+
SheetContainer.displayName = "SheetContainer";
|
|
687
|
+
var SheetContainer_default = SheetContainer;
|
|
688
|
+
var SheetContent = forwardRef(
|
|
689
|
+
({ children, style, disableDrag, className = "", ...rest }, ref) => {
|
|
690
|
+
const sheetContext = useSheetContext();
|
|
691
|
+
const sheetScrollerContext = useSheetScrollerContext();
|
|
692
|
+
const { constraintsRef, onMeasureDragConstraints } = useDragConstraints();
|
|
693
|
+
const dragProps = disableDrag || sheetScrollerContext.disableDrag ? void 0 : sheetContext.dragProps;
|
|
694
|
+
return /* @__PURE__ */ React2.createElement(
|
|
695
|
+
motion.div,
|
|
696
|
+
{
|
|
697
|
+
...rest,
|
|
698
|
+
ref: mergeRefs([ref, constraintsRef]),
|
|
699
|
+
className: `react-modal-sheet-content ${className}`,
|
|
700
|
+
style: { ...styles_default.content, ...style },
|
|
701
|
+
...dragProps,
|
|
702
|
+
dragConstraints: constraintsRef,
|
|
703
|
+
onMeasureDragConstraints
|
|
704
|
+
},
|
|
705
|
+
children
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
);
|
|
709
|
+
SheetContent.displayName = "SheetContent";
|
|
710
|
+
var SheetContent_default = SheetContent;
|
|
711
|
+
var SheetHeader = forwardRef(
|
|
712
|
+
({ children, style, disableDrag, ...rest }, ref) => {
|
|
713
|
+
const { indicatorRotation, dragProps } = useSheetContext();
|
|
714
|
+
const { constraintsRef, onMeasureDragConstraints } = useDragConstraints();
|
|
715
|
+
const _dragProps = disableDrag ? void 0 : dragProps;
|
|
716
|
+
const indicator1Transform = useTransform(
|
|
717
|
+
indicatorRotation,
|
|
718
|
+
(r) => `translateX(2px) rotate(${r}deg)`
|
|
719
|
+
);
|
|
720
|
+
const indicator2Transform = useTransform(
|
|
721
|
+
indicatorRotation,
|
|
722
|
+
(r) => `translateX(-2px) rotate(${-1 * r}deg)`
|
|
723
|
+
);
|
|
724
|
+
return /* @__PURE__ */ React2.createElement(
|
|
725
|
+
motion.div,
|
|
726
|
+
{
|
|
727
|
+
...rest,
|
|
728
|
+
ref: mergeRefs([ref, constraintsRef]),
|
|
729
|
+
style: { ...styles_default.headerWrapper, ...style },
|
|
730
|
+
..._dragProps,
|
|
731
|
+
dragConstraints: constraintsRef,
|
|
732
|
+
onMeasureDragConstraints
|
|
733
|
+
},
|
|
734
|
+
children || /* @__PURE__ */ React2.createElement("div", { className: "react-modal-sheet-header", style: styles_default.header }, /* @__PURE__ */ React2.createElement(
|
|
735
|
+
motion.span,
|
|
736
|
+
{
|
|
737
|
+
className: "react-modal-sheet-drag-indicator",
|
|
738
|
+
style: { ...styles_default.indicator, transform: indicator1Transform }
|
|
739
|
+
}
|
|
740
|
+
), /* @__PURE__ */ React2.createElement(
|
|
741
|
+
motion.span,
|
|
742
|
+
{
|
|
743
|
+
className: "react-modal-sheet-drag-indicator",
|
|
744
|
+
style: { ...styles_default.indicator, transform: indicator2Transform }
|
|
745
|
+
}
|
|
746
|
+
))
|
|
747
|
+
);
|
|
748
|
+
}
|
|
749
|
+
);
|
|
750
|
+
SheetHeader.displayName = "SheetHeader";
|
|
751
|
+
var SheetHeader_default = SheetHeader;
|
|
752
|
+
var isClickable = (props) => !!props.onClick || !!props.onTap;
|
|
753
|
+
var SheetBackdrop = forwardRef(
|
|
754
|
+
({ style = {}, className = "", ...rest }, ref) => {
|
|
755
|
+
const Comp = isClickable(rest) ? motion.button : motion.div;
|
|
756
|
+
const pointerEvents = isClickable(rest) ? "auto" : "none";
|
|
757
|
+
return /* @__PURE__ */ React2.createElement(
|
|
758
|
+
Comp,
|
|
759
|
+
{
|
|
760
|
+
...rest,
|
|
761
|
+
ref,
|
|
762
|
+
className: `react-modal-sheet-backdrop ${className}`,
|
|
763
|
+
style: { ...styles_default.backdrop, ...style, pointerEvents },
|
|
764
|
+
initial: { opacity: 0 },
|
|
765
|
+
animate: { opacity: 1 },
|
|
766
|
+
exit: { opacity: 0 }
|
|
767
|
+
}
|
|
768
|
+
);
|
|
769
|
+
}
|
|
770
|
+
);
|
|
771
|
+
SheetBackdrop.displayName = "SheetBackdrop";
|
|
772
|
+
var SheetBackdrop_default = SheetBackdrop;
|
|
773
|
+
var SheetScroller = forwardRef(
|
|
774
|
+
({ draggableAt = "top", children, style, className = "", ...rest }, ref) => {
|
|
775
|
+
const sheetScrollerContext = useSheetScrollerContext();
|
|
776
|
+
function determineDragState(element) {
|
|
777
|
+
const { scrollTop, scrollHeight, clientHeight } = element;
|
|
778
|
+
const isScrollable = scrollHeight > clientHeight;
|
|
779
|
+
if (!isScrollable)
|
|
780
|
+
return;
|
|
781
|
+
const isAtTop = scrollTop <= 0;
|
|
782
|
+
const isAtBottom = scrollHeight - scrollTop === clientHeight;
|
|
783
|
+
const shouldEnable = draggableAt === "top" && isAtTop || draggableAt === "bottom" && isAtBottom || draggableAt === "both" && (isAtTop || isAtBottom);
|
|
784
|
+
if (shouldEnable) {
|
|
785
|
+
sheetScrollerContext.setDragEnabled();
|
|
786
|
+
} else {
|
|
787
|
+
sheetScrollerContext.setDragDisabled();
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
function onScroll(e) {
|
|
791
|
+
determineDragState(e.currentTarget);
|
|
792
|
+
}
|
|
793
|
+
function onTouchStart(e) {
|
|
794
|
+
determineDragState(e.currentTarget);
|
|
795
|
+
}
|
|
796
|
+
const scrollProps = isTouchDevice() ? { onScroll, onTouchStart } : void 0;
|
|
797
|
+
return /* @__PURE__ */ React2.createElement(
|
|
798
|
+
"div",
|
|
799
|
+
{
|
|
800
|
+
...rest,
|
|
801
|
+
ref,
|
|
802
|
+
className: `react-modal-sheet-scroller ${className}`,
|
|
803
|
+
style: { ...styles_default.scroller, ...style },
|
|
804
|
+
...scrollProps
|
|
805
|
+
},
|
|
806
|
+
children
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
);
|
|
810
|
+
SheetScroller.displayName = "SheetScroller";
|
|
811
|
+
var SheetScroller_default = SheetScroller;
|
|
812
|
+
|
|
813
|
+
// src/index.tsx
|
|
814
|
+
var _SheetCompound = sheet_default;
|
|
815
|
+
_SheetCompound.Container = SheetContainer_default;
|
|
816
|
+
_SheetCompound.Header = SheetHeader_default;
|
|
817
|
+
_SheetCompound.Content = SheetContent_default;
|
|
818
|
+
_SheetCompound.Backdrop = SheetBackdrop_default;
|
|
819
|
+
_SheetCompound.Scroller = SheetScroller_default;
|
|
820
|
+
var Sheet2 = _SheetCompound;
|
|
821
|
+
|
|
822
|
+
export { Sheet2 as Sheet };
|
|
823
|
+
//# sourceMappingURL=out.js.map
|
|
824
|
+
//# sourceMappingURL=index.mjs.map
|