55 lines
1.4 KiB
TypeScript
55 lines
1.4 KiB
TypeScript
import React from 'react';
|
|
import { Pressable, PressableProps } from 'react-native';
|
|
import Animated, {
|
|
useAnimatedStyle,
|
|
useSharedValue,
|
|
withSpring,
|
|
} from 'react-native-reanimated';
|
|
import { triggerHaptic } from '@/utils/haptics';
|
|
|
|
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
|
|
|
|
interface PressableScaleProps extends PressableProps {
|
|
haptic?: 'light' | 'medium' | 'selection';
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
export default function PressableScale({
|
|
haptic = 'light',
|
|
children,
|
|
style,
|
|
onPress,
|
|
...props
|
|
}: PressableScaleProps) {
|
|
const scale = useSharedValue(1);
|
|
const translateY = useSharedValue(0);
|
|
|
|
const animatedStyle = useAnimatedStyle(() => ({
|
|
transform: [
|
|
{ scale: scale.value },
|
|
{ translateY: translateY.value },
|
|
],
|
|
}));
|
|
|
|
return (
|
|
<AnimatedPressable
|
|
onPressIn={() => {
|
|
scale.value = withSpring(0.97, { damping: 15, stiffness: 150 });
|
|
translateY.value = withSpring(-2, { damping: 15, stiffness: 150 });
|
|
}}
|
|
onPressOut={() => {
|
|
scale.value = withSpring(1, { damping: 15, stiffness: 150 });
|
|
translateY.value = withSpring(0, { damping: 15, stiffness: 150 });
|
|
}}
|
|
onPress={(e) => {
|
|
triggerHaptic(haptic);
|
|
onPress?.(e);
|
|
}}
|
|
style={[animatedStyle, style as any]}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</AnimatedPressable>
|
|
);
|
|
}
|