From 65a829f9648045353da52b00bdc0ef8c95785e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Tue, 19 Nov 2024 17:21:06 +0100 Subject: [PATCH 01/11] remove all legacy swipeable references --- Swipeable/package.json | 6 - example/App.tsx | 2 - .../swipeableReanimation/index.tsx | 68 +- .../swipeable/AppleStyleSwipeableRow.tsx | 123 ---- .../swipeable/GmailStyleSwipeableRow.tsx | 90 --- example/src/showcase/swipeable/index.tsx | 141 ----- package.json | 1 - src/components/Swipeable.tsx | 592 ------------------ src/index.ts | 2 - 9 files changed, 1 insertion(+), 1024 deletions(-) delete mode 100644 Swipeable/package.json delete mode 100644 example/src/showcase/swipeable/AppleStyleSwipeableRow.tsx delete mode 100644 example/src/showcase/swipeable/GmailStyleSwipeableRow.tsx delete mode 100644 example/src/showcase/swipeable/index.tsx delete mode 100644 src/components/Swipeable.tsx diff --git a/Swipeable/package.json b/Swipeable/package.json deleted file mode 100644 index ed038794ba..0000000000 --- a/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/example/App.tsx b/example/App.tsx index 9e9dfb6957..913b0dfc5b 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -43,7 +43,6 @@ import TwoFingerPan from './src/release_tests/twoFingerPan'; 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'; @@ -157,7 +156,6 @@ const EXAMPLES: ExamplesSection[] = [ sectionTitle: 'Showcase', data: [ { name: 'Bottom sheet', component: BottomSheet }, - { name: 'Swipeables', component: Swipeables }, { name: 'Chat heads', component: ChatHeads }, ], }, diff --git a/example/src/release_tests/swipeableReanimation/index.tsx b/example/src/release_tests/swipeableReanimation/index.tsx index 25d49536c8..72417220f4 100644 --- a/example/src/release_tests/swipeableReanimation/index.tsx +++ b/example/src/release_tests/swipeableReanimation/index.tsx @@ -1,8 +1,7 @@ import React, { useRef } from 'react'; -import { Text, Animated, StyleSheet, View } from 'react-native'; +import { Text, StyleSheet, View } from 'react-native'; import { - Swipeable, GestureHandlerRootView, Pressable, } from 'react-native-gesture-handler'; @@ -48,55 +47,8 @@ function RightAction(prog: SharedValue, drag: SharedValue) { ); } -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 ( @@ -109,7 +61,6 @@ export default function Example() { style={styles.control} onPress={() => { reanimatedRef.current!.openLeft(); - legacyRef.current?.openLeft(); }}> open left @@ -117,7 +68,6 @@ export default function Example() { style={styles.control} onPress={() => { reanimatedRef.current!.close(); - legacyRef.current!.close(); }}> close @@ -125,7 +75,6 @@ export default function Example() { style={styles.control} onPress={() => { reanimatedRef.current!.reset(); - legacyRef.current!.reset(); }}> reset @@ -133,7 +82,6 @@ export default function Example() { style={styles.control} onPress={() => { reanimatedRef.current!.openRight(); - legacyRef.current!.openRight(); }}> open right @@ -155,20 +103,6 @@ export default function Example() { - - - [Legacy] Swipe me! - - - ); } diff --git a/example/src/showcase/swipeable/AppleStyleSwipeableRow.tsx b/example/src/showcase/swipeable/AppleStyleSwipeableRow.tsx deleted file mode 100644 index 0b4ea549b2..0000000000 --- a/example/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/example/src/showcase/swipeable/GmailStyleSwipeableRow.tsx b/example/src/showcase/swipeable/GmailStyleSwipeableRow.tsx deleted file mode 100644 index 1504c50a70..0000000000 --- a/example/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/example/src/showcase/swipeable/index.tsx b/example/src/showcase/swipeable/index.tsx deleted file mode 100644 index 5c6da6b892..0000000000 --- a/example/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/package.json b/package.json index 9b36680056..14f2451fb7 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,6 @@ "android/reanimated/src/main/java/", "android/noreanimated/src/main/java/", "apple/", - "Swipeable/", "ReanimatedSwipeable/", "jest-utils/", "DrawerLayout/", diff --git a/src/components/Swipeable.tsx b/src/components/Swipeable.tsx deleted file mode 100644 index 593ab59740..0000000000 --- a/src/components/Swipeable.tsx +++ /dev/null @@ -1,592 +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! } - ); - } - - 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); - }; - - openLeft = () => { - const { leftWidth = 0 } = this.state; - this.animateRow(this.currentOffset(), leftWidth); - }; - - openRight = () => { - const { rowWidth = 0 } = this.state; - const { rightOffset = rowWidth } = this.state; - const rightWidth = rowWidth - rightOffset; - this.animateRow(this.currentOffset(), -rightWidth); - }; - - reset = () => { - const { dragX, rowTranslation } = this.state; - dragX.setValue(0); - rowTranslation.setValue(0); - this.setState({ rowState: 0 }); - }; - - 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/src/index.ts b/src/index.ts index d636ad1a7a..2c5304f80e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -142,8 +142,6 @@ export type { BorderlessButtonProperties, } from './handlers/gestureHandlerTypesCompat'; -export type { SwipeableProps } from './components/Swipeable'; -export { default as Swipeable } from './components/Swipeable'; export type { PressableProps } from './components/Pressable'; export { default as Pressable } from './components/Pressable'; From 1bc1f513a876e42c91322d12032b4d43675c792a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Wed, 20 Nov 2024 11:06:09 +0100 Subject: [PATCH 02/11] remove legacy drawer layout and it's references --- DrawerLayout/package.json | 6 - example/App.tsx | 2 - example/src/basic/horizontalDrawer/index.tsx | 194 ----- .../new_api/betterHorizontalDrawer/index.tsx | 4 +- package.json | 1 - src/components/DrawerLayout.tsx | 756 ------------------ src/index.ts | 10 - 7 files changed, 3 insertions(+), 970 deletions(-) delete mode 100644 DrawerLayout/package.json delete mode 100644 example/src/basic/horizontalDrawer/index.tsx delete mode 100644 src/components/DrawerLayout.tsx diff --git a/DrawerLayout/package.json b/DrawerLayout/package.json deleted file mode 100644 index 3e0e4a2fac..0000000000 --- a/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/example/App.tsx b/example/App.tsx index 913b0dfc5b..28306907ff 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -48,7 +48,6 @@ 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'; @@ -131,7 +130,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, diff --git a/example/src/basic/horizontalDrawer/index.tsx b/example/src/basic/horizontalDrawer/index.tsx deleted file mode 100644 index a99ba85ba2..0000000000 --- a/example/src/basic/horizontalDrawer/index.tsx +++ /dev/null @@ -1,194 +0,0 @@ -import React, { Component } from 'react'; -import { - Platform, - StyleSheet, - Text, - Animated, - View, - TextInput, -} from 'react-native'; - -import { RectButton } from 'react-native-gesture-handler'; - -import { 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/example/src/new_api/betterHorizontalDrawer/index.tsx b/example/src/new_api/betterHorizontalDrawer/index.tsx index c2f7008a8e..f704ff269a 100644 --- a/example/src/new_api/betterHorizontalDrawer/index.tsx +++ b/example/src/new_api/betterHorizontalDrawer/index.tsx @@ -2,7 +2,7 @@ import React, { useRef, useState } from 'react'; import { StyleSheet, Text, View, TextInput } from 'react-native'; -import { DrawerType, RectButton } from 'react-native-gesture-handler'; +import { RectButton } from 'react-native-gesture-handler'; import { DrawerLayoutController, DrawerLayout, @@ -12,6 +12,8 @@ import Animated, { interpolate, } from 'react-native-reanimated'; +type DrawerType = 'front' | 'back' | 'back' | 'slide'; + const TYPES: DrawerType[] = ['front', 'back', 'back', 'slide']; const PARALLAX = [false, false, true, false]; diff --git a/package.json b/package.json index 14f2451fb7..cc0a891c8a 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,6 @@ "apple/", "ReanimatedSwipeable/", "jest-utils/", - "DrawerLayout/", "ReanimatedDrawerLayout/", "README.md", "jestSetup.js", diff --git a/src/components/DrawerLayout.tsx b/src/components/DrawerLayout.tsx deleted file mode 100644 index 5708e30d9d..0000000000 --- a/src/components/DrawerLayout.tsx +++ /dev/null @@ -1,756 +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'; - -export type DrawerPosition = 'left' | 'right'; - -export type DrawerState = 'Idle' | 'Dragging' | 'Settling'; - -export type DrawerType = 'front' | 'back' | 'slide'; - -export type DrawerLockMode = 'unlocked' | 'locked-closed' | 'locked-open'; - -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; -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; -} - -export type DrawerLayoutState = { - dragX: Animated.Value; - touchX: Animated.Value; - drawerTranslation: Animated.Value; - containerWidth: number; - drawerState: DrawerState; - drawerOpened: boolean; -}; - -export type DrawerMovementOption = { - velocity?: number; - speed?: number; -}; -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); - } - - 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?.(); - } - } - }); - }; - - 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); - }; - - 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/src/index.ts b/src/index.ts index 2c5304f80e..0539142ce4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -145,16 +145,6 @@ export type { export type { PressableProps } 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 { enableExperimentalWebImplementation, enableLegacyWebImplementation, From ac1873d202de30426d490aeec2f754469da0e1ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Wed, 20 Nov 2024 11:11:54 +0100 Subject: [PATCH 03/11] fix DrawerType definition --- example/src/new_api/betterHorizontalDrawer/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/src/new_api/betterHorizontalDrawer/index.tsx b/example/src/new_api/betterHorizontalDrawer/index.tsx index f704ff269a..ead8e3c84f 100644 --- a/example/src/new_api/betterHorizontalDrawer/index.tsx +++ b/example/src/new_api/betterHorizontalDrawer/index.tsx @@ -12,7 +12,7 @@ import Animated, { interpolate, } from 'react-native-reanimated'; -type DrawerType = 'front' | 'back' | 'back' | 'slide'; +type DrawerType = 'front' | 'back' | 'slide'; const TYPES: DrawerType[] = ['front', 'back', 'back', 'slide']; const PARALLAX = [false, false, true, false]; From 06aa9100f4d648d88c4a642f7f850a1dc4dc877a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Wed, 20 Nov 2024 11:54:16 +0100 Subject: [PATCH 04/11] remove obsolete drawer layout implementation draft --- example/App.tsx | 5 - .../BetterHorizonatalDrawer.tsx | 627 ------------------ .../new_api/betterHorizontalDrawer/index.tsx | 164 ----- 3 files changed, 796 deletions(-) delete mode 100644 example/src/new_api/betterHorizontalDrawer/BetterHorizonatalDrawer.tsx delete mode 100644 example/src/new_api/betterHorizontalDrawer/index.tsx diff --git a/example/App.tsx b/example/App.tsx index 28306907ff..7ea20a8771 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -62,7 +62,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 +112,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, diff --git a/example/src/new_api/betterHorizontalDrawer/BetterHorizonatalDrawer.tsx b/example/src/new_api/betterHorizontalDrawer/BetterHorizonatalDrawer.tsx deleted file mode 100644 index 950505b7d8..0000000000 --- a/example/src/new_api/betterHorizontalDrawer/BetterHorizonatalDrawer.tsx +++ /dev/null @@ -1,627 +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 = React.forwardRef< - DrawerLayoutController, - BetterDrawerLayoutProps ->( - ( - { - 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 - ) => { - 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') { - ref(controller); - } else { - 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/example/src/new_api/betterHorizontalDrawer/index.tsx b/example/src/new_api/betterHorizontalDrawer/index.tsx deleted file mode 100644 index ead8e3c84f..0000000000 --- a/example/src/new_api/betterHorizontalDrawer/index.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import React, { useRef, useState } from 'react'; - -import { StyleSheet, Text, View, TextInput } from 'react-native'; - -import { RectButton } from 'react-native-gesture-handler'; -import { - DrawerLayoutController, - DrawerLayout, -} from './BetterHorizonatalDrawer'; -import Animated, { - useAnimatedStyle, - interpolate, -} from 'react-native-reanimated'; - -type DrawerType = 'front' | 'back' | 'slide'; - -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', - }, -}); From ad0ff9cdc2fc6abadfff01f537e8961d8e8ae1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Thu, 28 Nov 2024 11:51:20 +0100 Subject: [PATCH 05/11] remove docs pages referencing removed compoenents --- docs/docs/components/drawer-layout.mdx | 170 ------------------- docs/docs/components/swipeable.md | 226 ------------------------- 2 files changed, 396 deletions(-) delete mode 100644 docs/docs/components/drawer-layout.mdx delete mode 100644 docs/docs/components/swipeable.md diff --git a/docs/docs/components/drawer-layout.mdx b/docs/docs/components/drawer-layout.mdx deleted file mode 100644 index 5652ab1822..0000000000 --- a/docs/docs/components/drawer-layout.mdx +++ /dev/null @@ -1,170 +0,0 @@ ---- -id: drawer-layout -title: Drawer Layout -sidebar_label: DrawerLayout ---- - -import useBaseUrl from '@docusaurus/useBaseUrl'; -import GifGallery from '@site/components/GifGallery'; - -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/docs/docs/components/swipeable.md b/docs/docs/components/swipeable.md deleted file mode 100644 index da9bbc5593..0000000000 --- a/docs/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/example/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" - - ); - } -} -``` From 46a4c4b51398af3418e34e4bd203616c1747c019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Thu, 28 Nov 2024 11:57:42 +0100 Subject: [PATCH 06/11] remove another draft of swipeable component --- example/App.tsx | 2 - example/src/release_tests/combo/index.tsx | 35 +-- example/src/release_tests/rows/index.tsx | 283 ---------------------- 3 files changed, 5 insertions(+), 315 deletions(-) delete mode 100644 example/src/release_tests/rows/index.tsx diff --git a/example/App.tsx b/example/App.tsx index 7ea20a8771..e673a1bcdd 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -29,7 +29,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'; @@ -178,7 +177,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', diff --git a/example/src/release_tests/combo/index.tsx b/example/src/release_tests/combo/index.tsx index 30ac11b9d0..4a1eaa02d8 100644 --- a/example/src/release_tests/combo/index.tsx +++ b/example/src/release_tests/combo/index.tsx @@ -7,6 +7,7 @@ import { View, Alert, TouchableHighlightProps as RNTouchableHighlightProps, + Button, } from 'react-native'; import { @@ -21,7 +22,8 @@ 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'; @@ -174,41 +176,14 @@ class Combo extends Component { Alert.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). */} - +