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: {