import { useRef } from "react"; import { View, Text, Pressable, Animated, StyleSheet } from "react-native"; import { PanGestureHandler, State, PanGestureHandlerGestureEvent, PanGestureHandlerStateChangeEvent } from "react-native-gesture-handler"; type SwipeableRowProps = { children: React.ReactNode; onDelete: () => void; deleteLabel?: string; }; const MAX_LEFT = -80; export function SwipeableRow({ children, onDelete, deleteLabel = "Delete" }: SwipeableRowProps) { const translateX = useRef(new Animated.Value(0)).current; const offset = useRef(0); const onGestureEvent = (event: PanGestureHandlerGestureEvent) => { const raw = event.nativeEvent.translationX; const clamped = Math.max(MAX_LEFT, Math.min(0, offset.current + raw)); translateX.setValue(clamped); }; const onHandlerStateChange = (event: PanGestureHandlerStateChangeEvent) => { if (event.nativeEvent.oldState === State.ACTIVE) { const { translationX } = event.nativeEvent; const final = Math.max(MAX_LEFT, Math.min(0, offset.current + translationX)); Animated.spring(translateX, { toValue: final, useNativeDriver: true, }).start(); offset.current = final; } }; const handleDelete = () => { offset.current = -400; Animated.timing(translateX, { toValue: -400, duration: 200, useNativeDriver: true, }).start(() => { onDelete(); }); }; return ( {deleteLabel} {children} ); } const styles = StyleSheet.create({ container: { marginBottom: 12, }, deleteBackground: { position: "absolute", right: 0, top: 0, bottom: 0, width: 80, borderRadius: 16, backgroundColor: "#ef4444", justifyContent: "center", alignItems: "center", }, deleteButton: { flex: 1, justifyContent: "center", alignItems: "center", width: "100%", }, deleteText: { color: "white", fontWeight: "600", fontSize: 13, }, foreground: { backgroundColor: "white", borderRadius: 16, }, });