import { useAnimatedValueXY } from 'react-native';
import { useRef } from 'react';
import { Animated, PanResponder, Dimensions } from 'react-native';
function SwipeableCard({ onDismiss }: { onDismiss: () => void }) {
const position = useAnimatedValueXY({ x: 0, y: 0 });
const { width } = Dimensions.get('window');
const SWIPE_THRESHOLD = width * 0.4;
const panResponder = useRef(
PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: Animated.event(
[null, { dx: position.x, dy: position.y }],
{ useNativeDriver: false }
),
onPanResponderRelease: (_, gesture) => {
if (Math.abs(gesture.dx) > SWIPE_THRESHOLD) {
// Swipe off screen
Animated.timing(position, {
toValue: { x: gesture.dx > 0 ? width : -width, y: gesture.dy },
duration: 250,
useNativeDriver: false,
}).start(onDismiss);
} else {
// Return to center
Animated.spring(position, {
toValue: { x: 0, y: 0 },
useNativeDriver: false,
}).start();
}
},
})
).current;
const rotate = position.x.interpolate({
inputRange: [-width / 2, 0, width / 2],
outputRange: ['-10deg', '0deg', '10deg'],
extrapolate: 'clamp',
});
return (
<Animated.View
{...panResponder.panHandlers}
style={{
transform: [...position.getTranslateTransform(), { rotate }],
width: 300,
height: 400,
backgroundColor: 'white',
borderRadius: 16,
shadowColor: '#000',
shadowOpacity: 0.2,
shadowRadius: 8,
elevation: 4,
}}
/>
);
}