diff --git a/.github/workflows/yarn-validation.yml b/.github/workflows/yarn-validation.yml
index ba7abd352f..94416e2dee 100644
--- a/.github/workflows/yarn-validation.yml
+++ b/.github/workflows/yarn-validation.yml
@@ -45,9 +45,7 @@ jobs:
**/package.json
**/yarn.lock
files_ignore: |
- packages/react-native-gesture-handler/DrawerLayout/package.json
packages/react-native-gesture-handler/ReanimatedDrawerLayout/package.json
- packages/react-native-gesture-handler/Swipeable/package.json
packages/react-native-gesture-handler/ReanimatedSwipeable/package.json
packages/react-native-gesture-handler/jest-utils/package.json
diff --git a/apps/common-app/App.tsx b/apps/common-app/App.tsx
index b2a49d60f9..2e4a95d279 100644
--- a/apps/common-app/App.tsx
+++ b/apps/common-app/App.tsx
@@ -22,7 +22,6 @@ import {
TouchablesIndex,
TouchableExample,
} from './src/release_tests/touchables';
-import Rows from './src/release_tests/rows';
import NestedFling from './src/release_tests/nestedFling';
import MouseButtons from './src/release_tests/mouseButtons';
import ContextMenu from './src/release_tests/contextMenu';
@@ -30,7 +29,6 @@ import NestedTouchables from './src/release_tests/nestedTouchables';
import NestedPressables from './src/release_tests/nestedPressables';
import NestedButtons from './src/release_tests/nestedButtons';
import PointerType from './src/release_tests/pointerType';
-import SwipeableReanimation from './src/release_tests/swipeableReanimation';
import NestedGestureHandlerRootViewWithModal from './src/release_tests/nestedGHRootViewWithModal';
import TwoFingerPan from './src/release_tests/twoFingerPan';
import SvgCompatibility from './src/release_tests/svg';
@@ -40,14 +38,12 @@ import { PinchableBox } from './src/recipes/scaleAndRotate';
import PanAndScroll from './src/recipes/panAndScroll';
import { BottomSheet } from './src/showcase/bottomSheet';
-import Swipeables from './src/showcase/swipeable';
import ChatHeads from './src/showcase/chatHeads';
import Draggable from './src/basic/draggable';
import MultiTap from './src/basic/multitap';
import BouncingBox from './src/basic/bouncing';
import PanResponder from './src/basic/panResponder';
-import HorizontalDrawer from './src/basic/horizontalDrawer';
import PagerAndDrawer from './src/basic/pagerAndDrawer';
import ForceTouch from './src/basic/forcetouch';
import Fling from './src/basic/fling';
@@ -62,7 +58,6 @@ import Calculator from './src/new_api/calculator';
import BottomSheetNewApi from './src/new_api/bottom_sheet';
import ChatHeadsNewApi from './src/new_api/chat_heads';
import DragNDrop from './src/new_api/drag_n_drop';
-import BetterHorizontalDrawer from './src/new_api/betterHorizontalDrawer';
import ManualGestures from './src/new_api/manualGestures/index';
import Hover from './src/new_api/hover';
import HoverableIcons from './src/new_api/hoverable_icons';
@@ -113,10 +108,6 @@ const EXAMPLES: ExamplesSection[] = [
{ name: 'Pressable', component: Pressable },
{ name: 'Hover', component: Hover },
{ name: 'Hoverable icons', component: HoverableIcons },
- {
- name: 'Horizontal Drawer (Reanimated 2 & RNGH 2)',
- component: BetterHorizontalDrawer,
- },
{
name: 'Manual gestures',
component: ManualGestures,
@@ -130,7 +121,6 @@ const EXAMPLES: ExamplesSection[] = [
{ name: 'Multitap', component: MultiTap },
{ name: 'Bouncing box', component: BouncingBox },
{ name: 'Pan responder', component: PanResponder },
- { name: 'Horizontal drawer', component: HorizontalDrawer },
{
name: 'Pager & drawer',
component: PagerAndDrawer,
@@ -155,7 +145,6 @@ const EXAMPLES: ExamplesSection[] = [
sectionTitle: 'Showcase',
data: [
{ name: 'Bottom sheet', component: BottomSheet },
- { name: 'Swipeables', component: Swipeables },
{ name: 'Chat heads', component: ChatHeads },
],
},
@@ -189,7 +178,6 @@ const EXAMPLES: ExamplesSection[] = [
},
{ name: 'Double pinch & rotate', component: DoublePinchRotate },
{ name: 'Double draggable', component: DoubleDraggable },
- { name: 'Rows', component: Rows },
{ name: 'Nested Fling', component: NestedFling },
{
name: 'Combo',
@@ -205,7 +193,6 @@ const EXAMPLES: ExamplesSection[] = [
},
{ name: 'PointerType', component: PointerType },
{ name: 'Reanimated Drawer Layout', component: ReanimatedDrawerLayout },
- { name: 'Swipeable Reanimation', component: SwipeableReanimation },
{ name: 'RectButton (borders)', component: RectButtonBorders },
{ name: 'Gesturized pressable', component: GesturizedPressable },
{
diff --git a/apps/common-app/src/basic/horizontalDrawer/index.tsx b/apps/common-app/src/basic/horizontalDrawer/index.tsx
deleted file mode 100644
index 1f78ffb3c3..0000000000
--- a/apps/common-app/src/basic/horizontalDrawer/index.tsx
+++ /dev/null
@@ -1,196 +0,0 @@
-import React, { Component } from 'react';
-import {
- Platform,
- StyleSheet,
- Text,
- Animated,
- View,
- TextInput,
-} from 'react-native';
-
-import {
- RectButton,
- DrawerLayout,
- DrawerType,
-} from 'react-native-gesture-handler';
-
-const TYPES: DrawerType[] = ['front', 'back', 'back', 'slide'];
-const PARALLAX = [false, false, true, false];
-
-type PageProps = {
- fromLeft: boolean;
- type: DrawerType;
- parallaxOn: boolean;
- flipSide: () => void;
- nextType: () => void;
- openDrawer: () => void;
-};
-
-const Page = ({
- fromLeft,
- type,
- parallaxOn,
- flipSide,
- nextType,
- openDrawer,
-}: PageProps) => (
-
- Hi 👋
-
-
- Drawer to the {fromLeft ? 'left' : 'right'}! {'->'} Flip
-
-
-
-
- Type {type} {parallaxOn && 'with parallax!'} -> Next
-
-
-
- Open drawer
-
-
-
-);
-
-export default class Example extends Component<
- Record,
- { fromLeft: boolean; type: number }
-> {
- state = { fromLeft: true, type: 0 };
-
- private renderParallaxDrawer = (progressValue: Animated.Value) => {
- const parallax = progressValue.interpolate({
- inputRange: [0, 1],
- outputRange: [this.state.fromLeft ? -50 : 50, 0],
- });
- const animatedStyles = {
- transform: [{ translateX: parallax }],
- };
- return (
-
- I am in the drawer!
-
- Watch parallax animation while you pull the drawer!
-
-
- );
- };
-
- private renderDrawer = () => {
- return (
-
- I am in the drawer!
-
- );
- };
- private drawer?: DrawerLayout | null;
-
- render() {
- const drawerType: DrawerType = TYPES[this.state.type];
- const parallax = PARALLAX[this.state.type];
- return (
-
- {
- this.drawer = drawer;
- }}
- enableTrackpadTwoFingerGesture
- drawerWidth={200}
- keyboardDismissMode="on-drag"
- drawerPosition={this.state.fromLeft ? 'left' : 'right'}
- drawerType={drawerType}
- drawerBackgroundColor="#ddd"
- overlayColor={drawerType === 'front' ? 'black' : '#00000000'}
- renderNavigationView={
- parallax ? this.renderParallaxDrawer : this.renderDrawer
- }
- contentContainerStyle={
- // careful; don't elevate the child container
- // over top of the drawer when the drawer is supposed
- // to be in front - you won't be able to see/open it.
- drawerType === 'front'
- ? {}
- : Platform.select({
- ios: {
- shadowColor: '#000',
- shadowOpacity: 0.5,
- shadowOffset: { width: 0, height: 2 },
- shadowRadius: 60,
- },
- android: {
- elevation: 100,
- backgroundColor: '#000',
- },
- })
- }>
-
- this.setState((prevState) => ({
- fromLeft: !prevState.fromLeft,
- }))
- }
- nextType={() =>
- this.setState((prevState) => ({
- type: (prevState.type + 1) % TYPES.length,
- }))
- }
- openDrawer={() => this.drawer?.openDrawer({ speed: 14 })}
- />
-
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
- page: {
- ...StyleSheet.absoluteFillObject,
- alignItems: 'center',
- paddingTop: 40,
- backgroundColor: 'gray',
- },
- pageText: {
- fontSize: 21,
- color: 'white',
- },
- rectButton: {
- height: 60,
- padding: 10,
- alignSelf: 'stretch',
- alignItems: 'center',
- justifyContent: 'center',
- marginTop: 20,
- backgroundColor: 'white',
- },
- rectButtonText: {
- backgroundColor: 'transparent',
- },
- drawerContainer: {
- flex: 1,
- paddingTop: 10,
- },
- pageInput: {
- height: 60,
- padding: 10,
- alignSelf: 'stretch',
- alignItems: 'center',
- justifyContent: 'center',
- marginTop: 20,
- backgroundColor: '#eee',
- },
- drawerText: {
- margin: 10,
- fontSize: 15,
- textAlign: 'left',
- },
-});
diff --git a/apps/common-app/src/new_api/betterHorizontalDrawer/BetterHorizonatalDrawer.tsx b/apps/common-app/src/new_api/betterHorizontalDrawer/BetterHorizonatalDrawer.tsx
deleted file mode 100644
index 8389a6ee42..0000000000
--- a/apps/common-app/src/new_api/betterHorizontalDrawer/BetterHorizonatalDrawer.tsx
+++ /dev/null
@@ -1,623 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import {
- I18nManager,
- LayoutChangeEvent,
- StatusBarAnimation,
- StyleProp,
- StyleSheet,
- ViewStyle,
- Keyboard,
- StatusBar,
-} from 'react-native';
-import {
- DrawerKeyboardDismissMode,
- DrawerLockMode,
- DrawerPosition,
- DrawerType,
- GestureDetector,
- Gesture,
-} from 'react-native-gesture-handler';
-import Animated, {
- runOnJS,
- useAnimatedStyle,
- useDerivedValue,
- useSharedValue,
- withSpring,
-} from 'react-native-reanimated';
-
-export enum BetterDrawerState {
- IDLE = 'Idle',
- DRAGGING = 'Dragging',
- SETTLING = 'Settling',
-}
-
-export interface BetterDrawerLayoutProps {
- /**
- * This attribute is present in the standard implementation already and is one
- * of the required params. Gesture handler version of DrawerLayout make it
- * possible for the function passed as `renderNavigationView` to take an
- * Animated value as a parameter that indicates the progress of drawer
- * opening/closing animation (progress value is 0 when closed and 1 when
- * opened). This can be used by the drawer component to animated its children
- * while the drawer is opening or closing.
- */
- renderNavigationView: (
- progressAnimatedValue: Animated.SharedValue
- ) => React.ReactNode;
-
- drawerPosition?: DrawerPosition;
-
- drawerWidth?: number;
-
- drawerBackgroundColor?: string;
-
- drawerLockMode?: DrawerLockMode;
-
- keyboardDismissMode?: DrawerKeyboardDismissMode;
-
- /**
- * Called when the drawer is closed.
- */
- onDrawerClose?: () => void;
-
- /**
- * Called when the drawer is opened.
- */
- onDrawerOpen?: () => void;
-
- /**
- * Called when the status of the drawer changes.
- */
- onDrawerStateChanged?: (
- newState: BetterDrawerState,
- drawerWillShow: boolean
- ) => void;
-
- drawerType?: DrawerType;
-
- /**
- * Defines how far from the edge of the content view the gesture should
- * activate.
- */
- edgeWidth?: number;
-
- minSwipeDistance?: number;
-
- /**
- * When set to true Drawer component will use
- * {@link https://reactnative.dev/docs/statusbar StatusBar} API to hide the OS
- * status bar whenever the drawer is pulled or when its in an "open" state.
- */
- hideStatusBar?: boolean;
-
- /**
- * @default 'slide'
- *
- * Can be used when hideStatusBar is set to true and will select the animation
- * used for hiding/showing the status bar. See
- * {@link https://reactnative.dev/docs/statusbar StatusBar} documentation for
- * more details
- */
- statusBarAnimation?: StatusBarAnimation;
-
- /**
- * @default black
- *
- * Color of a semi-transparent overlay to be displayed on top of the content
- * view when drawer gets open. A solid color should be used as the opacity is
- * added by the Drawer itself and the opacity of the overlay is animated (from
- * 0% to 70%).
- */
- overlayColor?: string;
-
- contentContainerStyle?: StyleProp;
-
- drawerContainerStyle?: StyleProp;
-
- /**
- * Enables two-finger gestures on supported devices, for example iPads with
- * trackpads. If not enabled the gesture will require click + drag, with
- * `enableTrackpadTwoFingerGesture` swiping with two fingers will also trigger
- * the gesture.
- */
- enableTrackpadTwoFingerGesture?: boolean;
-
- /**
- * Called when the pan gesture gets updated, position represents a fraction of
- * the drawer that is visible
- */
- onDrawerSlide?: (position: number) => void;
-
- children?: React.ReactNode;
-}
-
-interface OverlayProps {
- drawerType: DrawerType;
- color: string;
- progress: Animated.SharedValue;
- lockMode: DrawerLockMode;
- close: () => void;
-}
-
-function Overlay(props: OverlayProps) {
- const overlayStyle = useAnimatedStyle(() => ({
- backgroundColor: props.color,
- opacity: props.progress.value,
- transform: [
- {
- translateX:
- // when the overlay should not be visible move it off the screen
- // to prevent it from intercepting touch events on Android
- props.drawerType !== 'front' || props.progress.value === 0
- ? 10000
- : 0,
- },
- ],
- }));
-
- const tap = Gesture.Tap();
- tap.onEnd((_event, success) => {
- 'worklet';
- if (success && props.lockMode !== 'locked-open') {
- // close the drawer when tapped on the overlay only if the gesture
- // was not cancelled and it's not locked in opened state
- props.close();
- }
- });
-
- return (
-
-
-
- );
-}
-
-export interface DrawerLayoutController {
- open: () => void;
- close: () => void;
-}
-
-export const DrawerLayout = ({
- ref,
- drawerWidth = 200,
- drawerPosition = 'left',
- drawerType = 'front',
- edgeWidth = 20,
- minSwipeDistance = 3,
- overlayColor = 'rgba(0, 0, 0, 0.7)',
- drawerLockMode = 'unlocked',
- enableTrackpadTwoFingerGesture = false,
- keyboardDismissMode,
- statusBarAnimation,
- hideStatusBar,
- drawerBackgroundColor,
- drawerContainerStyle,
- contentContainerStyle,
- children,
- renderNavigationView,
- onDrawerClose,
- onDrawerOpen,
- onDrawerSlide,
- onDrawerStateChanged,
-}: BetterDrawerLayoutProps & {
- ref?: React.RefObject;
-}) => {
- const animationConfig = { damping: 30, stiffness: 250 };
-
- const fromLeft = drawerPosition === 'left';
- const drawerSlide = drawerType !== 'back';
- const containerSlide = drawerType !== 'front';
-
- // setting NaN as a starting value allows to tell when the value gets changes
- // for the first time
- const [containerWidth, setContainerWidth] = useState(Number.NaN);
- const [drawerVisible, setDrawerVisible] = useState(false);
-
- const drawerState = useSharedValue(BetterDrawerState.IDLE);
- // between 0 and drawerWidth (drawer on the left) or -drawerWidth and 0 (drawer on the right)
- const drawerOffset = useSharedValue(0);
- // stores value of the offset at the start of the gesture
- const drawerSavedOffset = useSharedValue(0);
- // stores the translation that is supposed to be ignored (user tried to
- // drag while animation was running)
- const ignoredOffset = useSharedValue(0);
- // stores the x coordinate of the drag starting point (to ignore dragging on the overlay)
- const dragStartPosition = useSharedValue(0);
- // between 0 and 1, 0 - closed, 1 - opened
- const openingProgress = useDerivedValue(() => {
- if (fromLeft) {
- return drawerOffset.value / drawerWidth;
- } else {
- return -drawerOffset.value / drawerWidth;
- }
- }, [drawerOffset, containerWidth, drawerWidth, fromLeft]);
-
- // we rely on row and row-reverse flex directions to position the drawer
- // properly. Apparently for RTL these are flipped which requires us to use
- // the opposite setting for the drawer to appear from left or right
- // according to the drawerPosition prop
- const reverseContentDirection = I18nManager.isRTL ? fromLeft : !fromLeft;
-
- // set the drawer to closed position when the props change to prevent it from
- // opening or moving on the screen
- useEffect(() => {
- drawerOffset.value = 0;
- drawerSavedOffset.value = 0;
-
- setDrawerVisible(false);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [drawerWidth, drawerPosition, drawerType]);
-
- // measure the container
- function handleContainerLayout({ nativeEvent }: LayoutChangeEvent) {
- setContainerWidth(nativeEvent.layout.width);
- }
-
- function onDragStart() {
- if (keyboardDismissMode === 'on-drag') {
- Keyboard.dismiss();
- }
-
- // this is required in addition to the similar call below, because the gesture
- // doesn't change `drawerVisible` state to prevent re-render during gesture
- // so when dragging from closed it wouldn't hide the status bar
- if (hideStatusBar) {
- StatusBar.setHidden(true, statusBarAnimation ?? 'slide');
- }
- }
-
- function setState(newState: BetterDrawerState, willShow: boolean) {
- if (hideStatusBar) {
- StatusBar.setHidden(willShow, statusBarAnimation ?? 'slide');
- }
-
- // dispach events
- if (drawerState.value !== newState || drawerVisible !== willShow) {
- // send state change event only when the state changed or the visibility of the
- // drawer (for example when drawer is in SETTLING state after opening and the user
- // taps on the overlay the state is still settling, but willShow is now false)
- onDrawerStateChanged?.(newState, willShow);
- }
-
- if (drawerVisible !== willShow) {
- setDrawerVisible(willShow);
- }
-
- if (newState === BetterDrawerState.IDLE) {
- if (willShow) {
- onDrawerOpen?.();
- } else {
- onDrawerClose?.();
- }
- }
-
- drawerState.value = newState;
- }
-
- function open() {
- 'worklet';
- if (fromLeft && drawerOffset.value < drawerWidth) {
- // drawer is on the left and is not fully opened
- runOnJS(setState)(BetterDrawerState.SETTLING, true);
-
- drawerOffset.value = withSpring(
- drawerWidth,
- animationConfig,
- (finished) => {
- drawerSavedOffset.value = drawerOffset.value;
- if (finished) {
- // animation cannot be interrupted by a drag, but can be by
- // calling close or open (through tap or a controller)
- runOnJS(setState)(BetterDrawerState.IDLE, true);
- }
- }
- );
- } else if (!fromLeft && drawerOffset.value > -drawerWidth) {
- // drawer is on the right and is not fully opened
- runOnJS(setState)(BetterDrawerState.SETTLING, true);
-
- drawerOffset.value = withSpring(
- -drawerWidth,
- animationConfig,
- (finished) => {
- drawerSavedOffset.value = drawerOffset.value;
- if (finished) {
- // animation cannot be interrupted by a drag, but can be by
- // calling close or open (through tap or a controller)
- runOnJS(setState)(BetterDrawerState.IDLE, true);
- }
- }
- );
- } else {
- // drawer is fully opened
- runOnJS(setState)(BetterDrawerState.IDLE, true);
- }
- }
-
- function close() {
- 'worklet';
- if (fromLeft && drawerOffset.value > 0) {
- // drawer is on the left and is not fully closed
- runOnJS(setState)(BetterDrawerState.SETTLING, false);
-
- drawerOffset.value = withSpring(0, animationConfig, (finished) => {
- drawerSavedOffset.value = drawerOffset.value;
- if (finished) {
- // animation cannot be interrupted by a drag, but can be by
- // calling close or open (through tap or a controller)
- runOnJS(setState)(BetterDrawerState.IDLE, false);
- }
- });
- } else if (!fromLeft && drawerOffset.value < 0) {
- // drawer is on the right and is not fully closed
- runOnJS(setState)(BetterDrawerState.SETTLING, false);
-
- drawerOffset.value = withSpring(0, animationConfig, (finished) => {
- drawerSavedOffset.value = drawerOffset.value;
- if (finished) {
- // animation cannot be interrupted by a drag, but can be by
- // calling close or open (through tap or a controller)
- runOnJS(setState)(BetterDrawerState.IDLE, false);
- }
- });
- } else {
- // drawer is fully closed
- runOnJS(setState)(BetterDrawerState.IDLE, false);
- }
- }
-
- // gestureOrientation is 1 if the expected gesture is from left to right and
- // -1 otherwise e.g. when drawer is on the left and is closed we expect left
- // to right gesture, thus orientation will be 1.
- const gestureOrientation = (fromLeft ? 1 : -1) * (drawerVisible ? -1 : 1);
-
- // When drawer is closed we want the hitSlop to be horizontally shorter than
- // the container size by the value of SLOP. This will make it only activate
- // when gesture happens not further than SLOP away from the edge
- const hitSlop = fromLeft
- ? { left: 0, width: drawerVisible ? undefined : edgeWidth }
- : { right: 0, width: drawerVisible ? undefined : edgeWidth };
-
- // *** THIS IS THE LARGE COMMENT ABOVE ***
- //
- // While closing the drawer when user starts gesture outside of its area (in greyed
- // out part of the window), we want the drawer to follow only once finger reaches the
- // edge of the drawer.
- // E.g. on the diagram below drawer is illustrate by X signs and the greyed out area by
- // dots. The touch gesture starts at '*' and moves left, touch path is indicated by
- // an arrow pointing left
- // 1) +---------------+ 2) +---------------+ 3) +---------------+ 4) +---------------+
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|.<-*..| |XXXXXXXX|<--*..| |XXXXX|<-----*..|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // +---------------+ +---------------+ +---------------+ +---------------+
- //
- // For the above to work properly we define animated value that will keep
- // start position of the gesture. Then we use that value to calculate how
- // much we need to subtract from the dragX. If the gesture started on the
- // greyed out area we take the distance from the edge of the drawer to the
- // start position. Otherwise we don't subtract at all and the drawer be
- // pulled back as soon as you start the pan.
- //
- // This is used only when drawerType is "front"
- //
-
- const pan = Gesture.Pan();
- pan.failOffsetY([-15, 15]);
- pan.hitSlop(hitSlop);
- pan.activeOffsetX(gestureOrientation * minSwipeDistance);
- pan.enableTrackpadTwoFingerGesture(enableTrackpadTwoFingerGesture);
- pan.enabled(
- drawerLockMode !== 'locked-closed' && drawerLockMode !== 'locked-open'
- );
- pan.onStart((event) => {
- 'worklet';
- ignoredOffset.value = 0;
- dragStartPosition.value = event.x;
- });
- pan.onUpdate((event) => {
- 'worklet';
- if (drawerState.value === BetterDrawerState.IDLE) {
- runOnJS(setState)(BetterDrawerState.DRAGGING, drawerVisible);
- runOnJS(onDragStart)();
- }
-
- if (drawerState.value === BetterDrawerState.DRAGGING) {
- let newOffset =
- drawerSavedOffset.value + event.translationX - ignoredOffset.value;
-
- if (fromLeft) {
- // refer to the large comment above
- if (
- drawerType === 'front' &&
- event.translationX < 0 &&
- drawerOffset.value > 0
- ) {
- newOffset += dragStartPosition.value - drawerWidth;
- }
-
- // clamp the offset so the drawer does not move away from the edge
- newOffset = Math.max(0, Math.min(drawerWidth, newOffset));
- } else {
- // refer to the large comment above
- if (
- drawerType === 'front' &&
- event.translationX > 0 &&
- drawerOffset.value < 0
- ) {
- newOffset += dragStartPosition.value - (containerWidth - drawerWidth);
- }
-
- // clamp the offset so the drawer does not move away from the edge
- newOffset = Math.max(-drawerWidth, Math.min(0, newOffset));
- }
-
- drawerOffset.value = newOffset;
-
- // send event if there is a listener
- if (onDrawerSlide !== undefined) {
- runOnJS(onDrawerSlide)(openingProgress.value);
- }
- } else {
- // drawerState is SETTLING, save the translation to ignore it later
- ignoredOffset.value = event.translationX;
- }
- });
- pan.onEnd((_event) => {
- 'worklet';
- if (drawerState.value === BetterDrawerState.DRAGGING) {
- // update offsets and animations only when the drag was not ignored
- drawerSavedOffset.value = drawerOffset.value;
-
- // if the drawer was dragged more than half of its width open it,
- // otherwise close it
- if (fromLeft) {
- if (drawerOffset.value > drawerWidth / 2) {
- open();
- } else {
- close();
- }
- } else {
- if (drawerOffset.value < -drawerWidth / 2) {
- open();
- } else {
- close();
- }
- }
- }
- });
-
- const dynamicDrawerStyles = {
- backgroundColor: drawerBackgroundColor,
- width: drawerWidth,
- };
-
- const drawerStyle = useAnimatedStyle(() => {
- let translateX = 0;
-
- if (drawerSlide) {
- // drawer is supposed to be moved with the gesture (in this case
- // drawer is anchored to be off the screen when not opened)
- if (fromLeft) {
- translateX = -drawerWidth;
- } else {
- translateX = containerWidth;
- }
- translateX += drawerOffset.value;
- } else {
- // drawer is stationary (in this case drawer is below the content
- // so it's anchored left edge to left edge or right to right)
- if (fromLeft) {
- translateX = 0;
- } else {
- translateX = containerWidth - drawerWidth;
- }
- }
-
- // if the drawer is not visible move it off the screen to prevent it
- // from intercepting touch events on Android
- if (drawerOffset.value === 0) {
- translateX = 10000;
- }
-
- return {
- flexDirection: reverseContentDirection ? 'row-reverse' : 'row',
- transform: [{ translateX }],
- };
- });
-
- const containerStyle = useAnimatedStyle(() => {
- let translateX = 0;
-
- if (containerSlide) {
- // the container should be moved with the gesture
- translateX = drawerOffset.value;
- }
-
- return {
- transform: [{ translateX }],
- };
- });
-
- if (ref !== null) {
- // ref is set, create a controller and pass it
- const controller: DrawerLayoutController = {
- open: () => {
- open();
- },
- close: () => {
- close();
- },
- };
-
- if (typeof ref === 'function') {
- // @ts-ignore ref is function
- ref(controller);
- } else {
- // @ts-ignore ref is not undefined
- ref.current = controller;
- }
- }
-
- return (
-
-
-
- {children}
-
-
-
-
- {renderNavigationView(openingProgress)}
-
-
-
- );
-};
-
-const styles = StyleSheet.create({
- drawerContainer: {
- ...StyleSheet.absoluteFillObject,
- zIndex: 1001,
- flexDirection: 'row',
- },
- containerInFront: {
- ...StyleSheet.absoluteFillObject,
- zIndex: 1002,
- },
- containerOnBack: {
- ...StyleSheet.absoluteFillObject,
- },
- main: {
- flex: 1,
- zIndex: 0,
- overflow: 'hidden',
- },
- overlay: {
- ...StyleSheet.absoluteFillObject,
- zIndex: 1000,
- },
-});
diff --git a/apps/common-app/src/new_api/betterHorizontalDrawer/index.tsx b/apps/common-app/src/new_api/betterHorizontalDrawer/index.tsx
deleted file mode 100644
index c2f7008a8e..0000000000
--- a/apps/common-app/src/new_api/betterHorizontalDrawer/index.tsx
+++ /dev/null
@@ -1,162 +0,0 @@
-import React, { useRef, useState } from 'react';
-
-import { StyleSheet, Text, View, TextInput } from 'react-native';
-
-import { DrawerType, RectButton } from 'react-native-gesture-handler';
-import {
- DrawerLayoutController,
- DrawerLayout,
-} from './BetterHorizonatalDrawer';
-import Animated, {
- useAnimatedStyle,
- interpolate,
-} from 'react-native-reanimated';
-
-const TYPES: DrawerType[] = ['front', 'back', 'back', 'slide'];
-const PARALLAX = [false, false, true, false];
-
-interface PageProps {
- fromLeft: boolean;
- type: DrawerType;
- parallaxOn: boolean;
- flipSide: () => void;
- nextType: () => void;
- openDrawer: () => void;
-}
-
-function Page({
- fromLeft,
- type,
- parallaxOn,
- flipSide,
- nextType,
- openDrawer,
-}: PageProps) {
- return (
-
- Hi 👋
-
-
- Drawer to the {fromLeft ? 'left' : 'right'}! {'->'} Flip
-
-
-
-
- Type {type} {parallaxOn && 'with parallax!'} -> Next
-
-
-
- Open drawer
-
-
-
- );
-}
-
-function DrawerContent(
- offset: Animated.SharedValue,
- parallax: boolean,
- fromLeft: boolean
-) {
- const animatedStyles = useAnimatedStyle(() => ({
- transform: [
- {
- translateX: parallax
- ? interpolate(offset.value, [0, 1], [fromLeft ? -50 : 50, 0])
- : 0,
- },
- ],
- }));
-
- return (
-
-
- {parallax ? 'Drawer with parallax' : 'Drawer'}
-
-
- );
-}
-
-export default function Example() {
- const [onLeft, setOnLeft] = useState(true);
- const [type, setType] = useState(0);
- const controller = useRef(null);
-
- return (
-
- {
- return DrawerContent(offset, PARALLAX[type], onLeft);
- }}
- keyboardDismissMode="on-drag"
- drawerBackgroundColor="white"
- ref={controller}>
- {
- setOnLeft(!onLeft);
- }}
- type={TYPES[type]}
- nextType={() => {
- setType((type + 1) % TYPES.length);
- }}
- parallaxOn={PARALLAX[type]}
- openDrawer={() => {
- controller.current?.open();
- }}
- />
-
-
- );
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
- page: {
- ...StyleSheet.absoluteFillObject,
- alignItems: 'center',
- paddingTop: 40,
- backgroundColor: 'gray',
- },
- pageText: {
- fontSize: 21,
- color: 'white',
- },
- rectButton: {
- height: 60,
- padding: 10,
- alignSelf: 'stretch',
- alignItems: 'center',
- justifyContent: 'center',
- marginTop: 20,
- backgroundColor: 'white',
- },
- rectButtonText: {
- backgroundColor: 'transparent',
- },
- drawerContainer: {
- flex: 1,
- paddingTop: 10,
- },
- pageInput: {
- height: 60,
- padding: 10,
- alignSelf: 'stretch',
- alignItems: 'center',
- justifyContent: 'center',
- marginTop: 20,
- backgroundColor: '#eee',
- },
- drawerText: {
- margin: 10,
- fontSize: 15,
- textAlign: 'left',
- },
-});
diff --git a/apps/common-app/src/new_api/swipeable/index.tsx b/apps/common-app/src/new_api/swipeable/index.tsx
index f595afad8d..85138234fe 100644
--- a/apps/common-app/src/new_api/swipeable/index.tsx
+++ b/apps/common-app/src/new_api/swipeable/index.tsx
@@ -1,11 +1,20 @@
-import React from 'react';
+import React, { useRef } from 'react';
import { StyleSheet, Text, View, I18nManager } from 'react-native';
-import { FlatList, RectButton } from 'react-native-gesture-handler';
+import { FlatList, Pressable, RectButton } from 'react-native-gesture-handler';
+
+import Reanimated, {
+ SharedValue,
+ useAnimatedStyle,
+} from 'react-native-reanimated';
import AppleStyleSwipeableRow from './AppleStyleSwipeableRow';
import GmailStyleSwipeableRow from './GmailStyleSwipeableRow';
+import ReanimatedSwipeable, {
+ SwipeableMethods,
+} from 'react-native-gesture-handler/ReanimatedSwipeable';
+
// To toggle LTR/RTL change to `true`
I18nManager.allowRTL(false);
@@ -42,25 +51,111 @@ const SwipeableRow = ({ item, index }: { item: DataRow; index: number }) => {
}
};
+function LeftAction(prog: SharedValue, drag: SharedValue) {
+ const styleAnimation = useAnimatedStyle(() => {
+ console.log('[R] showLeftProgress:', prog.value);
+ console.log('[R] appliedTranslation:', drag.value);
+
+ return {
+ transform: [{ translateX: drag.value - 60 }],
+ };
+ });
+
+ return (
+
+ Text
+
+ );
+}
+
+function RightAction(prog: SharedValue, drag: SharedValue) {
+ const styleAnimation = useAnimatedStyle(() => {
+ console.log('[R] showRightProgress:', prog.value);
+ console.log('[R] appliedTranslation:', drag.value);
+
+ return {
+ transform: [{ translateX: drag.value + 60 }],
+ };
+ });
+
+ return (
+
+ Text
+
+ );
+}
+
const Separator = () => ;
export default function App() {
+ const reanimatedRef = useRef(null);
return (
- (
-
- )}
- keyExtractor={(_item, index) => `message ${index}`}
- />
+
+
+
+
+ Programatical controls
+
+ {
+ reanimatedRef.current!.openLeft();
+ }}>
+ open left
+
+ {
+ reanimatedRef.current!.close();
+ }}>
+ close
+
+ {
+ reanimatedRef.current!.reset();
+ }}>
+ reset
+
+ {
+ reanimatedRef.current!.openRight();
+ }}>
+ open right
+
+
+
+
+
+
+
+ Use the programatic control panel
+
+
+
+ (
+
+ )}
+ keyExtractor={(_item, index) => `message ${index}`}
+ />
+
);
}
const styles = StyleSheet.create({
rectButton: {
- flex: 1,
- height: 80,
paddingVertical: 10,
paddingHorizontal: 20,
justifyContent: 'space-between',
@@ -87,6 +182,31 @@ const styles = StyleSheet.create({
color: '#999',
fontWeight: 'bold',
},
+ leftAction: { width: 60, height: 60, backgroundColor: '#ff5ca3' },
+ rightAction: { width: 60, height: 60, backgroundColor: '#b658b6' },
+ swipeable: {
+ height: 60,
+ backgroundColor: 'white',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ controlPanelWrapper: {
+ backgroundColor: 'white',
+ alignItems: 'center',
+ },
+ controlPanel: {
+ backgroundColor: 'white',
+ alignItems: 'center',
+ flexDirection: 'row',
+ },
+ control: {
+ flex: 1,
+ height: 40,
+ borderWidth: StyleSheet.hairlineWidth,
+ borderColor: 'rgb(200, 199, 204)',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
});
const DATA: DataRow[] = [
diff --git a/apps/common-app/src/release_tests/combo/InfoButton.tsx b/apps/common-app/src/release_tests/combo/InfoButton.tsx
new file mode 100644
index 0000000000..353c372847
--- /dev/null
+++ b/apps/common-app/src/release_tests/combo/InfoButton.tsx
@@ -0,0 +1,39 @@
+import React, { View, Text, StyleSheet } from 'react-native';
+import {
+ BorderlessButton,
+ BorderlessButtonProps,
+} from 'react-native-gesture-handler';
+
+export const InfoButton = (props: BorderlessButtonProps & { name: string }) => (
+ window.alert(`${props.name} info button clicked`)}>
+
+ i
+
+
+);
+
+const styles = StyleSheet.create({
+ infoButton: {
+ width: 40,
+ height: 40,
+ },
+ infoButtonBorders: {
+ borderColor: '#467AFB',
+ borderWidth: 2,
+ width: 20,
+ height: 20,
+ alignItems: 'center',
+ justifyContent: 'center',
+ borderRadius: 10,
+ margin: 10,
+ },
+ infoButtonText: {
+ color: '#467AFB',
+ fontWeight: 'bold',
+ backgroundColor: 'transparent',
+ },
+});
diff --git a/apps/common-app/src/release_tests/combo/index.tsx b/apps/common-app/src/release_tests/combo/index.tsx
index 5e0b0febf9..d13922eb41 100644
--- a/apps/common-app/src/release_tests/combo/index.tsx
+++ b/apps/common-app/src/release_tests/combo/index.tsx
@@ -21,12 +21,14 @@ import {
} from 'react-native-gesture-handler';
import Slider from '@react-native-community/slider';
-import { Swipeable, InfoButton } from '../rows';
+import Swipeable from 'react-native-gesture-handler/ReanimatedSwipeable';
+
import { DraggableBox } from '../../basic/draggable';
import { PinchableBox } from '../../recipes/scaleAndRotate';
import { PressBox } from '../../basic/multitap';
import { LoremIpsum } from '../../common';
+import { InfoButton } from './InfoButton';
const WrappedSlider = createNativeWrapper(Slider, {
shouldCancelWhenOutside: false,
diff --git a/apps/common-app/src/release_tests/rows/index.tsx b/apps/common-app/src/release_tests/rows/index.tsx
deleted file mode 100644
index 02eae1ed6e..0000000000
--- a/apps/common-app/src/release_tests/rows/index.tsx
+++ /dev/null
@@ -1,283 +0,0 @@
-import React, { Component, PropsWithChildren } from 'react';
-import {
- Animated,
- StyleSheet,
- Text,
- View,
- LayoutChangeEvent,
-} from 'react-native';
-
-import {
- PanGestureHandler,
- ScrollView,
- State,
- RectButton,
- LongPressGestureHandler,
- PanGestureHandlerGestureEvent,
- PanGestureHandlerStateChangeEvent,
- BorderlessButton,
- BorderlessButtonProps,
-} from 'react-native-gesture-handler';
-
-import { USE_NATIVE_DRIVER } from '../../config';
-import { LoremIpsum } from '../../common';
-
-const RATIO = 3;
-
-type Props = {
- enableTrackpadTwoFingerGesture: boolean;
-};
-
-export class Swipeable extends Component> {
- private width: number;
- private dragX: Animated.Value;
- private transX: Animated.AnimatedInterpolation;
- private showLeftAction: Animated.AnimatedInterpolation;
- private showRightAction: Animated.AnimatedInterpolation;
- private onGestureEvent: (event: PanGestureHandlerGestureEvent) => void;
- constructor(props: Props) {
- super(props);
- this.width = 0;
- this.dragX = new Animated.Value(0);
- this.transX = this.dragX.interpolate({
- inputRange: [0, RATIO],
- outputRange: [0, 1],
- });
- this.showLeftAction = this.dragX.interpolate({
- inputRange: [-1, 0, 1],
- outputRange: [0, 0, 1],
- });
- this.showRightAction = this.dragX.interpolate({
- inputRange: [-1, 0, 1],
- outputRange: [1, 0, 0],
- });
- this.onGestureEvent = Animated.event(
- [{ nativeEvent: { translationX: this.dragX } }],
- { useNativeDriver: USE_NATIVE_DRIVER }
- );
- }
- private onHandlerStateChange = (event: PanGestureHandlerStateChangeEvent) => {
- if (event.nativeEvent.oldState === State.ACTIVE) {
- const dragToss = 0.05;
- const endOffsetX =
- event.nativeEvent.translationX + dragToss * event.nativeEvent.velocityX;
-
- let toValue = 0;
- if (endOffsetX > this.width / 2) {
- toValue = this.width * RATIO;
- } else if (endOffsetX < -this.width / 2) {
- toValue = -this.width * RATIO;
- }
-
- Animated.spring(this.dragX, {
- velocity: event.nativeEvent.velocityX,
- tension: 15,
- friction: 5,
- toValue,
- useNativeDriver: USE_NATIVE_DRIVER,
- }).start();
- }
- };
- private onLayout = (event: LayoutChangeEvent) => {
- this.width = event.nativeEvent.layout.width;
- };
- private reset = () => {
- Animated.spring(this.dragX, {
- toValue: 0,
- useNativeDriver: USE_NATIVE_DRIVER,
- tension: 15,
- friction: 5,
- }).start();
- };
- render() {
- const { children } = this.props;
- return (
-
-
-
- Green
-
-
-
-
- Red
-
-
-
-
- {children}
-
-
-
- );
- }
-}
-
-export const InfoButton = (props: BorderlessButtonProps & { name: string }) => (
- window.alert(`${props.name} info button clicked`)}>
-
- i
-
-
-);
-
-export default class Example extends Component {
- render() {
- return (
-
-
-
-
- window.alert('First row clicked')}>
-
- Swipe this row & observe highlight delay
-
- {/* Info icon will cancel when you scroll in the direction of the scrollview
- but if you move finger horizontally it would allow you to "re-enter" into
- an active state. This is typical for most of the buttons on iOS (but not
- on Android where the touch cancels as soon as you leave the area of the
- button). */}
-
-
-
-
- window.alert('Second row clicked')}>
-
- Second info icon will block scrolling
-
- {/* Info icon will block interaction with other gesture handlers including
- the scrollview handler its a descendant of. This is typical for buttons
- embedded in a scrollable content on iOS. */}
-
-
-
- window.alert('Third row clicked')}>
-
- This one will cancel when you drag outside
-
- {/* Info icon will cancel when you drag your finger outside of its bounds and
- then back unlike all the previous icons that would activate when you re-enter
- their activation area. This is a typical bahaviour for android but less frequent
- for most of the iOS native apps. */}
-
-
-
-
- window.alert('Fourth row clicked')}>
-
- This row is "disabled" but you can swipe it
-
-
-
-
-
- // eslint-disable-next-line no-alert
- nativeEvent.state === State.ACTIVE && window.alert('Long')
- }>
- window.alert('Fifth row clicked')}>
-
- Clickable row with long press handler
-
-
-
-
-
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
- rectButton: {
- flex: 1,
- height: 60,
- padding: 10,
- justifyContent: 'space-between',
- alignItems: 'center',
- flexDirection: 'row',
- backgroundColor: 'white',
- },
- rowAction: {
- ...StyleSheet.absoluteFillObject,
- justifyContent: 'center',
- alignItems: 'center',
- },
- leftAction: {
- backgroundColor: '#4CAF50',
- },
- rightAction: {
- backgroundColor: '#F44336',
- },
- actionButtonText: {
- color: 'white',
- fontSize: 16,
- },
- buttonDelimiter: {
- height: 1,
- backgroundColor: '#999',
- },
- buttonText: {
- fontWeight: 'bold',
- backgroundColor: 'transparent',
- },
- infoButton: {
- width: 40,
- height: 40,
- },
- infoButtonBorders: {
- borderColor: '#467AFB',
- borderWidth: 2,
- width: 20,
- height: 20,
- alignItems: 'center',
- justifyContent: 'center',
- borderRadius: 10,
- margin: 10,
- },
- infoButtonText: {
- color: '#467AFB',
- fontWeight: 'bold',
- backgroundColor: 'transparent',
- },
-});
diff --git a/apps/common-app/src/release_tests/swipeableReanimation/index.tsx b/apps/common-app/src/release_tests/swipeableReanimation/index.tsx
deleted file mode 100644
index 25d49536c8..0000000000
--- a/apps/common-app/src/release_tests/swipeableReanimation/index.tsx
+++ /dev/null
@@ -1,204 +0,0 @@
-import React, { useRef } from 'react';
-import { Text, Animated, StyleSheet, View } from 'react-native';
-
-import {
- Swipeable,
- GestureHandlerRootView,
- Pressable,
-} from 'react-native-gesture-handler';
-import ReanimatedSwipeable, {
- SwipeableMethods,
-} from 'react-native-gesture-handler/ReanimatedSwipeable';
-import Reanimated, {
- SharedValue,
- useAnimatedStyle,
-} from 'react-native-reanimated';
-
-function LeftAction(prog: SharedValue, drag: SharedValue) {
- const styleAnimation = useAnimatedStyle(() => {
- console.log('[R] showLeftProgress:', prog.value);
- console.log('[R] appliedTranslation:', drag.value);
-
- return {
- transform: [{ translateX: drag.value - 50 }],
- };
- });
-
- return (
-
- Text
-
- );
-}
-
-function RightAction(prog: SharedValue, drag: SharedValue) {
- const styleAnimation = useAnimatedStyle(() => {
- console.log('[R] showRightProgress:', prog.value);
- console.log('[R] appliedTranslation:', drag.value);
-
- return {
- transform: [{ translateX: drag.value + 50 }],
- };
- });
-
- return (
-
- Text
-
- );
-}
-
-function LegacyLeftAction(prog: any, drag: any) {
- prog.addListener((value: any) => {
- console.log('[L] showLeftProgress:', value.value);
- });
- drag.addListener((value: any) => {
- console.log('[L] appliedTranslation:', value.value);
- });
-
- const trans = Animated.subtract(drag, 50);
-
- return (
-
- Text
-
- );
-}
-
-function LegacyRightAction(prog: any, drag: any) {
- prog.addListener((value: any) => {
- console.log('[L] showRightProgress:', value.value);
- });
- drag.addListener((value: any) => {
- console.log('[L] appliedTranslation:', value.value);
- });
-
- const trans = Animated.add(drag, 50);
-
- return (
-
- Text
-
- );
-}
-
-export default function Example() {
- const reanimatedRef = useRef(null);
- const legacyRef = useRef(null);
-
- return (
-
-
-
-
- Programatical controls
-
- {
- reanimatedRef.current!.openLeft();
- legacyRef.current?.openLeft();
- }}>
- open left
-
- {
- reanimatedRef.current!.close();
- legacyRef.current!.close();
- }}>
- close
-
- {
- reanimatedRef.current!.reset();
- legacyRef.current!.reset();
- }}>
- reset
-
- {
- reanimatedRef.current!.openRight();
- legacyRef.current!.openRight();
- }}>
- open right
-
-
-
-
-
-
-
- [Reanimated] Swipe me!
-
-
-
-
-
- [Legacy] Swipe me!
-
-
-
-
- );
-}
-
-const styles = StyleSheet.create({
- leftAction: { width: 50, height: 50, backgroundColor: 'crimson' },
- rightAction: { width: 50, height: 50, backgroundColor: 'purple' },
- separator: {
- width: '100%',
- borderTopWidth: 1,
- },
- swipeable: {
- height: 50,
- backgroundColor: 'papayawhip',
- alignItems: 'center',
- },
- controlPanelWrapper: {
- backgroundColor: 'papayawhip',
- alignItems: 'center',
- },
- controlPanel: {
- backgroundColor: 'papayawhip',
- alignItems: 'center',
- flexDirection: 'row',
- },
- control: {
- flex: 1,
- height: 40,
- borderWidth: StyleSheet.hairlineWidth,
- alignItems: 'center',
- justifyContent: 'center',
- },
-});
diff --git a/apps/common-app/src/showcase/swipeable/AppleStyleSwipeableRow.tsx b/apps/common-app/src/showcase/swipeable/AppleStyleSwipeableRow.tsx
deleted file mode 100644
index 0b4ea549b2..0000000000
--- a/apps/common-app/src/showcase/swipeable/AppleStyleSwipeableRow.tsx
+++ /dev/null
@@ -1,123 +0,0 @@
-import React, { Component, PropsWithChildren } from 'react';
-import { Animated, StyleSheet, Text, View, I18nManager } from 'react-native';
-
-import { RectButton, Swipeable } from 'react-native-gesture-handler';
-
-export default class AppleStyleSwipeableRow extends Component<
- PropsWithChildren
-> {
- private renderLeftActions = (
- _progress: Animated.AnimatedInterpolation,
- dragX: Animated.AnimatedInterpolation
- ) => {
- const trans = dragX.interpolate({
- inputRange: [0, 50, 100, 101],
- outputRange: [-20, 0, 0, 1],
- extrapolate: 'clamp',
- });
- return (
-
-
- Archive
-
-
- );
- };
-
- private renderRightAction = (
- text: string,
- color: string,
- x: number,
- progress: Animated.AnimatedInterpolation
- ) => {
- const trans = progress.interpolate({
- inputRange: [0, 1],
- outputRange: [x, 0],
- });
- const pressHandler = () => {
- this.close();
- // eslint-disable-next-line no-alert
- window.alert(text);
- };
-
- return (
-
-
- {text}
-
-
- );
- };
-
- private renderRightActions = (
- progress: Animated.AnimatedInterpolation,
- _dragAnimatedValue: Animated.AnimatedInterpolation
- ) => (
-
- {this.renderRightAction('More', '#C8C7CD', 192, progress)}
- {this.renderRightAction('Flag', '#ffab00', 128, progress)}
- {this.renderRightAction('More', '#dd2c00', 64, progress)}
-
- );
-
- private swipeableRow?: Swipeable;
-
- private updateRef = (ref: Swipeable) => {
- this.swipeableRow = ref;
- };
- private close = () => {
- this.swipeableRow?.close();
- };
- render() {
- const { children } = this.props;
- return (
- {
- console.log(`Opening swipeable from the ${direction}`);
- }}
- onSwipeableClose={(direction) => {
- console.log(`Closing swipeable to the ${direction}`);
- }}>
- {children}
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- leftAction: {
- flex: 1,
- backgroundColor: '#497AFC',
- justifyContent: 'center',
- },
- actionText: {
- color: 'white',
- fontSize: 16,
- backgroundColor: 'transparent',
- padding: 10,
- },
- rightAction: {
- alignItems: 'center',
- flex: 1,
- justifyContent: 'center',
- },
-});
diff --git a/apps/common-app/src/showcase/swipeable/GmailStyleSwipeableRow.tsx b/apps/common-app/src/showcase/swipeable/GmailStyleSwipeableRow.tsx
deleted file mode 100644
index 1504c50a70..0000000000
--- a/apps/common-app/src/showcase/swipeable/GmailStyleSwipeableRow.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import React, { Component, PropsWithChildren } from 'react';
-import { Animated, StyleSheet, I18nManager, View } from 'react-native';
-
-import { RectButton, Swipeable } from 'react-native-gesture-handler';
-
-const AnimatedView = Animated.createAnimatedComponent(View);
-
-export default class GmailStyleSwipeableRow extends Component<
- PropsWithChildren
-> {
- private renderLeftActions = (
- _progress: Animated.AnimatedInterpolation,
- dragX: Animated.AnimatedInterpolation
- ) => {
- const scale = dragX.interpolate({
- inputRange: [0, 80],
- outputRange: [0, 1],
- extrapolate: 'clamp',
- });
- return (
-
- {/* Change it to some icons */}
-
-
- );
- };
- private renderRightActions = (
- _progress: Animated.AnimatedInterpolation,
- dragX: Animated.AnimatedInterpolation
- ) => {
- const scale = dragX.interpolate({
- inputRange: [-80, 0],
- outputRange: [1, 0],
- extrapolate: 'clamp',
- });
- return (
-
- {/* Change it to some icons */}
-
-
- );
- };
-
- private swipeableRow?: Swipeable;
-
- private updateRef = (ref: Swipeable) => {
- this.swipeableRow = ref;
- };
- private close = () => {
- this.swipeableRow?.close();
- };
- render() {
- const { children } = this.props;
- return (
-
- {children}
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- leftAction: {
- flex: 1,
- backgroundColor: '#388e3c',
- justifyContent: 'flex-end',
- alignItems: 'center',
- flexDirection: I18nManager.isRTL ? 'row' : 'row-reverse',
- },
- actionIcon: {
- width: 30,
- marginHorizontal: 10,
- backgroundColor: 'plum',
- height: 20,
- },
- rightAction: {
- alignItems: 'center',
- flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row',
- backgroundColor: '#dd2c00',
- flex: 1,
- justifyContent: 'flex-end',
- },
-});
diff --git a/apps/common-app/src/showcase/swipeable/index.tsx b/apps/common-app/src/showcase/swipeable/index.tsx
deleted file mode 100644
index 5c6da6b892..0000000000
--- a/apps/common-app/src/showcase/swipeable/index.tsx
+++ /dev/null
@@ -1,141 +0,0 @@
-import React, { Component } from 'react';
-import { StyleSheet, Text, View, I18nManager } from 'react-native';
-
-import { FlatList, RectButton } from 'react-native-gesture-handler';
-
-import AppleStyleSwipeableRow from './AppleStyleSwipeableRow';
-import GmailStyleSwipeableRow from './GmailStyleSwipeableRow';
-
-// To toggle LTR/RTL change to `true`
-I18nManager.allowRTL(false);
-
-type DataRow = {
- from: string;
- when: string;
- message: string;
-};
-
-const Row = ({ item }: { item: DataRow }) => (
- // eslint-disable-next-line no-alert
- window.alert(item.from)}>
- {item.from}
-
- {item.message}
-
- {item.when} ❭
-
-);
-
-const SwipeableRow = ({ item, index }: { item: DataRow; index: number }) => {
- if (index % 2 === 0) {
- return (
-
-
-
- );
- } else {
- return (
-
-
-
- );
- }
-};
-
-export default class Example extends Component {
- render() {
- return (
- }
- renderItem={({ item, index }) => (
-
- )}
- keyExtractor={(_item, index) => `message ${index}`}
- />
- );
- }
-}
-
-const styles = StyleSheet.create({
- rectButton: {
- flex: 1,
- height: 80,
- paddingVertical: 10,
- paddingHorizontal: 20,
- justifyContent: 'space-between',
- flexDirection: 'column',
- backgroundColor: 'white',
- },
- separator: {
- backgroundColor: 'rgb(200, 199, 204)',
- height: StyleSheet.hairlineWidth,
- },
- fromText: {
- fontWeight: 'bold',
- backgroundColor: 'transparent',
- },
- messageText: {
- color: '#999',
- backgroundColor: 'transparent',
- },
- dateText: {
- backgroundColor: 'transparent',
- position: 'absolute',
- right: 20,
- top: 10,
- color: '#999',
- fontWeight: 'bold',
- },
-});
-
-const DATA: DataRow[] = [
- {
- from: "D'Artagnan",
- when: '3:11 PM',
- message:
- 'Unus pro omnibus, omnes pro uno. Nunc scelerisque, massa non lacinia porta, quam odio dapibus enim, nec tincidunt dolor leo non neque',
- },
- {
- from: 'Aramis',
- when: '11:46 AM',
- message:
- 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus hendrerit ligula dignissim maximus aliquet. Integer tincidunt, tortor at finibus molestie, ex tellus laoreet libero, lobortis consectetur nisl diam viverra justo.',
- },
- {
- from: 'Athos',
- when: '6:06 AM',
- message:
- 'Sed non arcu ullamcorper, eleifend velit eu, tristique metus. Duis id sapien eu orci varius malesuada et ac ipsum. Ut a magna vel urna tristique sagittis et dapibus augue. Vivamus non mauris a turpis auctor sagittis vitae vel ex. Curabitur accumsan quis mauris quis venenatis.',
- },
- {
- from: 'Porthos',
- when: 'Yesterday',
- message:
- 'Vivamus id condimentum lorem. Duis semper euismod luctus. Morbi maximus urna ut mi tempus fermentum. Nam eget dui sed ligula rutrum venenatis.',
- },
- {
- from: 'Domestos',
- when: '2 days ago',
- message:
- 'Aliquam imperdiet dolor eget aliquet feugiat. Fusce tincidunt mi diam. Pellentesque cursus semper sem. Aliquam ut ullamcorper massa, sed tincidunt eros.',
- },
- {
- from: 'Cardinal Richelieu',
- when: '2 days ago',
- message:
- 'Pellentesque id quam ac tortor pellentesque tempor tristique ut nunc. Pellentesque posuere ut massa eget imperdiet. Ut at nisi magna. Ut volutpat tellus ut est viverra, eu egestas ex tincidunt. Cras tellus tellus, fringilla eget massa in, ultricies maximus eros.',
- },
- {
- from: "D'Artagnan",
- when: 'Week ago',
- message:
- 'Aliquam non aliquet mi. Proin feugiat nisl maximus arcu imperdiet euismod nec at purus. Vestibulum sed dui eget mauris consequat dignissim.',
- },
- {
- from: 'Cardinal Richelieu',
- when: '2 weeks ago',
- message:
- 'Vestibulum ac nisi non augue viverra ullamcorper quis vitae mi. Donec vitae risus aliquam, posuere urna fermentum, fermentum risus. ',
- },
-];
diff --git a/packages/docs-gesture-handler/docs/components/drawer-layout.mdx b/packages/docs-gesture-handler/docs/components/drawer-layout.mdx
deleted file mode 100644
index 10465c8b45..0000000000
--- a/packages/docs-gesture-handler/docs/components/drawer-layout.mdx
+++ /dev/null
@@ -1,176 +0,0 @@
----
-id: drawer-layout
-title: Drawer Layout
-sidebar_label: DrawerLayout
----
-
-import useBaseUrl from '@docusaurus/useBaseUrl';
-import GifGallery from '@site/components/GifGallery';
-
-:::caution
-This component is deprecated.
-Please use [the reanimated version](/react-native-gesture-handler/docs/components/reanimated-drawer-layout).
-:::
-
-
-This is a cross-platform replacement for React Native's [DrawerLayoutAndroid](http://reactnative.dev/docs/drawerlayoutandroid.html) component. It provides a compatible API but allows for the component to be used on both Android and iOS. Please refer to [React Native docs](http://reactnative.dev/docs/drawerlayoutandroid.html) for the detailed usage for standard parameters.
-
-## Usage:
-
-`DrawerLayout` component isn't exported by default from the `react-native-gesture-handler` package. To use it, import it in the following way:
-
-```js
-import DrawerLayout from 'react-native-gesture-handler/DrawerLayout';
-```
-
-## Properties:
-
-On top of the standard list of parameters DrawerLayout has an additional set of attributes to customize its behavior. Please refer to the list below:
-
-### `drawerType`
-
-possible values are: `front`, `back` or `slide` (default is `front`). It specifies the way the drawer will be displayed. When set to `front` the drawer will slide in and out along with the gesture and will display on top of the content view. When `back` is used the drawer displays behind the content view and can be revealed with gesture of pulling the content view to the side. Finally `slide` option makes the drawer appear like it is attached to the side of the content view; when you pull both content view and drawer will follow the gesture.
-
-Type `slide`:
-
-
-
-
-
-Type `front`:
-
-
-
-
-
-Type `back`:
-
-
-
-
-
-### `edgeWidth`
-
-number, allows for defining how far from the edge of the content view the gesture should activate.
-
-### `hideStatusBar`
-
-boolean, when set to `true` Drawer component will use [StatusBar](http://reactnative.dev/docs/statusbar.html) API to hide the OS status bar whenever the drawer is pulled or when its in an "open" state.
-
-### `statusBarAnimation`
-
-possible values are: `slide`, `none` or `fade` (defaults to `slide`). Can be used when `hideStatusBar` is set to `true` and will select the animation used for hiding/showing the status bar. See [StatusBar](http://reactnative.dev/docs/statusbar.html#statusbaranimation) documentation for more details.
-
-### `overlayColor`
-
-color (default to `"black"`) of a semi-transparent overlay to be displayed on top of the content view when drawer gets open. A solid color should be used as the opacity is added by the Drawer itself and the opacity of the overlay is animated (from 0% to 70%).
-
-### `renderNavigationView`
-
-function. This attribute is present in the standard implementation already and is one of the required params. Gesture handler version of DrawerLayout make it possible for the function passed as `renderNavigationView` to take an Animated value as a parameter that indicates the progress of drawer opening/closing animation (progress value is 0 when closed and 1 when opened). This can be used by the drawer component to animated its children while the drawer is opening or closing.
-
-### `onDrawerClose`
-
-function. This function is called when the drawer is closed.
-
-### `onDrawerOpen`
-
-function. This function is called when the drawer is opened.
-
-### `onDrawerSlide`
-
-function. This function is called as a drawer sliding open from touch events. The progress of the drawer opening/closing is passed back as 0 when closed and 1 when opened.
-
-### `onDrawerStateChanged`
-
-function. This function is called when the status of the drawer changes. It takes two arguments:
-
-- `newState: DrawerState` - state of the `Drawer`. It can be one of the following:
- - `Idle`
- - `Dragging`
- - `Settling`
-- `drawerWillShow: boolean` - if `true`, `Drawer` is about to open.
-
-### `enableTrackpadTwoFingerGesture` (iOS only)
-
-Enables two-finger gestures on supported devices, for example iPads with trackpads. If not enabled the gesture will require click + drag, with enableTrackpadTwoFingerGesture swiping with two fingers will also trigger the gesture.
-
-### `children`
-
-component or function. Children is a component which is rendered by default and is wrapped by drawer. However, it could be also a render function which takes an Animated value as a parameter that indicates the progress of drawer opening/closing animation (progress value is 0 when closed and 1 when opened) is the same way like `renderNavigationView` prop.
-
-### `mouseButton(value: MouseButton)` (Web & Android only)
-
-Allows users to choose which mouse button should handler respond to. The enum `MouseButton` consists of the following predefined fields:
-
-- `LEFT`
-- `RIGHT`
-- `MIDDLE`
-- `BUTTON_4`
-- `BUTTON_5`
-- `ALL`
-
-Arguments can be combined using `|` operator, e.g. `mouseButton(MouseButton.LEFT | MouseButton.RIGHT)`. Default value is set to `MouseButton.LEFT`.
-
-### `enableContextMenu(value: boolean)` (Web only)
-
-Specifies whether context menu should be enabled after clicking on underlying view with right mouse button. Default value is set to `false`.
-
-## Methods
-
-### `openDrawer(options)`
-
-`openDrawer` can take an optional `options` parameter which is an object, enabling further customization of the open animation.
-
-`options` has two optional properties:
-
-`velocity`: number, the initial velocity of the object attached to the spring. Default 0 (object is at rest).
-`speed`: number, controls speed of the animation. Default 12.
-
-### `closeDrawer(options)`
-
-`closeDrawer` can take an optional `options` parameter which is an object, enabling further customization of the close animation.
-
-`options` has two optional properties:
-
-`velocity`: number, the initial velocity of the object attached to the spring. Default 0 (object is at rest).
-`speed`: number, controls speed of the animation. Default 12.
-
-## Example:
-
-See the [drawer example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/basic/horizontalDrawer/index.tsx) from GestureHandler Example App or view it directly on your phone by visiting [our expo demo](https://snack.expo.io/@adamgrzybowski/react-native-gesture-handler-demo).
-
-```js
-class Drawerable extends Component {
- handleDrawerSlide = (status) => {
- // outputs a value between 0 and 1
- console.log(status);
- };
-
- renderDrawer = () => {
- return (
-
- I am in the drawer!
-
- );
- };
-
- render() {
- return (
-
-
-
- Hello, it's me
-
-
-
- );
- }
-}
-```
diff --git a/packages/docs-gesture-handler/docs/components/swipeable.md b/packages/docs-gesture-handler/docs/components/swipeable.md
deleted file mode 100644
index 42b53acca0..0000000000
--- a/packages/docs-gesture-handler/docs/components/swipeable.md
+++ /dev/null
@@ -1,226 +0,0 @@
----
-id: swipeable
-title: Swipeable
-sidebar_label: Swipeable
----
-
-import useBaseUrl from '@docusaurus/useBaseUrl';
-import GifGallery from '@site/components/GifGallery'
-
-
-
-
-
-:::caution
-This component is deprecated.
-Please use [the reanimated version](/react-native-gesture-handler/docs/components/reanimated_swipeable).
-:::
-
-This component allows for implementing swipeable rows or similar interaction. It renders its children within a panable container allows for horizontal swiping left and right. While swiping one of two "action" containers can be shown depends on whether user swipes left or right (containers can be rendered by `renderLeftActions` or `renderRightActions` props).
-
-### Usage:
-
-Similarly to the `DrawerLayout`, `Swipeable` component isn't exported by default from the `react-native-gesture-handler` package. To use it, import it in the following way:
-
-```js
-import Swipeable from 'react-native-gesture-handler/Swipeable';
-```
-
-## Properties
-
-### `friction`
-
-A number that specifies how much the visual interaction will be delayed compared to the gesture distance. e.g. value of `1` will indicate that the swipeable panel should exactly follow the gesture, `2` means it is going to be two times "slower".
-
-### `leftThreshold`
-
-Distance from the left edge at which released panel will animate to the open state (or the open panel will animate into the closed state). By default it's a half of the panel's width.
-
-### `rightThreshold`
-
-Distance from the right edge at which released panel will animate to the open state (or the open panel will animate into the closed state). By default it's a half of the panel's width.
-
-### `dragOffsetFromLeftEdge`
-
-Distance that the panel must be dragged from the left edge to be considered a swipe. The default value is `10`.
-
-### `dragOffsetFromRightEdge`
-
-Distance that the panel must be dragged from the right edge to be considered a swipe. The default value is `10`.
-
-### `overshootLeft`
-
-A boolean value indicating if the swipeable panel can be pulled further than the left actions panel's width. It is set to `true` by default as long as the left panel render method is present.
-
-### `overshootRight`
-
-A boolean value indicating if the swipeable panel can be pulled further than the right actions panel's width. It is set to `true` by default as long as the right panel render method is present.
-
-### `overshootFriction`
-
-A number that specifies how much the visual interaction will be delayed compared to the gesture distance at overshoot. Default value is `1`, it mean no friction, for a native feel, try `8` or above.
-
-### `onSwipeableLeftOpen`
-
-:::caution
-This callback is deprecated and will be removed in the next version. Please use `onSwipeableOpen(direction)`
-:::
-
-Method that is called when left action panel gets open.
-
-### `onSwipeableRightOpen`
-
-:::caution
-This callback is deprecated and will be removed in the next version. Please use `onSwipeableOpen(direction)`
-:::
-
-Method that is called when right action panel gets open.
-
-### `onSwipeableOpen`
-
-Method that is called when action panel gets open (either right or left). Takes swipe direction as
-an argument.
-
-### `onSwipeableClose`
-
-Method that is called when action panel is closed. Takes swipe direction as
-an argument.
-
-### `onSwipeableLeftWillOpen`
-
-:::caution
-This callback is deprecated and will be removed in the next version. Please use `onSwipeableWillOpen(direction)`
-:::
-
-Method that is called when left action panel starts animating on open.
-
-### `onSwipeableRightWillOpen`
-
-:::caution
-This callback is deprecated and will be removed in the next version. Please use `onSwipeableWillOpen(direction)`
-:::
-
-Method that is called when right action panel starts animating on open.
-
-### `onSwipeableWillOpen`
-
-Method that is called when action panel starts animating on open (either right or left). Takes swipe direction as
-an argument.
-
-### `onSwipeableWillClose`
-
-Method that is called when action panel starts animating on close. Takes swipe direction as
-an argument.
-
-### `renderLeftActions`
-
-Method that is expected to return an action panel that is going to be revealed from the left side when user swipes right.
-This map describes the values to use as inputRange for extra interpolation:
-AnimatedValue: [startValue, endValue]
-
-progressAnimatedValue: `[0, 1]`
-dragAnimatedValue: `[0, +]`
-
-To support `rtl` flexbox layouts use `flexDirection` styling.
-
-### `renderRightActions`
-
-Method that is expected to return an action panel that is going to be revealed from the right side when user swipes left.
-This map describes the values to use as inputRange for extra interpolation:
-AnimatedValue: [startValue, endValue]
-
-progressAnimatedValue: `[0, 1]`
-dragAnimatedValue: `[0, -]`
-
-To support `rtl` flexbox layouts use `flexDirection` styling.
-
-### `containerStyle`
-
-Style object for the container (Animated.View), for example to override `overflow: 'hidden'`.
-
-### `childrenContainerStyle`
-
-Style object for the children container (Animated.View), for example to apply `flex: 1`.
-
-### `enableTrackpadTwoFingerGesture` (iOS only)
-
-Enables two-finger gestures on supported devices, for example iPads with trackpads. If not enabled the gesture will require click + drag, with enableTrackpadTwoFingerGesture swiping with two fingers will also trigger the gesture.
-
-### `mouseButton(value: MouseButton)` (Web & Android only)
-
-Allows users to choose which mouse button should handler respond to. The enum `MouseButton` consists of the following predefined fields:
-
-- `LEFT`
-- `RIGHT`
-- `MIDDLE`
-- `BUTTON_4`
-- `BUTTON_5`
-- `ALL`
-
-Arguments can be combined using `|` operator, e.g. `mouseButton(MouseButton.LEFT | MouseButton.RIGHT)`. Default value is set to `MouseButton.LEFT`.
-
-### `enableContextMenu(value: boolean)` (Web only)
-
-Specifies whether context menu should be enabled after clicking on underlying view with right mouse button. Default value is set to `false`.
-
-## Methods
-
-Using reference to `Swipeable` it's possible to trigger some actions on it
-
-### `close`
-
-Method that closes component.
-
-### `openLeft`
-
-Method that opens component on left side.
-
-### `openRight`
-
-Method that opens component on right side.
-
-### `reset`
-
-Method that resets the swiping states of this `Swipeable` component.
-
-Unlike method `close`, this method does not trigger any animation.
-
-### Example:
-
-See the [swipeable example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/apps/common-app/src/showcase/swipeable/index.tsx) from GestureHandler Example App or view it directly on your phone by visiting [our expo demo](https://snack.expo.io/@adamgrzybowski/react-native-gesture-handler-demo).
-
-```js
-import React, { Component } from 'react';
-import { Animated, StyleSheet, View } from 'react-native';
-import { RectButton } from 'react-native-gesture-handler';
-import Swipeable from 'react-native-gesture-handler/Swipeable';
-
-class AppleStyleSwipeableRow extends Component {
- renderLeftActions = (progress, dragX) => {
- const trans = dragX.interpolate({
- inputRange: [0, 50, 100, 101],
- outputRange: [-20, 0, 0, 1],
- });
- return (
-
-
- Archive
-
-
- );
- };
- render() {
- return (
-
- "hello"
-
- );
- }
-}
-```
diff --git a/packages/react-native-gesture-handler/DrawerLayout/package.json b/packages/react-native-gesture-handler/DrawerLayout/package.json
deleted file mode 100644
index 3e0e4a2fac..0000000000
--- a/packages/react-native-gesture-handler/DrawerLayout/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "main": "../lib/commonjs/components/DrawerLayout",
- "module": "../lib/module/components/DrawerLayout",
- "react-native": "../src/components/DrawerLayout",
- "types": "../lib/typescript/components/DrawerLayout.d.ts"
-}
diff --git a/packages/react-native-gesture-handler/Swipeable/package.json b/packages/react-native-gesture-handler/Swipeable/package.json
deleted file mode 100644
index ed038794ba..0000000000
--- a/packages/react-native-gesture-handler/Swipeable/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "main": "../lib/commonjs/components/Swipeable",
- "module": "../lib/module/components/Swipeable",
- "react-native": "../src/components/Swipeable",
- "types": "../lib/typescript/components/Swipeable.d.ts"
-}
diff --git a/packages/react-native-gesture-handler/package.json b/packages/react-native-gesture-handler/package.json
index d5769487c6..4af1062b40 100644
--- a/packages/react-native-gesture-handler/package.json
+++ b/packages/react-native-gesture-handler/package.json
@@ -42,10 +42,8 @@
"apple/",
"shared/",
"scripts/",
- "Swipeable/",
"ReanimatedSwipeable/",
"jest-utils/",
- "DrawerLayout/",
"ReanimatedDrawerLayout/",
"README.md",
"jestSetup.js",
diff --git a/packages/react-native-gesture-handler/src/components/DrawerLayout.tsx b/packages/react-native-gesture-handler/src/components/DrawerLayout.tsx
deleted file mode 100644
index a18150fe96..0000000000
--- a/packages/react-native-gesture-handler/src/components/DrawerLayout.tsx
+++ /dev/null
@@ -1,791 +0,0 @@
-// This component is based on RN's DrawerLayoutAndroid API
-//
-// It perhaps deserves to be put in a separate repo, but since it relies on
-// react-native-gesture-handler library which isn't very popular at the moment I
-// decided to keep it here for the time being. It will allow us to move faster
-// and fix issues that may arise in gesture handler library that could be found
-// when using the drawer component
-
-import * as React from 'react';
-import { Component } from 'react';
-import invariant from 'invariant';
-import {
- Animated,
- StyleSheet,
- View,
- Keyboard,
- StatusBar,
- I18nManager,
- StatusBarAnimation,
- StyleProp,
- ViewStyle,
- LayoutChangeEvent,
- NativeSyntheticEvent,
-} from 'react-native';
-
-import {
- GestureEvent,
- HandlerStateChangeEvent,
- UserSelect,
- ActiveCursor,
- MouseButton,
-} from '../handlers/gestureHandlerCommon';
-import { PanGestureHandler } from '../handlers/PanGestureHandler';
-import type {
- PanGestureHandlerEventPayload,
- TapGestureHandlerEventPayload,
-} from '../handlers/GestureHandlerEventPayload';
-import { TapGestureHandler } from '../handlers/TapGestureHandler';
-import { State } from '../State';
-
-const DRAG_TOSS = 0.05;
-
-const IDLE: DrawerState = 'Idle';
-const DRAGGING: DrawerState = 'Dragging';
-const SETTLING: DrawerState = 'Settling';
-
-/**
- * @deprecated DrawerLayout is deprecated. Use Reanimated version of DrawerLayout instead.
- */
-export type DrawerPosition = 'left' | 'right';
-
-/**
- * @deprecated DrawerLayout is deprecated. Use Reanimated version of DrawerLayout instead.
- */
-export type DrawerState = 'Idle' | 'Dragging' | 'Settling';
-
-/**
- * @deprecated DrawerLayout is deprecated. Use Reanimated version of DrawerLayout instead.
- */
-export type DrawerType = 'front' | 'back' | 'slide';
-
-/**
- * @deprecated DrawerLayout is deprecated. Use Reanimated version of DrawerLayout instead.
- */
-export type DrawerLockMode = 'unlocked' | 'locked-closed' | 'locked-open';
-
-/**
- * @deprecated DrawerLayout is deprecated. Use Reanimated version of DrawerLayout instead.
- */
-export type DrawerKeyboardDismissMode = 'none' | 'on-drag';
-
-// Animated.AnimatedInterpolation has been converted to a generic type
-// in @types/react-native 0.70. This way we can maintain compatibility
-// with all versions of @types/react-native`
-type AnimatedInterpolation = ReturnType;
-
-/**
- * @deprecated DrawerLayout is deprecated. Use Reanimated version of DrawerLayout instead.
- */
-export interface DrawerLayoutProps {
- /**
- * This attribute is present in the standard implementation already and is one
- * of the required params. Gesture handler version of DrawerLayout make it
- * possible for the function passed as `renderNavigationView` to take an
- * Animated value as a parameter that indicates the progress of drawer
- * opening/closing animation (progress value is 0 when closed and 1 when
- * opened). This can be used by the drawer component to animated its children
- * while the drawer is opening or closing.
- */
- renderNavigationView: (
- progressAnimatedValue: Animated.Value
- ) => React.ReactNode;
-
- drawerPosition?: DrawerPosition;
-
- drawerWidth?: number;
-
- drawerBackgroundColor?: string;
-
- drawerLockMode?: DrawerLockMode;
-
- keyboardDismissMode?: DrawerKeyboardDismissMode;
-
- /**
- * Called when the drawer is closed.
- */
- onDrawerClose?: () => void;
-
- /**
- * Called when the drawer is opened.
- */
- onDrawerOpen?: () => void;
-
- /**
- * Called when the status of the drawer changes.
- */
- onDrawerStateChanged?: (
- newState: DrawerState,
- drawerWillShow: boolean
- ) => void;
- useNativeAnimations?: boolean;
-
- drawerType?: DrawerType;
-
- /**
- * Defines how far from the edge of the content view the gesture should
- * activate.
- */
- edgeWidth?: number;
-
- minSwipeDistance?: number;
-
- /**
- * When set to true Drawer component will use
- * {@link https://reactnative.dev/docs/statusbar StatusBar} API to hide the OS
- * status bar whenever the drawer is pulled or when its in an "open" state.
- */
- hideStatusBar?: boolean;
-
- /**
- * @default 'slide'
- *
- * Can be used when hideStatusBar is set to true and will select the animation
- * used for hiding/showing the status bar. See
- * {@link https://reactnative.dev/docs/statusbar StatusBar} documentation for
- * more details
- */
- statusBarAnimation?: StatusBarAnimation;
-
- /**
- * @default black
- *
- * Color of a semi-transparent overlay to be displayed on top of the content
- * view when drawer gets open. A solid color should be used as the opacity is
- * added by the Drawer itself and the opacity of the overlay is animated (from
- * 0% to 70%).
- */
- overlayColor?: string;
-
- contentContainerStyle?: StyleProp;
-
- drawerContainerStyle?: StyleProp;
-
- /**
- * Enables two-finger gestures on supported devices, for example iPads with
- * trackpads. If not enabled the gesture will require click + drag, with
- * `enableTrackpadTwoFingerGesture` swiping with two fingers will also trigger
- * the gesture.
- */
- enableTrackpadTwoFingerGesture?: boolean;
-
- onDrawerSlide?: (position: number) => void;
-
- onGestureRef?: (ref: PanGestureHandler) => void;
-
- // Implicit `children` prop has been removed in @types/react^18.0.0
- children?:
- | React.ReactNode
- | ((openValue?: AnimatedInterpolation) => React.ReactNode);
-
- /**
- * @default 'none'
- * Defines which userSelect property should be used.
- * Values: 'none'|'text'|'auto'
- */
- userSelect?: UserSelect;
-
- /**
- * @default 'auto'
- * Defines which cursor property should be used when gesture activates.
- * Values: see CSS cursor values
- */
- activeCursor?: ActiveCursor;
-
- /**
- * @default 'MouseButton.LEFT'
- * Allows to choose which mouse button should underlying pan handler react to.
- */
- mouseButton?: MouseButton;
-
- /**
- * @default 'false if MouseButton.RIGHT is specified'
- * Allows to enable/disable context menu.
- */
- enableContextMenu?: boolean;
-}
-
-/**
- * @deprecated DrawerLayout is deprecated. Use Reanimated version of DrawerLayout instead.
- */
-export type DrawerLayoutState = {
- dragX: Animated.Value;
- touchX: Animated.Value;
- drawerTranslation: Animated.Value;
- containerWidth: number;
- drawerState: DrawerState;
- drawerOpened: boolean;
-};
-
-/**
- * @deprecated DrawerLayout is deprecated. Use Reanimated version of DrawerLayout instead.
- */
-export type DrawerMovementOption = {
- velocity?: number;
- speed?: number;
-};
-
-/**
- * @deprecated use Reanimated version of DrawerLayout instead
- */
-export default class DrawerLayout extends Component<
- DrawerLayoutProps,
- DrawerLayoutState
-> {
- static defaultProps = {
- drawerWidth: 200,
- drawerPosition: 'left',
- useNativeAnimations: true,
- drawerType: 'front',
- edgeWidth: 20,
- minSwipeDistance: 3,
- overlayColor: 'rgba(0, 0, 0, 0.7)',
- drawerLockMode: 'unlocked',
- enableTrackpadTwoFingerGesture: false,
- };
-
- constructor(props: DrawerLayoutProps) {
- super(props);
-
- const dragX = new Animated.Value(0);
- const touchX = new Animated.Value(0);
- const drawerTranslation = new Animated.Value(0);
-
- this.state = {
- dragX,
- touchX,
- drawerTranslation,
- containerWidth: 0,
- drawerState: IDLE,
- drawerOpened: false,
- };
-
- this.updateAnimatedEvent(props, this.state);
- }
-
- override shouldComponentUpdate(
- props: DrawerLayoutProps,
- state: DrawerLayoutState
- ) {
- if (
- this.props.drawerPosition !== props.drawerPosition ||
- this.props.drawerWidth !== props.drawerWidth ||
- this.props.drawerType !== props.drawerType ||
- this.state.containerWidth !== state.containerWidth
- ) {
- this.updateAnimatedEvent(props, state);
- }
-
- return true;
- }
-
- private openValue?: AnimatedInterpolation;
- private onGestureEvent?: (
- event: GestureEvent
- ) => void;
- private accessibilityIsModalView =
- React.createRef>();
- private pointerEventsView =
- React.createRef>();
- private panGestureHandler = React.createRef();
- private drawerShown = false;
-
- static positions = {
- Left: 'left',
- Right: 'right',
- };
-
- private updateAnimatedEvent = (
- props: DrawerLayoutProps,
- state: DrawerLayoutState
- ) => {
- // Event definition is based on
- const { drawerPosition, drawerWidth, drawerType } = props;
- const {
- dragX: dragXValue,
- touchX: touchXValue,
- drawerTranslation,
- containerWidth,
- } = state;
-
- let dragX = dragXValue;
- let touchX = touchXValue;
-
- if (drawerPosition !== 'left') {
- // Most of the code is written in a way to handle left-side drawer. In
- // order to handle right-side drawer the only thing we need to do is to
- // reverse events coming from gesture handler in a way they emulate
- // left-side drawer gestures. E.g. dragX is simply -dragX, and touchX is
- // calulcated by subtracing real touchX from the width of the container
- // (such that when touch happens at the right edge the value is simply 0)
- dragX = Animated.multiply(
- new Animated.Value(-1),
- dragXValue
- ) as Animated.Value; // TODO(TS): (for all "as" in this file) make sure we can map this
- touchX = Animated.add(
- new Animated.Value(containerWidth),
- Animated.multiply(new Animated.Value(-1), touchXValue)
- ) as Animated.Value; // TODO(TS): make sure we can map this;
- touchXValue.setValue(containerWidth);
- } else {
- touchXValue.setValue(0);
- }
-
- // While closing the drawer when user starts gesture outside of its area (in greyed
- // out part of the window), we want the drawer to follow only once finger reaches the
- // edge of the drawer.
- // E.g. on the diagram below drawer is illustrate by X signs and the greyed out area by
- // dots. The touch gesture starts at '*' and moves left, touch path is indicated by
- // an arrow pointing left
- // 1) +---------------+ 2) +---------------+ 3) +---------------+ 4) +---------------+
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|.<-*..| |XXXXXXXX|<--*..| |XXXXX|<-----*..|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // +---------------+ +---------------+ +---------------+ +---------------+
- //
- // For the above to work properly we define animated value that will keep
- // start position of the gesture. Then we use that value to calculate how
- // much we need to subtract from the dragX. If the gesture started on the
- // greyed out area we take the distance from the edge of the drawer to the
- // start position. Otherwise we don't subtract at all and the drawer be
- // pulled back as soon as you start the pan.
- //
- // This is used only when drawerType is "front"
- //
- let translationX = dragX;
- if (drawerType === 'front') {
- const startPositionX = Animated.add(
- touchX,
- Animated.multiply(new Animated.Value(-1), dragX)
- );
-
- const dragOffsetFromOnStartPosition = startPositionX.interpolate({
- inputRange: [drawerWidth! - 1, drawerWidth!, drawerWidth! + 1],
- outputRange: [0, 0, 1],
- });
- translationX = Animated.add(
- dragX,
- dragOffsetFromOnStartPosition
- ) as Animated.Value; // TODO: as above
- }
-
- this.openValue = Animated.add(translationX, drawerTranslation).interpolate({
- inputRange: [0, drawerWidth!],
- outputRange: [0, 1],
- extrapolate: 'clamp',
- });
-
- const gestureOptions: {
- useNativeDriver: boolean;
- // TODO: make sure it is correct
- listener?: (
- ev: NativeSyntheticEvent
- ) => void;
- } = {
- useNativeDriver: props.useNativeAnimations!,
- };
-
- if (this.props.onDrawerSlide) {
- gestureOptions.listener = (ev) => {
- const translationX = Math.floor(Math.abs(ev.nativeEvent.translationX));
- const position = translationX / this.state.containerWidth;
-
- this.props.onDrawerSlide?.(position);
- };
- }
-
- this.onGestureEvent = Animated.event(
- [{ nativeEvent: { translationX: dragXValue, x: touchXValue } }],
- gestureOptions
- );
- };
-
- private handleContainerLayout = ({ nativeEvent }: LayoutChangeEvent) => {
- this.setState({ containerWidth: nativeEvent.layout.width });
- };
-
- private emitStateChanged = (
- newState: DrawerState,
- drawerWillShow: boolean
- ) => {
- this.props.onDrawerStateChanged?.(newState, drawerWillShow);
- };
-
- private openingHandlerStateChange = ({
- nativeEvent,
- }: HandlerStateChangeEvent) => {
- if (nativeEvent.oldState === State.ACTIVE) {
- this.handleRelease({ nativeEvent });
- } else if (nativeEvent.state === State.ACTIVE) {
- this.emitStateChanged(DRAGGING, false);
- this.setState({ drawerState: DRAGGING });
- if (this.props.keyboardDismissMode === 'on-drag') {
- Keyboard.dismiss();
- }
- if (this.props.hideStatusBar) {
- StatusBar.setHidden(true, this.props.statusBarAnimation || 'slide');
- }
- }
- };
-
- private onTapHandlerStateChange = ({
- nativeEvent,
- }: HandlerStateChangeEvent) => {
- if (
- this.drawerShown &&
- nativeEvent.oldState === State.ACTIVE &&
- this.props.drawerLockMode !== 'locked-open'
- ) {
- this.closeDrawer();
- }
- };
-
- private handleRelease = ({
- nativeEvent,
- }: HandlerStateChangeEvent) => {
- const { drawerWidth, drawerPosition, drawerType } = this.props;
- const { containerWidth } = this.state;
- let { translationX: dragX, velocityX, x: touchX } = nativeEvent;
-
- if (drawerPosition !== 'left') {
- // See description in _updateAnimatedEvent about why events are flipped
- // for right-side drawer
- dragX = -dragX;
- touchX = containerWidth - touchX;
- velocityX = -velocityX;
- }
-
- const gestureStartX = touchX - dragX;
- let dragOffsetBasedOnStart = 0;
-
- if (drawerType === 'front') {
- dragOffsetBasedOnStart =
- gestureStartX > drawerWidth! ? gestureStartX - drawerWidth! : 0;
- }
-
- const startOffsetX =
- dragX + dragOffsetBasedOnStart + (this.drawerShown ? drawerWidth! : 0);
- const projOffsetX = startOffsetX + DRAG_TOSS * velocityX;
-
- const shouldOpen = projOffsetX > drawerWidth! / 2;
-
- if (shouldOpen) {
- this.animateDrawer(startOffsetX, drawerWidth!, velocityX);
- } else {
- this.animateDrawer(startOffsetX, 0, velocityX);
- }
- };
-
- private updateShowing = (showing: boolean) => {
- this.drawerShown = showing;
- this.accessibilityIsModalView.current?.setNativeProps({
- accessibilityViewIsModal: showing,
- });
- this.pointerEventsView.current?.setNativeProps({
- pointerEvents: showing ? 'auto' : 'none',
- });
- const { drawerPosition, minSwipeDistance, edgeWidth } = this.props;
- const fromLeft = drawerPosition === 'left';
- // gestureOrientation is 1 if the expected gesture is from left to right and
- // -1 otherwise e.g. when drawer is on the left and is closed we expect left
- // to right gesture, thus orientation will be 1.
- const gestureOrientation =
- (fromLeft ? 1 : -1) * (this.drawerShown ? -1 : 1);
- // When drawer is closed we want the hitSlop to be horizontally shorter than
- // the container size by the value of SLOP. This will make it only activate
- // when gesture happens not further than SLOP away from the edge
- const hitSlop = fromLeft
- ? { left: 0, width: showing ? undefined : edgeWidth }
- : { right: 0, width: showing ? undefined : edgeWidth };
- // @ts-ignore internal API, maybe could be fixed in handler types
- this.panGestureHandler.current?.setNativeProps({
- hitSlop,
- activeOffsetX: gestureOrientation * minSwipeDistance!,
- });
- };
-
- private animateDrawer = (
- fromValue: number | null | undefined,
- toValue: number,
- velocity: number,
- speed?: number
- ) => {
- this.state.dragX.setValue(0);
- this.state.touchX.setValue(
- this.props.drawerPosition === 'left' ? 0 : this.state.containerWidth
- );
-
- if (fromValue != null) {
- let nextFramePosition = fromValue;
- if (this.props.useNativeAnimations) {
- // When using native driver, we predict the next position of the
- // animation because it takes one frame of a roundtrip to pass RELEASE
- // event from native driver to JS before we can start animating. Without
- // it, it is more noticable that the frame is dropped.
- if (fromValue < toValue && velocity > 0) {
- nextFramePosition = Math.min(fromValue + velocity / 60.0, toValue);
- } else if (fromValue > toValue && velocity < 0) {
- nextFramePosition = Math.max(fromValue + velocity / 60.0, toValue);
- }
- }
- this.state.drawerTranslation.setValue(nextFramePosition);
- }
-
- const willShow = toValue !== 0;
- this.updateShowing(willShow);
- this.emitStateChanged(SETTLING, willShow);
- this.setState({ drawerState: SETTLING });
- if (this.props.hideStatusBar) {
- StatusBar.setHidden(willShow, this.props.statusBarAnimation || 'slide');
- }
- Animated.spring(this.state.drawerTranslation, {
- velocity,
- bounciness: 0,
- toValue,
- useNativeDriver: this.props.useNativeAnimations!,
- speed: speed ?? undefined,
- }).start(({ finished }) => {
- if (finished) {
- this.emitStateChanged(IDLE, willShow);
- this.setState({ drawerOpened: willShow });
- if (this.state.drawerState !== DRAGGING) {
- // It's possilbe that user started drag while the drawer
- // was settling, don't override state in this case
- this.setState({ drawerState: IDLE });
- }
- if (willShow) {
- this.props.onDrawerOpen?.();
- } else {
- this.props.onDrawerClose?.();
- }
- }
- });
- };
-
- // eslint-disable-next-line @eslint-react/no-unused-class-component-members
- openDrawer = (options: DrawerMovementOption = {}) => {
- this.animateDrawer(
- // TODO: decide if it should be null or undefined is the proper value
- undefined,
- this.props.drawerWidth!,
- options.velocity ? options.velocity : 0,
- options.speed
- );
-
- // We need to force the update, otherwise the overlay is not rerendered and
- // it would not be clickable
- this.forceUpdate();
- };
-
- closeDrawer = (options: DrawerMovementOption = {}) => {
- // TODO: decide if it should be null or undefined is the proper value
- this.animateDrawer(
- undefined,
- 0,
- options.velocity ? options.velocity : 0,
- options.speed
- );
-
- // We need to force the update, otherwise the overlay is not rerendered and
- // it would be still clickable
- this.forceUpdate();
- };
-
- private renderOverlay = () => {
- /* Overlay styles */
- invariant(this.openValue, 'should be set');
- let overlayOpacity;
-
- if (this.state.drawerState !== IDLE) {
- overlayOpacity = this.openValue;
- } else {
- overlayOpacity = this.state.drawerOpened ? 1 : 0;
- }
-
- const dynamicOverlayStyles = {
- opacity: overlayOpacity,
- backgroundColor: this.props.overlayColor,
- };
-
- return (
-
-
-
- );
- };
-
- private renderDrawer = () => {
- const {
- drawerBackgroundColor,
- drawerWidth,
- drawerPosition,
- drawerType,
- drawerContainerStyle,
- contentContainerStyle,
- } = this.props;
-
- const fromLeft = drawerPosition === 'left';
- const drawerSlide = drawerType !== 'back';
- const containerSlide = drawerType !== 'front';
-
- // We rely on row and row-reverse flex directions to position the drawer
- // properly. Apparently for RTL these are flipped which requires us to use
- // the opposite setting for the drawer to appear from left or right
- // according to the drawerPosition prop
- const reverseContentDirection = I18nManager.isRTL ? fromLeft : !fromLeft;
-
- const dynamicDrawerStyles = {
- backgroundColor: drawerBackgroundColor,
- width: drawerWidth,
- };
- const openValue = this.openValue;
- invariant(openValue, 'should be set');
-
- let containerStyles;
- if (containerSlide) {
- const containerTranslateX = openValue.interpolate({
- inputRange: [0, 1],
- outputRange: fromLeft ? [0, drawerWidth!] : [0, -drawerWidth!],
- extrapolate: 'clamp',
- });
- containerStyles = {
- transform: [{ translateX: containerTranslateX }],
- };
- }
-
- let drawerTranslateX: number | AnimatedInterpolation = 0;
- if (drawerSlide) {
- const closedDrawerOffset = fromLeft ? -drawerWidth! : drawerWidth!;
- if (this.state.drawerState !== IDLE) {
- drawerTranslateX = openValue.interpolate({
- inputRange: [0, 1],
- outputRange: [closedDrawerOffset, 0],
- extrapolate: 'clamp',
- });
- } else {
- drawerTranslateX = this.state.drawerOpened ? 0 : closedDrawerOffset;
- }
- }
- const drawerStyles: {
- transform: { translateX: number | AnimatedInterpolation }[];
- flexDirection: 'row-reverse' | 'row';
- } = {
- transform: [{ translateX: drawerTranslateX }],
- flexDirection: reverseContentDirection ? 'row-reverse' : 'row',
- };
-
- return (
-
-
- {typeof this.props.children === 'function'
- ? this.props.children(this.openValue)
- : this.props.children}
- {this.renderOverlay()}
-
-
-
- {this.props.renderNavigationView(this.openValue as Animated.Value)}
-
-
-
- );
- };
-
- private setPanGestureRef = (ref: PanGestureHandler) => {
- // TODO(TS): make sure it is OK taken from
- // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31065#issuecomment-596081842
- (
- this.panGestureHandler as React.MutableRefObject
- ).current = ref;
- this.props.onGestureRef?.(ref);
- };
-
- override render() {
- const { drawerPosition, drawerLockMode, edgeWidth, minSwipeDistance } =
- this.props;
-
- const fromLeft = drawerPosition === 'left';
-
- // gestureOrientation is 1 if the expected gesture is from left to right and
- // -1 otherwise e.g. when drawer is on the left and is closed we expect left
- // to right gesture, thus orientation will be 1.
- const gestureOrientation =
- (fromLeft ? 1 : -1) * (this.drawerShown ? -1 : 1);
-
- // When drawer is closed we want the hitSlop to be horizontally shorter than
- // the container size by the value of SLOP. This will make it only activate
- // when gesture happens not further than SLOP away from the edge
- const hitSlop = fromLeft
- ? { left: 0, width: this.drawerShown ? undefined : edgeWidth }
- : { right: 0, width: this.drawerShown ? undefined : edgeWidth };
-
- return (
-
- {this.renderDrawer()}
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- drawerContainer: {
- ...StyleSheet.absoluteFillObject,
- zIndex: 1001,
- flexDirection: 'row',
- },
- containerInFront: {
- ...StyleSheet.absoluteFillObject,
- zIndex: 1002,
- },
- containerOnBack: {
- ...StyleSheet.absoluteFillObject,
- },
- main: {
- flex: 1,
- zIndex: 0,
- overflow: 'hidden',
- },
- overlay: {
- ...StyleSheet.absoluteFillObject,
- zIndex: 1000,
- },
-});
diff --git a/packages/react-native-gesture-handler/src/components/Swipeable.tsx b/packages/react-native-gesture-handler/src/components/Swipeable.tsx
deleted file mode 100644
index 66abd0d47b..0000000000
--- a/packages/react-native-gesture-handler/src/components/Swipeable.tsx
+++ /dev/null
@@ -1,595 +0,0 @@
-// Similarily to the DrawerLayout component this deserves to be put in a
-// separate repo. Although, keeping it here for the time being will allow us to
-// move faster and fix possible issues quicker
-
-import * as React from 'react';
-import { Component } from 'react';
-import {
- Animated,
- StyleSheet,
- View,
- I18nManager,
- LayoutChangeEvent,
- StyleProp,
- ViewStyle,
-} from 'react-native';
-
-import {
- GestureEvent,
- HandlerStateChangeEvent,
-} from '../handlers/gestureHandlerCommon';
-import {
- PanGestureHandler,
- PanGestureHandlerProps,
-} from '../handlers/PanGestureHandler';
-import {
- PanGestureHandlerEventPayload,
- TapGestureHandlerEventPayload,
-} from '../handlers/GestureHandlerEventPayload';
-import { TapGestureHandler } from '../handlers/TapGestureHandler';
-import { State } from '../State';
-
-const DRAG_TOSS = 0.05;
-
-type SwipeableExcludes = Exclude<
- keyof PanGestureHandlerProps,
- 'onGestureEvent' | 'onHandlerStateChange'
->;
-
-// Animated.AnimatedInterpolation has been converted to a generic type
-// in @types/react-native 0.70. This way we can maintain compatibility
-// with all versions of @types/react-native
-type AnimatedInterpolation = ReturnType;
-
-export interface SwipeableProps
- extends Pick {
- /**
- * Enables two-finger gestures on supported devices, for example iPads with
- * trackpads. If not enabled the gesture will require click + drag, with
- * `enableTrackpadTwoFingerGesture` swiping with two fingers will also trigger
- * the gesture.
- */
- enableTrackpadTwoFingerGesture?: boolean;
-
- /**
- * Specifies how much the visual interaction will be delayed compared to the
- * gesture distance. e.g. value of 1 will indicate that the swipeable panel
- * should exactly follow the gesture, 2 means it is going to be two times
- * "slower".
- */
- friction?: number;
-
- /**
- * Distance from the left edge at which released panel will animate to the
- * open state (or the open panel will animate into the closed state). By
- * default it's a half of the panel's width.
- */
- leftThreshold?: number;
-
- /**
- * Distance from the right edge at which released panel will animate to the
- * open state (or the open panel will animate into the closed state). By
- * default it's a half of the panel's width.
- */
- rightThreshold?: number;
-
- /**
- * Distance that the panel must be dragged from the left edge to be considered
- * a swipe. The default value is 10.
- */
- dragOffsetFromLeftEdge?: number;
-
- /**
- * Distance that the panel must be dragged from the right edge to be considered
- * a swipe. The default value is 10.
- */
- dragOffsetFromRightEdge?: number;
-
- /**
- * Value indicating if the swipeable panel can be pulled further than the left
- * actions panel's width. It is set to true by default as long as the left
- * panel render method is present.
- */
- overshootLeft?: boolean;
-
- /**
- * Value indicating if the swipeable panel can be pulled further than the
- * right actions panel's width. It is set to true by default as long as the
- * right panel render method is present.
- */
- overshootRight?: boolean;
-
- /**
- * Specifies how much the visual interaction will be delayed compared to the
- * gesture distance at overshoot. Default value is 1, it mean no friction, for
- * a native feel, try 8 or above.
- */
- overshootFriction?: number;
-
- /**
- * @deprecated Use `direction` argument of onSwipeableOpen()
- *
- * Called when left action panel gets open.
- */
- onSwipeableLeftOpen?: () => void;
-
- /**
- * @deprecated Use `direction` argument of onSwipeableOpen()
- *
- * Called when right action panel gets open.
- */
- onSwipeableRightOpen?: () => void;
-
- /**
- * Called when action panel gets open (either right or left).
- */
- onSwipeableOpen?: (direction: 'left' | 'right', swipeable: Swipeable) => void;
-
- /**
- * Called when action panel is closed.
- */
- onSwipeableClose?: (
- direction: 'left' | 'right',
- swipeable: Swipeable
- ) => void;
-
- /**
- * @deprecated Use `direction` argument of onSwipeableWillOpen()
- *
- * Called when left action panel starts animating on open.
- */
- onSwipeableLeftWillOpen?: () => void;
-
- /**
- * @deprecated Use `direction` argument of onSwipeableWillOpen()
- *
- * Called when right action panel starts animating on open.
- */
- onSwipeableRightWillOpen?: () => void;
-
- /**
- * Called when action panel starts animating on open (either right or left).
- */
- onSwipeableWillOpen?: (direction: 'left' | 'right') => void;
-
- /**
- * Called when action panel starts animating on close.
- */
- onSwipeableWillClose?: (direction: 'left' | 'right') => void;
-
- /**
- * Called when action panel starts being shown on dragging to open.
- */
- onSwipeableOpenStartDrag?: (direction: 'left' | 'right') => void;
-
- /**
- * Called when action panel starts being shown on dragging to close.
- */
- onSwipeableCloseStartDrag?: (direction: 'left' | 'right') => void;
-
- /**
- *
- * This map describes the values to use as inputRange for extra interpolation:
- * AnimatedValue: [startValue, endValue]
- *
- * progressAnimatedValue: [0, 1] dragAnimatedValue: [0, +]
- *
- * To support `rtl` flexbox layouts use `flexDirection` styling.
- * */
- renderLeftActions?: (
- progressAnimatedValue: AnimatedInterpolation,
- dragAnimatedValue: AnimatedInterpolation,
- swipeable: Swipeable
- ) => React.ReactNode;
- /**
- *
- * This map describes the values to use as inputRange for extra interpolation:
- * AnimatedValue: [startValue, endValue]
- *
- * progressAnimatedValue: [0, 1] dragAnimatedValue: [0, -]
- *
- * To support `rtl` flexbox layouts use `flexDirection` styling.
- * */
- renderRightActions?: (
- progressAnimatedValue: AnimatedInterpolation,
- dragAnimatedValue: AnimatedInterpolation,
- swipeable: Swipeable
- ) => React.ReactNode;
-
- useNativeAnimations?: boolean;
-
- animationOptions?: Record;
-
- /**
- * Style object for the container (`Animated.View`), for example to override
- * `overflow: 'hidden'`.
- */
- containerStyle?: StyleProp;
-
- /**
- * Style object for the children container (`Animated.View`), for example to
- * apply `flex: 1`
- */
- childrenContainerStyle?: StyleProp;
-}
-
-type SwipeableState = {
- dragX: Animated.Value;
- rowTranslation: Animated.Value;
- rowState: number;
- leftWidth?: number;
- rightOffset?: number;
- rowWidth?: number;
-};
-
-/**
- * @deprecated use Reanimated version of Swipeable instead
- *
- * This component allows for implementing swipeable rows or similar interaction.
- */
-
-export default class Swipeable extends Component<
- SwipeableProps,
- SwipeableState
-> {
- static defaultProps = {
- friction: 1,
- overshootFriction: 1,
- useNativeAnimations: true,
- };
-
- constructor(props: SwipeableProps) {
- super(props);
- const dragX = new Animated.Value(0);
- this.state = {
- dragX,
- rowTranslation: new Animated.Value(0),
- rowState: 0,
- leftWidth: undefined,
- rightOffset: undefined,
- rowWidth: undefined,
- };
- this.updateAnimatedEvent(props, this.state);
-
- this.onGestureEvent = Animated.event(
- [{ nativeEvent: { translationX: dragX } }],
- { useNativeDriver: props.useNativeAnimations! }
- );
- }
-
- override shouldComponentUpdate(props: SwipeableProps, state: SwipeableState) {
- if (
- this.props.friction !== props.friction ||
- this.props.overshootLeft !== props.overshootLeft ||
- this.props.overshootRight !== props.overshootRight ||
- this.props.overshootFriction !== props.overshootFriction ||
- this.state.leftWidth !== state.leftWidth ||
- this.state.rightOffset !== state.rightOffset ||
- this.state.rowWidth !== state.rowWidth
- ) {
- this.updateAnimatedEvent(props, state);
- }
-
- return true;
- }
-
- private onGestureEvent?: (
- event: GestureEvent
- ) => void;
- private transX?: AnimatedInterpolation;
- private showLeftAction?: AnimatedInterpolation | Animated.Value;
- private leftActionTranslate?: AnimatedInterpolation;
- private showRightAction?: AnimatedInterpolation | Animated.Value;
- private rightActionTranslate?: AnimatedInterpolation;
-
- private updateAnimatedEvent = (
- props: SwipeableProps,
- state: SwipeableState
- ) => {
- const { friction, overshootFriction } = props;
- const { dragX, rowTranslation, leftWidth = 0, rowWidth = 0 } = state;
- const { rightOffset = rowWidth } = state;
- const rightWidth = Math.max(0, rowWidth - rightOffset);
-
- const { overshootLeft = leftWidth > 0, overshootRight = rightWidth > 0 } =
- props;
-
- const transX = Animated.add(
- rowTranslation,
- dragX.interpolate({
- inputRange: [0, friction!],
- outputRange: [0, 1],
- })
- ).interpolate({
- inputRange: [-rightWidth - 1, -rightWidth, leftWidth, leftWidth + 1],
- outputRange: [
- -rightWidth - (overshootRight ? 1 / overshootFriction! : 0),
- -rightWidth,
- leftWidth,
- leftWidth + (overshootLeft ? 1 / overshootFriction! : 0),
- ],
- });
- this.transX = transX;
- this.showLeftAction =
- leftWidth > 0
- ? transX.interpolate({
- inputRange: [-1, 0, leftWidth],
- outputRange: [0, 0, 1],
- })
- : new Animated.Value(0);
- this.leftActionTranslate = this.showLeftAction.interpolate({
- inputRange: [0, Number.MIN_VALUE],
- outputRange: [-10000, 0],
- extrapolate: 'clamp',
- });
- this.showRightAction =
- rightWidth > 0
- ? transX.interpolate({
- inputRange: [-rightWidth, 0, 1],
- outputRange: [1, 0, 0],
- })
- : new Animated.Value(0);
- this.rightActionTranslate = this.showRightAction.interpolate({
- inputRange: [0, Number.MIN_VALUE],
- outputRange: [-10000, 0],
- extrapolate: 'clamp',
- });
- };
-
- private onTapHandlerStateChange = ({
- nativeEvent,
- }: HandlerStateChangeEvent) => {
- if (nativeEvent.oldState === State.ACTIVE) {
- this.close();
- }
- };
-
- private onHandlerStateChange = (
- ev: HandlerStateChangeEvent
- ) => {
- if (ev.nativeEvent.oldState === State.ACTIVE) {
- this.handleRelease(ev);
- }
-
- if (ev.nativeEvent.state === State.ACTIVE) {
- const { velocityX, translationX: dragX } = ev.nativeEvent;
- const { rowState } = this.state;
- const { friction } = this.props;
-
- const translationX = (dragX + DRAG_TOSS * velocityX) / friction!;
-
- const direction =
- rowState === -1
- ? 'right'
- : rowState === 1
- ? 'left'
- : translationX > 0
- ? 'left'
- : 'right';
-
- if (rowState === 0) {
- this.props.onSwipeableOpenStartDrag?.(direction);
- } else {
- this.props.onSwipeableCloseStartDrag?.(direction);
- }
- }
- };
-
- private handleRelease = (
- ev: HandlerStateChangeEvent
- ) => {
- const { velocityX, translationX: dragX } = ev.nativeEvent;
- const { leftWidth = 0, rowWidth = 0, rowState } = this.state;
- const { rightOffset = rowWidth } = this.state;
- const rightWidth = rowWidth - rightOffset;
- const {
- friction,
- leftThreshold = leftWidth / 2,
- rightThreshold = rightWidth / 2,
- } = this.props;
-
- const startOffsetX = this.currentOffset() + dragX / friction!;
- const translationX = (dragX + DRAG_TOSS * velocityX) / friction!;
-
- let toValue = 0;
- if (rowState === 0) {
- if (translationX > leftThreshold) {
- toValue = leftWidth;
- } else if (translationX < -rightThreshold) {
- toValue = -rightWidth;
- }
- } else if (rowState === 1) {
- // Swiped to left
- if (translationX > -leftThreshold) {
- toValue = leftWidth;
- }
- } else {
- // Swiped to right
- if (translationX < rightThreshold) {
- toValue = -rightWidth;
- }
- }
-
- this.animateRow(startOffsetX, toValue, velocityX / friction!);
- };
-
- private animateRow = (
- fromValue: number,
- toValue: number,
- velocityX?:
- | number
- | {
- x: number;
- y: number;
- }
- ) => {
- const { dragX, rowTranslation } = this.state;
- dragX.setValue(0);
- rowTranslation.setValue(fromValue);
-
- this.setState({ rowState: Math.sign(toValue) });
- Animated.spring(rowTranslation, {
- restSpeedThreshold: 1.7,
- restDisplacementThreshold: 0.4,
- velocity: velocityX,
- bounciness: 0,
- toValue,
- useNativeDriver: this.props.useNativeAnimations!,
- ...this.props.animationOptions,
- }).start(({ finished }) => {
- if (finished) {
- if (toValue > 0) {
- this.props.onSwipeableLeftOpen?.();
- this.props.onSwipeableOpen?.('left', this);
- } else if (toValue < 0) {
- this.props.onSwipeableRightOpen?.();
- this.props.onSwipeableOpen?.('right', this);
- } else {
- const closingDirection = fromValue > 0 ? 'left' : 'right';
- this.props.onSwipeableClose?.(closingDirection, this);
- }
- }
- });
- if (toValue > 0) {
- this.props.onSwipeableLeftWillOpen?.();
- this.props.onSwipeableWillOpen?.('left');
- } else if (toValue < 0) {
- this.props.onSwipeableRightWillOpen?.();
- this.props.onSwipeableWillOpen?.('right');
- } else {
- const closingDirection = fromValue > 0 ? 'left' : 'right';
- this.props.onSwipeableWillClose?.(closingDirection);
- }
- };
-
- private onRowLayout = ({ nativeEvent }: LayoutChangeEvent) => {
- this.setState({ rowWidth: nativeEvent.layout.width });
- };
-
- private currentOffset = () => {
- const { leftWidth = 0, rowWidth = 0, rowState } = this.state;
- const { rightOffset = rowWidth } = this.state;
- const rightWidth = rowWidth - rightOffset;
- if (rowState === 1) {
- return leftWidth;
- } else if (rowState === -1) {
- return -rightWidth;
- }
- return 0;
- };
-
- close = () => {
- this.animateRow(this.currentOffset(), 0);
- };
-
- // eslint-disable-next-line @eslint-react/no-unused-class-component-members
- openLeft = () => {
- const { leftWidth = 0 } = this.state;
- this.animateRow(this.currentOffset(), leftWidth);
- };
-
- // eslint-disable-next-line @eslint-react/no-unused-class-component-members
- openRight = () => {
- const { rowWidth = 0 } = this.state;
- const { rightOffset = rowWidth } = this.state;
- const rightWidth = rowWidth - rightOffset;
- this.animateRow(this.currentOffset(), -rightWidth);
- };
-
- // eslint-disable-next-line @eslint-react/no-unused-class-component-members
- reset = () => {
- const { dragX, rowTranslation } = this.state;
- dragX.setValue(0);
- rowTranslation.setValue(0);
- this.setState({ rowState: 0 });
- };
-
- override render() {
- const { rowState } = this.state;
- const {
- children,
- renderLeftActions,
- renderRightActions,
- dragOffsetFromLeftEdge = 10,
- dragOffsetFromRightEdge = 10,
- } = this.props;
-
- const left = renderLeftActions && (
-
- {renderLeftActions(this.showLeftAction!, this.transX!, this)}
-
- this.setState({ leftWidth: nativeEvent.layout.x })
- }
- />
-
- );
-
- const right = renderRightActions && (
-
- {renderRightActions(this.showRightAction!, this.transX!, this)}
-
- this.setState({ rightOffset: nativeEvent.layout.x })
- }
- />
-
- );
-
- return (
-
-
- {left}
- {right}
-
-
- {children}
-
-
-
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- container: {
- overflow: 'hidden',
- },
- leftActions: {
- ...StyleSheet.absoluteFillObject,
- flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row',
- },
- rightActions: {
- ...StyleSheet.absoluteFillObject,
- flexDirection: I18nManager.isRTL ? 'row' : 'row-reverse',
- },
-});
diff --git a/packages/react-native-gesture-handler/src/index.ts b/packages/react-native-gesture-handler/src/index.ts
index 8c9d8b0ef3..a6c170e1fd 100644
--- a/packages/react-native-gesture-handler/src/index.ts
+++ b/packages/react-native-gesture-handler/src/index.ts
@@ -144,24 +144,12 @@ export type {
BorderlessButtonProperties,
} from './handlers/gestureHandlerTypesCompat';
-export type { SwipeableProps } from './components/Swipeable';
-export { default as Swipeable } from './components/Swipeable';
export type {
PressableProps,
PressableStateCallbackType,
} from './components/Pressable';
export { default as Pressable } from './components/Pressable';
-export type {
- DrawerLayoutProps,
- DrawerPosition,
- DrawerState,
- DrawerType,
- DrawerLockMode,
- DrawerKeyboardDismissMode,
-} from './components/DrawerLayout';
-export { default as DrawerLayout } from './components/DrawerLayout';
-
export type { NativeDetectorProps } from './v3/NativeDetector/NativeDetector';
export { NativeDetector } from './v3/NativeDetector/NativeDetector';