react-native-pressable-opacity
Version:
A <PressableOpacity> and a supercharged <NativePressableOpacity> components for React Native
48 lines (47 loc) • 2.04 kB
JavaScript
import React, { useMemo } from 'react';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Reanimated, { withDelay, Easing, useAnimatedStyle, useSharedValue, withTiming, useDerivedValue, runOnJS, } from 'react-native-reanimated';
import { PRESSABLE_IN_LIST_DELAY } from './Constants';
/**
* A Pressable that lowers opacity when pressed. Uses the native responder system from react-native-gesture-handler instead of the JS Pressability API.
*/
export function NativePressableOpacity(props) {
const { activeOpacity = 0.2, isInList, duration = 50, easing = Easing.linear, disabled = false, disabledOpacity = 0.3, ref, style, onPress, ...passThroughProps } = props;
const isPressed = useSharedValue(false);
const timingConfig = useMemo(() => ({ duration, easing }), [duration, easing]);
const opacity = useDerivedValue(() => {
if (disabled) {
return withTiming(disabledOpacity, timingConfig);
}
else {
if (isPressed.value) {
if (isInList) {
return withDelay(PRESSABLE_IN_LIST_DELAY, withTiming(activeOpacity, timingConfig));
}
else {
return withTiming(activeOpacity, timingConfig);
}
}
else {
return withTiming(1, timingConfig);
}
}
}, [disabled, disabledOpacity, timingConfig, isPressed, isInList, activeOpacity]);
const animatedStyle = useAnimatedStyle(() => ({ opacity: opacity.value }), [opacity]);
let tap = Gesture.Tap()
.onStart(() => {
isPressed.value = true;
})
.onEnd(() => {
runOnJS(onPress)();
})
.onFinalize(() => {
isPressed.value = false;
}).enabled(!disabled).shouldCancelWhenOutside(true);
if (ref != null) {
tap = tap.withRef(ref);
}
return (<GestureDetector gesture={tap}>
<Reanimated.View style={[style, animatedStyle]} {...passThroughProps}/>
</GestureDetector>);
}