Files
SwimBuddy/src/components/SwipeableRow.tsx
T

98 lines
2.5 KiB
TypeScript

import { useRef } from "react";
import { View, Text, Pressable, Animated, StyleSheet } from "react-native";
import { PanGestureHandler, State, PanGestureHandlerGestureEvent } 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: PanGestureHandlerGestureEvent) => {
if (event.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 (
<View style={styles.container}>
<View style={styles.deleteBackground}>
<Pressable onPress={handleDelete} style={styles.deleteButton}>
<Text style={styles.deleteText}>{deleteLabel}</Text>
</Pressable>
</View>
<PanGestureHandler
onGestureEvent={onGestureEvent}
onHandlerStateChange={onHandlerStateChange}
failOffsetY={[-5, 5]}
>
<Animated.View style={[styles.foreground, { transform: [{ translateX }] }]}>
{children}
</Animated.View>
</PanGestureHandler>
</View>
);
}
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,
},
});