diff --git a/packages/react-dom/src/client/ReactDOMHostConfig.js b/packages/react-dom/src/client/ReactDOMHostConfig.js index b4fa2dd61b..cdea9f903b 100644 --- a/packages/react-dom/src/client/ReactDOMHostConfig.js +++ b/packages/react-dom/src/client/ReactDOMHostConfig.js @@ -897,18 +897,19 @@ export function mountEventComponent( ): void { if (enableEventAPI) { const rootContainerInstance = ((eventComponentInstance.rootInstance: any): Container); - const rootElement = rootContainerInstance.ownerDocument; + const doc = rootContainerInstance.ownerDocument; + const documentBody = doc.body || doc; const responder = eventComponentInstance.responder; const {rootEventTypes, targetEventTypes} = responder; if (targetEventTypes !== undefined) { - listenToEventResponderEventTypes(targetEventTypes, rootElement); + listenToEventResponderEventTypes(targetEventTypes, documentBody); } if (rootEventTypes !== undefined) { addRootEventTypesForComponentInstance( eventComponentInstance, rootEventTypes, ); - listenToEventResponderEventTypes(rootEventTypes, rootElement); + listenToEventResponderEventTypes(rootEventTypes, documentBody); } mountEventResponder(eventComponentInstance); } diff --git a/packages/react-events/src/Press.js b/packages/react-events/src/Press.js index 6781c562f9..ecc3e807d1 100644 --- a/packages/react-events/src/Press.js +++ b/packages/react-events/src/Press.js @@ -37,6 +37,7 @@ type PressProps = { left: number, }, preventDefault: boolean, + stopPropagation: boolean, }; type PointerType = '' | 'mouse' | 'keyboard' | 'pen' | 'touch'; @@ -130,16 +131,18 @@ const rootEventTypes = [ 'pointermove', 'scroll', 'pointercancel', + // We listen to this here so stopPropagation can + // block other mouseup events used internally + {name: 'mouseup', passive: false}, + 'touchend', ]; // If PointerEvents is not supported (e.g., Safari), also listen to touch and mouse events. if (typeof window !== 'undefined' && window.PointerEvent === undefined) { targetEventTypes.push('touchstart', 'mousedown'); rootEventTypes.push( - {name: 'mouseup', passive: false}, 'mousemove', 'touchmove', - 'touchend', 'touchcancel', // Used as a 'cancel' signal for mouse interactions 'dragstart', @@ -617,6 +620,9 @@ const PressResponder = { const nativeEvent: any = event.nativeEvent; const pointerType = context.getEventPointerType(event); + if (props.stopPropagation === true) { + nativeEvent.stopPropagation(); + } switch (type) { // START case 'pointerdown': @@ -740,6 +746,9 @@ const PressResponder = { const nativeEvent: any = event.nativeEvent; const pointerType = context.getEventPointerType(event); + if (props.stopPropagation === true) { + nativeEvent.stopPropagation(); + } switch (type) { // MOVE case 'pointermove': diff --git a/packages/react-events/src/__tests__/Press-test.internal.js b/packages/react-events/src/__tests__/Press-test.internal.js index 044873dc60..0561154ce4 100644 --- a/packages/react-events/src/__tests__/Press-test.internal.js +++ b/packages/react-events/src/__tests__/Press-test.internal.js @@ -2591,4 +2591,22 @@ describe('Event responder: Press', () => { expect(onContextMenu).toHaveBeenCalledTimes(0); }); }); + + it('should work correctly with stopPropagation set to true', () => { + const ref = React.createRef(); + const element = ( + +
+ + ); + const pointerDownEvent = jest.fn(); + container.addEventListener('pointerdown', pointerDownEvent); + ReactDOM.render(element, container); + + ref.current.dispatchEvent( + createEvent('pointerdown', {pointerType: 'mouse', button: 0}), + ); + container.removeEventListener('pointerdown', pointerDownEvent); + expect(pointerDownEvent).toHaveBeenCalledTimes(0); + }); });