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/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) {
|
|
@@ -104,7 +104,8 @@ function preventScrollStandard() {
|
|
|
104
104
|
function preventScrollMobileSafari() {
|
|
105
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,7 @@ function preventScrollMobileSafari() {
|
|
|
117
118
|
lastY = e.changedTouches[0].pageY;
|
|
118
119
|
};
|
|
119
120
|
|
|
120
|
-
|
|
121
|
+
const onTouchMove = (e: TouchEvent) => {
|
|
121
122
|
// In special situations, `onTouchStart` may be called without `onTouchStart` being called.
|
|
122
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).
|
|
123
124
|
// If `onTouchStart` is not called, `scrollable` is `undefined`. Therefore, such cases are ignored.
|
|
@@ -138,9 +139,9 @@ function preventScrollMobileSafari() {
|
|
|
138
139
|
// of a nested scrollable area, otherwise mobile Safari will start scrolling
|
|
139
140
|
// the window instead. Unfortunately, this disables bounce scrolling when at
|
|
140
141
|
// the top but it's the best we can do.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
const y = e.changedTouches[0].pageY;
|
|
143
|
+
const scrollTop = scrollable.scrollTop;
|
|
144
|
+
const bottom = scrollable.scrollHeight - scrollable.clientHeight;
|
|
144
145
|
|
|
145
146
|
// Fix for: https://github.com/adobe/react-spectrum/pull/3780/files
|
|
146
147
|
if (bottom === 0) {
|
|
@@ -154,8 +155,8 @@ function preventScrollMobileSafari() {
|
|
|
154
155
|
lastY = y;
|
|
155
156
|
};
|
|
156
157
|
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
const onTouchEnd = (e: TouchEvent) => {
|
|
159
|
+
const target = e.target as HTMLElement;
|
|
159
160
|
|
|
160
161
|
// Apply this change if we're not already focused on the target element
|
|
161
162
|
if (willOpenKeyboard(target) && target !== document.activeElement) {
|
|
@@ -172,8 +173,8 @@ function preventScrollMobileSafari() {
|
|
|
172
173
|
}
|
|
173
174
|
};
|
|
174
175
|
|
|
175
|
-
|
|
176
|
-
|
|
176
|
+
const onFocus = (e: FocusEvent) => {
|
|
177
|
+
const target = e.target as HTMLElement;
|
|
177
178
|
if (willOpenKeyboard(target)) {
|
|
178
179
|
// Transform also needs to be applied in the focus event in cases where focus moves
|
|
179
180
|
// other than tapping on an input directly, e.g. the next/previous buttons in the
|
|
@@ -197,7 +198,9 @@ function preventScrollMobileSafari() {
|
|
|
197
198
|
// measure the correct position to scroll to.
|
|
198
199
|
visualViewport.addEventListener(
|
|
199
200
|
'resize',
|
|
200
|
-
() =>
|
|
201
|
+
() => {
|
|
202
|
+
scrollIntoView(target);
|
|
203
|
+
},
|
|
201
204
|
{ once: true }
|
|
202
205
|
);
|
|
203
206
|
}
|
|
@@ -206,7 +209,7 @@ function preventScrollMobileSafari() {
|
|
|
206
209
|
}
|
|
207
210
|
};
|
|
208
211
|
|
|
209
|
-
|
|
212
|
+
const onWindowScroll = () => {
|
|
210
213
|
// Last resort. If the window scrolled, scroll it back to the top.
|
|
211
214
|
// It should always be at the top because the body will have a negative margin (see below).
|
|
212
215
|
window.scrollTo(0, 0);
|
|
@@ -215,10 +218,10 @@ function preventScrollMobileSafari() {
|
|
|
215
218
|
// Record the original scroll position so we can restore it.
|
|
216
219
|
// Then apply a negative margin to the body to offset it by the scroll position. This will
|
|
217
220
|
// enable us to scroll the window to the top, which is required for the rest of this to work.
|
|
218
|
-
|
|
219
|
-
|
|
221
|
+
const scrollX = window.pageXOffset;
|
|
222
|
+
const scrollY = window.pageYOffset;
|
|
220
223
|
|
|
221
|
-
|
|
224
|
+
const restoreStyles = chain(
|
|
222
225
|
setStyle(
|
|
223
226
|
document.documentElement,
|
|
224
227
|
'paddingRight',
|
|
@@ -231,7 +234,7 @@ function preventScrollMobileSafari() {
|
|
|
231
234
|
// Scroll to the top. The negative margin on the body will make this appear the same.
|
|
232
235
|
window.scrollTo(0, 0);
|
|
233
236
|
|
|
234
|
-
|
|
237
|
+
const removeEvents = chain(
|
|
235
238
|
addEvent(document, 'touchstart', onTouchStart, {
|
|
236
239
|
passive: false,
|
|
237
240
|
capture: true,
|
|
@@ -258,7 +261,7 @@ function preventScrollMobileSafari() {
|
|
|
258
261
|
|
|
259
262
|
// Sets a CSS property on an element, and returns a function to revert it to the previous value.
|
|
260
263
|
function setStyle(element: any, style: string, value: string) {
|
|
261
|
-
|
|
264
|
+
const cur = element.style[style];
|
|
262
265
|
element.style[style] = value;
|
|
263
266
|
|
|
264
267
|
return () => {
|
|
@@ -280,17 +283,17 @@ function addEvent<K extends keyof GlobalEventHandlersEventMap>(
|
|
|
280
283
|
}
|
|
281
284
|
|
|
282
285
|
function scrollIntoView(target: Element) {
|
|
283
|
-
|
|
286
|
+
const root = document.scrollingElement || document.documentElement;
|
|
284
287
|
while (target && target !== root) {
|
|
285
288
|
// Find the parent scrollable element and adjust the scroll position if the target is not already in view.
|
|
286
|
-
|
|
289
|
+
const scrollable = getScrollParent(target);
|
|
287
290
|
if (
|
|
288
291
|
scrollable !== document.documentElement &&
|
|
289
292
|
scrollable !== document.body &&
|
|
290
293
|
scrollable !== target
|
|
291
294
|
) {
|
|
292
|
-
|
|
293
|
-
|
|
295
|
+
const scrollableTop = scrollable.getBoundingClientRect().top;
|
|
296
|
+
const targetTop = target.getBoundingClientRect().top;
|
|
294
297
|
if (targetTop > scrollableTop + target.clientHeight) {
|
|
295
298
|
scrollable.scrollTop += targetTop - scrollableTop;
|
|
296
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
|
-
};
|