react-native-ui-lib
Version:
<p align="center"> <img src="https://user-images.githubusercontent.com/1780255/105469025-56759000-5ca0-11eb-993d-3568c1fd54f4.png" height="250px" style="display:block"/> </p> <p align="center">UI Toolset & Components Library for React Native</p> <p a
114 lines (108 loc) • 3.69 kB
JavaScript
import React, { useCallback, useMemo } from 'react';
import Reanimated, { useAnimatedGestureHandler, useAnimatedStyle, useSharedValue, withTiming, interpolate, interpolateColor, runOnJS } from 'react-native-reanimated';
import { TapGestureHandler, LongPressGestureHandler } from 'react-native-gesture-handler';
import { asBaseComponent, forwardRef } from "../commons/new";
import View from "../components/view";
import { Colors } from "../../src/style";
/**
* @description: a Better, enhanced TouchableOpacity component
* @modifiers: flex, margin, padding, background
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/incubatorScreens/TouchableOpacityScreen.js
*/
function TouchableOpacity(props) {
const {
children,
modifiers,
style,
disabled,
forwardedRef,
feedbackColor,
activeOpacity = 0.2,
activeScale = 1,
...others
} = props;
const {
borderRadius,
paddings,
margins,
alignments,
flexStyle
} = modifiers;
const isActive = useSharedValue(0);
/* This flag is for fixing an issue with long press triggering twice
TODO: Consider revisiting this issue to see if it still occurs */
const isLongPressed = useSharedValue(false);
const backgroundColor = useMemo(() => {
return props.backgroundColor || modifiers.backgroundColor || Colors.transparent;
}, [props.backgroundColor, modifiers.backgroundColor]);
const onPress = useCallback(() => {
props.onPress?.(props);
}, [props.onPress, props.customValue]);
const onLongPress = useCallback(() => {
props.onLongPress?.(props);
}, [props.onLongPress, props.customValue]);
const toggleActive = value => {
'worklet';
isActive.value = withTiming(value, {
duration: 200
});
};
const tapGestureHandler = useAnimatedGestureHandler({
onStart: () => {
toggleActive(1);
},
onEnd: () => {
toggleActive(0);
runOnJS(onPress)();
},
onFail: () => {
if (!isLongPressed.value) {
toggleActive(0);
}
}
});
const longPressGestureHandler = useAnimatedGestureHandler({
onActive: () => {
if (!isLongPressed.value) {
isLongPressed.value = true;
runOnJS(onLongPress)();
}
},
onFinish: () => {
toggleActive(0);
isLongPressed.value = false;
}
});
const animatedStyle = useAnimatedStyle(() => {
const activeColor = feedbackColor || backgroundColor;
const opacity = interpolate(isActive.value, [0, 1], [1, activeOpacity]);
const scale = interpolate(isActive.value, [0, 1], [1, activeScale]);
return {
backgroundColor: !feedbackColor ? backgroundColor : interpolateColor(isActive.value, [0, 1], [backgroundColor, activeColor]),
opacity,
transform: [{
scale
}]
};
}, [backgroundColor, feedbackColor]);
const Container = props.onLongPress ? LongPressGestureHandler : View;
return <TapGestureHandler // @ts-expect-error
onGestureEvent={tapGestureHandler} shouldCancelWhenOutside enabled={!disabled}>
<Reanimated.View>
{
/* @ts-expect-error */
}
<Container onGestureEvent={longPressGestureHandler} shouldCancelWhenOutside>
<Reanimated.View {...others} ref={forwardedRef} style={[borderRadius && {
borderRadius
}, flexStyle, paddings, margins, alignments, {
backgroundColor
}, style, animatedStyle]}>
{children}
</Reanimated.View>
</Container>
</Reanimated.View>
</TapGestureHandler>;
}
TouchableOpacity.displayName = 'Incubator.TouchableOpacity';
export default asBaseComponent(forwardRef(TouchableOpacity));