Skip to content

Commit e50be67

Browse files
committed
chore: add an array of middle points to intercept gesture navigation
1 parent f95b056 commit e50be67

File tree

3 files changed

+39
-10
lines changed

3 files changed

+39
-10
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## Unreleased
6+
7+
### ✨ Improvements
8+
9+
- Add new prop `snapPoints` to receive an array of points instead of a single one ([#395](https://github.com/jeremybarbet/react-native-modalize/pull/395))
10+
511
## [2.0.8] - 2020-12-04
612

713
### 👀 Bug Fixes

src/index.tsx

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ const ModalizeBase = (
7676

7777
// Layout
7878
snapPoint,
79+
snapPoints = [],
7980
modalHeight,
8081
modalTopOffset = Platform.select({
8182
ios: 0,
@@ -138,24 +139,31 @@ const ModalizeBase = (
138139
}: IProps,
139140
ref: React.Ref<React.ReactNode>,
140141
): JSX.Element | null => {
142+
const hasMiddlePoints = snapPoints.length > 0;
141143
const { height: screenHeight } = useDimensions();
142144
const isHandleOutside = handlePosition === 'outside';
143145
const handleHeight = withHandle ? 20 : isHandleOutside ? 35 : 20;
144146
const fullHeight = screenHeight - modalTopOffset;
145147
const computedHeight = fullHeight - handleHeight - (isIphoneX ? 34 : 0);
146148
const endHeight = modalHeight || computedHeight;
147149
const adjustValue = adjustToContentHeight ? undefined : endHeight;
148-
const snaps = snapPoint ? [0, endHeight - snapPoint, endHeight] : [0, endHeight];
150+
const snaps = hasMiddlePoints
151+
? [0, ...snapPoints, endHeight]
152+
: snapPoint
153+
? [0, endHeight - snapPoint, endHeight]
154+
: [0, endHeight];
149155

150156
const [modalHeightValue, setModalHeightValue] = React.useState(adjustValue);
151-
const [lastSnap, setLastSnap] = React.useState(snapPoint ? endHeight - snapPoint : 0);
157+
const [lastSnap, setLastSnap] = React.useState(
158+
hasMiddlePoints ? snapPoints[snapPoints.length - 1] : snapPoint ? endHeight - snapPoint : 0,
159+
);
152160
const [isVisible, setIsVisible] = React.useState(false);
153161
const [showContent, setShowContent] = React.useState(true);
154162
const [enableBounces, setEnableBounces] = React.useState(true);
155163
const [keyboardToggle, setKeyboardToggle] = React.useState(false);
156164
const [keyboardHeight, setKeyboardHeight] = React.useState(0);
157165
const [disableScroll, setDisableScroll] = React.useState(
158-
alwaysOpen || snapPoint ? true : undefined,
166+
alwaysOpen || snapPoint || hasMiddlePoints ? true : undefined,
159167
);
160168
const [beginScrollYValue, setBeginScrollYValue] = React.useState(0);
161169
const [modalPosition, setModalPosition] = React.useState<TPosition>('initial');
@@ -240,6 +248,8 @@ const ModalizeBase = (
240248
toValue = 0;
241249
} else if (alwaysOpenValue) {
242250
toValue = (modalHeightValue || 0) - alwaysOpenValue;
251+
} else if (hasMiddlePoints) {
252+
toValue = (modalHeightValue || 0) - snapPoints[0];
243253
} else if (snapPoint) {
244254
toValue = (modalHeightValue || 0) - snapPoint;
245255
}
@@ -257,7 +267,10 @@ const ModalizeBase = (
257267
setIsVisible(true);
258268
setShowContent(true);
259269

260-
if ((alwaysOpenValue && dest !== 'top') || (snapPoint && dest === 'default')) {
270+
if (
271+
(alwaysOpenValue && dest !== 'top') ||
272+
((hasMiddlePoints || snapPoint) && dest === 'default')
273+
) {
261274
newPosition = 'initial';
262275
} else {
263276
newPosition = 'top';
@@ -307,7 +320,7 @@ const ModalizeBase = (
307320

308321
const handleAnimateClose = (dest: TClose = 'default', callback?: () => void): void => {
309322
const { timing, spring } = closeAnimationConfig;
310-
const lastSnapValue = snapPoint ? snaps[1] : 80;
323+
const lastSnapValue = hasMiddlePoints || snapPoint ? snaps[snaps.length - 1] : 80;
311324
const toInitialAlwaysOpen = dest === 'alwaysOpen' && Boolean(alwaysOpen);
312325
const toValue =
313326
toInitialAlwaysOpen && alwaysOpen ? (modalHeightValue || 0) - alwaysOpen : screenHeight;
@@ -452,7 +465,7 @@ const ModalizeBase = (
452465
const { velocityY, translationY } = nativeEvent;
453466
const negativeReverseScroll =
454467
modalPosition === 'top' &&
455-
beginScrollYValue >= (snapPoint ? 0 : SCROLL_THRESHOLD) &&
468+
beginScrollYValue >= (snapPoint || hasMiddlePoints ? 0 : SCROLL_THRESHOLD) &&
456469
translationY < 0;
457470
const thresholdProps = translationY > threshold && beginScrollYValue === 0;
458471
const closeThreshold = velocity
@@ -473,7 +486,7 @@ const ModalizeBase = (
473486
setCancelClose(false);
474487

475488
if (
476-
!closeSnapPointStraightEnabled && snapPoint
489+
!closeSnapPointStraightEnabled && (snapPoint || hasMiddlePoints)
477490
? beginScrollYValue > 0
478491
: beginScrollYValue > 0 || negativeReverseScroll
479492
) {
@@ -488,7 +501,8 @@ const ModalizeBase = (
488501

489502
if (!tapGestureEnabled) {
490503
setDisableScroll(
491-
(Boolean(snapPoint) || Boolean(alwaysOpen)) && modalPosition === 'initial',
504+
(Boolean(snapPoint) || Boolean(hasMiddlePoints) || Boolean(alwaysOpen)) &&
505+
modalPosition === 'initial',
492506
);
493507
}
494508
}
@@ -506,7 +520,7 @@ const ModalizeBase = (
506520
const toValue = translationY - beginScrollYValue;
507521
let destSnapPoint = 0;
508522

509-
if (snapPoint || alwaysOpen) {
523+
if (hasMiddlePoints || snapPoint || alwaysOpen) {
510524
const endOffsetY = lastSnap + toValue + dragToss * velocityY;
511525

512526
/**
@@ -631,7 +645,7 @@ const ModalizeBase = (
631645
useNativeDriver: USE_NATIVE_DRIVER,
632646
listener: ({ nativeEvent: { translationY } }: PanGestureHandlerStateChangeEvent) => {
633647
if (panGestureAnimatedValue) {
634-
const offset = alwaysOpen ?? snapPoint ?? 0;
648+
const offset = alwaysOpen ?? snapPoint ?? snapPoints[0] ?? 0;
635649
const diff = Math.abs(translationY / (endHeight - offset));
636650
const y = translationY <= 0 ? diff : 1 - diff;
637651
let value: number;
@@ -875,6 +889,10 @@ const ModalizeBase = (
875889
(scrollViewProps || children) && sectionListProps,
876890
`You have defined 'sectionListProps' along with 'scrollViewProps' or 'children' props. Remove 'scrollViewProps' or 'children' or 'sectionListProps' to fix the error.`,
877891
);
892+
invariant(
893+
snapPoint && snapPoints,
894+
`You can't use both 'snapPoint' and 'snapPoints' props at the same time. Only choose one of the two.`,
895+
);
878896
}, [
879897
modalHeight,
880898
adjustToContentHeight,

src/options.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ export interface IProps<ListItem = any> {
102102
*/
103103
snapPoint?: number;
104104

105+
/**
106+
* An array of numbers to enable the snapping feature with intermediate points before opening the modal to full screen.
107+
*/
108+
snapPoints?: number[];
109+
105110
/**
106111
* A number to define the modal's total height.
107112
*/

0 commit comments

Comments
 (0)