mirror of
https://github.com/react/react.git
synced 2026-10-19 13:15:13 +08:00
Event API: ensure preventDefault works for nested targets (#15633)
This commit is contained in:
@@ -208,6 +208,7 @@ const eventResponderContext: ReactResponderContext = {
|
||||
childTarget: Element | Document,
|
||||
parentTarget: Element | Document,
|
||||
): boolean {
|
||||
validateResponderContext();
|
||||
const childFiber = getClosestInstanceFromNode(childTarget);
|
||||
const parentFiber = getClosestInstanceFromNode(parentTarget);
|
||||
|
||||
@@ -345,6 +346,7 @@ const eventResponderContext: ReactResponderContext = {
|
||||
}
|
||||
},
|
||||
getFocusableElementsInScope(): Array<HTMLElement> {
|
||||
validateResponderContext();
|
||||
const focusableElements = [];
|
||||
const eventComponentInstance = ((currentInstance: any): ReactEventComponentInstance);
|
||||
let node = ((eventComponentInstance.currentFiber: any): Fiber).child;
|
||||
@@ -383,6 +385,7 @@ const eventResponderContext: ReactResponderContext = {
|
||||
getEventPointerType(
|
||||
event: ReactResponderEvent,
|
||||
): '' | 'mouse' | 'keyboard' | 'pen' | 'touch' {
|
||||
validateResponderContext();
|
||||
const nativeEvent: any = event.nativeEvent;
|
||||
const {type, pointerType} = nativeEvent;
|
||||
if (pointerType != null) {
|
||||
@@ -400,6 +403,7 @@ const eventResponderContext: ReactResponderContext = {
|
||||
return '';
|
||||
},
|
||||
getEventCurrentTarget(event: ReactResponderEvent): Element {
|
||||
validateResponderContext();
|
||||
const target: any = event.target;
|
||||
let currentTarget = target;
|
||||
while (
|
||||
@@ -412,8 +416,26 @@ const eventResponderContext: ReactResponderContext = {
|
||||
return currentTarget;
|
||||
},
|
||||
getTimeStamp(): number {
|
||||
validateResponderContext();
|
||||
return currentTimeStamp;
|
||||
},
|
||||
isTargetWithinHostComponent(
|
||||
target: Element | Document,
|
||||
elementType: string,
|
||||
): boolean {
|
||||
validateResponderContext();
|
||||
let fiber = getClosestInstanceFromNode(target);
|
||||
while (fiber !== null) {
|
||||
if (fiber.stateNode === currentInstance) {
|
||||
return false;
|
||||
}
|
||||
if (fiber.tag === HostComponent && fiber.type === elementType) {
|
||||
return true;
|
||||
}
|
||||
fiber = fiber.return;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
function isTargetWithinEventComponent(target: Element | Document): boolean {
|
||||
|
||||
Vendored
+1
-5
@@ -418,10 +418,6 @@ function dispatchCancel(
|
||||
}
|
||||
}
|
||||
|
||||
function isAnchorTagElement(eventTarget: EventTarget): boolean {
|
||||
return (eventTarget: any).nodeName === 'A';
|
||||
}
|
||||
|
||||
function isValidKeyPress(key: string): boolean {
|
||||
// Accessibility for keyboards. Space and Enter only.
|
||||
return key === ' ' || key === 'Enter';
|
||||
@@ -673,7 +669,7 @@ const PressResponder = {
|
||||
}
|
||||
|
||||
case 'click': {
|
||||
if (isAnchorTagElement(target)) {
|
||||
if (context.isTargetWithinHostComponent(target, 'a')) {
|
||||
const {
|
||||
altKey,
|
||||
ctrlKey,
|
||||
|
||||
@@ -1965,6 +1965,25 @@ describe('Event responder: Press', () => {
|
||||
expect(preventDefault).toBeCalled();
|
||||
});
|
||||
|
||||
it('prevents native behaviour by default with nested elements', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
const ref = React.createRef();
|
||||
const element = (
|
||||
<Press onPress={onPress}>
|
||||
<a href="#">
|
||||
<div ref={ref} />
|
||||
</a>
|
||||
</Press>
|
||||
);
|
||||
ReactDOM.render(element, container);
|
||||
|
||||
ref.current.dispatchEvent(createEvent('pointerdown'));
|
||||
ref.current.dispatchEvent(createEvent('pointerup'));
|
||||
ref.current.dispatchEvent(createEvent('click', {preventDefault}));
|
||||
expect(preventDefault).toBeCalled();
|
||||
});
|
||||
|
||||
it('uses native behaviour for interactions with modifier keys', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
||||
@@ -194,4 +194,8 @@ export type ReactResponderContext = {
|
||||
): '' | 'mouse' | 'keyboard' | 'pen' | 'touch',
|
||||
getEventCurrentTarget(event: ReactResponderEvent): Element,
|
||||
getTimeStamp: () => number,
|
||||
isTargetWithinHostComponent: (
|
||||
target: Element | Document,
|
||||
elementType: string,
|
||||
) => boolean,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user