Skip to content

Instantly share code, notes, and snippets.

@AlexeyTsutsoev
Created March 16, 2023 08:13
Show Gist options
  • Save AlexeyTsutsoev/2647e4b0160ce45d08678de31b339fba to your computer and use it in GitHub Desktop.
Save AlexeyTsutsoev/2647e4b0160ce45d08678de31b339fba to your computer and use it in GitHub Desktop.
Custom Pressable component
import React, { FC, useCallback } from 'react';
import {
GestureResponderEvent,
Pressable as PressableBase,
PressableProps,
StyleProp,
ViewStyle,
} from 'react-native';
import Animated, {
useSharedValue,
withTiming,
interpolate,
Easing,
useAnimatedStyle,
} from 'react-native-reanimated';
import { lightImpact } from '@shared/lib/utils';
type Props = PressableProps & {
style?: StyleProp<ViewStyle>;
/**
* flag for enabling impact
*/
withFeedback?: boolean;
};
const Pressable = Animated.createAnimatedComponent(PressableBase);
/**
* Wrapper on `Pressable` from `react-native`
* Provide scale animation when press and light impact when press out if `withFeedback` enabled
*/
export const AnimatedPressable: FC<Props> = ({
onPressIn,
onPressOut,
children,
style,
withFeedback,
...rest
}: Props) => {
const pressed = useSharedValue(0);
const onPressInDecorator = useCallback(
(event: GestureResponderEvent) => {
pressed.value = withTiming(1, { duration: 150 });
if (onPressIn) {
onPressIn(event);
}
},
[pressed, onPressIn],
);
const onPressOutDecorator = useCallback(
(event: GestureResponderEvent) => {
pressed.value = withTiming(0, { duration: 250, easing: Easing.ease });
if (onPressOut) {
onPressOut(event);
}
if (withFeedback) {
lightImpact();
}
},
[pressed, onPressOut],
);
const animatedStyles = useAnimatedStyle(() => {
return {
transform: [
{
scale: interpolate(pressed.value, [0, 1], [1, 0.98]),
},
],
opacity: interpolate(
pressed.value,
[0, 1],
[1, 0.6],
Animated.Extrapolate.CLAMP,
),
};
});
return (
<Pressable
onPressIn={onPressInDecorator}
onPressOut={onPressOutDecorator}
{...rest}
style={[animatedStyles, style]}>
{children}
</Pressable>
);
};
/**
* template function for a simple weak impact
*/
export const lightImpact = () => {
if (Platform.OS !== 'ios') {
return;
}
HapticFeedback.trigger('impactLight');
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment