react-modal-sheet 1.6.3 → 1.7.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 -15
- package/dist/SheetBackdrop.d.ts +1 -1
- package/dist/SheetContent.d.ts +1 -1
- package/dist/SheetHeader.d.ts +1 -1
- package/dist/constants.d.ts +9 -0
- package/dist/hooks.d.ts +4 -0
- package/dist/react-modal-sheet.cjs.development.js +168 -115
- package/dist/react-modal-sheet.cjs.development.js.map +1 -1
- package/dist/react-modal-sheet.cjs.production.min.js +1 -1
- package/dist/react-modal-sheet.cjs.production.min.js.map +1 -1
- package/dist/react-modal-sheet.esm.js +169 -116
- package/dist/react-modal-sheet.esm.js.map +1 -1
- package/dist/sheet.d.ts +1 -0
- package/dist/types.d.ts +4 -2
- package/dist/utils.d.ts +6 -4
- package/package.json +2 -2
- package/src/SheetContainer.tsx +10 -5
- package/src/SheetContent.tsx +3 -3
- package/src/SheetHeader.tsx +2 -2
- package/src/constants.ts +13 -0
- package/src/hooks.tsx +35 -2
- package/src/sheet.tsx +109 -66
- package/src/types.tsx +5 -2
- package/src/utils.ts +21 -23
package/README.md
CHANGED
|
@@ -40,11 +40,11 @@ npm install framer-motion
|
|
|
40
40
|
## Usage
|
|
41
41
|
|
|
42
42
|
```jsx
|
|
43
|
-
import React from 'react';
|
|
44
43
|
import Sheet from 'react-modal-sheet';
|
|
44
|
+
import { useState } from 'react';
|
|
45
45
|
|
|
46
46
|
function Example() {
|
|
47
|
-
const [isOpen, setOpen] =
|
|
47
|
+
const [isOpen, setOpen] = useState(false);
|
|
48
48
|
|
|
49
49
|
return (
|
|
50
50
|
<>
|
|
@@ -77,6 +77,7 @@ Also, by constructing the sheet from smaller pieces makes it easier to apply any
|
|
|
77
77
|
| `isOpen` | yes | | Boolean that indicates whether the sheet is open or not. |
|
|
78
78
|
| `onClose` | yes | | Callback fn that is called when the sheet is closed by the user. |
|
|
79
79
|
| `disableDrag` | no | false | Disable drag for the whole sheet. |
|
|
80
|
+
| `detent` | no | `'full-height'` | The [detent](https://developer.apple.com/design/human-interface-guidelines/components/presentation/sheets#ios-ipados) in which the sheet should be in when opened. Available values: `'full-height'` or `'content-height'`. |
|
|
80
81
|
| `onOpenStart` | no | | Callback fn that is called when the sheet opening animation starts. |
|
|
81
82
|
| `onOpenEnd` | no | | Callback fn that is called when the sheet opening animation is completed. |
|
|
82
83
|
| `onCloseStart` | no | | Callback fn that is called when the sheet closing animation starts. |
|
|
@@ -107,12 +108,12 @@ Spring animation happens when the sheet is opened/closed or when it snaps to a s
|
|
|
107
108
|
Imperative method that can be accessed via a ref for snapping to a snap point in given index.
|
|
108
109
|
|
|
109
110
|
```tsx
|
|
110
|
-
import React from 'react';
|
|
111
111
|
import Sheet, { SheetRef } from 'react-modal-sheet';
|
|
112
|
+
import { useState, useRef } from 'react';
|
|
112
113
|
|
|
113
114
|
function Example() {
|
|
114
|
-
const [isOpen, setOpen] =
|
|
115
|
-
const ref =
|
|
115
|
+
const [isOpen, setOpen] = useState(false);
|
|
116
|
+
const ref = useRef<SheetRef>();
|
|
116
117
|
const snapTo = (i: number) => ref.current?.snapTo(i);
|
|
117
118
|
|
|
118
119
|
return (
|
|
@@ -153,12 +154,12 @@ Similarly to the `snapTo` method the `y` value can be accessed via a ref.
|
|
|
153
154
|
The `y` value can be useful for certain situtation eg. when you want to combine snap points with scrollable sheet content and ensure that the content stays properly scrollable in any snap point. Below you can see a simplified example of this situation and for a more detailed example take a look at the [ScrollableSnapPoints](example/components/ScrollableSnapPoints.tsx) component in the example app.
|
|
154
155
|
|
|
155
156
|
```tsx
|
|
156
|
-
import React from 'react';
|
|
157
157
|
import Sheet, { SheetRef } from 'react-modal-sheet';
|
|
158
|
+
import { useState, useRef } from 'react';
|
|
158
159
|
|
|
159
160
|
function Example() {
|
|
160
|
-
const [isOpen, setOpen] =
|
|
161
|
-
const ref =
|
|
161
|
+
const [isOpen, setOpen] = useState(false);
|
|
162
|
+
const ref = useRef<SheetRef>();
|
|
162
163
|
|
|
163
164
|
return (
|
|
164
165
|
<>
|
|
@@ -189,6 +190,36 @@ function Example() {
|
|
|
189
190
|
}
|
|
190
191
|
```
|
|
191
192
|
|
|
193
|
+
### Detents
|
|
194
|
+
|
|
195
|
+
By default the sheet will take the full height of the page minus top padding and safe area inset. If you want the sheet height to be based on it's content you can pass `detent="content-height"` prop to the `Sheet` component:
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
function Example() {
|
|
199
|
+
const [isOpen, setOpen] = useState(false);
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<Sheet
|
|
203
|
+
isOpen={isOpen}
|
|
204
|
+
onClose={() => setOpen(false)}
|
|
205
|
+
detent="content-height"
|
|
206
|
+
>
|
|
207
|
+
<Sheet.Container>
|
|
208
|
+
<Sheet.Content>
|
|
209
|
+
<div style={{ height: 200 }}>Some content</div>
|
|
210
|
+
</Sheet.Content>
|
|
211
|
+
</Sheet.Container>
|
|
212
|
+
</Sheet>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
If the sheet height changes dynamically the sheet will grow until it hits the maximum full height after which it becomes scrollable.
|
|
218
|
+
|
|
219
|
+
It is possible to use snap points with `detent="content-height"` **but** the snap points are restricted by the content height. For example if one of the snap points is 800px and the sheet height is only 700px then snapping to the 800px snap point would only snap to 700px since otherwise the sheet would become detached from the bottom.
|
|
220
|
+
|
|
221
|
+
> ℹ️ If you are wondering where the term `detent` comes from it's from Apple's [Human Interface Guidelines](<[detent](https://developer.apple.com/design/human-interface-guidelines/components/presentation/sheets#ios-ipados)>).
|
|
222
|
+
|
|
192
223
|
## Compound Components
|
|
193
224
|
|
|
194
225
|
### `Sheet.Container`
|
|
@@ -300,9 +331,9 @@ You can add your own styles or override the default sheet styles via the exposed
|
|
|
300
331
|
#### CSS-in-JS
|
|
301
332
|
|
|
302
333
|
```jsx
|
|
303
|
-
import React from 'react';
|
|
304
|
-
import styled from 'styled-components';
|
|
305
334
|
import Sheet from 'react-modal-sheeet';
|
|
335
|
+
import styled from 'styled-components';
|
|
336
|
+
import { useState } from 'react';
|
|
306
337
|
|
|
307
338
|
const CustomSheet = styled(Sheet)`
|
|
308
339
|
.react-modal-sheet-backdrop {
|
|
@@ -323,7 +354,7 @@ const CustomSheet = styled(Sheet)`
|
|
|
323
354
|
`;
|
|
324
355
|
|
|
325
356
|
function Example() {
|
|
326
|
-
const [isOpen, setOpen] =
|
|
357
|
+
const [isOpen, setOpen] = useState(false);
|
|
327
358
|
|
|
328
359
|
return (
|
|
329
360
|
<>
|
|
@@ -351,8 +382,8 @@ The example below utilizes React Aria to achieve an accessible modal-like bottom
|
|
|
351
382
|
> ℹ️ The example was built by following the React Aria's [useDialog](https://react-spectrum.adobe.com/react-aria/useDialog.html) documentation.
|
|
352
383
|
|
|
353
384
|
```jsx
|
|
354
|
-
import React from 'react';
|
|
355
385
|
import Sheet from 'react-modal-sheet';
|
|
386
|
+
import { useRef } from 'react';
|
|
356
387
|
import { useOverlayTriggerState } from 'react-stately';
|
|
357
388
|
|
|
358
389
|
import {
|
|
@@ -366,7 +397,7 @@ import {
|
|
|
366
397
|
|
|
367
398
|
const A11yExample = () => {
|
|
368
399
|
const sheetState = useOverlayTriggerState({});
|
|
369
|
-
const openButtonRef =
|
|
400
|
+
const openButtonRef = useRef(null);
|
|
370
401
|
const openButton = useButton({ onPress: sheetState.open }, openButtonRef);
|
|
371
402
|
|
|
372
403
|
return (
|
|
@@ -387,14 +418,14 @@ const A11yExample = () => {
|
|
|
387
418
|
};
|
|
388
419
|
|
|
389
420
|
const SheetComp = ({ sheetState }) => {
|
|
390
|
-
const containerRef =
|
|
421
|
+
const containerRef = useRef(null);
|
|
391
422
|
const dialog = useDialog({}, containerRef);
|
|
392
423
|
const overlay = useOverlay(
|
|
393
424
|
{ onClose: sheetState.close, isOpen: true, isDismissable: true },
|
|
394
425
|
containerRef
|
|
395
426
|
);
|
|
396
427
|
|
|
397
|
-
const closeButtonRef =
|
|
428
|
+
const closeButtonRef = useRef(null);
|
|
398
429
|
const closeButton = useButton(
|
|
399
430
|
{ onPress: sheetState.close, 'aria-label': 'Close sheet' },
|
|
400
431
|
closeButtonRef
|
package/dist/SheetBackdrop.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
declare const SheetBackdrop: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps, "style" | "transformTemplate" | "transformValues" | "variants" | "transition" | "
|
|
2
|
+
declare const SheetBackdrop: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps, "style" | "transformTemplate" | "transformValues" | "variants" | "transition" | "onBeforeLayoutMeasure" | "onLayoutMeasure" | "onLayoutAnimationStart" | "onLayoutAnimationComplete" | "onUpdate" | "onAnimationStart" | "onAnimationComplete" | "onUnmount" | "onPan" | "onPanStart" | "onPanSessionStart" | "onPanEnd" | "onTap" | "onTapStart" | "onTapCancel" | "whileTap" | "whileHover" | "onHoverStart" | "onHoverEnd" | "whileFocus" | "whileInView" | "onViewportEnter" | "onViewportLeave" | "viewport" | "drag" | "whileDrag" | "dragDirectionLock" | "dragPropagation" | "dragConstraints" | "dragElastic" | "dragMomentum" | "dragTransition" | "dragControls" | "dragSnapToOrigin" | "dragListener" | "onMeasureDragConstraints" | "_dragX" | "_dragY" | "onDragStart" | "onDragEnd" | "onDrag" | "onDirectionLock" | "onDragTransitionEnd" | "layout" | "layoutId" | "layoutDependency" | "layoutScroll" | "custom" | "inherit"> & React.RefAttributes<any>>;
|
|
3
3
|
export default SheetBackdrop;
|
package/dist/SheetContent.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
declare const SheetContent: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps, "
|
|
2
|
+
declare const SheetContent: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps, "style" | "transformTemplate" | "transformValues" | "initial" | "animate" | "exit" | "variants" | "transition" | "onBeforeLayoutMeasure" | "onLayoutMeasure" | "onLayoutAnimationStart" | "onLayoutAnimationComplete" | "onUpdate" | "onAnimationStart" | "onAnimationComplete" | "onUnmount" | "onPan" | "onPanStart" | "onPanSessionStart" | "onPanEnd" | "onTap" | "onTapStart" | "onTapCancel" | "whileTap" | "whileHover" | "onHoverStart" | "onHoverEnd" | "whileFocus" | "whileInView" | "onViewportEnter" | "onViewportLeave" | "viewport" | "whileDrag" | "dragDirectionLock" | "dragPropagation" | "dragTransition" | "dragControls" | "dragSnapToOrigin" | "dragListener" | "onMeasureDragConstraints" | "_dragX" | "_dragY" | "onDirectionLock" | "onDragTransitionEnd" | "layout" | "layoutId" | "layoutDependency" | "layoutScroll" | "custom" | "inherit"> & {
|
|
3
3
|
children?: React.ReactNode;
|
|
4
4
|
disableDrag?: boolean | undefined;
|
|
5
5
|
} & React.RefAttributes<any>>;
|
package/dist/SheetHeader.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
declare const SheetHeader: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps, "
|
|
2
|
+
declare const SheetHeader: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps, "style" | "transformTemplate" | "transformValues" | "initial" | "animate" | "exit" | "variants" | "transition" | "onBeforeLayoutMeasure" | "onLayoutMeasure" | "onLayoutAnimationStart" | "onLayoutAnimationComplete" | "onUpdate" | "onAnimationStart" | "onAnimationComplete" | "onUnmount" | "onPan" | "onPanStart" | "onPanSessionStart" | "onPanEnd" | "onTap" | "onTapStart" | "onTapCancel" | "whileTap" | "whileHover" | "onHoverStart" | "onHoverEnd" | "whileFocus" | "whileInView" | "onViewportEnter" | "onViewportLeave" | "viewport" | "whileDrag" | "dragDirectionLock" | "dragPropagation" | "dragTransition" | "dragControls" | "dragSnapToOrigin" | "dragListener" | "onMeasureDragConstraints" | "_dragX" | "_dragY" | "onDirectionLock" | "onDragTransitionEnd" | "layout" | "layoutId" | "layoutDependency" | "layoutScroll" | "custom" | "inherit"> & {
|
|
3
3
|
children?: React.ReactNode;
|
|
4
4
|
disableDrag?: boolean | undefined;
|
|
5
5
|
} & React.RefAttributes<any>>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const MAX_HEIGHT = "calc(100% - env(safe-area-inset-top) - 34px)";
|
|
2
|
+
export declare const IS_SSR: boolean;
|
|
3
|
+
export declare const DEFAULT_SPRING_CONFIG: {
|
|
4
|
+
stiffness: number;
|
|
5
|
+
damping: number;
|
|
6
|
+
mass: number;
|
|
7
|
+
};
|
|
8
|
+
export declare const DRAG_CLOSE_THRESHOLD = 0.6;
|
|
9
|
+
export declare const DRAG_VELOCITY_THRESHOLD = 500;
|
package/dist/hooks.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { SheetEvents } from './types';
|
|
3
|
+
export declare const useIsomorphicLayoutEffect: typeof React.useEffect;
|
|
3
4
|
export declare const useModalEffect: (isOpen: boolean, rootId?: string | undefined) => void;
|
|
4
5
|
export declare const useEventCallbacks: (isOpen: boolean, callbacks: React.MutableRefObject<SheetEvents>) => {
|
|
5
6
|
handleAnimationComplete: () => void;
|
|
6
7
|
};
|
|
8
|
+
export declare function useWindowHeight(): number;
|
|
9
|
+
export declare function usePrevious<T>(state: T): T | undefined;
|
|
10
|
+
export declare function useEvent<T extends (...args: any[]) => any>(handler: T): T;
|
|
@@ -43,12 +43,21 @@ function _objectWithoutPropertiesLoose(source, excluded) {
|
|
|
43
43
|
return target;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
var
|
|
47
|
-
var
|
|
46
|
+
var MAX_HEIGHT = 'calc(100% - env(safe-area-inset-top) - 34px)';
|
|
47
|
+
var IS_SSR = typeof window === 'undefined';
|
|
48
|
+
var DEFAULT_SPRING_CONFIG = {
|
|
49
|
+
stiffness: 300,
|
|
50
|
+
damping: 30,
|
|
51
|
+
mass: 0.2
|
|
52
|
+
};
|
|
53
|
+
var DRAG_CLOSE_THRESHOLD = 0.6;
|
|
54
|
+
var DRAG_VELOCITY_THRESHOLD = 500;
|
|
55
|
+
|
|
56
|
+
function getClosest(nums, goal) {
|
|
48
57
|
return nums.reduce(function (prev, curr) {
|
|
49
58
|
return Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev;
|
|
50
59
|
});
|
|
51
|
-
}
|
|
60
|
+
}
|
|
52
61
|
var highlightId = 'react-modal-sheet-highlight';
|
|
53
62
|
function applyRootStyles(rootId) {
|
|
54
63
|
var body = document.querySelector('body');
|
|
@@ -110,40 +119,25 @@ function cleanupRootStyles(rootId) {
|
|
|
110
119
|
root.addEventListener('transitionend', onTransitionEnd);
|
|
111
120
|
}
|
|
112
121
|
}
|
|
113
|
-
|
|
114
|
-
function useWindowHeight() {
|
|
115
|
-
var _useState = React.useState(0),
|
|
116
|
-
windowHeight = _useState[0],
|
|
117
|
-
setWindowHeight = _useState[1];
|
|
118
|
-
|
|
119
|
-
useIsomorphicLayoutEffect(function () {
|
|
120
|
-
var updateHeight = function updateHeight() {
|
|
121
|
-
return setWindowHeight(window.innerHeight);
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
window.addEventListener('resize', updateHeight);
|
|
125
|
-
updateHeight();
|
|
126
|
-
return function () {
|
|
127
|
-
return window.removeEventListener('resize', updateHeight);
|
|
128
|
-
};
|
|
129
|
-
}, []);
|
|
130
|
-
return windowHeight;
|
|
131
|
-
}
|
|
132
|
-
var inDescendingOrder = function inDescendingOrder(arr) {
|
|
122
|
+
function inDescendingOrder(arr) {
|
|
133
123
|
for (var i = 0; i < arr.length; i++) {
|
|
134
124
|
if (arr[i + 1] > arr[i]) return false;
|
|
135
125
|
}
|
|
136
126
|
|
|
137
127
|
return true;
|
|
138
|
-
}
|
|
128
|
+
}
|
|
129
|
+
function validateSnapTo(_ref) {
|
|
130
|
+
var snapTo = _ref.snapTo,
|
|
131
|
+
sheetHeight = _ref.sheetHeight;
|
|
139
132
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return
|
|
145
|
-
}
|
|
133
|
+
if (snapTo < 0) {
|
|
134
|
+
console.warn("Snap point is out of bounds. Sheet height is " + sheetHeight + " but snap point is " + (sheetHeight + Math.abs(snapTo)) + ".");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return Math.max(Math.round(snapTo), 0);
|
|
138
|
+
}
|
|
146
139
|
|
|
140
|
+
var useIsomorphicLayoutEffect = IS_SSR ? React.useEffect : React.useLayoutEffect;
|
|
147
141
|
var useModalEffect = function useModalEffect(isOpen, rootId) {
|
|
148
142
|
var prevOpen = usePrevious(isOpen); // Automatically apply the iOS modal effect to the body when sheet opens/closes
|
|
149
143
|
|
|
@@ -190,13 +184,54 @@ var useEventCallbacks = function useEventCallbacks(isOpen, callbacks) {
|
|
|
190
184
|
handleAnimationComplete: handleAnimationComplete
|
|
191
185
|
};
|
|
192
186
|
};
|
|
187
|
+
function useWindowHeight() {
|
|
188
|
+
var _React$useState = React.useState(0),
|
|
189
|
+
windowHeight = _React$useState[0],
|
|
190
|
+
setWindowHeight = _React$useState[1];
|
|
191
|
+
|
|
192
|
+
useIsomorphicLayoutEffect(function () {
|
|
193
|
+
var updateHeight = function updateHeight() {
|
|
194
|
+
return setWindowHeight(window.innerHeight);
|
|
195
|
+
};
|
|
193
196
|
|
|
194
|
-
|
|
197
|
+
window.addEventListener('resize', updateHeight);
|
|
198
|
+
updateHeight();
|
|
199
|
+
return function () {
|
|
200
|
+
return window.removeEventListener('resize', updateHeight);
|
|
201
|
+
};
|
|
202
|
+
}, []);
|
|
203
|
+
return windowHeight;
|
|
204
|
+
}
|
|
205
|
+
function usePrevious(state) {
|
|
195
206
|
var ref = React.useRef();
|
|
196
207
|
React.useEffect(function () {
|
|
197
208
|
ref.current = state;
|
|
198
209
|
});
|
|
199
210
|
return ref.current;
|
|
211
|
+
} // Userland version of the `useEvent` React hook:
|
|
212
|
+
// RFC: https://github.com/reactjs/rfcs/blob/useevent/text/0000-useevent.md
|
|
213
|
+
|
|
214
|
+
function useEvent(handler) {
|
|
215
|
+
var handlerRef = React.useRef();
|
|
216
|
+
useIsomorphicLayoutEffect(function () {
|
|
217
|
+
handlerRef.current = handler;
|
|
218
|
+
});
|
|
219
|
+
return React.useCallback(function () {
|
|
220
|
+
var fn = handlerRef.current;
|
|
221
|
+
|
|
222
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
223
|
+
args[_key] = arguments[_key];
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return fn == null ? void 0 : fn.apply(void 0, args);
|
|
227
|
+
}, []);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
var SheetContext = /*#__PURE__*/React.createContext(undefined);
|
|
231
|
+
var useSheetContext = function useSheetContext() {
|
|
232
|
+
var context = React.useContext(SheetContext);
|
|
233
|
+
if (!context) throw Error('Sheet context error');
|
|
234
|
+
return context;
|
|
200
235
|
};
|
|
201
236
|
|
|
202
237
|
var styles = {
|
|
@@ -259,56 +294,62 @@ var styles = {
|
|
|
259
294
|
};
|
|
260
295
|
|
|
261
296
|
var Sheet = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
262
|
-
var
|
|
263
|
-
isOpen = _ref.isOpen,
|
|
264
|
-
onClose = _ref.onClose,
|
|
265
|
-
onOpenStart = _ref.onOpenStart,
|
|
297
|
+
var onOpenStart = _ref.onOpenStart,
|
|
266
298
|
onOpenEnd = _ref.onOpenEnd,
|
|
299
|
+
onClose = _ref.onClose,
|
|
267
300
|
onCloseStart = _ref.onCloseStart,
|
|
268
301
|
onCloseEnd = _ref.onCloseEnd,
|
|
269
302
|
onSnap = _ref.onSnap,
|
|
303
|
+
children = _ref.children,
|
|
304
|
+
isOpen = _ref.isOpen,
|
|
270
305
|
snapPoints = _ref.snapPoints,
|
|
306
|
+
detent = _ref.detent,
|
|
271
307
|
_ref$initialSnap = _ref.initialSnap,
|
|
272
308
|
initialSnap = _ref$initialSnap === void 0 ? 0 : _ref$initialSnap,
|
|
273
309
|
rootId = _ref.rootId,
|
|
274
310
|
mountPoint = _ref.mountPoint,
|
|
275
311
|
_ref$springConfig = _ref.springConfig,
|
|
276
|
-
springConfig = _ref$springConfig === void 0 ?
|
|
277
|
-
stiffness: 300,
|
|
278
|
-
damping: 30,
|
|
279
|
-
mass: 0.2
|
|
280
|
-
} : _ref$springConfig,
|
|
312
|
+
springConfig = _ref$springConfig === void 0 ? DEFAULT_SPRING_CONFIG : _ref$springConfig,
|
|
281
313
|
_ref$disableDrag = _ref.disableDrag,
|
|
282
314
|
disableDrag = _ref$disableDrag === void 0 ? false : _ref$disableDrag,
|
|
283
315
|
style = _ref.style,
|
|
284
|
-
rest = _objectWithoutPropertiesLoose(_ref, ["
|
|
316
|
+
rest = _objectWithoutPropertiesLoose(_ref, ["onOpenStart", "onOpenEnd", "onClose", "onCloseStart", "onCloseEnd", "onSnap", "children", "isOpen", "snapPoints", "detent", "initialSnap", "rootId", "mountPoint", "springConfig", "disableDrag", "style"]);
|
|
285
317
|
|
|
286
318
|
var sheetRef = React.useRef(null);
|
|
287
|
-
var callbacks = React.useRef({
|
|
288
|
-
onOpenStart: onOpenStart,
|
|
289
|
-
onOpenEnd: onOpenEnd,
|
|
290
|
-
onCloseStart: onCloseStart,
|
|
291
|
-
onCloseEnd: onCloseEnd
|
|
292
|
-
}); // prettier-ignore
|
|
293
|
-
|
|
294
319
|
var indicatorRotation = framerMotion.useMotionValue(0);
|
|
295
320
|
var windowHeight = useWindowHeight(); // NOTE: the inital value for `y` doesn't matter since it is overwritten by
|
|
296
321
|
// the value driven by the `AnimatePresence` component when the sheet is opened
|
|
297
322
|
// and after that it is driven by the gestures and/or snapping
|
|
298
323
|
|
|
299
|
-
var y = framerMotion.useMotionValue(0);
|
|
324
|
+
var y = framerMotion.useMotionValue(0); // Keep the callback fns up-to-date so that they can be accessed inside
|
|
325
|
+
// the effect without including them to the dependencies array
|
|
326
|
+
|
|
327
|
+
var callbacks = React.useRef({
|
|
328
|
+
onOpenStart: onOpenStart,
|
|
329
|
+
onOpenEnd: onOpenEnd,
|
|
330
|
+
onCloseStart: onCloseStart,
|
|
331
|
+
onCloseEnd: onCloseEnd
|
|
332
|
+
});
|
|
333
|
+
useIsomorphicLayoutEffect(function () {
|
|
334
|
+
callbacks.current = {
|
|
335
|
+
onOpenStart: onOpenStart,
|
|
336
|
+
onOpenEnd: onOpenEnd,
|
|
337
|
+
onCloseStart: onCloseStart,
|
|
338
|
+
onCloseEnd: onCloseEnd
|
|
339
|
+
};
|
|
340
|
+
});
|
|
300
341
|
|
|
301
342
|
if (snapPoints) {
|
|
302
343
|
// Convert negative / percentage snap points to absolute values
|
|
303
344
|
snapPoints = snapPoints.map(function (point) {
|
|
304
|
-
|
|
305
|
-
|
|
345
|
+
// Percentage values e.g. between 0.0 and 1.0
|
|
346
|
+
if (point > 0 && point <= 1) return Math.round(point * windowHeight);
|
|
306
347
|
return point < 0 ? windowHeight + point : point; // negative values
|
|
307
348
|
});
|
|
308
349
|
console.assert(inDescendingOrder(snapPoints) || windowHeight === 0, "Snap points need to be in descending order got: [" + snapPoints + "]");
|
|
309
350
|
}
|
|
310
351
|
|
|
311
|
-
var
|
|
352
|
+
var onDrag = useEvent(function (_, _ref2) {
|
|
312
353
|
var delta = _ref2.delta;
|
|
313
354
|
// Update drag indicator rotation based on drag velocity
|
|
314
355
|
var velocity = y.getVelocity();
|
|
@@ -316,22 +357,42 @@ var Sheet = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
316
357
|
if (velocity < 0) indicatorRotation.set(-10); // Make sure user cannot drag beyond the top of the sheet
|
|
317
358
|
|
|
318
359
|
y.set(Math.max(y.get() + delta.y, 0));
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
var handleDragEnd = React.useCallback(function (_, _ref3) {
|
|
360
|
+
});
|
|
361
|
+
var onDragEnd = useEvent(function (_, _ref3) {
|
|
322
362
|
var velocity = _ref3.velocity;
|
|
323
363
|
|
|
324
|
-
if (velocity.y >
|
|
364
|
+
if (velocity.y > DRAG_VELOCITY_THRESHOLD) {
|
|
325
365
|
// User flicked the sheet down
|
|
326
366
|
onClose();
|
|
327
367
|
} else {
|
|
328
368
|
var sheetEl = sheetRef.current;
|
|
329
|
-
var
|
|
330
|
-
var
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
369
|
+
var sheetHeight = sheetEl.getBoundingClientRect().height;
|
|
370
|
+
var currentY = y.get();
|
|
371
|
+
var snapTo = 0;
|
|
372
|
+
|
|
373
|
+
if (snapPoints) {
|
|
374
|
+
var snapToValues = snapPoints.map(function (p) {
|
|
375
|
+
return sheetHeight - p;
|
|
376
|
+
}).filter(function (p) {
|
|
377
|
+
return p >= 0;
|
|
378
|
+
}); // negative values can occur with `content-height` detent
|
|
379
|
+
// Allow snapping to the top of the sheet if detent is set to `content-height`
|
|
380
|
+
|
|
381
|
+
if (detent === 'content-height' && !snapToValues.includes(0)) {
|
|
382
|
+
snapToValues.unshift(0);
|
|
383
|
+
} // Get the closest snap point
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
snapTo = getClosest(snapToValues, currentY);
|
|
387
|
+
} else if (currentY / sheetHeight > DRAG_CLOSE_THRESHOLD) {
|
|
388
|
+
// Close if dragged over enough far
|
|
389
|
+
snapTo = sheetHeight;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
snapTo = validateSnapTo({
|
|
393
|
+
snapTo: snapTo,
|
|
394
|
+
sheetHeight: sheetHeight
|
|
395
|
+
}); // Update the spring value so that the sheet is animated to the snap point
|
|
335
396
|
|
|
336
397
|
framerMotion.animate(y, snapTo, _extends({
|
|
337
398
|
type: 'spring'
|
|
@@ -344,22 +405,11 @@ var Sheet = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
344
405
|
onSnap(snapIndex);
|
|
345
406
|
}
|
|
346
407
|
|
|
347
|
-
if (snapTo >=
|
|
408
|
+
if (snapTo >= sheetHeight) onClose();
|
|
348
409
|
} // Reset indicator rotation after dragging
|
|
349
410
|
|
|
350
411
|
|
|
351
412
|
indicatorRotation.set(0);
|
|
352
|
-
}, [onClose, onSnap] // eslint-disable-line
|
|
353
|
-
); // Keep the callback fns up-to-date so that they can be accessed inside
|
|
354
|
-
// the effect without including them to the dependencies array
|
|
355
|
-
|
|
356
|
-
React.useEffect(function () {
|
|
357
|
-
callbacks.current = {
|
|
358
|
-
onOpenStart: onOpenStart,
|
|
359
|
-
onOpenEnd: onOpenEnd,
|
|
360
|
-
onCloseStart: onCloseStart,
|
|
361
|
-
onCloseEnd: onCloseEnd
|
|
362
|
-
};
|
|
363
413
|
}); // Trigger onSnap callback when sheet is opened or closed
|
|
364
414
|
|
|
365
415
|
React.useEffect(function () {
|
|
@@ -375,13 +425,17 @@ var Sheet = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
375
425
|
var sheetEl = sheetRef.current;
|
|
376
426
|
|
|
377
427
|
if (snapPoints && snapPoints[snapIndex] !== undefined && sheetEl !== null) {
|
|
378
|
-
var
|
|
379
|
-
var
|
|
428
|
+
var sheetHeight = sheetEl.getBoundingClientRect().height;
|
|
429
|
+
var snapPoint = snapPoints[snapIndex];
|
|
430
|
+
var snapTo = validateSnapTo({
|
|
431
|
+
snapTo: sheetHeight - snapPoint,
|
|
432
|
+
sheetHeight: sheetHeight
|
|
433
|
+
});
|
|
380
434
|
framerMotion.animate(y, snapTo, _extends({
|
|
381
435
|
type: 'spring'
|
|
382
436
|
}, springConfig));
|
|
383
437
|
if (onSnap) onSnap(snapIndex);
|
|
384
|
-
if (snapTo >=
|
|
438
|
+
if (snapTo >= sheetHeight) onClose();
|
|
385
439
|
}
|
|
386
440
|
}
|
|
387
441
|
};
|
|
@@ -392,47 +446,48 @@ var Sheet = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
392
446
|
overlays.usePreventScroll({
|
|
393
447
|
isDisabled: !isOpen
|
|
394
448
|
});
|
|
395
|
-
var dragProps =
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
449
|
+
var dragProps = React.useMemo(function () {
|
|
450
|
+
var dragProps = {
|
|
451
|
+
drag: 'y',
|
|
452
|
+
dragElastic: 0,
|
|
453
|
+
dragConstraints: {
|
|
454
|
+
top: 0,
|
|
455
|
+
bottom: 0
|
|
456
|
+
},
|
|
457
|
+
dragMomentum: false,
|
|
458
|
+
onDrag: onDrag,
|
|
459
|
+
onDragEnd: onDragEnd
|
|
460
|
+
};
|
|
461
|
+
return disableDrag ? undefined : dragProps;
|
|
462
|
+
}, [disableDrag]); // eslint-disable-line
|
|
463
|
+
|
|
406
464
|
var context = {
|
|
407
465
|
y: y,
|
|
408
466
|
sheetRef: sheetRef,
|
|
409
467
|
isOpen: isOpen,
|
|
410
468
|
initialSnap: initialSnap,
|
|
411
469
|
snapPoints: snapPoints,
|
|
470
|
+
detent: detent,
|
|
412
471
|
indicatorRotation: indicatorRotation,
|
|
413
472
|
callbacks: callbacks,
|
|
414
473
|
dragProps: dragProps,
|
|
415
474
|
windowHeight: windowHeight,
|
|
416
475
|
springConfig: springConfig
|
|
417
476
|
};
|
|
418
|
-
|
|
419
|
-
var wrapperProps = _extends({}, rest, {
|
|
420
|
-
ref: ref,
|
|
421
|
-
style: _extends({}, styles.wrapper, style)
|
|
422
|
-
});
|
|
423
|
-
|
|
424
477
|
var sheet = React.createElement(SheetContext.Provider, {
|
|
425
478
|
value: context
|
|
426
|
-
}, React.createElement("div", Object.assign({},
|
|
479
|
+
}, React.createElement("div", Object.assign({}, rest, {
|
|
480
|
+
ref: ref,
|
|
481
|
+
style: _extends({}, styles.wrapper, style)
|
|
482
|
+
}), React.createElement(framerMotion.AnimatePresence, null, isOpen ? React.Children.map(children, function (child, i) {
|
|
427
483
|
return React.cloneElement(child, {
|
|
428
484
|
key: "sheet-child-" + i
|
|
429
485
|
});
|
|
430
486
|
}) : null)));
|
|
431
|
-
if (
|
|
487
|
+
if (IS_SSR) return sheet;
|
|
432
488
|
return ReactDOM.createPortal(sheet, mountPoint != null ? mountPoint : document.body);
|
|
433
489
|
});
|
|
434
490
|
|
|
435
|
-
var MAX_HEIGHT = 'calc(100% - env(safe-area-inset-top) - 34px)';
|
|
436
491
|
var SheetContainer = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
437
492
|
var children = _ref.children,
|
|
438
493
|
_ref$style = _ref.style,
|
|
@@ -448,20 +503,24 @@ var SheetContainer = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
448
503
|
initialSnap = _useSheetContext$init === void 0 ? 0 : _useSheetContext$init,
|
|
449
504
|
sheetRef = _useSheetContext.sheetRef,
|
|
450
505
|
windowHeight = _useSheetContext.windowHeight,
|
|
451
|
-
springConfig = _useSheetContext.springConfig
|
|
506
|
+
springConfig = _useSheetContext.springConfig,
|
|
507
|
+
_useSheetContext$dete = _useSheetContext.detent,
|
|
508
|
+
detent = _useSheetContext$dete === void 0 ? 'full-height' : _useSheetContext$dete;
|
|
452
509
|
|
|
453
510
|
var _useEventCallbacks = useEventCallbacks(isOpen, callbacks),
|
|
454
511
|
handleAnimationComplete = _useEventCallbacks.handleAnimationComplete;
|
|
455
512
|
|
|
456
513
|
var initialY = snapPoints ? snapPoints[0] - snapPoints[initialSnap] : 0;
|
|
457
|
-
var
|
|
458
|
-
var
|
|
514
|
+
var maxSnapHeight = snapPoints ? snapPoints[0] : null;
|
|
515
|
+
var height = maxSnapHeight !== null ? "min(" + maxSnapHeight + "px, " + MAX_HEIGHT + ")" : MAX_HEIGHT;
|
|
459
516
|
return React.createElement(framerMotion.motion.div, Object.assign({}, rest, {
|
|
460
517
|
ref: mergeRefs([sheetRef, ref]),
|
|
461
518
|
className: "react-modal-sheet-container",
|
|
462
|
-
style: _extends({}, styles.container, {
|
|
463
|
-
height:
|
|
464
|
-
},
|
|
519
|
+
style: _extends({}, styles.container, style, detent === 'full-height' && {
|
|
520
|
+
height: height
|
|
521
|
+
}, detent === 'content-height' && {
|
|
522
|
+
maxHeight: height
|
|
523
|
+
}, {
|
|
465
524
|
y: y
|
|
466
525
|
}),
|
|
467
526
|
initial: {
|
|
@@ -482,11 +541,8 @@ var SheetContainer = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
482
541
|
|
|
483
542
|
var SheetContent = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
484
543
|
var children = _ref.children,
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
_ref$style = _ref.style,
|
|
488
|
-
style = _ref$style === void 0 ? {} : _ref$style,
|
|
489
|
-
rest = _objectWithoutPropertiesLoose(_ref, ["children", "disableDrag", "style"]);
|
|
544
|
+
style = _ref.style,
|
|
545
|
+
rest = _objectWithoutPropertiesLoose(_ref, ["children", "style"]);
|
|
490
546
|
|
|
491
547
|
var _useSheetContext = useSheetContext(),
|
|
492
548
|
dragProps = _useSheetContext.dragProps;
|
|
@@ -495,16 +551,13 @@ var SheetContent = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
495
551
|
ref: ref,
|
|
496
552
|
className: "react-modal-sheet-content",
|
|
497
553
|
style: _extends({}, styles.content, style)
|
|
498
|
-
},
|
|
554
|
+
}, dragProps), children);
|
|
499
555
|
});
|
|
500
556
|
|
|
501
557
|
var SheetHeader = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
502
558
|
var children = _ref.children,
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
_ref$style = _ref.style,
|
|
506
|
-
style = _ref$style === void 0 ? {} : _ref$style,
|
|
507
|
-
rest = _objectWithoutPropertiesLoose(_ref, ["children", "disableDrag", "style"]);
|
|
559
|
+
style = _ref.style,
|
|
560
|
+
rest = _objectWithoutPropertiesLoose(_ref, ["children", "style"]);
|
|
508
561
|
|
|
509
562
|
var _useSheetContext = useSheetContext(),
|
|
510
563
|
indicatorRotation = _useSheetContext.indicatorRotation,
|
|
@@ -519,7 +572,7 @@ var SheetHeader = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
519
572
|
return React.createElement(framerMotion.motion.div, Object.assign({}, rest, {
|
|
520
573
|
ref: ref,
|
|
521
574
|
style: _extends({}, styles.headerWrapper, style)
|
|
522
|
-
},
|
|
575
|
+
}, dragProps), children || React.createElement("div", {
|
|
523
576
|
className: "react-modal-sheet-header",
|
|
524
577
|
style: styles.header
|
|
525
578
|
}, React.createElement(framerMotion.motion.span, {
|