Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/components/bottomSheet/BottomSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
//#region gesture interaction / animation
// variables
const animationState = useSharedValue(ANIMATION_STATE.UNDETERMINED, false);
const animatedSnapPoints = useSharedValue(snapPoints, true);
const animatedPosition = useSharedValue(initialPosition, true);
const animatedIndex = useDerivedValue(() => {
const adjustedSnapPoints = snapPoints.slice().reverse();
Expand Down Expand Up @@ -323,7 +324,7 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
] = useInteractivePanGestureHandler(
GESTURE.CONTENT,
animatedPosition,
snapPoints,
animatedSnapPoints,
animateToPoint,
enableOverDrag,
overDragResistanceFactor,
Expand All @@ -336,7 +337,7 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
] = useInteractivePanGestureHandler(
GESTURE.HANDLE,
animatedPosition,
snapPoints,
animatedSnapPoints,
animateToPoint,
enableOverDrag,
overDragResistanceFactor
Expand Down
58 changes: 27 additions & 31 deletions src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import React, { memo, useCallback, useMemo, useRef } from 'react';
import { TouchableWithoutFeedback } from 'react-native';
import React, { memo, useMemo, useRef } from 'react';
import Animated, {
interpolate,
Extrapolate,
useAnimatedStyle,
useAnimatedProps,
useSharedValue,
useAnimatedReaction,
useAnimatedGestureHandler,
runOnJS,
} from 'react-native-reanimated';
import {
TapGestureHandler,
TapGestureHandlerGestureEvent,
} from 'react-native-gesture-handler';
import isEqual from 'lodash.isequal';
import { useBottomSheet } from '../../hooks/useBottomSheet';
import {
Expand All @@ -21,10 +26,6 @@ import { WINDOW_HEIGHT } from '../../constants';
import type { BottomSheetDefaultBackdropProps } from './types';
import { styles } from './styles';

const AnimatedTouchableWithoutFeedback = Animated.createAnimatedComponent(
TouchableWithoutFeedback
);

const BottomSheetBackdropComponent = ({
animatedIndex,
opacity = DEFAULT_OPACITY,
Expand All @@ -45,30 +46,27 @@ const BottomSheetBackdropComponent = ({
]);
//#endregion

//#region callbacks
const handleOnPress = useCallback(() => {
close();
}, [close]);
//#region tap gesture
const gestureHandler = useAnimatedGestureHandler<TapGestureHandlerGestureEvent>(
{
onStart: () => {
runOnJS(close)();
},
}
);
//#endregion

//#region animated props
const isContainerTouchable = useSharedValue<boolean>(closeOnPress, true);
const containerAnimatedProps = useAnimatedProps(() => ({
pointerEvents: isContainerTouchable.value ? 'auto' : 'none',
}));
//#endregion

//#region styles
const buttonAnimatedStyle = useAnimatedStyle(
const containerAnimatedProps = useAnimatedProps(
() => ({
top: animatedIndex.value <= disappearsOnIndex ? WINDOW_HEIGHT : 0,
pointerEvents: animatedIndex.value > disappearsOnIndex ? 'auto' : 'none',
}),
[disappearsOnIndex]
);
const buttonStyle = useMemo(() => [style, buttonAnimatedStyle], [
style,
buttonAnimatedStyle,
]);
//#endregion

//#region styles
const containerAnimatedStyle = useAnimatedStyle(
() => ({
opacity: interpolate(
Expand All @@ -77,6 +75,7 @@ const BottomSheetBackdropComponent = ({
[0, 0, opacity],
Extrapolate.CLAMP
),
top: animatedIndex.value <= disappearsOnIndex ? WINDOW_HEIGHT : 0,
}),
[opacity, disappearsOnIndex, appearsOnIndex]
);
Expand All @@ -101,21 +100,18 @@ const BottomSheetBackdropComponent = ({
//#endregion

return closeOnPress ? (
<AnimatedTouchableWithoutFeedback
accessible={true}
accessibilityRole="button"
accessibilityLabel="Bottom Sheet backdrop"
accessibilityHint="Tap to close the Bottom Sheet"
onPress={handleOnPress}
style={buttonStyle}
>
<TapGestureHandler onGestureEvent={gestureHandler}>
<Animated.View
ref={containerRef}
style={containerStyle}
accessible={true}
accessibilityRole="button"
accessibilityLabel="Bottom Sheet backdrop"
accessibilityHint="Tap to close the Bottom Sheet"
// @ts-ignore
animatedProps={containerAnimatedProps}
/>
</AnimatedTouchableWithoutFeedback>
</TapGestureHandler>
) : (
<Animated.View pointerEvents={pointerEvents} style={containerStyle} />
);
Expand Down
31 changes: 18 additions & 13 deletions src/hooks/useInteractivePanGestureHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type InteractivePanGestureHandlerContextType = {
export const useInteractivePanGestureHandler = (
type: GESTURE,
animatedPosition: Animated.SharedValue<number>,
snapPoints: number[],
snapPoints: Animated.SharedValue<number[]>,
animateToPoint: (point: number, velocity: number) => void,
enableOverDrag: boolean,
overDragResistanceFactor: number,
Expand Down Expand Up @@ -56,33 +56,36 @@ export const useInteractivePanGestureHandler = (

const position = context.currentPosition + translationY;
const negativeScrollableContentOffset =
context.currentPosition === snapPoints[snapPoints.length - 1] &&
context.currentPosition ===
snapPoints.value[snapPoints.value.length - 1] &&
scrollableContentOffsetY
? scrollableContentOffsetY.value * -1
: 0;
const clampedPosition = clamp(
position + negativeScrollableContentOffset,
snapPoints[snapPoints.length - 1],
snapPoints[0]
snapPoints.value[snapPoints.value.length - 1],
snapPoints.value[0]
);

if (enableOverDrag) {
if (
type === GESTURE.HANDLE &&
position <= snapPoints[snapPoints.length - 1]
position <= snapPoints.value[snapPoints.value.length - 1]
) {
const resistedPosition =
snapPoints[snapPoints.length - 1] -
Math.sqrt(1 + (snapPoints[snapPoints.length - 1] - position)) *
snapPoints.value[snapPoints.value.length - 1] -
Math.sqrt(
1 + (snapPoints.value[snapPoints.value.length - 1] - position)
) *
overDragResistanceFactor;
animatedPosition.value = resistedPosition;
return;
}

if (position >= snapPoints[0]) {
if (position >= snapPoints.value[0]) {
const resistedPosition =
snapPoints[0] +
Math.sqrt(1 + (position - snapPoints[0])) *
snapPoints.value[0] +
Math.sqrt(1 + (position - snapPoints.value[0])) *
overDragResistanceFactor;
animatedPosition.value = resistedPosition;
return;
Expand All @@ -97,7 +100,7 @@ export const useInteractivePanGestureHandler = (
const destinationPoint = snapPoint(
gestureTranslationY.value + context.currentPosition,
gestureVelocityY.value,
snapPoints
snapPoints.value
);

/**
Expand All @@ -110,8 +113,10 @@ export const useInteractivePanGestureHandler = (

if (
(scrollableContentOffsetY ? scrollableContentOffsetY.value : 0) > 0 &&
context.currentPosition === snapPoints[snapPoints.length - 1] &&
animatedPosition.value === snapPoints[snapPoints.length - 1]
context.currentPosition ===
snapPoints.value[snapPoints.value.length - 1] &&
animatedPosition.value ===
snapPoints.value[snapPoints.value.length - 1]
) {
return;
}
Expand Down