gorhom / react-native-bottom-sheet

A performant interactive bottom sheet with fully configurable options 🚀
https://gorhom.dev/react-native-bottom-sheet/
MIT License
7.04k stars 768 forks source link

[v4] Nested Gesture Handler does not work #1121

Closed ospfranco closed 2 years ago

ospfranco commented 2 years ago

Bug

I would like to attach a pan gesture handler to the elements inside the bottom sheet to trigger a drag-and-drop animation on the parent component. Currently, when I put a GestureDetector inside it is not firing at all.

Environment info

Library Version
@gorhom/bottom-sheet ^4
react-native 0.70.1
react-native-reanimated 2.10.0
react-native-gesture-handler 2.6.2

Steps To Reproduce

Place a inside the bottom sheet and it will not trigger

  1. My nested GestureDetector component would start the pan gesture

Reproducible sample code

Here is my component code:

import NativeBottomSheet, {
  BottomSheetBackdrop,
  BottomSheetTextInput,
} from '@gorhom/bottom-sheet';
import {observer} from 'mobx-react-lite';
import React, {FC, useRef} from 'react';
import {Text, View} from 'react-native';
import {
  Gesture,
  GestureDetector,
  TextInput,
} from 'react-native-gesture-handler';
import {runOnJS, SharedValue} from 'react-native-reanimated';
import {useStore} from 'stores';

const snapPoints = ['50%'];

interface Props {
  dragY: SharedValue<number>;
  dragX: SharedValue<number>;
  height: SharedValue<number>;
  isDragging: SharedValue<boolean>;
}

export const BottomSheet: FC<Props> = observer(
  ({dragY, dragX, isDragging, height}) => {
    const store = useStore();
    const textInputRef = useRef<TextInput | null>(null);
    const bottomSheetRef = useRef<NativeBottomSheet>(null);

    const close = () => {
      bottomSheetRef.current?.close();
    };

    const blur = () => {
      textInputRef.current?.blur();
    };

    const panGesture = Gesture.Pan()
      .onStart(() => {
        runOnJS(blur)();
        runOnJS(close)();
        height.value = 64;
        isDragging.value = true;
      })
      .onUpdate(e => {
        console.warn('translation y', e.absoluteY);
        dragY.value = e.absoluteY;
        dragX.value = e.absoluteX;
      })
      .onEnd(() => {
        isDragging.value = false;
      })
      .activateAfterLongPress(500);

    return (
      <NativeBottomSheet
        ref={bottomSheetRef}
        snapPoints={snapPoints}
        index={store.ui.bottomSheetIndex}
        enablePanDownToClose
        onChange={store.ui.setBottomSheetIndex}
        backdropComponent={props => (
          <BottomSheetBackdrop
            enableTouchThrough={true}
            appearsOnIndex={0}
            disappearsOnIndex={-1}
            opacity={0.2}
            {...props}
          />
        )}>
        <View className="p-4 flex-1">
          <GestureDetector gesture={panGesture}>
            <Text>Blah</Text>
            {/* <BottomSheetTextInput
              placeholder="Type a task..."
              autoFocus={!__DEV__}
              ref={textInputRef}
            /> */}
          </GestureDetector>
        </View>
      </NativeBottomSheet>
    );
  },
);
AlirezaHadjar commented 2 years ago

I was having an issue with webview scrolling inside the bottom sheet and managed to fix it by doing this:

<BottomSheetModal waitFor={gestureRef}>
    <NativeViewGestureHandler ref={gestureRef}>
                 {your content}
    </NativeViewGestureHandler>
</BottomSheetModal>

Give it a try.

ospfranco commented 2 years ago

That works, I think the documentation does not encourage it but it definitely works. Also important to note waitFor can take an array of refs, which is exactly what I needed. Thanks!

OlehOutlierlabs commented 1 year ago

@ospfranco how did you do this for array of refs? im having same issue

ospfranco commented 1 year ago

Create a fake-hook and just pass it on every render:

https://twitter.com/ospfranco/status/1575782214117208064