import React, { forwardRef, memo, useMemo } from 'react'; import { BackgroundPropType, Platform, Pressable, StyleProp, StyleSheet, TouchableNativeFeedback, TouchableWithoutFeedback, View, ViewStyle, } from 'react-native'; import { withUnistyles } from 'react-native-unistyles'; import { touchableRippleStyles } from './utils'; const ANDROID_VERSION_LOLLIPOP = 21; const ANDROID_VERSION_PIE = 28; type Props = React.ComponentProps & { borderless?: boolean; background?: BackgroundPropType; disabled?: boolean; onPress?: () => void | null; rippleColor?: string; underlayColor?: string; children: React.ReactNode; style?: StyleProp; }; const TouchableRipple = ( { style, background, borderless = false, disabled: disabledProp, rippleColor: rippleColorProp, underlayColor: underlayColorProp, children, ...rest }: Props, ref: any, ) => { const disabled = disabledProp || !rest.onPress; const componentStyles = touchableRippleStyles; const { rippleColor, underlayColor, containerStyle } = useMemo(() => { return { rippleColor: rippleColorProp, underlayColor: underlayColorProp || rippleColorProp, containerStyle: [borderless && styles.borderless, componentStyles.root, style], }; }, [borderless, componentStyles.root, rippleColorProp, style, underlayColorProp]); // A workaround for ripple on Android P is to use useForeground + overflow: 'hidden' // https://github.com/facebook/react-native/issues/6480 const useForeground = Platform.OS === 'android' && Platform.Version >= ANDROID_VERSION_PIE && borderless; if (TouchableRipple.supported) { return ( {React.Children.only(children)} ); } return ( [ containerStyle, pressed && { backgroundColor: underlayColor }, ]}> {React.Children.only(children)} ); }; const styles = StyleSheet.create({ borderless: { overflow: 'hidden', }, }); TouchableRipple.supported = Platform.OS === 'android' && Platform.Version >= ANDROID_VERSION_LOLLIPOP; export default memo( withUnistyles(forwardRef(TouchableRipple), theme => ({ rippleColor: theme.colors.onSurfaceRipple, })), );