@samitouri / QOS-React / commits / 3f058debc2

Event API: various bug fixes (#15485)

Dominic Gannaway committed Apr 24, 2019 at 17:56 UTC 3f058debc29ccb05a47ac8a8d747c5a5b29a6ed3
5 files changed +93 -63
packages/react-dom/src/client/ReactDOMHostConfig.js
+9 -2
@@ -966,6 +966,13 @@ export function handleEventTarget(
966 rootContainerInstance: Container,
967 internalInstanceHandle: Object,
968 ): boolean {
969 + if (
970 + __DEV__ &&
971 + type === REACT_EVENT_TARGET_TOUCH_HIT &&
972 + (props.left || props.right || props.top || props.bottom)
973 + ) {
974 + return true;
975 + }
976 return false;
977 }
978
@@ -992,9 +999,9 @@ export function commitEventTarget(
999 'value of "relative".',
1000 );
1001 warning(
995 - computedStyles.getPropertyValue('zIndex') !== '',
1002 + computedStyles.getPropertyValue('z-index') !== '',
1003 '<TouchHitTarget> inserts an empty <div> with "z-index" of "-1". ' +
997 - 'This requires its parent DOM node to have a "z-index" great than "-1",' +
1004 + 'This requires its parent DOM node to have a "z-index" greater than "-1",' +
1005 'but the parent DOM node was found to no "z-index" value set.' +
1006 ' Try using a "z-index" value of "0" or greater.',
1007 );
packages/react-events/src/Focus.js
+1 -1
@@ -108,7 +108,7 @@ const FocusResponder = {
108 onEvent(
109 event: ReactResponderEvent,
110 context: ReactResponderContext,
111 - props: Object,
111 + props: FocusProps,
112 state: FocusState,
113 ): void {
114 const {type, target} = event;
packages/react-events/src/Press.js
+15 -10
@@ -94,7 +94,9 @@ const targetEventTypes = [
94 {name: 'keydown', passive: false},
95 {name: 'keypress', passive: false},
96 {name: 'contextmenu', passive: false},
97 - 'pointerdown',
97 + // We need to preventDefault on pointerdown for mouse/pen events
98 + // that are in hit target area but not the element area.
99 + {name: 'pointerdown', passive: false},
100 'pointercancel',
101 ];
102 const rootEventTypes = ['keyup', 'pointerup', 'pointermove', 'scroll'];
@@ -447,15 +449,18 @@ const PressResponder = {
449 }
450 }
451
450 - // Ignore emulated mouse events and mouse pressing on touch hit target
451 - // area
452 - if (type === 'mousedown') {
453 - if (
454 - state.ignoreEmulatedMouseEvents ||
455 - isEventPositionWithinTouchHitTarget(event, context)
456 - ) {
457 - return;
458 - }
452 + // Ignore emulated mouse events
453 + if (type === 'mousedown' && state.ignoreEmulatedMouseEvents) {
454 + return;
455 + }
456 + // Ignore mouse/pen pressing on touch hit target area
457 + if (
458 + (pointerType === 'mouse' || pointerType === 'pen') &&
459 + isEventPositionWithinTouchHitTarget(event, context)
460 + ) {
461 + // We need to prevent the native event to block the focus
462 + nativeEvent.preventDefault();
463 + return;
464 }
465
466 // Ignore any device buttons except left-mouse and touch/pen contact
packages/react-events/src/__tests__/TouchHitTarget-test.internal.js
+33 -21
@@ -318,7 +318,7 @@ describe('TouchHitTarget', () => {
318
319 const Test = () => (
320 <EventComponent>
321 - <div>
321 + <div style={{position: 'relative', zIndex: 0}}>
322 {cond ? null : (
323 <TouchHitTarget top={10} left={10} right={10} bottom={10} />
324 )}
@@ -330,14 +330,16 @@ describe('TouchHitTarget', () => {
330 ReactDOM.render(<Test />, container);
331 expect(Scheduler).toFlushWithoutYielding();
332 expect(container.innerHTML).toBe(
333 - '<div><div style="position: absolute; z-index: -1; bottom: -10px; ' +
333 + '<div style="position: relative; z-index: 0;"><div style="position: absolute; z-index: -1; bottom: -10px; ' +
334 'left: -10px; right: -10px; top: -10px;"></div></div>',
335 );
336
337 cond = true;
338 ReactDOM.render(<Test />, container);
339 expect(Scheduler).toFlushWithoutYielding();
340 - expect(container.innerHTML).toBe('<div></div>');
340 + expect(container.innerHTML).toBe(
341 + '<div style="position: relative; z-index: 0;"></div>',
342 + );
343 });
344
345 it('should render a conditional TouchHitTarget correctly (true -> false)', () => {
@@ -345,7 +347,7 @@ describe('TouchHitTarget', () => {
347
348 const Test = () => (
349 <EventComponent>
348 - <div>
350 + <div style={{position: 'relative', zIndex: 0}}>
351 {cond ? null : (
352 <TouchHitTarget top={10} left={10} right={10} bottom={10} />
353 )}
@@ -356,13 +358,15 @@ describe('TouchHitTarget', () => {
358 const container = document.createElement('div');
359 ReactDOM.render(<Test />, container);
360 expect(Scheduler).toFlushWithoutYielding();
359 - expect(container.innerHTML).toBe('<div></div>');
361 + expect(container.innerHTML).toBe(
362 + '<div style="position: relative; z-index: 0;"></div>',
363 + );
364
365 cond = false;
366 ReactDOM.render(<Test />, container);
367 expect(Scheduler).toFlushWithoutYielding();
368 expect(container.innerHTML).toBe(
365 - '<div><div style="position: absolute; z-index: -1; bottom: -10px; ' +
369 + '<div style="position: relative; z-index: 0;"><div style="position: absolute; z-index: -1; bottom: -10px; ' +
370 'left: -10px; right: -10px; top: -10px;"></div></div>',
371 );
372 });
@@ -372,7 +376,7 @@ describe('TouchHitTarget', () => {
376
377 const Test = () => (
378 <EventComponent>
375 - <div>
379 + <div style={{position: 'relative', zIndex: 0}}>
380 {cond ? (
381 <TouchHitTarget />
382 ) : (
@@ -386,14 +390,16 @@ describe('TouchHitTarget', () => {
390 ReactDOM.render(<Test />, container);
391 expect(Scheduler).toFlushWithoutYielding();
392 expect(container.innerHTML).toBe(
389 - '<div><div style="position: absolute; z-index: -1; bottom: -10px; ' +
393 + '<div style="position: relative; z-index: 0;"><div style="position: absolute; z-index: -1; bottom: -10px; ' +
394 'left: -10px; right: -10px; top: -10px;"></div></div>',
395 );
396
397 cond = true;
398 ReactDOM.render(<Test />, container);
399 expect(Scheduler).toFlushWithoutYielding();
396 - expect(container.innerHTML).toBe('<div></div>');
400 + expect(container.innerHTML).toBe(
401 + '<div style="position: relative; z-index: 0;"></div>',
402 + );
403 });
404
405 it('should render a conditional TouchHitTarget hit slop correctly (true -> false)', () => {
@@ -401,7 +407,7 @@ describe('TouchHitTarget', () => {
407
408 const Test = () => (
409 <EventComponent>
404 - <div>
410 + <div style={{position: 'relative', zIndex: 0}}>
411 <span>Random span 1</span>
412 {cond ? (
413 <TouchHitTarget />
@@ -417,14 +423,15 @@ describe('TouchHitTarget', () => {
423 ReactDOM.render(<Test />, container);
424 expect(Scheduler).toFlushWithoutYielding();
425 expect(container.innerHTML).toBe(
420 - '<div><span>Random span 1</span><span>Random span 2</span></div>',
426 + '<div style="position: relative; z-index: 0;"><span>Random span 1</span><span>Random span 2</span></div>',
427 );
428
429 cond = false;
430 ReactDOM.render(<Test />, container);
431 expect(Scheduler).toFlushWithoutYielding();
432 expect(container.innerHTML).toBe(
427 - '<div><span>Random span 1</span><div style="position: absolute; z-index: -1; bottom: -10px; ' +
433 + '<div style="position: relative; z-index: 0;"><span>Random span 1</span>' +
434 + '<div style="position: absolute; z-index: -1; bottom: -10px; ' +
435 'left: -10px; right: -10px; top: -10px;"></div><span>Random span 2</span></div>',
436 );
437 });
@@ -434,7 +441,7 @@ describe('TouchHitTarget', () => {
441
442 const Test = () => (
443 <EventComponent>
437 - <div>
444 + <div style={{position: 'relative', zIndex: 0}}>
445 <span>Random span 1</span>
446 {cond ? (
447 <TouchHitTarget top={10} left={null} right={10} bottom={10} />
@@ -455,7 +462,8 @@ describe('TouchHitTarget', () => {
462 ReactDOM.render(<Test />, container);
463 expect(Scheduler).toFlushWithoutYielding();
464 expect(container.innerHTML).toBe(
458 - '<div><span>Random span 1</span><div style="position: absolute; z-index: -1; bottom: 0px; ' +
465 + '<div style="position: relative; z-index: 0;"><span>Random span 1</span>' +
466 + '<div style="position: absolute; z-index: -1; bottom: 0px; ' +
467 'left: -20px; right: 0px; top: 0px;"></div><span>Random span 2</span></div>',
468 );
469
@@ -463,7 +471,8 @@ describe('TouchHitTarget', () => {
471 ReactDOM.render(<Test />, container);
472 expect(Scheduler).toFlushWithoutYielding();
473 expect(container.innerHTML).toBe(
466 - '<div><span>Random span 1</span><div style="position: absolute; z-index: -1; bottom: 0px; ' +
474 + '<div style="position: relative; z-index: 0;"><span>Random span 1</span>' +
475 + '<div style="position: absolute; z-index: -1; bottom: 0px; ' +
476 'left: -20px; right: 0px; top: 0px;"></div><span>Random span 2</span></div>',
477 );
478 });
@@ -473,7 +482,7 @@ describe('TouchHitTarget', () => {
482
483 const Test = () => (
484 <EventComponent>
476 - <div>
485 + <div style={{position: 'relative', zIndex: 0}}>
486 <span>Random span 1</span>
487 {cond ? (
488 <TouchHitTarget top={10} left={null} right={10} bottom={10} />
@@ -494,7 +503,8 @@ describe('TouchHitTarget', () => {
503 ReactDOM.render(<Test />, container);
504 expect(Scheduler).toFlushWithoutYielding();
505 expect(container.innerHTML).toBe(
497 - '<div><span>Random span 1</span><div style="position: absolute; z-index: -1; bottom: -10px; ' +
506 + '<div style="position: relative; z-index: 0;"><span>Random span 1</span>' +
507 + '<div style="position: absolute; z-index: -1; bottom: -10px; ' +
508 'left: 0px; right: -10px; top: -10px;"></div><span>Random span 2</span></div>',
509 );
510
@@ -502,7 +512,8 @@ describe('TouchHitTarget', () => {
512 ReactDOM.render(<Test />, container);
513 expect(Scheduler).toFlushWithoutYielding();
514 expect(container.innerHTML).toBe(
505 - '<div><span>Random span 1</span><div style="position: absolute; z-index: -1; bottom: -10px; ' +
515 + '<div style="position: relative; z-index: 0;"><span>Random span 1</span>' +
516 + '<div style="position: absolute; z-index: -1; bottom: -10px; ' +
517 'left: 0px; right: -10px; top: -10px;"></div><span>Random span 2</span></div>',
518 );
519 });
@@ -510,14 +521,15 @@ describe('TouchHitTarget', () => {
521 it('should hydrate TouchHitTarget hit slop elements correcty and patch them', () => {
522 const Test = () => (
523 <EventComponent>
513 - <div>
524 + <div style={{position: 'relative', zIndex: 0}}>
525 <TouchHitTarget top={10} left={10} right={10} bottom={10} />
526 </div>
527 </EventComponent>
528 );
529
530 const container = document.createElement('div');
520 - container.innerHTML = '<div></div>';
531 + container.innerHTML =
532 + '<div style="position: relative; z-index: 0"></div>';
533 expect(() => {
534 ReactDOM.hydrate(<Test />, container);
535 expect(Scheduler).toFlushWithoutYielding();
@@ -527,7 +539,7 @@ describe('TouchHitTarget', () => {
539 );
540 expect(Scheduler).toFlushWithoutYielding();
541 expect(container.innerHTML).toBe(
530 - '<div><div style="position: absolute; z-index: -1; bottom: -10px; ' +
542 + '<div style="position: relative; z-index: 0"><div style="position: absolute; z-index: -1; bottom: -10px; ' +
543 'left: -10px; right: -10px; top: -10px;"></div></div>',
544 );
545 });
packages/react-reconciler/src/ReactFiberCommitWork.js
+35 -29
@@ -595,9 +595,41 @@ function commitLifeCycles(
595 }
596 case SuspenseComponent:
597 case IncompleteClassComponent:
598 - case EventTarget:
599 - case EventComponent:
600 - break;
598 + return;
599 + case EventTarget: {
600 + if (enableEventAPI) {
601 + const type = finishedWork.type.type;
602 + const props = finishedWork.memoizedProps;
603 + const instance = finishedWork.stateNode;
604 + let parentInstance = null;
605 +
606 + let node = finishedWork.return;
607 + // Traverse up the fiber tree until we find the parent host node.
608 + while (node !== null) {
609 + if (node.tag === HostComponent) {
610 + parentInstance = node.stateNode;
611 + break;
612 + } else if (node.tag === HostRoot) {
613 + parentInstance = node.stateNode.containerInfo;
614 + break;
615 + }
616 + node = node.return;
617 + }
618 + invariant(
619 + parentInstance !== null,
620 + 'This should have a parent host component initialized. This error is likely ' +
621 + 'caused by a bug in React. Please file an issue.',
622 + );
623 + commitEventTarget(type, props, instance, parentInstance);
624 + }
625 + return;
626 + }
627 + case EventComponent: {
628 + if (enableEventAPI) {
629 + mountEventComponent(finishedWork.stateNode);
630 + }
631 + return;
632 + }
633 default: {
634 invariant(
635 false,
@@ -1218,31 +1250,6 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1250 return;
1251 }
1252 case EventTarget: {
1221 - if (enableEventAPI) {
1222 - const type = finishedWork.type.type;
1223 - const props = finishedWork.memoizedProps;
1224 - const instance = finishedWork.stateNode;
1225 - let parentInstance = null;
1226 -
1227 - let node = finishedWork.return;
1228 - // Traverse up the fiber tree until we find the parent host node.
1229 - while (node !== null) {
1230 - if (node.tag === HostComponent) {
1231 - parentInstance = node.stateNode;
1232 - break;
1233 - } else if (node.tag === HostRoot) {
1234 - parentInstance = node.stateNode.containerInfo;
1235 - break;
1236 - }
1237 - node = node.return;
1238 - }
1239 - invariant(
1240 - parentInstance !== null,
1241 - 'This should have a parent host component initialized. This error is likely ' +
1242 - 'caused by a bug in React. Please file an issue.',
1243 - );
1244 - commitEventTarget(type, props, instance, parentInstance);
1245 - }
1253 return;
1254 }
1255 case HostRoot: {
@@ -1259,7 +1266,6 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1266 return;
1267 }
1268 case EventComponent: {
1262 - mountEventComponent(finishedWork.stateNode);
1269 return;
1270 }
1271 default: {