refactor(components): simplify SwipeableRow gesture handling and add vertical scroll conflict prevention
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { View, Text, Pressable, Animated, StyleSheet } from "react-native";
|
import { View, Text, Pressable, Animated, StyleSheet } from "react-native";
|
||||||
import { PanGestureHandler, State } from "react-native-gesture-handler";
|
import { PanGestureHandler, State, PanGestureHandlerGestureEvent } from "react-native-gesture-handler";
|
||||||
|
|
||||||
type SwipeableRowProps = {
|
type SwipeableRowProps = {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
@@ -8,37 +8,33 @@ type SwipeableRowProps = {
|
|||||||
deleteLabel?: string;
|
deleteLabel?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const MAX_LEFT = -80;
|
||||||
|
|
||||||
export function SwipeableRow({ children, onDelete, deleteLabel = "Delete" }: SwipeableRowProps) {
|
export function SwipeableRow({ children, onDelete, deleteLabel = "Delete" }: SwipeableRowProps) {
|
||||||
const translateX = useRef(new Animated.Value(0)).current;
|
const translateX = useRef(new Animated.Value(0)).current;
|
||||||
const lastOffset = useRef(0);
|
const offset = useRef(0);
|
||||||
|
|
||||||
const onGestureEvent = Animated.event([{ nativeEvent: { translationX: translateX } }], {
|
const onGestureEvent = (event: PanGestureHandlerGestureEvent) => {
|
||||||
useNativeDriver: true,
|
const raw = event.nativeEvent.translationX;
|
||||||
});
|
const clamped = Math.max(MAX_LEFT, Math.min(0, offset.current + raw));
|
||||||
|
translateX.setValue(clamped);
|
||||||
|
};
|
||||||
|
|
||||||
const onHandlerStateChange = (event: any) => {
|
const onHandlerStateChange = (event: PanGestureHandlerGestureEvent) => {
|
||||||
if (event.oldState === State.ACTIVE) {
|
if (event.oldState === State.ACTIVE) {
|
||||||
const { translationX } = event.nativeEvent;
|
const { translationX } = event.nativeEvent;
|
||||||
const clampedTranslation = Math.min(0, translationX);
|
const final = Math.max(MAX_LEFT, Math.min(0, offset.current + translationX));
|
||||||
const newOffset = lastOffset.current + clampedTranslation;
|
|
||||||
|
|
||||||
if (newOffset < -80) {
|
|
||||||
Animated.spring(translateX, {
|
Animated.spring(translateX, {
|
||||||
toValue: -80,
|
toValue: final,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}).start();
|
}).start();
|
||||||
lastOffset.current = -80;
|
offset.current = final;
|
||||||
} else {
|
|
||||||
Animated.spring(translateX, {
|
|
||||||
toValue: 0,
|
|
||||||
useNativeDriver: true,
|
|
||||||
}).start();
|
|
||||||
lastOffset.current = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
|
offset.current = -400;
|
||||||
Animated.timing(translateX, {
|
Animated.timing(translateX, {
|
||||||
toValue: -400,
|
toValue: -400,
|
||||||
duration: 200,
|
duration: 200,
|
||||||
@@ -58,6 +54,7 @@ export function SwipeableRow({ children, onDelete, deleteLabel = "Delete" }: Swi
|
|||||||
<PanGestureHandler
|
<PanGestureHandler
|
||||||
onGestureEvent={onGestureEvent}
|
onGestureEvent={onGestureEvent}
|
||||||
onHandlerStateChange={onHandlerStateChange}
|
onHandlerStateChange={onHandlerStateChange}
|
||||||
|
failOffsetY={[-5, 5]}
|
||||||
>
|
>
|
||||||
<Animated.View style={[styles.foreground, { transform: [{ translateX }] }]}>
|
<Animated.View style={[styles.foreground, { transform: [{ translateX }] }]}>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
Reference in New Issue
Block a user