Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/components/GestureButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ import type {
BorderlessButtonWithRefProps,
BorderlessButtonProps,
} from './GestureButtonsProps';
import { isFabric } from '../utils';

export const RawButton = createNativeWrapper(GestureHandlerButton, {
shouldCancelWhenOutside: false,
shouldActivateOnStart: false,
});

let IS_FABRIC: null | boolean = null;

class InnerBaseButton extends React.Component<BaseButtonWithRefProps> {
static defaultProps = {
delayLongPress: 600,
Expand Down Expand Up @@ -120,12 +123,20 @@ class InnerBaseButton extends React.Component<BaseButtonWithRefProps> {
};

render() {
const { rippleColor, style, ...rest } = this.props;
const { rippleColor: unprocessedRippleColor, style, ...rest } = this.props;

if (IS_FABRIC === null) {
IS_FABRIC = isFabric();
}

const rippleColor = IS_FABRIC
? unprocessedRippleColor
: processColor(unprocessedRippleColor ?? undefined);

return (
<RawButton
ref={this.props.innerRef}
rippleColor={processColor(rippleColor)}
rippleColor={rippleColor}
style={[style, Platform.OS === 'ios' && { cursor: undefined }]}
{...rest}
onGestureEvent={this.onGestureEvent}
Expand Down
9 changes: 7 additions & 2 deletions src/components/GestureButtonsProps.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import * as React from 'react';
import { AccessibilityProps, StyleProp, ViewStyle } from 'react-native';
import {
AccessibilityProps,
ColorValue,
StyleProp,
ViewStyle,
} from 'react-native';
import type { NativeViewGestureHandlerProps } from '../handlers/NativeViewGestureHandler';

export interface RawButtonProps
Expand All @@ -16,7 +21,7 @@ export interface RawButtonProps
*
* Defines color of native ripple animation used since API level 21.
*/
rippleColor?: any; // it was present in BaseButtonProps before but is used here in code
rippleColor?: number | ColorValue | null;

/**
* Android only.
Expand Down
20 changes: 16 additions & 4 deletions src/components/Pressable/Pressable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ import {
} from './utils';
import { PressabilityDebugView } from '../../handlers/PressabilityDebugView';
import { GestureTouchEvent } from '../../handlers/gestureHandlerCommon';
import { INT32_MAX, isTestEnv } from '../../utils';
import { INT32_MAX, isFabric, isTestEnv } from '../../utils';

const DEFAULT_LONG_PRESS_DURATION = 500;
const IS_TEST_ENV = isTestEnv();

let IS_FABRIC: null | boolean = null;

export default function Pressable(props: PressableProps) {
const {
testOnly_pressed,
Expand Down Expand Up @@ -367,8 +369,6 @@ export default function Pressable(props: PressableProps) {

const gesture = Gesture.Simultaneous(...gestures);

const defaultRippleColor = android_ripple ? undefined : 'transparent';

// `cursor: 'pointer'` on `RNButton` crashes iOS
const pointerStyle: StyleProp<ViewStyle> =
Platform.OS === 'web' ? { cursor: 'pointer' } : {};
Expand All @@ -381,6 +381,18 @@ export default function Pressable(props: PressableProps) {
? children({ pressed: pressedState })
: children;

const rippleColor = useMemo(() => {
if (IS_FABRIC === null) {
IS_FABRIC = isFabric();
}

const defaultRippleColor = android_ripple ? undefined : 'transparent';
const unprocessedRippleColor = android_ripple?.color ?? defaultRippleColor;
Comment on lines +389 to +390
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be

const unprocessedRippleColor = android_ripple?.color ?? 'transparent';

?

I don't really see the point of defaultRippleColor in that case.

Copy link
Member Author

@latekvo latekvo Feb 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defaultRippleColor is required to properly replicate the behaviour of RN Pressable.
When android_ripple is set, but the color field is not provided, we want to set color to undefined, so that it uses the default system value (opaque whiteish).
When android_ripple is not set, we want to remove the ripple altogether, which is done via 'transparent'.

return IS_FABRIC
? unprocessedRippleColor
: processColor(unprocessedRippleColor);
}, [android_ripple]);

return (
<GestureDetector gesture={gesture}>
<NativeButton
Expand All @@ -389,7 +401,7 @@ export default function Pressable(props: PressableProps) {
hitSlop={appliedHitSlop}
enabled={isPressableEnabled}
touchSoundDisabled={android_disableSound ?? undefined}
rippleColor={processColor(android_ripple?.color ?? defaultRippleColor)}
rippleColor={rippleColor}
rippleRadius={android_ripple?.radius ?? undefined}
style={[pointerStyle, styleProp]}
testOnly_onPress={IS_TEST_ENV ? onPress : undefined}
Expand Down
Loading