From 40b4e11efb4bef0417cf2e2f14df5bc17253f8da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Tue, 20 Aug 2024 14:04:08 +0200 Subject: [PATCH] Forward unused props in `ReanimatedSwipeable` and `Pressable` to their inner components (#3039) ## Description Currently large portion of the props accepted by `ReanimatedSwipeable` and `Pressable` components remain unused. This issue mostly refers to all the `accessibility` props. This PR adds the use of `spread` operator to `ReanimatedSwipeable` and `Pressable` to forward all the remaining props to inner components, which are not explicitly used otherwise. Fixes: #3032 ## Test plan - turn on radio description - open the nested `Pressable` example - add `accessibilityLabel` prop to one of the `Pressables` - navigate over the modified `Pressable` with your keyboard (use `Tab` and `Shift-Tab` to navigate) - hear as your label is being read out, which wouldn't occur without this change --- src/components/Pressable/Pressable.tsx | 109 ++++++++++++++----------- src/components/ReanimatedSwipeable.tsx | 97 +++++++++++++--------- 2 files changed, 119 insertions(+), 87 deletions(-) diff --git a/src/components/Pressable/Pressable.tsx b/src/components/Pressable/Pressable.tsx index 5c77e56c05..9315b55ab9 100644 --- a/src/components/Pressable/Pressable.tsx +++ b/src/components/Pressable/Pressable.tsx @@ -27,9 +27,29 @@ import { INT32_MAX } from '../../utils'; const DEFAULT_LONG_PRESS_DURATION = 500; export default function Pressable(props: PressableProps) { - const [pressedState, setPressedState] = useState( - props.testOnly_pressed ?? false - ); + const { + testOnly_pressed, + hitSlop, + pressRetentionOffset, + delayHoverIn, + onHoverIn, + delayHoverOut, + onHoverOut, + delayLongPress, + unstable_pressDelay, + onPress, + onPressIn, + onPressOut, + onLongPress, + style, + children, + android_disableSound, + android_ripple, + disabled, + ...remainingProps + } = props; + + const [pressedState, setPressedState] = useState(testOnly_pressed ?? false); const pressableRef = useRef(null); @@ -40,18 +60,16 @@ export default function Pressable(props: PressableProps) { const normalizedHitSlop: Insets = useMemo( () => - typeof props.hitSlop === 'number' - ? numberAsInset(props.hitSlop) - : props.hitSlop ?? {}, - [props.hitSlop] + typeof hitSlop === 'number' ? numberAsInset(hitSlop) : hitSlop ?? {}, + [hitSlop] ); const normalizedPressRetentionOffset: Insets = useMemo( () => - typeof props.pressRetentionOffset === 'number' - ? numberAsInset(props.pressRetentionOffset) - : props.pressRetentionOffset ?? {}, - [props.pressRetentionOffset] + typeof pressRetentionOffset === 'number' + ? numberAsInset(pressRetentionOffset) + : pressRetentionOffset ?? {}, + [pressRetentionOffset] ); const hoverInTimeout = useRef(null); @@ -66,29 +84,29 @@ export default function Pressable(props: PressableProps) { if (hoverOutTimeout.current) { clearTimeout(hoverOutTimeout.current); } - if (props.delayHoverIn) { + if (delayHoverIn) { hoverInTimeout.current = setTimeout( - () => props.onHoverIn?.(gestureToPressableEvent(event)), - props.delayHoverIn + () => onHoverIn?.(gestureToPressableEvent(event)), + delayHoverIn ); return; } - props.onHoverIn?.(gestureToPressableEvent(event)); + onHoverIn?.(gestureToPressableEvent(event)); }) .onFinalize((event) => { if (hoverInTimeout.current) { clearTimeout(hoverInTimeout.current); } - if (props.delayHoverOut) { + if (delayHoverOut) { hoverOutTimeout.current = setTimeout( - () => props.onHoverOut?.(gestureToPressableEvent(event)), - props.delayHoverOut + () => onHoverOut?.(gestureToPressableEvent(event)), + delayHoverOut ); return; } - props.onHoverOut?.(gestureToPressableEvent(event)); + onHoverOut?.(gestureToPressableEvent(event)); }), - [props] + [delayHoverIn, delayHoverOut, onHoverIn, onHoverOut] ); const pressDelayTimeoutRef = useRef(null); @@ -109,12 +127,12 @@ export default function Pressable(props: PressableProps) { deferredEventPayload.current = null; - props.onPressIn?.(event); + onPressIn?.(event); isPressCallbackEnabled.current = true; pressDelayTimeoutRef.current = null; setPressedState(true); }, - [props] + [onPressIn] ); const pressOutHandler = useCallback( @@ -127,7 +145,7 @@ export default function Pressable(props: PressableProps) { return; } - if (props.unstable_pressDelay && pressDelayTimeoutRef.current !== null) { + if (unstable_pressDelay && pressDelayTimeoutRef.current !== null) { // When delay is preemptively finished by lifting touches, // we want to immediately activate it's effects - pressInHandler, // even though we are located at the pressOutHandler @@ -136,14 +154,14 @@ export default function Pressable(props: PressableProps) { } if (deferredEventPayload.current) { - props.onPressIn?.(deferredEventPayload.current); + onPressIn?.(deferredEventPayload.current); deferredEventPayload.current = null; } - props.onPressOut?.(event); + onPressOut?.(event); if (isPressCallbackEnabled.current) { - props.onPress?.(event); + onPress?.(event); } if (longPressTimeoutRef.current) { @@ -156,7 +174,7 @@ export default function Pressable(props: PressableProps) { isPressCallbackEnabled.current = true; setPressedState(false); }, - [pressInHandler, props] + [onPress, onPressIn, onPressOut, pressInHandler, unstable_pressDelay] ); const handlingOnTouchesDown = useRef(false); @@ -170,7 +188,7 @@ export default function Pressable(props: PressableProps) { } if (hasPassedBoundsChecks.current) { - props.onLongPress?.(gestureTouchToPressableEvent(event)); + onLongPress?.(gestureTouchToPressableEvent(event)); isPressCallbackEnabled.current = false; } @@ -179,13 +197,13 @@ export default function Pressable(props: PressableProps) { longPressTimeoutRef.current = null; } }, - [props] + [onLongPress] ); const longPressTimeoutRef = useRef(null); const longPressMinDuration = - (props.delayLongPress ?? DEFAULT_LONG_PRESS_DURATION) + - (props.unstable_pressDelay ?? 0); + (delayLongPress ?? DEFAULT_LONG_PRESS_DURATION) + + (unstable_pressDelay ?? 0); const pressAndTouchGesture = useMemo( () => @@ -225,10 +243,10 @@ export default function Pressable(props: PressableProps) { ); } - if (props.unstable_pressDelay) { + if (unstable_pressDelay) { pressDelayTimeoutRef.current = setTimeout(() => { pressInHandler(gestureTouchToPressableEvent(event)); - }, props.unstable_pressDelay); + }, unstable_pressDelay); } else { pressInHandler(gestureTouchToPressableEvent(event)); } @@ -276,7 +294,7 @@ export default function Pressable(props: PressableProps) { normalizedHitSlop, pressInHandler, pressOutHandler, - props.unstable_pressDelay, + unstable_pressDelay, ] ); @@ -334,7 +352,7 @@ export default function Pressable(props: PressableProps) { normalizedPressRetentionOffset ); - const isPressableEnabled = props.disabled !== true; + const isPressableEnabled = disabled !== true; const gestures = [pressAndTouchGesture, hoverGesture, buttonGesture]; @@ -354,39 +372,36 @@ export default function Pressable(props: PressableProps) { const gesture = Gesture.Simultaneous(...gestures); - const defaultRippleColor = props.android_ripple ? undefined : 'transparent'; + const defaultRippleColor = android_ripple ? undefined : 'transparent'; // `cursor: 'pointer'` on `RNButton` crashes iOS const pointerStyle: StyleProp = Platform.OS === 'web' ? { cursor: 'pointer' } : {}; const styleProp = - typeof props.style === 'function' - ? props.style({ pressed: pressedState }) - : props.style; + typeof style === 'function' ? style({ pressed: pressedState }) : style; const childrenProp = - typeof props.children === 'function' - ? props.children({ pressed: pressedState }) - : props.children; + typeof children === 'function' + ? children({ pressed: pressedState }) + : children; const flattenedStyles = StyleSheet.flatten(styleProp ?? {}); const [innerStyles, outerStyles] = splitStyles(flattenedStyles); return ( - + ( props: SwipeableProps, ref: ForwardedRef ) { + const { + leftThreshold, + rightThreshold, + onSwipeableOpenStartDrag, + onSwipeableCloseStartDrag, + enableTrackpadTwoFingerGesture, + enabled, + containerStyle, + childrenContainerStyle, + animationOptions, + overshootLeft, + overshootRight, + onSwipeableWillOpen, + onSwipeableWillClose, + onSwipeableOpen, + onSwipeableClose, + testID, + ...remainingProps + } = props; + const rowState = useSharedValue(0); const userDrag = useSharedValue(0); @@ -240,8 +260,8 @@ const Swipeable = forwardRef( overshootFriction = defaultProps.overshootFriction, } = props; - const overshootLeftProp = props.overshootLeft; - const overshootRightProp = props.overshootRight; + const overshootLeftProp = overshootLeft; + const overshootRightProp = overshootRight; const calculateCurrentOffset = useCallback(() => { 'worklet'; @@ -317,38 +337,33 @@ const Swipeable = forwardRef( const dispatchImmediateEvents = useCallback( (fromValue: number, toValue: number) => { - if (toValue > 0 && props.onSwipeableWillOpen) { - props.onSwipeableWillOpen('left'); - } else if (toValue < 0 && props.onSwipeableWillOpen) { - props.onSwipeableWillOpen('right'); - } else if (props.onSwipeableWillClose) { + if (toValue > 0 && onSwipeableWillOpen) { + onSwipeableWillOpen('left'); + } else if (toValue < 0 && onSwipeableWillOpen) { + onSwipeableWillOpen('right'); + } else if (onSwipeableWillClose) { const closingDirection = fromValue > 0 ? 'left' : 'right'; - props.onSwipeableWillClose(closingDirection); + onSwipeableWillClose(closingDirection); } }, - [ - props, - props.onSwipeableWillClose, - props.onSwipeableWillOpen, - swipeableMethods, - ] + [onSwipeableWillClose, onSwipeableWillOpen] ); const dispatchEndEvents = useCallback( (fromValue: number, toValue: number) => { - if (toValue > 0 && props.onSwipeableOpen) { - props.onSwipeableOpen('left', swipeableMethods.current); - } else if (toValue < 0 && props.onSwipeableOpen) { - props.onSwipeableOpen('right', swipeableMethods.current); - } else if (props.onSwipeableClose) { + if (toValue > 0 && onSwipeableOpen) { + onSwipeableOpen('left', swipeableMethods.current); + } else if (toValue < 0 && onSwipeableOpen) { + onSwipeableOpen('right', swipeableMethods.current); + } else if (onSwipeableClose) { const closingDirection = fromValue > 0 ? 'left' : 'right'; - props.onSwipeableClose(closingDirection, swipeableMethods.current); + onSwipeableClose(closingDirection, swipeableMethods.current); } }, - [props, props.onSwipeableClose, props.onSwipeableOpen, swipeableMethods] + [onSwipeableClose, onSwipeableOpen] ); - const animationOptionsProp = props.animationOptions; + const animationOptionsProp = animationOptions; const animateRow = useCallback( (fromValue: number, toValue: number, velocityX?: number) => { @@ -393,12 +408,15 @@ const Swipeable = forwardRef( runOnJS(dispatchImmediateEvents)(fromValue, toValue); }, [ - showLeftProgress, + rowState, + animationOptionsProp, appliedTranslation, - dispatchEndEvents, + showLeftProgress, + leftWidth.value, + showRightProgress, + rightWidth.value, dispatchImmediateEvents, - animationOptionsProp, - rowState, + dispatchEndEvents, ] ); @@ -489,8 +507,8 @@ const Swipeable = forwardRef( ); - const leftThresholdProp = props.leftThreshold; - const rightThresholdProp = props.rightThreshold; + const leftThresholdProp = leftThreshold; + const rightThresholdProp = rightThreshold; const handleRelease = ( event: GestureStateChangeEvent @@ -541,9 +559,6 @@ const Swipeable = forwardRef( } }); - const onSwipeableOpenStartDrag = props.onSwipeableOpenStartDrag; - const onSwipeableCloseStartDrag = props.onSwipeableCloseStartDrag; - const panGesture = Gesture.Pan() .onUpdate((event: GestureUpdateEvent) => { userDrag.value = event.translationX; @@ -570,10 +585,8 @@ const Swipeable = forwardRef( } ); - if (props.enableTrackpadTwoFingerGesture) { - panGesture.enableTrackpadTwoFingerGesture( - props.enableTrackpadTwoFingerGesture - ); + if (enableTrackpadTwoFingerGesture) { + panGesture.enableTrackpadTwoFingerGesture(enableTrackpadTwoFingerGesture); } panGesture.activeOffsetX([ @@ -586,7 +599,7 @@ const Swipeable = forwardRef( swipeableMethods, ]); - panGesture.enabled(props.enabled !== false); + panGesture.enabled(enabled !== false); const animatedStyle = useAnimatedStyle( () => ({ @@ -596,12 +609,10 @@ const Swipeable = forwardRef( [appliedTranslation, rowState] ); - const containerStyle = props.containerStyle; - const childrenContainerStyle = props.childrenContainerStyle; - - return ( + const swipeableComponent = ( {leftElement} @@ -614,6 +625,12 @@ const Swipeable = forwardRef( ); + + return testID ? ( + {swipeableComponent} + ) : ( + swipeableComponent + ); } );