react-native-pressable-scale
Version:
A <PressableScale> and a supercharged <NativePressableScale> components for React Native
47 lines (46 loc) • 2.1 kB
JavaScript
import React, { useCallback, useMemo } from 'react';
import { TouchableWithoutFeedback, View } from 'react-native';
import Reanimated, { useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
const ReanimatedTouchableWithoutFeedback = Reanimated.createAnimatedComponent(TouchableWithoutFeedback);
/**
* A Pressable that scales down when pressed. Uses the JS Pressability API.
*/
export function PressableScale(props) {
const { activeScale = 0.95, weight = 'heavy', damping = 15, stiffness = 150, overshootClamping = true, restSpeedThreshold = 0.001, restDisplacementThreshold = 0.001, style, onPressIn: _onPressIn, onPressOut: _onPressOut, delayPressIn = 0, children, ...passThroughProps } = props;
const mass = useMemo(() => {
switch (weight) {
case 'light':
return 0.15;
case 'medium':
return 0.2;
case 'heavy':
default:
return 0.3;
}
}, [weight]);
const isPressedIn = useSharedValue(false);
const springConfig = useMemo(() => ({
damping,
mass,
stiffness,
overshootClamping,
restSpeedThreshold,
restDisplacementThreshold,
}), [damping, mass, overshootClamping, restDisplacementThreshold, restSpeedThreshold, stiffness]);
const touchableStyle = useAnimatedStyle(() => ({ transform: [{ scale: withSpring(isPressedIn.value ? activeScale : 1, springConfig) }] }), [
activeScale,
isPressedIn,
springConfig,
]);
const onPressIn = useCallback((event) => {
isPressedIn.value = true;
_onPressIn?.(event);
}, [_onPressIn, isPressedIn]);
const onPressOut = useCallback((event) => {
isPressedIn.value = false;
_onPressOut?.(event);
}, [_onPressOut, isPressedIn]);
return (<ReanimatedTouchableWithoutFeedback delayPressIn={delayPressIn} onPressIn={onPressIn} onPressOut={onPressOut} style={touchableStyle} {...passThroughProps}>
<View style={style}>{children}</View>
</ReanimatedTouchableWithoutFeedback>);
}