mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-05-24 07:09:03 +00:00
[fix] ResponderSystem negotiation logic
This fixes a bug in the negotiation logic that caused a cycle of terminate->grant events to be sent to the current responder during a pointer move. The root cause was using an incorrect event path in the calculation of the lowest common ancestor's index. The fix is to ensure that the event path stored with the current responder is pruned to begin with the node that is the current responder (rather than any child responders it may have contained).
This commit is contained in:
@@ -64,3 +64,9 @@ Called when the pointer is released, but not if cancelled (e.g. by a scroll that
|
||||
<Stories.feedbackEvents />
|
||||
</Story>
|
||||
</Preview>
|
||||
|
||||
<Preview withSource='none'>
|
||||
<Story name="panAndPress">
|
||||
<Stories.panAndPress />
|
||||
</Story>
|
||||
</Preview>
|
||||
|
||||
@@ -56,13 +56,12 @@ export default function FeedbackEvents() {
|
||||
}}
|
||||
>
|
||||
<Pressable
|
||||
accessibilityRole="none"
|
||||
accessibilityRole="button"
|
||||
onLongPress={handlePress('longPress - inner')}
|
||||
onPress={handlePress('press - inner')}
|
||||
onPressIn={handlePress('pressIn - inner')}
|
||||
onPressOut={handlePress('pressOut - inner')}
|
||||
style={({ hovered, pressed, focused }) => {
|
||||
console.log(focused);
|
||||
let backgroundColor = 'white';
|
||||
if (hovered) {
|
||||
backgroundColor = 'lightgray';
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { Animated, View, StyleSheet, PanResponder, Text, TouchableOpacity } from 'react-native';
|
||||
|
||||
const App = () => {
|
||||
const pan = useRef(new Animated.ValueXY()).current;
|
||||
const [x, setX] = useState(0);
|
||||
|
||||
const panResponder = useRef(null);
|
||||
if (panResponder.current == null) {
|
||||
panResponder.current = PanResponder.create({
|
||||
onMoveShouldSetPanResponder: () => true,
|
||||
onPanResponderGrant: e => {
|
||||
console.log('pan grant');
|
||||
pan.setOffset({
|
||||
x: pan.x._value,
|
||||
y: pan.y._value
|
||||
});
|
||||
},
|
||||
onPanResponderMove: Animated.event([null, { dx: pan.x, dy: pan.y }]),
|
||||
onPanResponderRelease: () => {
|
||||
console.log('pan release');
|
||||
pan.flattenOffset();
|
||||
},
|
||||
onPanResponderTerminate() {
|
||||
console.log('pan terminate');
|
||||
pan.flattenOffset();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.titleText}>Pressed: {x}</Text>
|
||||
<Animated.View
|
||||
style={{
|
||||
transform: [{ translateX: pan.x }, { translateY: pan.y }]
|
||||
}}
|
||||
{...panResponder.current.panHandlers}
|
||||
>
|
||||
<View style={styles.box}>
|
||||
<TouchableOpacity onPress={() => setX(x + 1)} style={styles.outerTouchable}>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
console.log('press inner');
|
||||
}}
|
||||
style={styles.innerTouchable}
|
||||
/>
|
||||
<TouchableOpacity disabled style={styles.innerTouchable} />
|
||||
<TouchableOpacity
|
||||
accessibilityRole="button"
|
||||
disabled
|
||||
style={[styles.innerTouchable, styles.disabledButton]}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</Animated.View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
userSelect: 'none'
|
||||
},
|
||||
titleText: {
|
||||
fontSize: 14,
|
||||
lineHeight: 24,
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
box: {
|
||||
height: 200,
|
||||
width: 150,
|
||||
backgroundColor: 'lightblue',
|
||||
borderRadius: 5
|
||||
},
|
||||
outerTouchable: {
|
||||
height: 150,
|
||||
width: 100,
|
||||
margin: 25,
|
||||
backgroundColor: 'blue',
|
||||
borderRadius: 5,
|
||||
justifyContent: 'center'
|
||||
},
|
||||
innerTouchable: {
|
||||
height: 20,
|
||||
flex: 1,
|
||||
marginVertical: 10,
|
||||
marginHorizontal: 20,
|
||||
backgroundColor: 'green',
|
||||
borderRadius: 5
|
||||
},
|
||||
disabledButton: {
|
||||
backgroundColor: 'red'
|
||||
}
|
||||
});
|
||||
|
||||
export default App;
|
||||
@@ -1,3 +1,4 @@
|
||||
export { default as delayEvents } from './DelayEvents';
|
||||
export { default as disabled } from './Disabled';
|
||||
export { default as feedbackEvents } from './FeedbackEvents';
|
||||
export { default as panAndPress } from './PanAndPress';
|
||||
|
||||
Reference in New Issue
Block a user