Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3510026
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
5 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/native/components/gesture-touchable-opacity.react.js b/native/components/gesture-touchable-opacity.react.js
index aca76c2e3..0a586b3aa 100644
--- a/native/components/gesture-touchable-opacity.react.js
+++ b/native/components/gesture-touchable-opacity.react.js
@@ -1,193 +1,197 @@
// @flow
import type { ViewStyle } from '../types/styles';
import * as React from 'react';
import { StyleSheet } from 'react-native';
import {
LongPressGestureHandler,
TapGestureHandler,
State as GestureState,
} from 'react-native-gesture-handler';
import Animated, { Easing } from 'react-native-reanimated';
import { runTiming } from '../utils/animation-utils';
/* eslint-disable import/no-named-as-default-member */
const {
Value,
Clock,
block,
event,
set,
call,
cond,
not,
and,
or,
eq,
stopClock,
clockRunning,
} = Animated;
/* eslint-enable import/no-named-as-default-member */
const pressAnimationSpec = {
duration: 150,
easing: Easing.inOut(Easing.quad),
};
const resetAnimationSpec = {
duration: 250,
easing: Easing.inOut(Easing.quad),
};
type Props = {|
+activeOpacity?: number,
+onPress?: () => mixed,
+onLongPress?: () => mixed,
+children?: React.Node,
+style?: ViewStyle,
// If stickyActive is a boolean, we assume that we should stay active after a
// successful onPress or onLongPress. We will wait for stickyActive to flip
// from true to false before animating back to our deactivated mode.
+stickyActive?: boolean,
+ +overlay?: React.Node,
|};
function GestureTouchableOpacity(props: Props) {
const { onPress: innerOnPress, onLongPress: innerOnLongPress } = props;
const onPress = React.useCallback(() => {
innerOnPress && innerOnPress();
}, [innerOnPress]);
const onLongPress = React.useCallback(() => {
innerOnLongPress && innerOnLongPress();
}, [innerOnLongPress]);
const activeOpacity = props.activeOpacity ?? 0.2;
const { stickyActive } = props;
const prevStickyActiveRef = React.useRef(stickyActive);
const activeValueRef = React.useRef(new Value(stickyActive ? 1 : 0));
React.useEffect(() => {
const prevActive = prevStickyActiveRef.current;
if (!prevActive && stickyActive) {
activeValueRef.current.setValue(1);
} else if (prevActive && !stickyActive) {
activeValueRef.current.setValue(0);
}
prevStickyActiveRef.current = stickyActive;
}, [stickyActive]);
const activeValue = activeValueRef.current;
const stickyActiveEnabled =
stickyActive !== null && stickyActive !== undefined;
const { longPressEvent, tapEvent, transformStyle } = React.useMemo(() => {
const longPressState = new Value(-1);
const innerLongPressEvent = event([
{
nativeEvent: {
state: longPressState,
},
},
]);
const tapState = new Value(-1);
const innerTapEvent = event([
{
nativeEvent: {
state: tapState,
},
},
]);
const gestureActive = or(
eq(longPressState, GestureState.ACTIVE),
eq(tapState, GestureState.BEGAN),
eq(tapState, GestureState.ACTIVE),
activeValue,
);
const tapSuccess = eq(tapState, GestureState.END);
const prevTapSuccess = new Value(0);
const longPressSuccess = eq(longPressState, GestureState.ACTIVE);
const prevLongPressSuccess = new Value(0);
const curOpacity = new Value(1);
const pressClock = new Clock();
const resetClock = new Clock();
const opacity = block([
cond(or(gestureActive, clockRunning(pressClock)), [
set(
curOpacity,
runTiming(
pressClock,
curOpacity,
activeOpacity,
true,
pressAnimationSpec,
),
),
stopClock(resetClock),
]),
// We have to do two separate conds here even though the condition is the
// same because if runTiming stops the pressClock, we need to immediately
// start the resetClock or Reanimated won't keep running the code because
// it will think there is nothing left to do
cond(
not(or(gestureActive, clockRunning(pressClock))),
set(
curOpacity,
runTiming(resetClock, curOpacity, 1, true, resetAnimationSpec),
),
),
[
cond(and(tapSuccess, not(prevTapSuccess)), [
stickyActiveEnabled ? set(activeValue, 1) : undefined,
call([], onPress),
]),
set(prevTapSuccess, tapSuccess),
],
[
cond(and(longPressSuccess, not(prevLongPressSuccess)), [
stickyActiveEnabled ? set(activeValue, 1) : undefined,
call([], onLongPress),
]),
set(prevLongPressSuccess, longPressSuccess),
],
curOpacity,
]);
const innerTransformStyle = {
flex: 1,
opacity,
};
return {
longPressEvent: innerLongPressEvent,
tapEvent: innerTapEvent,
transformStyle: innerTransformStyle,
};
}, [onPress, onLongPress, activeOpacity, activeValue, stickyActiveEnabled]);
const tapHandler = (
<TapGestureHandler onHandlerStateChange={tapEvent} maxDurationMs={100000}>
- <Animated.View style={[transformStyle, props.style]}>
- {props.children}
+ <Animated.View style={styles.fill}>
+ <Animated.View style={[transformStyle, props.style]}>
+ {props.children}
+ </Animated.View>
+ {props.overlay}
</Animated.View>
</TapGestureHandler>
);
if (!innerOnLongPress) {
return tapHandler;
}
return (
<LongPressGestureHandler
onHandlerStateChange={longPressEvent}
minDurationMs={370}
>
<Animated.View style={styles.fill}>{tapHandler}</Animated.View>
</LongPressGestureHandler>
);
}
const styles = StyleSheet.create({
fill: {
flex: 1,
},
});
export default GestureTouchableOpacity;
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Dec 23, 10:38 AM (18 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2690783
Default Alt Text
(5 KB)
Attached To
Mode
rCOMM Comm
Attached
Detach File
Event Timeline
Log In to Comment