From 6088a201e12258a6d0e36dbb0d2208a57ec133ba Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Tue, 25 Jun 2019 14:31:48 +0100 Subject: [PATCH] [Flare] Fix Press scroll cancellation handling (#15983) --- .../src/events/DOMEventResponderSystem.js | 6 ++- packages/react-events/src/dom/Press.js | 17 +++++- .../src/dom/__tests__/Press-test.internal.js | 54 +++++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/packages/react-dom/src/events/DOMEventResponderSystem.js b/packages/react-dom/src/events/DOMEventResponderSystem.js index eef152b502..a918ebc9c9 100644 --- a/packages/react-dom/src/events/DOMEventResponderSystem.js +++ b/packages/react-dom/src/events/DOMEventResponderSystem.js @@ -1037,7 +1037,11 @@ export function dispatchEventForResponderEventSystem( const previouslyInHook = currentlyInHook; currentTimers = null; currentEventQueue = createEventQueue(); - currentDocument = (nativeEventTarget: any).ownerDocument; + // nodeType 9 is DOCUMENT_NODE + currentDocument = + (nativeEventTarget: any).nodeType === 9 + ? ((nativeEventTarget: any): Document) + : (nativeEventTarget: any).ownerDocument; // We might want to control timeStamp another way here currentTimeStamp = (nativeEvent: any).timeStamp; try { diff --git a/packages/react-events/src/dom/Press.js b/packages/react-events/src/dom/Press.js index e4453bc332..d61f7664bb 100644 --- a/packages/react-events/src/dom/Press.js +++ b/packages/react-events/src/dom/Press.js @@ -1002,8 +1002,23 @@ const PressResponder: ReactDOMEventResponder = { } // CANCEL + case 'scroll': { + const pressTarget = state.pressTarget; + const scrollTarget = nativeEvent.target; + const doc = context.getActiveDocument(); + // If the scroll target is the document or if the press target + // is inside the scroll target, then this a scroll that should + // trigger a cancel. + if ( + pressTarget !== null && + (scrollTarget === doc || + context.isTargetWithinElement(pressTarget, scrollTarget)) + ) { + dispatchCancel(event, context, props, state); + } + break; + } case 'pointercancel': - case 'scroll': case 'touchcancel': case 'dragstart': { dispatchCancel(event, context, props, state); diff --git a/packages/react-events/src/dom/__tests__/Press-test.internal.js b/packages/react-events/src/dom/__tests__/Press-test.internal.js index 165b87f812..2a033f8cde 100644 --- a/packages/react-events/src/dom/__tests__/Press-test.internal.js +++ b/packages/react-events/src/dom/__tests__/Press-test.internal.js @@ -2458,6 +2458,60 @@ describe('Event responder: Press', () => { }); }); + it('does end on "scroll" to document', () => { + const onPressEnd = jest.fn(); + const ref = React.createRef(); + const element = ( +
+ + + +
+ ); + ReactDOM.render(element, container); + + ref.current.dispatchEvent(createEvent('pointerdown')); + document.dispatchEvent(createEvent('scroll')); + expect(onPressEnd).toHaveBeenCalledTimes(1); + }); + + it('does end on "scroll" to a parent container', () => { + const onPressEnd = jest.fn(); + const ref = React.createRef(); + const containerRef = React.createRef(); + const element = ( +
+ + + +
+ ); + ReactDOM.render(element, container); + + ref.current.dispatchEvent(createEvent('pointerdown')); + containerRef.current.dispatchEvent(createEvent('scroll')); + expect(onPressEnd).toHaveBeenCalledTimes(1); + }); + + it('does not end on "scroll" to an element outside', () => { + const onPressEnd = jest.fn(); + const ref = React.createRef(); + const outsideRef = React.createRef(); + const element = ( +
+ + + + +
+ ); + ReactDOM.render(element, container); + + ref.current.dispatchEvent(createEvent('pointerdown')); + outsideRef.current.dispatchEvent(createEvent('scroll')); + expect(onPressEnd).not.toBeCalled(); + }); + it('expect displayName to show up for event component', () => { expect(Press.responder.displayName).toBe('Press'); });