mirror of
https://github.com/zhigang1992/react-native-bottom-sheet.git
synced 2026-06-17 23:15:07 +08:00
feat: add third party gestures integration (#143)
* chore: added simultaneousHandlers and waitFor props * chore: added view pager example
This commit is contained in:
@@ -6,13 +6,15 @@
|
||||
"scripts": {
|
||||
"android": "react-native run-android",
|
||||
"ios": "react-native run-ios",
|
||||
"start": "react-native start"
|
||||
"start": "react-native start",
|
||||
"posxtinstall": "npx patch-package"
|
||||
},
|
||||
"dependencies": {
|
||||
"@gorhom/portal": "^0.1.4",
|
||||
"@gorhom/showcase-template": "^1.0.2",
|
||||
"@react-native-community/blur": "^3.6.0",
|
||||
"@react-native-community/masked-view": "0.1.10",
|
||||
"@react-navigation/material-top-tabs": "^5.3.10",
|
||||
"@react-navigation/native": "^5.8.10",
|
||||
"@react-navigation/stack": "^5.12.8",
|
||||
"faker": "^4.1.0",
|
||||
@@ -25,7 +27,8 @@
|
||||
"react-native-reanimated": "^2.0.0-rc.1",
|
||||
"react-native-redash": "^16.0.4",
|
||||
"react-native-safe-area-context": "0.7.3",
|
||||
"react-native-screens": "^2.16.1"
|
||||
"react-native-screens": "^2.16.1",
|
||||
"react-native-tab-view": "^2.15.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.10",
|
||||
|
||||
138
example/patches/react-native-tab-view+2.15.2.patch
Normal file
138
example/patches/react-native-tab-view+2.15.2.patch
Normal file
@@ -0,0 +1,138 @@
|
||||
diff --git a/node_modules/react-native-tab-view/lib/commonjs/Pager.js b/node_modules/react-native-tab-view/lib/commonjs/Pager.js
|
||||
index 1c491e8..14241b1 100644
|
||||
--- a/node_modules/react-native-tab-view/lib/commonjs/Pager.js
|
||||
+++ b/node_modules/react-native-tab-view/lib/commonjs/Pager.js
|
||||
@@ -96,7 +96,10 @@ class Pager extends React.Component {
|
||||
|
||||
_defineProperty(this, "mounted", false);
|
||||
|
||||
+ _defineProperty(this, "gestureHandlerRef", /*#__PURE__*/React.createRef());
|
||||
+
|
||||
_defineProperty(this, "providerVal", {
|
||||
+ pagerRef: this.gestureHandlerRef,
|
||||
addGestureHandlerRef: ref => {
|
||||
if (!this.state.childPanGestureHandlerRefs.includes(ref) && this.mounted) {
|
||||
this.setState(prevState => ({
|
||||
@@ -106,8 +109,6 @@ class Pager extends React.Component {
|
||||
}
|
||||
});
|
||||
|
||||
- _defineProperty(this, "gestureHandlerRef", /*#__PURE__*/React.createRef());
|
||||
-
|
||||
_defineProperty(this, "clock", new Clock());
|
||||
|
||||
_defineProperty(this, "velocityX", new Value(0));
|
||||
diff --git a/node_modules/react-native-tab-view/lib/commonjs/index.js b/node_modules/react-native-tab-view/lib/commonjs/index.js
|
||||
index e3f00fc..9a39fc8 100644
|
||||
--- a/node_modules/react-native-tab-view/lib/commonjs/index.js
|
||||
+++ b/node_modules/react-native-tab-view/lib/commonjs/index.js
|
||||
@@ -15,6 +15,12 @@ Object.defineProperty(exports, "TabView", {
|
||||
return _TabView.default;
|
||||
}
|
||||
});
|
||||
+Object.defineProperty(exports, "Pager", {
|
||||
+ enumerable: true,
|
||||
+ get: function get() {
|
||||
+ return _Pager.default;
|
||||
+ }
|
||||
+});
|
||||
Object.defineProperty(exports, "TabBarIndicator", {
|
||||
enumerable: true,
|
||||
get: function get() {
|
||||
@@ -60,5 +66,7 @@ var _SceneMap = _interopRequireDefault(require("./SceneMap"));
|
||||
|
||||
var _ScrollPager = _interopRequireDefault(require("./ScrollPager"));
|
||||
|
||||
+var _Pager = _interopRequireDefault(require("./Pager"));
|
||||
+
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
//# sourceMappingURL=index.js.map
|
||||
\ No newline at end of file
|
||||
diff --git a/node_modules/react-native-tab-view/lib/module/Pager.js b/node_modules/react-native-tab-view/lib/module/Pager.js
|
||||
index 406e30a..4482bcb 100644
|
||||
--- a/node_modules/react-native-tab-view/lib/module/Pager.js
|
||||
+++ b/node_modules/react-native-tab-view/lib/module/Pager.js
|
||||
@@ -78,7 +78,10 @@ export default class Pager extends React.Component {
|
||||
|
||||
_defineProperty(this, "mounted", false);
|
||||
|
||||
+ _defineProperty(this, "gestureHandlerRef", /*#__PURE__*/React.createRef());
|
||||
+
|
||||
_defineProperty(this, "providerVal", {
|
||||
+ pagerRef: this.gestureHandlerRef,
|
||||
addGestureHandlerRef: ref => {
|
||||
if (!this.state.childPanGestureHandlerRefs.includes(ref) && this.mounted) {
|
||||
this.setState(prevState => ({
|
||||
@@ -88,8 +91,6 @@ export default class Pager extends React.Component {
|
||||
}
|
||||
});
|
||||
|
||||
- _defineProperty(this, "gestureHandlerRef", /*#__PURE__*/React.createRef());
|
||||
-
|
||||
_defineProperty(this, "clock", new Clock());
|
||||
|
||||
_defineProperty(this, "velocityX", new Value(0));
|
||||
diff --git a/node_modules/react-native-tab-view/lib/module/index.js b/node_modules/react-native-tab-view/lib/module/index.js
|
||||
index c687a54..5466d89 100644
|
||||
--- a/node_modules/react-native-tab-view/lib/module/index.js
|
||||
+++ b/node_modules/react-native-tab-view/lib/module/index.js
|
||||
@@ -5,4 +5,5 @@ export { default as TabBarItem } from './TabBarItem';
|
||||
export { default as TouchableItem } from './TouchableItem';
|
||||
export { default as SceneMap } from './SceneMap';
|
||||
export { default as ScrollPager } from './ScrollPager';
|
||||
+export { default as Pager } from './Pager';
|
||||
//# sourceMappingURL=index.js.map
|
||||
\ No newline at end of file
|
||||
diff --git a/node_modules/react-native-tab-view/lib/typescript/src/index.d.ts b/node_modules/react-native-tab-view/lib/typescript/src/index.d.ts
|
||||
index 60cada6..2dc8881 100644
|
||||
--- a/node_modules/react-native-tab-view/lib/typescript/src/index.d.ts
|
||||
+++ b/node_modules/react-native-tab-view/lib/typescript/src/index.d.ts
|
||||
@@ -9,4 +9,5 @@ export type { Props as TabBarItemProps } from './TabBarItem';
|
||||
export { default as TouchableItem } from './TouchableItem';
|
||||
export { default as SceneMap } from './SceneMap';
|
||||
export { default as ScrollPager } from './ScrollPager';
|
||||
+export { default as Pager } from './Pager';
|
||||
export type { Route, NavigationState, SceneRendererProps } from './types';
|
||||
diff --git a/node_modules/react-native-tab-view/src/Pager.tsx b/node_modules/react-native-tab-view/src/Pager.tsx
|
||||
index 3441d69..1202c35 100644
|
||||
--- a/node_modules/react-native-tab-view/src/Pager.tsx
|
||||
+++ b/node_modules/react-native-tab-view/src/Pager.tsx
|
||||
@@ -245,9 +245,15 @@ export default class Pager<T extends Route> extends React.Component<
|
||||
|
||||
static contextType = PagerContext;
|
||||
|
||||
+ // PanGestureHandler ref used for coordination with parent handlers
|
||||
+ private gestureHandlerRef: React.RefObject<
|
||||
+ PanGestureHandler
|
||||
+ > = React.createRef();
|
||||
+
|
||||
// Mechanism to add child PanGestureHandler refs in the case that this
|
||||
// Pager is a parent to child Pagers. Allows for coordination between handlers
|
||||
private providerVal = {
|
||||
+ pagerRef: this.gestureHandlerRef,
|
||||
addGestureHandlerRef: (ref: React.RefObject<PanGestureHandler>) => {
|
||||
if (
|
||||
!this.state.childPanGestureHandlerRefs.includes(ref) &&
|
||||
@@ -263,11 +269,6 @@ export default class Pager<T extends Route> extends React.Component<
|
||||
},
|
||||
};
|
||||
|
||||
- // PanGestureHandler ref used for coordination with parent handlers
|
||||
- private gestureHandlerRef: React.RefObject<
|
||||
- PanGestureHandler
|
||||
- > = React.createRef();
|
||||
-
|
||||
// Clock used for tab transition animations
|
||||
private clock = new Clock();
|
||||
|
||||
diff --git a/node_modules/react-native-tab-view/src/index.tsx b/node_modules/react-native-tab-view/src/index.tsx
|
||||
index ce01571..a7dffb4 100644
|
||||
--- a/node_modules/react-native-tab-view/src/index.tsx
|
||||
+++ b/node_modules/react-native-tab-view/src/index.tsx
|
||||
@@ -14,5 +14,6 @@ export { default as TouchableItem } from './TouchableItem';
|
||||
|
||||
export { default as SceneMap } from './SceneMap';
|
||||
export { default as ScrollPager } from './ScrollPager';
|
||||
+export { default as Pager } from './Pager';
|
||||
|
||||
export type { Route, NavigationState, SceneRendererProps } from './types';
|
||||
@@ -133,6 +133,16 @@ function App() {
|
||||
require('./screens/advanced/DynamicSnapPointExample').default
|
||||
}
|
||||
/>
|
||||
|
||||
<Stack.Screen
|
||||
name="Advanced/ViewPagerExample"
|
||||
options={{
|
||||
title: 'ViewPager Example',
|
||||
}}
|
||||
getComponent={() =>
|
||||
require('./screens/advanced/ViewPagerExample').default
|
||||
}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
</AppearanceProvider>
|
||||
|
||||
@@ -70,6 +70,10 @@ const data = [
|
||||
name: 'Dynamic Snap Point',
|
||||
slug: 'Advanced/DynamicSnapPointExample',
|
||||
},
|
||||
{
|
||||
name: 'View Pager',
|
||||
slug: 'Advanced/ViewPagerExample',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
61
example/src/screens/advanced/ViewPagerExample.tsx
Normal file
61
example/src/screens/advanced/ViewPagerExample.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import React, { useContext, useMemo } from 'react';
|
||||
import { View, Text, StyleSheet } from 'react-native';
|
||||
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
|
||||
import { Pager } from 'react-native-tab-view';
|
||||
import BottomSheet from '@gorhom/bottom-sheet';
|
||||
import ContactList from '../../components/contactList';
|
||||
|
||||
const FirstRoute = () => {
|
||||
// @ts-ignore
|
||||
const { pagerRef } = useContext(Pager.contextType);
|
||||
const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);
|
||||
|
||||
return (
|
||||
<View style={[styles.scene, styles.firstScene]}>
|
||||
<BottomSheet
|
||||
snapPoints={snapPoints}
|
||||
waitFor={pagerRef}
|
||||
animateOnMount={true}
|
||||
>
|
||||
<ContactList type="FlatList" count={15} />
|
||||
</BottomSheet>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const SecondRoute = () => (
|
||||
<View style={[styles.scene, styles.secondScene]}>
|
||||
<Text style={styles.emoji}>🙈</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const Tab = createMaterialTopTabNavigator();
|
||||
|
||||
const ViewPagerScreen = () => {
|
||||
return (
|
||||
<Tab.Navigator>
|
||||
<Tab.Screen name="Home" component={FirstRoute} />
|
||||
<Tab.Screen name="Settings" component={SecondRoute} />
|
||||
</Tab.Navigator>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
scene: {
|
||||
flex: 1,
|
||||
},
|
||||
firstScene: {
|
||||
backgroundColor: '#ff4081',
|
||||
},
|
||||
secondScene: {
|
||||
alignContent: 'center',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: '#673ab7',
|
||||
},
|
||||
emoji: {
|
||||
fontSize: 46,
|
||||
},
|
||||
});
|
||||
|
||||
export default ViewPagerScreen;
|
||||
1
example/src/types.d.ts
vendored
1
example/src/types.d.ts
vendored
@@ -19,6 +19,7 @@ export type AppStackParamsList = {
|
||||
['Advanced/BackdropExample']: undefined;
|
||||
['Advanced/MapExample']: undefined;
|
||||
['Advanced/DynamicSnapPointExample']: undefined;
|
||||
['Advanced/ViewPagerExample']: undefined;
|
||||
};
|
||||
|
||||
export type Contact = {
|
||||
|
||||
@@ -1102,6 +1102,13 @@
|
||||
query-string "^6.13.6"
|
||||
react-is "^16.13.0"
|
||||
|
||||
"@react-navigation/material-top-tabs@^5.3.10":
|
||||
version "5.3.10"
|
||||
resolved "https://registry.yarnpkg.com/@react-navigation/material-top-tabs/-/material-top-tabs-5.3.10.tgz#158b694e87bff2eb9577e8142415de8ac3547412"
|
||||
integrity sha512-mmQYEBhcLp1DwvuD8+HiFtYPk5zP43272C/38iX2T8AblcwRdoJejuO/GUzQcEPrmZHjeAnA5GDaMiXQM4EXLQ==
|
||||
dependencies:
|
||||
color "^3.1.3"
|
||||
|
||||
"@react-navigation/native@^5.8.10":
|
||||
version "5.8.10"
|
||||
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-5.8.10.tgz#3fe806abff9efb085bcf595212803dd05a1347ca"
|
||||
@@ -3904,6 +3911,11 @@ react-native-screens@^2.16.1:
|
||||
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-2.16.1.tgz#b105a127378d90018a46daf0c2f6518fca60c06f"
|
||||
integrity sha512-WZ7m0sBDVaHbBnlHxwQnUlI6KNfQKHq+Unfw+VBuAlnSXvT+aw6Bb/K2bUlHzBgvrPjwY3Spc7ZERFuTwRLLwg==
|
||||
|
||||
react-native-tab-view@^2.15.2:
|
||||
version "2.15.2"
|
||||
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-2.15.2.tgz#4bc7832d33a119306614efee667509672a7ee64e"
|
||||
integrity sha512-2hxLkBnZtEKFDyfvNO5EUywhy3f/EiLOBO8SWqKj4BMBTO0QwnybaPE5MVF00Fhz+VA4+h/iI40Dkrrtq70dGg==
|
||||
|
||||
react-native@0.63.4:
|
||||
version "0.63.4"
|
||||
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.63.4.tgz#2210fdd404c94a5fa6b423c6de86f8e48810ec36"
|
||||
|
||||
@@ -92,6 +92,11 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
|
||||
// animated callback shared values
|
||||
animatedPosition: _providedAnimatedPosition,
|
||||
animatedIndex: _providedAnimatedIndex,
|
||||
|
||||
// gestures
|
||||
simultaneousHandlers: _providedSimultaneousHandlers,
|
||||
waitFor: _providedWaitFor,
|
||||
|
||||
// callbacks
|
||||
onChange: _providedOnChange,
|
||||
onAnimate: _providedOnAnimate,
|
||||
@@ -395,6 +400,8 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
|
||||
contentPanGestureHandler,
|
||||
scrollableContentOffsetY,
|
||||
scrollableDecelerationRate,
|
||||
simultaneousHandlers: _providedSimultaneousHandlers,
|
||||
waitFor: _providedWaitFor,
|
||||
setScrollableRef: handleSettingScrollableRef,
|
||||
removeScrollableRef,
|
||||
}),
|
||||
@@ -409,6 +416,8 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
|
||||
scrollableContentOffsetY,
|
||||
scrollableDecelerationRate,
|
||||
enableContentPanningGesture,
|
||||
_providedSimultaneousHandlers,
|
||||
_providedWaitFor,
|
||||
]
|
||||
);
|
||||
const externalContextVariables = useMemo(
|
||||
|
||||
5
src/components/bottomSheet/types.d.ts
vendored
5
src/components/bottomSheet/types.d.ts
vendored
@@ -1,10 +1,13 @@
|
||||
import type React from 'react';
|
||||
import type Animated from 'react-native-reanimated';
|
||||
import type { GestureHandlerProperties } from 'react-native-gesture-handler';
|
||||
import type { BottomSheetHandleProps } from '../bottomSheetHandle';
|
||||
import type { BottomSheetBackdropProps } from '../bottomSheetBackdrop';
|
||||
import type { BottomSheetBackgroundProps } from '../bottomSheetBackground';
|
||||
|
||||
export interface BottomSheetProps extends BottomSheetAnimationConfigs {
|
||||
export interface BottomSheetProps
|
||||
extends BottomSheetAnimationConfigs,
|
||||
Pick<GestureHandlerProperties, 'waitFor' | 'simultaneousHandlers'> {
|
||||
// configuration
|
||||
/**
|
||||
* Initial snap index, you also could provide `-1` to initiate bottom sheet in closed state.
|
||||
|
||||
@@ -20,16 +20,32 @@ const BottomSheetDraggableViewComponent = ({
|
||||
enableContentPanningGesture,
|
||||
contentWrapperGestureRef,
|
||||
contentPanGestureHandler,
|
||||
simultaneousHandlers: _providedSimultaneousHandlers,
|
||||
waitFor,
|
||||
} = useBottomSheetInternal();
|
||||
|
||||
// variables
|
||||
const simultaneousHandlers = useMemo(
|
||||
() =>
|
||||
nativeGestureRef
|
||||
? [contentWrapperGestureRef, nativeGestureRef]
|
||||
: contentWrapperGestureRef,
|
||||
[contentWrapperGestureRef, nativeGestureRef]
|
||||
);
|
||||
const simultaneousHandlers = useMemo(() => {
|
||||
const refs = [contentWrapperGestureRef];
|
||||
|
||||
if (nativeGestureRef) {
|
||||
refs.push(nativeGestureRef);
|
||||
}
|
||||
|
||||
if (_providedSimultaneousHandlers) {
|
||||
if (Array.isArray(_providedSimultaneousHandlers)) {
|
||||
refs.push(..._providedSimultaneousHandlers);
|
||||
} else {
|
||||
refs.push(_providedSimultaneousHandlers);
|
||||
}
|
||||
}
|
||||
|
||||
return refs;
|
||||
}, [
|
||||
_providedSimultaneousHandlers,
|
||||
contentWrapperGestureRef,
|
||||
nativeGestureRef,
|
||||
]);
|
||||
|
||||
// styles
|
||||
const containerStyle = useMemo(
|
||||
@@ -43,6 +59,7 @@ const BottomSheetDraggableViewComponent = ({
|
||||
enabled={enableContentPanningGesture}
|
||||
simultaneousHandlers={simultaneousHandlers}
|
||||
shouldCancelWhenOutside={false}
|
||||
waitFor={waitFor}
|
||||
onGestureEvent={contentPanGestureHandler}
|
||||
>
|
||||
<Animated.View style={containerStyle} {...rest}>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { createContext, Ref, RefObject } from 'react';
|
||||
import type { TapGestureHandler } from 'react-native-gesture-handler';
|
||||
import type {
|
||||
TapGestureHandler,
|
||||
GestureHandlerProperties,
|
||||
} from 'react-native-gesture-handler';
|
||||
import type Animated from 'react-native-reanimated';
|
||||
import { ANIMATION_STATE } from '../constants';
|
||||
import type { ANIMATION_STATE } from '../constants';
|
||||
import type { Scrollable, ScrollableRef } from '../types';
|
||||
|
||||
export type BottomSheetInternalContextType = {
|
||||
@@ -16,7 +19,7 @@ export type BottomSheetInternalContextType = {
|
||||
scrollableDecelerationRate: Animated.SharedValue<number>;
|
||||
setScrollableRef: (ref: ScrollableRef) => void;
|
||||
removeScrollableRef: (ref: RefObject<Scrollable>) => void;
|
||||
};
|
||||
} & Pick<GestureHandlerProperties, 'simultaneousHandlers' | 'waitFor'>;
|
||||
|
||||
// @ts-ignore
|
||||
export const BottomSheetInternalContext = createContext<BottomSheetInternalContextType>();
|
||||
|
||||
Reference in New Issue
Block a user