react-modal-sheet 4.2.0 → 4.4.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/src/sheet.tsx CHANGED
@@ -30,11 +30,10 @@ import {
30
30
  } from './constants';
31
31
 
32
32
  import {
33
- getClosest,
34
33
  getSheetHeight,
35
34
  getSnapY,
36
35
  getSnapPoints,
37
- validateSnapTo,
36
+ getClosestSnapPoint,
38
37
  } from './utils';
39
38
 
40
39
  import { type SheetContextType, type SheetProps } from './types';
@@ -116,7 +115,24 @@ export const Sheet = forwardRef<any, SheetProps>(
116
115
  };
117
116
  });
118
117
 
119
- const onDrag = useStableCallback((_, { delta }: PanInfo) => {
118
+ const onDrag = useStableCallback((_: PointerEvent, info: PanInfo) => {
119
+ const currentY = y.get();
120
+
121
+ /**
122
+ * Make sure the user cannot drag the sheet beyond the upmost snap point
123
+ * if the `snapPoints` prop is provided.
124
+ */
125
+ if (snapPointsProp) {
126
+ const sheetHeight = getSheetHeight(sheetRef);
127
+ const snapPoints = getSnapPoints({ snapPointsProp, sheetHeight });
128
+ const topSnapPoint = sheetHeight - snapPoints[0];
129
+
130
+ if (info.delta.y < 0 && currentY <= topSnapPoint) {
131
+ y.set(topSnapPoint);
132
+ return;
133
+ }
134
+ }
135
+
120
136
  // Update drag indicator rotation based on drag velocity
121
137
  const velocity = y.getVelocity();
122
138
 
@@ -124,7 +140,7 @@ export const Sheet = forwardRef<any, SheetProps>(
124
140
  if (velocity < 0) indicatorRotation.set(-10);
125
141
 
126
142
  // Make sure user cannot drag beyond the top of the sheet
127
- y.set(Math.max(y.get() + delta.y, 0));
143
+ y.set(Math.max(currentY + info.delta.y, 0));
128
144
  });
129
145
 
130
146
  const onDragStart = useStableCallback(() => {
@@ -158,25 +174,15 @@ export const Sheet = forwardRef<any, SheetProps>(
158
174
  : undefined;
159
175
 
160
176
  if (snapPoints) {
161
- // Inverse values are the values that can be passed to `animate`
162
- const snapInverse = snapPoints.map(
163
- (p) => sheetHeight - Math.min(p, sheetHeight)
164
- );
165
-
166
- // Allow snapping to the top of the sheet if detent is set to `content-height`
167
- if (detent === 'content-height' && !snapInverse.includes(0)) {
168
- snapInverse.unshift(0);
169
- }
170
-
171
- // Get the closest snap point
172
- const snapTo = getClosest(snapInverse, currentY);
173
- const snapIndex = snapInverse.indexOf(snapTo);
174
-
175
- yTo = validateSnapTo({
176
- snapTo: getClosest(snapInverse, currentY),
177
+ const { snapY, snapIndex } = getClosestSnapPoint({
178
+ snapPoints,
179
+ currentY,
177
180
  sheetHeight,
181
+ detent,
178
182
  });
179
183
 
184
+ yTo = snapY;
185
+
180
186
  // This happens before calling `animate` but it doesn't really matter
181
187
  onSnap?.(snapIndex);
182
188
  } else if (currentY / sheetHeight > dragCloseThreshold) {
@@ -214,10 +220,10 @@ export const Sheet = forwardRef<any, SheetProps>(
214
220
  const snapIndex = initialSnap;
215
221
  const sheetHeight = getSheetHeight(sheetRef);
216
222
  const snapPoints = getSnapPoints({ snapPointsProp, sheetHeight });
217
- const ySnap = getSnapY({ sheetHeight, snapPoints, snapIndex });
223
+ const snapY = getSnapY({ sheetHeight, snapPoints, snapIndex });
218
224
 
219
- if (ySnap !== null) {
220
- yTo = ySnap;
225
+ if (snapY !== null) {
226
+ yTo = snapY;
221
227
  }
222
228
  }
223
229
 
@@ -234,14 +240,14 @@ export const Sheet = forwardRef<any, SheetProps>(
234
240
 
235
241
  const sheetHeight = getSheetHeight(sheetRef);
236
242
  const snapPoints = getSnapPoints({ snapPointsProp, sheetHeight });
237
- const ySnap = getSnapY({ sheetHeight, snapPoints, snapIndex });
243
+ const snapY = getSnapY({ sheetHeight, snapPoints, snapIndex });
238
244
 
239
- if (ySnap !== null) {
240
- animate(y, ySnap, animationOptions);
245
+ if (snapY !== null) {
246
+ animate(y, snapY, animationOptions);
241
247
  onSnap?.(snapIndex);
242
248
 
243
249
  // +1px for imprecision tolerance
244
- if (ySnap + 1 >= sheetHeight) {
250
+ if (snapY + 1 >= sheetHeight) {
245
251
  onClose();
246
252
  }
247
253
  }
package/src/styles.ts CHANGED
@@ -20,6 +20,7 @@ export const styles: Record<string, Properties> = {
20
20
  backgroundColor: 'rgba(0, 0, 0, 0.2)',
21
21
  touchAction: 'none',
22
22
  border: 'none',
23
+ userSelect: 'none',
23
24
  WebkitTapHighlightColor: 'transparent',
24
25
  },
25
26
  container: {
@@ -63,5 +64,6 @@ export const styles: Record<string, Properties> = {
63
64
  scroller: {
64
65
  height: '100%',
65
66
  overflowY: 'auto',
67
+ overscrollBehaviorY: 'none',
66
68
  },
67
69
  };
package/src/types.tsx CHANGED
@@ -1,8 +1,6 @@
1
1
  import {
2
2
  type ComponentPropsWithoutRef,
3
3
  type ForwardRefExoticComponent,
4
- type HTMLAttributes,
5
- type MutableRefObject,
6
4
  type ReactNode,
7
5
  type RefAttributes,
8
6
  type RefObject,
@@ -31,6 +29,8 @@ type CommonProps = MotionProps & {
31
29
  className?: string;
32
30
  };
33
31
 
32
+ type MotionDivProps = ComponentPropsWithoutRef<typeof motion.div>;
33
+
34
34
  export interface SheetTweenConfig {
35
35
  ease: EasingDefinition;
36
36
  duration: number;
@@ -55,7 +55,7 @@ export type SheetProps = {
55
55
  dragCloseThreshold?: number;
56
56
  modalEffectThreshold?: number;
57
57
  } & SheetEvents &
58
- ComponentPropsWithoutRef<typeof motion.div>;
58
+ MotionDivProps;
59
59
 
60
60
  export type SheetContainerProps = Omit<
61
61
  CommonProps,
@@ -83,8 +83,10 @@ export type SheetBackdropProps = Omit<
83
83
  'initial' | 'animate' | 'exit'
84
84
  >;
85
85
 
86
- export type SheetScrollerProps = HTMLAttributes<HTMLDivElement> & {
86
+ export type SheetScrollerProps = MotionDivProps & {
87
87
  draggableAt?: 'top' | 'bottom' | 'both';
88
+ disableScroll?: boolean;
89
+ autoPadding?: boolean;
88
90
  };
89
91
 
90
92
  export interface SheetDragProps {
package/src/utils.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type ForwardedRef, type RefCallback, type RefObject } from 'react';
2
2
  import { IS_SSR } from './constants';
3
+ import type { SheetDetent } from './types';
3
4
 
4
5
  /**
5
6
  * Get the rounded height of the sheet element and log a warning if the
@@ -45,6 +46,39 @@ export function getSnapPoints({
45
46
  return snapPointValues;
46
47
  }
47
48
 
49
+ export function getClosestSnapPoint({
50
+ snapPoints,
51
+ currentY,
52
+ sheetHeight,
53
+ detent,
54
+ }: {
55
+ snapPoints: number[];
56
+ currentY: number;
57
+ sheetHeight: number;
58
+ detent?: SheetDetent;
59
+ }) {
60
+ // Inverse values are the values that can be passed to `animate`
61
+ const snapInverse = snapPoints.map(
62
+ (p) => sheetHeight - Math.min(p, sheetHeight)
63
+ );
64
+
65
+ // Allow snapping to the top of the sheet if detent is set to `content-height`
66
+ if (detent === 'content-height' && !snapInverse.includes(0)) {
67
+ snapInverse.unshift(0);
68
+ }
69
+
70
+ // Get the closest snap point
71
+ const snapTo = getClosest(snapInverse, currentY);
72
+ const snapIndex = snapInverse.indexOf(snapTo);
73
+
74
+ const snapY = validateSnapTo({
75
+ snapTo: getClosest(snapInverse, currentY),
76
+ sheetHeight,
77
+ });
78
+
79
+ return { snapY, snapIndex };
80
+ }
81
+
48
82
  /**
49
83
  * Get the closest number to the goal from the array of numbers.
50
84
  */