mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-05-23 23:06:24 +00:00
[fix] Pressable keyboard onPress bug
Don't call onPress when keyup is called on a different element than the target. Fix #2605 Close #2632
This commit is contained in:
committed by
Nicolas Gallagher
parent
a0cd8ffba4
commit
7d60ff83d3
+3
-3
@@ -61,14 +61,14 @@ exports[`components/Pressable hover interaction 3`] = `
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Pressable press interaction (keyboard) 1`] = `
|
||||
exports[`components/Pressable press interaction (keyboard) trigger press when keyup is on the same element 1`] = `
|
||||
<div
|
||||
class="css-view-175oi2r r-cursor-1loqt21 r-touchAction-1otgn73"
|
||||
tabindex="0"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Pressable press interaction (keyboard) 2`] = `
|
||||
exports[`components/Pressable press interaction (keyboard) trigger press when keyup is on the same element 2`] = `
|
||||
<div
|
||||
class="css-view-175oi2r r-cursor-1loqt21 r-touchAction-1otgn73"
|
||||
style="outline: press-ring;"
|
||||
@@ -80,7 +80,7 @@ exports[`components/Pressable press interaction (keyboard) 2`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/Pressable press interaction (keyboard) 3`] = `null`;
|
||||
exports[`components/Pressable press interaction (keyboard) trigger press when keyup is on the same element 3`] = `null`;
|
||||
|
||||
exports[`components/Pressable press interaction (pointer) 1`] = `
|
||||
<div
|
||||
|
||||
@@ -200,50 +200,80 @@ describe('components/Pressable', () => {
|
||||
expect(onContextMenu).toBeCalled();
|
||||
});
|
||||
|
||||
test('press interaction (keyboard)', () => {
|
||||
let container;
|
||||
const onPress = jest.fn();
|
||||
const onPressIn = jest.fn();
|
||||
const onPressOut = jest.fn();
|
||||
const ref = React.createRef();
|
||||
describe('press interaction (keyboard)', () => {
|
||||
test('trigger press when keyup is on the same element', () => {
|
||||
let container;
|
||||
const onPress = jest.fn();
|
||||
const onPressIn = jest.fn();
|
||||
const onPressOut = jest.fn();
|
||||
const ref = React.createRef();
|
||||
|
||||
function TestCase() {
|
||||
const [shown, setShown] = React.useState(true);
|
||||
return shown ? (
|
||||
<Pressable
|
||||
children={({ pressed }) =>
|
||||
pressed ? <div data-testid="press-content" /> : null
|
||||
}
|
||||
onPress={(e) => {
|
||||
onPress(e);
|
||||
setShown(false);
|
||||
}}
|
||||
onPressIn={onPressIn}
|
||||
onPressOut={onPressOut}
|
||||
ref={ref}
|
||||
style={({ pressed }) => [pressed && { outline: 'press-ring' }]}
|
||||
/>
|
||||
) : null;
|
||||
}
|
||||
function TestCase() {
|
||||
const [shown, setShown] = React.useState(true);
|
||||
return shown ? (
|
||||
<Pressable
|
||||
children={({ pressed }) =>
|
||||
pressed ? <div data-testid="press-content" /> : null
|
||||
}
|
||||
onPress={(e) => {
|
||||
onPress(e);
|
||||
setShown(false);
|
||||
}}
|
||||
onPressIn={onPressIn}
|
||||
onPressOut={onPressOut}
|
||||
ref={ref}
|
||||
style={({ pressed }) => [pressed && { outline: 'press-ring' }]}
|
||||
/>
|
||||
) : null;
|
||||
}
|
||||
|
||||
act(() => {
|
||||
({ container } = render(<TestCase />));
|
||||
act(() => {
|
||||
({ container } = render(<TestCase />));
|
||||
});
|
||||
const target = createEventTarget(ref.current);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
act(() => {
|
||||
target.keydown({ key: 'Enter' });
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect(onPressIn).toBeCalled();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
act(() => {
|
||||
target.keyup({ key: 'Enter' });
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect(onPressOut).toBeCalled();
|
||||
expect(onPress).toBeCalled();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
const target = createEventTarget(ref.current);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
act(() => {
|
||||
target.keydown({ key: 'Enter' });
|
||||
jest.runAllTimers();
|
||||
|
||||
test('ignore press when keyup is on a different element', () => {
|
||||
const onPress = jest.fn();
|
||||
const firstRef = React.createRef();
|
||||
|
||||
function TestCase() {
|
||||
return (
|
||||
<Pressable
|
||||
onPress={(e) => {
|
||||
onPress(e);
|
||||
}}
|
||||
ref={firstRef}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
act(() => {
|
||||
render(<TestCase />);
|
||||
});
|
||||
const target = createEventTarget(firstRef.current);
|
||||
const body = createEventTarget(document.body);
|
||||
act(() => {
|
||||
target.keydown({ key: 'Enter' });
|
||||
body.keyup({ key: 'Enter' });
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect(onPress).not.toBeCalled();
|
||||
});
|
||||
expect(onPressIn).toBeCalled();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
act(() => {
|
||||
target.keyup({ key: 'Enter' });
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect(onPressOut).toBeCalled();
|
||||
expect(onPress).toBeCalled();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('press interaction as button (keyboard)', () => {
|
||||
|
||||
@@ -233,6 +233,7 @@ export default class PressResponder {
|
||||
pageY: number
|
||||
|}>;
|
||||
_touchState: TouchState = NOT_RESPONDER;
|
||||
_responderElement: ?HTMLElement = null;
|
||||
|
||||
constructor(config: PressResponderConfig) {
|
||||
this.configure(config);
|
||||
@@ -320,10 +321,13 @@ export default class PressResponder {
|
||||
elementType === 'input' ||
|
||||
elementType === 'select' ||
|
||||
elementType === 'textarea';
|
||||
const isActiveElement = this._responderElement === target;
|
||||
|
||||
if (onPress != null && !isNativeInteractiveElement) {
|
||||
if (onPress != null && !isNativeInteractiveElement && isActiveElement) {
|
||||
onPress(event);
|
||||
}
|
||||
|
||||
this._responderElement = null;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -345,6 +349,7 @@ export default class PressResponder {
|
||||
if (!disabled && isValidKeyPress(event)) {
|
||||
if (this._touchState === NOT_RESPONDER) {
|
||||
start(event, false);
|
||||
this._responderElement = target;
|
||||
// Listen to 'keyup' on document to account for situations where
|
||||
// focus is moved to another element during 'keydown'.
|
||||
document.addEventListener('keyup', keyupHandler);
|
||||
|
||||
Reference in New Issue
Block a user