react-modal-sheet 2.2.0 → 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 +6 -6
- 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 +34 -24
- 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 -934
- 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 -930
- 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/src/sheet.tsx
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
Children,
|
|
3
|
+
cloneElement,
|
|
4
|
+
forwardRef,
|
|
5
|
+
useEffect,
|
|
6
|
+
useImperativeHandle,
|
|
7
|
+
useMemo,
|
|
8
|
+
useRef,
|
|
9
|
+
} from 'react';
|
|
10
|
+
|
|
11
|
+
import { createPortal } from 'react-dom';
|
|
3
12
|
|
|
4
13
|
import {
|
|
5
14
|
animate,
|
|
6
15
|
AnimatePresence,
|
|
7
16
|
motion,
|
|
8
|
-
PanInfo,
|
|
9
|
-
Transition,
|
|
17
|
+
type PanInfo,
|
|
18
|
+
type Transition,
|
|
10
19
|
useMotionValue,
|
|
11
20
|
useReducedMotion,
|
|
12
21
|
useTransform,
|
|
@@ -14,7 +23,7 @@ import {
|
|
|
14
23
|
|
|
15
24
|
import {
|
|
16
25
|
useModalEffect,
|
|
17
|
-
|
|
26
|
+
useDimensions,
|
|
18
27
|
useIsomorphicLayoutEffect,
|
|
19
28
|
useEvent,
|
|
20
29
|
} from './hooks';
|
|
@@ -27,13 +36,18 @@ import {
|
|
|
27
36
|
IS_SSR,
|
|
28
37
|
} from './constants';
|
|
29
38
|
|
|
30
|
-
import { SheetContextType, SheetProps } from './types';
|
|
39
|
+
import { type SheetContextType, type SheetProps } from './types';
|
|
31
40
|
import { SheetScrollerContextProvider, SheetContext } from './context';
|
|
32
|
-
import {
|
|
41
|
+
import {
|
|
42
|
+
getClosest,
|
|
43
|
+
inDescendingOrder,
|
|
44
|
+
mergeRefs,
|
|
45
|
+
validateSnapTo,
|
|
46
|
+
} from './utils';
|
|
33
47
|
import { usePreventScroll } from './use-prevent-scroll';
|
|
34
48
|
import styles from './styles';
|
|
35
49
|
|
|
36
|
-
const Sheet =
|
|
50
|
+
const Sheet = forwardRef<any, SheetProps>(
|
|
37
51
|
(
|
|
38
52
|
{
|
|
39
53
|
onOpenStart,
|
|
@@ -58,9 +72,10 @@ const Sheet = React.forwardRef<any, SheetProps>(
|
|
|
58
72
|
},
|
|
59
73
|
ref
|
|
60
74
|
) => {
|
|
61
|
-
const sheetRef =
|
|
75
|
+
const sheetRef = useRef<any>(null);
|
|
76
|
+
const constraintsRef = useRef<any>(null);
|
|
62
77
|
const indicatorRotation = useMotionValue(0);
|
|
63
|
-
const windowHeight =
|
|
78
|
+
const { height: windowHeight } = useDimensions();
|
|
64
79
|
const shouldReduceMotion = useReducedMotion();
|
|
65
80
|
const reduceMotion = Boolean(prefersReducedMotion || shouldReduceMotion);
|
|
66
81
|
const animationOptions: Transition = {
|
|
@@ -73,17 +88,17 @@ const Sheet = React.forwardRef<any, SheetProps>(
|
|
|
73
88
|
// and after that it is driven by the gestures and/or snapping
|
|
74
89
|
const y = useMotionValue(0);
|
|
75
90
|
|
|
76
|
-
const zIndex = useTransform(y, value =>
|
|
91
|
+
const zIndex = useTransform(y, (value) =>
|
|
77
92
|
value >= windowHeight ? -1 : 9999999
|
|
78
93
|
);
|
|
79
94
|
|
|
80
|
-
const visibility = useTransform(y, value =>
|
|
95
|
+
const visibility = useTransform(y, (value) =>
|
|
81
96
|
value >= windowHeight ? 'hidden' : 'visible'
|
|
82
97
|
);
|
|
83
98
|
|
|
84
99
|
// Keep the callback fns up-to-date so that they can be accessed inside
|
|
85
100
|
// the effect without including them to the dependencies array
|
|
86
|
-
const callbacks =
|
|
101
|
+
const callbacks = useRef({
|
|
87
102
|
onOpenStart,
|
|
88
103
|
onOpenEnd,
|
|
89
104
|
onCloseStart,
|
|
@@ -101,7 +116,7 @@ const Sheet = React.forwardRef<any, SheetProps>(
|
|
|
101
116
|
|
|
102
117
|
if (snapPoints) {
|
|
103
118
|
// Convert negative / percentage snap points to absolute values
|
|
104
|
-
snapPoints = snapPoints.map(point => {
|
|
119
|
+
snapPoints = snapPoints.map((point) => {
|
|
105
120
|
// Percentage values e.g. between 0.0 and 1.0
|
|
106
121
|
if (point > 0 && point <= 1) return Math.round(point * windowHeight);
|
|
107
122
|
return point < 0 ? windowHeight + point : point; // negative values
|
|
@@ -109,7 +124,9 @@ const Sheet = React.forwardRef<any, SheetProps>(
|
|
|
109
124
|
|
|
110
125
|
console.assert(
|
|
111
126
|
inDescendingOrder(snapPoints) || windowHeight === 0,
|
|
112
|
-
`Snap points need to be in descending order got: [${snapPoints
|
|
127
|
+
`Snap points need to be in descending order got: [${snapPoints.join(
|
|
128
|
+
', '
|
|
129
|
+
)}]`
|
|
113
130
|
);
|
|
114
131
|
}
|
|
115
132
|
|
|
@@ -137,7 +154,7 @@ const Sheet = React.forwardRef<any, SheetProps>(
|
|
|
137
154
|
|
|
138
155
|
if (snapPoints) {
|
|
139
156
|
const snapToValues = snapPoints.map(
|
|
140
|
-
p => sheetHeight - Math.min(p, sheetHeight)
|
|
157
|
+
(p) => sheetHeight - Math.min(p, sheetHeight)
|
|
141
158
|
);
|
|
142
159
|
|
|
143
160
|
// Allow snapping to the top of the sheet if detent is set to `content-height`
|
|
@@ -155,7 +172,7 @@ const Sheet = React.forwardRef<any, SheetProps>(
|
|
|
155
172
|
snapTo = validateSnapTo({ snapTo, sheetHeight });
|
|
156
173
|
|
|
157
174
|
// Update the spring value so that the sheet is animated to the snap point
|
|
158
|
-
animate(y, snapTo, animationOptions);
|
|
175
|
+
void animate(y, snapTo, animationOptions);
|
|
159
176
|
|
|
160
177
|
if (snapPoints && onSnap) {
|
|
161
178
|
const snapValue = Math.abs(Math.round(snapPoints[0] - snapTo));
|
|
@@ -174,22 +191,18 @@ const Sheet = React.forwardRef<any, SheetProps>(
|
|
|
174
191
|
});
|
|
175
192
|
|
|
176
193
|
// Trigger onSnap callback when sheet is opened or closed
|
|
177
|
-
|
|
194
|
+
useEffect(() => {
|
|
178
195
|
if (!snapPoints || !onSnap) return;
|
|
179
196
|
const snapIndex = isOpen ? initialSnap : snapPoints.length - 1;
|
|
180
197
|
onSnap(snapIndex);
|
|
181
198
|
}, [isOpen]); // eslint-disable-line
|
|
182
199
|
|
|
183
|
-
|
|
200
|
+
useImperativeHandle(ref, () => ({
|
|
184
201
|
y,
|
|
185
202
|
snapTo: (snapIndex: number) => {
|
|
186
203
|
const sheetEl = sheetRef.current as HTMLDivElement | null;
|
|
187
204
|
|
|
188
|
-
if (
|
|
189
|
-
snapPoints &&
|
|
190
|
-
snapPoints[snapIndex] !== undefined &&
|
|
191
|
-
sheetEl !== null
|
|
192
|
-
) {
|
|
205
|
+
if (snapPoints?.[snapIndex] !== undefined && sheetEl !== null) {
|
|
193
206
|
const sheetHeight = sheetEl.getBoundingClientRect().height;
|
|
194
207
|
const snapPoint = snapPoints[snapIndex];
|
|
195
208
|
const snapTo = validateSnapTo({
|
|
@@ -197,7 +210,7 @@ const Sheet = React.forwardRef<any, SheetProps>(
|
|
|
197
210
|
sheetHeight,
|
|
198
211
|
});
|
|
199
212
|
|
|
200
|
-
animate(y, snapTo, animationOptions);
|
|
213
|
+
void animate(y, snapTo, animationOptions);
|
|
201
214
|
if (onSnap) onSnap(snapIndex);
|
|
202
215
|
if (snapTo >= sheetHeight) onClose();
|
|
203
216
|
}
|
|
@@ -208,9 +221,9 @@ const Sheet = React.forwardRef<any, SheetProps>(
|
|
|
208
221
|
|
|
209
222
|
// Framer Motion should handle body scroll locking but it's not working
|
|
210
223
|
// properly on iOS. Scroll locking from React Aria seems to work much better.
|
|
211
|
-
usePreventScroll({ isDisabled: disableScrollLocking
|
|
224
|
+
usePreventScroll({ isDisabled: disableScrollLocking || !isOpen });
|
|
212
225
|
|
|
213
|
-
const dragProps =
|
|
226
|
+
const dragProps = useMemo(() => {
|
|
214
227
|
const dragProps: SheetContextType['dragProps'] = {
|
|
215
228
|
drag: 'y',
|
|
216
229
|
dragElastic: 0,
|
|
@@ -221,7 +234,7 @@ const Sheet = React.forwardRef<any, SheetProps>(
|
|
|
221
234
|
};
|
|
222
235
|
|
|
223
236
|
return disableDrag ? undefined : dragProps;
|
|
224
|
-
}, [disableDrag]); // eslint-disable-line
|
|
237
|
+
}, [disableDrag, windowHeight]); // eslint-disable-line
|
|
225
238
|
|
|
226
239
|
const context: SheetContextType = {
|
|
227
240
|
y,
|
|
@@ -243,15 +256,15 @@ const Sheet = React.forwardRef<any, SheetProps>(
|
|
|
243
256
|
<SheetContext.Provider value={context}>
|
|
244
257
|
<motion.div
|
|
245
258
|
{...rest}
|
|
246
|
-
ref={ref}
|
|
259
|
+
ref={mergeRefs([ref, constraintsRef])}
|
|
247
260
|
style={{ ...styles.wrapper, zIndex, visibility, ...style }}
|
|
248
261
|
>
|
|
249
262
|
<AnimatePresence>
|
|
250
263
|
{/* NOTE: AnimatePresence requires us to set keys to children */}
|
|
251
264
|
{isOpen ? (
|
|
252
265
|
<SheetScrollerContextProvider>
|
|
253
|
-
{
|
|
254
|
-
|
|
266
|
+
{Children.map(children, (child: any, i) =>
|
|
267
|
+
cloneElement(child, { key: `sheet-child-${i}` })
|
|
255
268
|
)}
|
|
256
269
|
</SheetScrollerContextProvider>
|
|
257
270
|
) : null}
|
|
@@ -262,8 +275,10 @@ const Sheet = React.forwardRef<any, SheetProps>(
|
|
|
262
275
|
|
|
263
276
|
if (IS_SSR) return sheet;
|
|
264
277
|
|
|
265
|
-
return
|
|
278
|
+
return createPortal(sheet, mountPoint ?? document.body);
|
|
266
279
|
}
|
|
267
280
|
);
|
|
268
281
|
|
|
282
|
+
Sheet.displayName = 'Sheet';
|
|
283
|
+
|
|
269
284
|
export default Sheet;
|
package/src/styles.ts
CHANGED
package/src/types.tsx
CHANGED
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
type ComponentPropsWithoutRef,
|
|
3
|
+
type ForwardRefExoticComponent,
|
|
4
|
+
type HTMLAttributes,
|
|
5
|
+
type MutableRefObject,
|
|
6
|
+
type ReactNode,
|
|
7
|
+
type RefAttributes,
|
|
8
|
+
} from 'react';
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
type DragHandlers,
|
|
12
|
+
type MotionValue,
|
|
13
|
+
type MotionProps,
|
|
14
|
+
type motion,
|
|
15
|
+
type EasingDefinition,
|
|
16
|
+
type Transition,
|
|
8
17
|
} from 'framer-motion';
|
|
9
18
|
|
|
10
|
-
export
|
|
19
|
+
export interface SheetEvents {
|
|
11
20
|
onOpenStart?: () => void;
|
|
12
21
|
onOpenEnd?: () => void;
|
|
13
22
|
onCloseStart?: () => void;
|
|
14
23
|
onCloseEnd?: () => void;
|
|
15
24
|
onSnap?: (index: number) => void;
|
|
16
|
-
}
|
|
25
|
+
}
|
|
17
26
|
|
|
18
27
|
export type SheetDetent = 'full-height' | 'content-height';
|
|
19
28
|
|
|
@@ -21,14 +30,14 @@ type CommonProps = MotionProps & {
|
|
|
21
30
|
className?: string;
|
|
22
31
|
};
|
|
23
32
|
|
|
24
|
-
export
|
|
33
|
+
export interface SheetTweenConfig {
|
|
25
34
|
ease: EasingDefinition;
|
|
26
35
|
duration: number;
|
|
27
|
-
}
|
|
36
|
+
}
|
|
28
37
|
|
|
29
38
|
export type SheetProps = {
|
|
30
39
|
isOpen: boolean;
|
|
31
|
-
children:
|
|
40
|
+
children: ReactNode;
|
|
32
41
|
onClose: () => void;
|
|
33
42
|
rootId?: string;
|
|
34
43
|
mountPoint?: Element;
|
|
@@ -40,13 +49,13 @@ export type SheetProps = {
|
|
|
40
49
|
disableScrollLocking?: boolean;
|
|
41
50
|
prefersReducedMotion?: boolean;
|
|
42
51
|
} & SheetEvents &
|
|
43
|
-
|
|
52
|
+
ComponentPropsWithoutRef<typeof motion.div>;
|
|
44
53
|
|
|
45
54
|
export type SheetContainerProps = Omit<
|
|
46
55
|
CommonProps,
|
|
47
56
|
'initial' | 'animate' | 'exit' | 'onAnimationComplete'
|
|
48
57
|
> & {
|
|
49
|
-
children:
|
|
58
|
+
children: ReactNode;
|
|
50
59
|
};
|
|
51
60
|
|
|
52
61
|
export type SheetDraggableProps = Omit<
|
|
@@ -59,7 +68,7 @@ export type SheetDraggableProps = Omit<
|
|
|
59
68
|
| 'onDragStart'
|
|
60
69
|
| 'onDragEnd'
|
|
61
70
|
> & {
|
|
62
|
-
children?:
|
|
71
|
+
children?: ReactNode;
|
|
63
72
|
disableDrag?: boolean;
|
|
64
73
|
};
|
|
65
74
|
|
|
@@ -68,67 +77,67 @@ export type SheetBackdropProps = Omit<
|
|
|
68
77
|
'initial' | 'animate' | 'exit'
|
|
69
78
|
>;
|
|
70
79
|
|
|
71
|
-
export type SheetScrollerProps =
|
|
80
|
+
export type SheetScrollerProps = HTMLAttributes<HTMLDivElement> & {
|
|
72
81
|
draggableAt?: 'top' | 'bottom' | 'both';
|
|
73
82
|
};
|
|
74
83
|
|
|
75
|
-
export
|
|
84
|
+
export interface SheetDragProps {
|
|
76
85
|
drag: 'y';
|
|
77
86
|
dragElastic: number;
|
|
78
87
|
dragMomentum: boolean;
|
|
79
88
|
dragPropagation: boolean;
|
|
80
89
|
onDrag: DragHandlers['onDrag'];
|
|
81
90
|
onDragEnd: DragHandlers['onDragEnd'];
|
|
82
|
-
}
|
|
91
|
+
}
|
|
83
92
|
|
|
84
|
-
export
|
|
93
|
+
export interface SheetContextType {
|
|
85
94
|
y: MotionValue<any>;
|
|
86
|
-
sheetRef:
|
|
95
|
+
sheetRef: MutableRefObject<any>;
|
|
87
96
|
isOpen: boolean;
|
|
88
97
|
snapPoints: SheetProps['snapPoints'];
|
|
89
98
|
detent: SheetDetent;
|
|
90
99
|
initialSnap: SheetProps['initialSnap'];
|
|
91
100
|
indicatorRotation: MotionValue<number>;
|
|
92
|
-
callbacks:
|
|
101
|
+
callbacks: MutableRefObject<SheetEvents>;
|
|
93
102
|
dragProps?: SheetDragProps;
|
|
94
103
|
windowHeight: number;
|
|
95
104
|
animationOptions: Transition;
|
|
96
105
|
reduceMotion: boolean;
|
|
97
106
|
disableDrag: boolean;
|
|
98
|
-
}
|
|
107
|
+
}
|
|
99
108
|
|
|
100
|
-
export
|
|
109
|
+
export interface SheetScrollerContextType {
|
|
101
110
|
disableDrag: boolean;
|
|
102
111
|
setDragDisabled: () => void;
|
|
103
112
|
setDragEnabled: () => void;
|
|
104
|
-
}
|
|
113
|
+
}
|
|
105
114
|
|
|
106
|
-
type ContainerComponent =
|
|
107
|
-
SheetContainerProps &
|
|
115
|
+
type ContainerComponent = ForwardRefExoticComponent<
|
|
116
|
+
SheetContainerProps & RefAttributes<any>
|
|
108
117
|
>;
|
|
109
118
|
|
|
110
|
-
type DraggableComponent =
|
|
111
|
-
SheetDraggableProps &
|
|
119
|
+
type DraggableComponent = ForwardRefExoticComponent<
|
|
120
|
+
SheetDraggableProps & RefAttributes<any>
|
|
112
121
|
>;
|
|
113
122
|
|
|
114
|
-
type BackdropComponent =
|
|
115
|
-
SheetBackdropProps &
|
|
123
|
+
type BackdropComponent = ForwardRefExoticComponent<
|
|
124
|
+
SheetBackdropProps & RefAttributes<any>
|
|
116
125
|
>;
|
|
117
126
|
|
|
118
|
-
type SheetComponent =
|
|
119
|
-
SheetProps &
|
|
127
|
+
type SheetComponent = ForwardRefExoticComponent<
|
|
128
|
+
SheetProps & RefAttributes<any>
|
|
120
129
|
>;
|
|
121
130
|
|
|
122
|
-
type ScrollerComponent =
|
|
123
|
-
SheetScrollerProps &
|
|
131
|
+
type ScrollerComponent = ForwardRefExoticComponent<
|
|
132
|
+
SheetScrollerProps & RefAttributes<any>
|
|
124
133
|
>;
|
|
125
134
|
|
|
126
|
-
|
|
135
|
+
interface SheetCompoundComponent {
|
|
127
136
|
Container: ContainerComponent;
|
|
128
137
|
Header: DraggableComponent;
|
|
129
138
|
Content: DraggableComponent;
|
|
130
139
|
Backdrop: BackdropComponent;
|
|
131
140
|
Scroller: ScrollerComponent;
|
|
132
|
-
}
|
|
141
|
+
}
|
|
133
142
|
|
|
134
143
|
export type SheetCompound = SheetComponent & SheetCompoundComponent;
|
|
@@ -11,8 +11,8 @@ interface PreventScrollOptions {
|
|
|
11
11
|
isDisabled?: boolean;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const visualViewport =
|
|
15
|
+
typeof window !== 'undefined' ? (window as any).visualViewport : undefined;
|
|
16
16
|
|
|
17
17
|
// HTML input types that do not cause the software keyboard to appear.
|
|
18
18
|
const nonTextInputTypes = new Set([
|
|
@@ -37,7 +37,7 @@ let restore: any;
|
|
|
37
37
|
* shift due to the scrollbars disappearing.
|
|
38
38
|
*/
|
|
39
39
|
export function usePreventScroll(options: PreventScrollOptions = {}) {
|
|
40
|
-
|
|
40
|
+
const { isDisabled } = options;
|
|
41
41
|
|
|
42
42
|
useLayoutEffect(() => {
|
|
43
43
|
if (isDisabled) {
|
|
@@ -102,9 +102,10 @@ function preventScrollStandard() {
|
|
|
102
102
|
// 6. As a last resort, handle window scroll events, and scroll back to the top. This can happen when attempting
|
|
103
103
|
// to navigate to an input with the next/previous buttons that's outside a modal.
|
|
104
104
|
function preventScrollMobileSafari() {
|
|
105
|
-
let scrollable: Element;
|
|
105
|
+
let scrollable: Element | undefined;
|
|
106
106
|
let lastY = 0;
|
|
107
|
-
|
|
107
|
+
|
|
108
|
+
const onTouchStart = (e: TouchEvent) => {
|
|
108
109
|
// Store the nearest scrollable parent element from the element that the user touched.
|
|
109
110
|
scrollable = getScrollParent(e.target as Element);
|
|
110
111
|
if (
|
|
@@ -117,7 +118,14 @@ function preventScrollMobileSafari() {
|
|
|
117
118
|
lastY = e.changedTouches[0].pageY;
|
|
118
119
|
};
|
|
119
120
|
|
|
120
|
-
|
|
121
|
+
const onTouchMove = (e: TouchEvent) => {
|
|
122
|
+
// In special situations, `onTouchStart` may be called without `onTouchStart` being called.
|
|
123
|
+
// (e.g. when the user places a finger on the screen before the <Sheet> is mounted and then moves the finger after it is mounted).
|
|
124
|
+
// If `onTouchStart` is not called, `scrollable` is `undefined`. Therefore, such cases are ignored.
|
|
125
|
+
if (scrollable === undefined) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
121
129
|
// Prevent scrolling the window.
|
|
122
130
|
if (
|
|
123
131
|
scrollable === document.documentElement ||
|
|
@@ -131,9 +139,9 @@ function preventScrollMobileSafari() {
|
|
|
131
139
|
// of a nested scrollable area, otherwise mobile Safari will start scrolling
|
|
132
140
|
// the window instead. Unfortunately, this disables bounce scrolling when at
|
|
133
141
|
// the top but it's the best we can do.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
142
|
+
const y = e.changedTouches[0].pageY;
|
|
143
|
+
const scrollTop = scrollable.scrollTop;
|
|
144
|
+
const bottom = scrollable.scrollHeight - scrollable.clientHeight;
|
|
137
145
|
|
|
138
146
|
// Fix for: https://github.com/adobe/react-spectrum/pull/3780/files
|
|
139
147
|
if (bottom === 0) {
|
|
@@ -147,8 +155,8 @@ function preventScrollMobileSafari() {
|
|
|
147
155
|
lastY = y;
|
|
148
156
|
};
|
|
149
157
|
|
|
150
|
-
|
|
151
|
-
|
|
158
|
+
const onTouchEnd = (e: TouchEvent) => {
|
|
159
|
+
const target = e.target as HTMLElement;
|
|
152
160
|
|
|
153
161
|
// Apply this change if we're not already focused on the target element
|
|
154
162
|
if (willOpenKeyboard(target) && target !== document.activeElement) {
|
|
@@ -165,8 +173,8 @@ function preventScrollMobileSafari() {
|
|
|
165
173
|
}
|
|
166
174
|
};
|
|
167
175
|
|
|
168
|
-
|
|
169
|
-
|
|
176
|
+
const onFocus = (e: FocusEvent) => {
|
|
177
|
+
const target = e.target as HTMLElement;
|
|
170
178
|
if (willOpenKeyboard(target)) {
|
|
171
179
|
// Transform also needs to be applied in the focus event in cases where focus moves
|
|
172
180
|
// other than tapping on an input directly, e.g. the next/previous buttons in the
|
|
@@ -190,7 +198,9 @@ function preventScrollMobileSafari() {
|
|
|
190
198
|
// measure the correct position to scroll to.
|
|
191
199
|
visualViewport.addEventListener(
|
|
192
200
|
'resize',
|
|
193
|
-
() =>
|
|
201
|
+
() => {
|
|
202
|
+
scrollIntoView(target);
|
|
203
|
+
},
|
|
194
204
|
{ once: true }
|
|
195
205
|
);
|
|
196
206
|
}
|
|
@@ -199,7 +209,7 @@ function preventScrollMobileSafari() {
|
|
|
199
209
|
}
|
|
200
210
|
};
|
|
201
211
|
|
|
202
|
-
|
|
212
|
+
const onWindowScroll = () => {
|
|
203
213
|
// Last resort. If the window scrolled, scroll it back to the top.
|
|
204
214
|
// It should always be at the top because the body will have a negative margin (see below).
|
|
205
215
|
window.scrollTo(0, 0);
|
|
@@ -208,10 +218,10 @@ function preventScrollMobileSafari() {
|
|
|
208
218
|
// Record the original scroll position so we can restore it.
|
|
209
219
|
// Then apply a negative margin to the body to offset it by the scroll position. This will
|
|
210
220
|
// enable us to scroll the window to the top, which is required for the rest of this to work.
|
|
211
|
-
|
|
212
|
-
|
|
221
|
+
const scrollX = window.pageXOffset;
|
|
222
|
+
const scrollY = window.pageYOffset;
|
|
213
223
|
|
|
214
|
-
|
|
224
|
+
const restoreStyles = chain(
|
|
215
225
|
setStyle(
|
|
216
226
|
document.documentElement,
|
|
217
227
|
'paddingRight',
|
|
@@ -224,7 +234,7 @@ function preventScrollMobileSafari() {
|
|
|
224
234
|
// Scroll to the top. The negative margin on the body will make this appear the same.
|
|
225
235
|
window.scrollTo(0, 0);
|
|
226
236
|
|
|
227
|
-
|
|
237
|
+
const removeEvents = chain(
|
|
228
238
|
addEvent(document, 'touchstart', onTouchStart, {
|
|
229
239
|
passive: false,
|
|
230
240
|
capture: true,
|
|
@@ -251,7 +261,7 @@ function preventScrollMobileSafari() {
|
|
|
251
261
|
|
|
252
262
|
// Sets a CSS property on an element, and returns a function to revert it to the previous value.
|
|
253
263
|
function setStyle(element: any, style: string, value: string) {
|
|
254
|
-
|
|
264
|
+
const cur = element.style[style];
|
|
255
265
|
element.style[style] = value;
|
|
256
266
|
|
|
257
267
|
return () => {
|
|
@@ -273,17 +283,17 @@ function addEvent<K extends keyof GlobalEventHandlersEventMap>(
|
|
|
273
283
|
}
|
|
274
284
|
|
|
275
285
|
function scrollIntoView(target: Element) {
|
|
276
|
-
|
|
286
|
+
const root = document.scrollingElement || document.documentElement;
|
|
277
287
|
while (target && target !== root) {
|
|
278
288
|
// Find the parent scrollable element and adjust the scroll position if the target is not already in view.
|
|
279
|
-
|
|
289
|
+
const scrollable = getScrollParent(target);
|
|
280
290
|
if (
|
|
281
291
|
scrollable !== document.documentElement &&
|
|
282
292
|
scrollable !== document.body &&
|
|
283
293
|
scrollable !== target
|
|
284
294
|
) {
|
|
285
|
-
|
|
286
|
-
|
|
295
|
+
const scrollableTop = scrollable.getBoundingClientRect().top;
|
|
296
|
+
const targetTop = target.getBoundingClientRect().top;
|
|
287
297
|
if (targetTop > scrollableTop + target.clientHeight) {
|
|
288
298
|
scrollable.scrollTop += targetTop - scrollableTop;
|
|
289
299
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type ForwardedRef, type RefCallback } from 'react';
|
|
2
2
|
|
|
3
3
|
export function getClosest(nums: number[], goal: number) {
|
|
4
4
|
let closest = nums[0];
|
|
@@ -82,9 +82,7 @@ export function validateSnapTo({
|
|
|
82
82
|
return Math.max(Math.round(snapTo), 0);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
export function mergeRefs<T = any>(
|
|
86
|
-
refs: React.ForwardedRef<T>[]
|
|
87
|
-
): React.RefCallback<T> {
|
|
85
|
+
export function mergeRefs<T = any>(refs: Array<ForwardedRef<T>>): RefCallback<T> {
|
|
88
86
|
return (value: any) => {
|
|
89
87
|
refs.forEach((ref: any) => {
|
|
90
88
|
if (typeof ref === 'function') {
|
package/dist/SheetBackdrop.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
declare const SheetBackdrop: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps & {
|
|
3
|
-
className?: string | undefined;
|
|
4
|
-
}, "style" | "transformTemplate" | "transformValues" | "children" | "variants" | "transition" | "onBeforeLayoutMeasure" | "onLayoutMeasure" | "onUpdate" | "onAnimationStart" | "onAnimationComplete" | "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" | "onLayoutAnimationStart" | "onLayoutAnimationComplete" | "layoutDependency" | "layoutScroll" | "layoutRoot" | "custom" | "inherit" | "ignoreStrict" | "className"> & React.RefAttributes<any>>;
|
|
5
|
-
export default SheetBackdrop;
|
package/dist/SheetContainer.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
declare const SheetContainer: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps & {
|
|
3
|
-
className?: string | undefined;
|
|
4
|
-
}, "style" | "transformTemplate" | "transformValues" | "children" | "variants" | "transition" | "onBeforeLayoutMeasure" | "onLayoutMeasure" | "onUpdate" | "onAnimationStart" | "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" | "onLayoutAnimationStart" | "onLayoutAnimationComplete" | "layoutDependency" | "layoutScroll" | "layoutRoot" | "custom" | "inherit" | "ignoreStrict" | "className"> & {
|
|
5
|
-
children: React.ReactNode;
|
|
6
|
-
} & React.RefAttributes<any>>;
|
|
7
|
-
export default SheetContainer;
|
package/dist/SheetContent.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
declare const SheetContent: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps & {
|
|
3
|
-
className?: string | undefined;
|
|
4
|
-
}, "style" | "transformTemplate" | "transformValues" | "children" | "initial" | "animate" | "exit" | "variants" | "transition" | "onBeforeLayoutMeasure" | "onLayoutMeasure" | "onUpdate" | "onAnimationStart" | "onAnimationComplete" | "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" | "onLayoutAnimationStart" | "onLayoutAnimationComplete" | "layoutDependency" | "layoutScroll" | "layoutRoot" | "custom" | "inherit" | "ignoreStrict" | "className"> & {
|
|
5
|
-
children?: React.ReactNode;
|
|
6
|
-
disableDrag?: boolean | undefined;
|
|
7
|
-
} & React.RefAttributes<any>>;
|
|
8
|
-
export default SheetContent;
|
package/dist/SheetHeader.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
declare const SheetHeader: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps & {
|
|
3
|
-
className?: string | undefined;
|
|
4
|
-
}, "style" | "transformTemplate" | "transformValues" | "children" | "initial" | "animate" | "exit" | "variants" | "transition" | "onBeforeLayoutMeasure" | "onLayoutMeasure" | "onUpdate" | "onAnimationStart" | "onAnimationComplete" | "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" | "onLayoutAnimationStart" | "onLayoutAnimationComplete" | "layoutDependency" | "layoutScroll" | "layoutRoot" | "custom" | "inherit" | "ignoreStrict" | "className"> & {
|
|
5
|
-
children?: React.ReactNode;
|
|
6
|
-
disableDrag?: boolean | undefined;
|
|
7
|
-
} & React.RefAttributes<any>>;
|
|
8
|
-
export default SheetHeader;
|
package/dist/SheetScroller.d.ts
DELETED
package/dist/constants.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
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_TWEEN_CONFIG: {
|
|
4
|
-
ease: string;
|
|
5
|
-
duration: number;
|
|
6
|
-
};
|
|
7
|
-
export declare const REDUCED_MOTION_TWEEN_CONFIG: {
|
|
8
|
-
ease: string;
|
|
9
|
-
duration: number;
|
|
10
|
-
};
|
|
11
|
-
export declare const DRAG_CLOSE_THRESHOLD = 0.6;
|
|
12
|
-
export declare const DRAG_VELOCITY_THRESHOLD = 500;
|
package/dist/context.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { SheetScrollerContextType, SheetContextType } from './types';
|
|
3
|
-
export declare const SheetContext: React.Context<SheetContextType | undefined>;
|
|
4
|
-
export declare const useSheetContext: () => SheetContextType;
|
|
5
|
-
export declare const SheetScrollerContext: React.Context<SheetScrollerContextType | undefined>;
|
|
6
|
-
export declare function SheetScrollerContextProvider({ children, }: {
|
|
7
|
-
children: React.ReactNode;
|
|
8
|
-
}): React.JSX.Element;
|
|
9
|
-
export declare const useSheetScrollerContext: () => SheetScrollerContextType;
|
package/dist/hooks.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { SheetEvents } from './types';
|
|
3
|
-
import { BoundingBox } from 'framer-motion';
|
|
4
|
-
export declare const useIsomorphicLayoutEffect: typeof React.useEffect;
|
|
5
|
-
export declare function useModalEffect(isOpen: boolean, rootId?: string): void;
|
|
6
|
-
export declare function useEventCallbacks(isOpen: boolean, callbacks: React.MutableRefObject<SheetEvents>): {
|
|
7
|
-
handleAnimationComplete: () => void;
|
|
8
|
-
};
|
|
9
|
-
export declare function useWindowHeight(): number;
|
|
10
|
-
export declare function usePrevious<T>(state: T): T | undefined;
|
|
11
|
-
export declare function useEvent<T extends (...args: any[]) => any>(handler: T): T;
|
|
12
|
-
export declare function useDragConstraints(): {
|
|
13
|
-
constraintsRef: React.MutableRefObject<any>;
|
|
14
|
-
onMeasureDragConstraints: () => BoundingBox;
|
|
15
|
-
};
|