[Flare] Fix Press scroll cancellation handling (#15983)
Dominic Gannaway committed
Jun 25, 2019 at 14:31 UTC
6088a201e12258a6d0e36dbb0d2208a57ec133ba
3 files changed
+75
-2
packages/react-dom/src/events/DOMEventResponderSystem.js
+5
-1
@@ -1037,7 +1037,11 @@ export function dispatchEventForResponderEventSystem(
1037
const previouslyInHook = currentlyInHook;
1038
currentTimers = null;
1039
currentEventQueue = createEventQueue();
1040
- currentDocument = (nativeEventTarget: any).ownerDocument;
1040
+ // nodeType 9 is DOCUMENT_NODE
1041
+ currentDocument =
1042
+ (nativeEventTarget: any).nodeType === 9
1043
+ ? ((nativeEventTarget: any): Document)
1044
+ : (nativeEventTarget: any).ownerDocument;
1045
// We might want to control timeStamp another way here
1046
currentTimeStamp = (nativeEvent: any).timeStamp;
1047
try {
packages/react-events/src/dom/Press.js
+16
-1
@@ -1002,8 +1002,23 @@ const PressResponder: ReactDOMEventResponder = {
1002
}
1003
1004
// CANCEL
1005
+ case 'scroll': {
1006
+ const pressTarget = state.pressTarget;
1007
+ const scrollTarget = nativeEvent.target;
1008
+ const doc = context.getActiveDocument();
1009
+ // If the scroll target is the document or if the press target
1010
+ // is inside the scroll target, then this a scroll that should
1011
+ // trigger a cancel.
1012
+ if (
1013
+ pressTarget !== null &&
1014
+ (scrollTarget === doc ||
1015
+ context.isTargetWithinElement(pressTarget, scrollTarget))
1016
+ ) {
1017
+ dispatchCancel(event, context, props, state);
1018
+ }
1019
+ break;
1020
+ }
1021
case 'pointercancel':
1006
- case 'scroll':
1022
case 'touchcancel':
1023
case 'dragstart': {
1024
dispatchCancel(event, context, props, state);
packages/react-events/src/dom/__tests__/Press-test.internal.js
+54
@@ -2458,6 +2458,60 @@ describe('Event responder: Press', () => {
2458
});
2459
});
2460
2461
+ it('does end on "scroll" to document', () => {
2462
+ const onPressEnd = jest.fn();
2463
+ const ref = React.createRef();
2464
+ const element = (
2465
+ <div>
2466
+ <Press onPressEnd={onPressEnd}>
2467
+ <a href="#" ref={ref} />
2468
+ </Press>
2469
+ </div>
2470
+ );
2471
+ ReactDOM.render(element, container);
2472
+
2473
+ ref.current.dispatchEvent(createEvent('pointerdown'));
2474
+ document.dispatchEvent(createEvent('scroll'));
2475
+ expect(onPressEnd).toHaveBeenCalledTimes(1);
2476
+ });
2477
+
2478
+ it('does end on "scroll" to a parent container', () => {
2479
+ const onPressEnd = jest.fn();
2480
+ const ref = React.createRef();
2481
+ const containerRef = React.createRef();
2482
+ const element = (
2483
+ <div ref={containerRef}>
2484
+ <Press onPressEnd={onPressEnd}>
2485
+ <a href="#" ref={ref} />
2486
+ </Press>
2487
+ </div>
2488
+ );
2489
+ ReactDOM.render(element, container);
2490
+
2491
+ ref.current.dispatchEvent(createEvent('pointerdown'));
2492
+ containerRef.current.dispatchEvent(createEvent('scroll'));
2493
+ expect(onPressEnd).toHaveBeenCalledTimes(1);
2494
+ });
2495
+
2496
+ it('does not end on "scroll" to an element outside', () => {
2497
+ const onPressEnd = jest.fn();
2498
+ const ref = React.createRef();
2499
+ const outsideRef = React.createRef();
2500
+ const element = (
2501
+ <div>
2502
+ <Press onPressEnd={onPressEnd}>
2503
+ <a href="#" ref={ref} />
2504
+ </Press>
2505
+ <span ref={outsideRef} />
2506
+ </div>
2507
+ );
2508
+ ReactDOM.render(element, container);
2509
+
2510
+ ref.current.dispatchEvent(createEvent('pointerdown'));
2511
+ outsideRef.current.dispatchEvent(createEvent('scroll'));
2512
+ expect(onPressEnd).not.toBeCalled();
2513
+ });
2514
+
2515
it('expect displayName to show up for event component', () => {
2516
expect(Press.responder.displayName).toBe('Press');
2517
});