Event API: various bug fixes (#15485)

This commit is contained in:
Dominic Gannaway
2019-04-24 17:56:21 +01:00
committed by GitHub
parent fb28e90482
commit 3f058debc2
5 changed files with 93 additions and 63 deletions
+9 -2
View File
@@ -966,6 +966,13 @@ export function handleEventTarget(
rootContainerInstance: Container,
internalInstanceHandle: Object,
): boolean {
if (
__DEV__ &&
type === REACT_EVENT_TARGET_TOUCH_HIT &&
(props.left || props.right || props.top || props.bottom)
) {
return true;
}
return false;
}
@@ -992,9 +999,9 @@ export function commitEventTarget(
'value of "relative".',
);
warning(
computedStyles.getPropertyValue('zIndex') !== '',
computedStyles.getPropertyValue('z-index') !== '',
'<TouchHitTarget> inserts an empty <div> with "z-index" of "-1". ' +
'This requires its parent DOM node to have a "z-index" great than "-1",' +
'This requires its parent DOM node to have a "z-index" greater than "-1",' +
'but the parent DOM node was found to no "z-index" value set.' +
' Try using a "z-index" value of "0" or greater.',
);
+1 -1
View File
@@ -108,7 +108,7 @@ const FocusResponder = {
onEvent(
event: ReactResponderEvent,
context: ReactResponderContext,
props: Object,
props: FocusProps,
state: FocusState,
): void {
const {type, target} = event;
+15 -10
View File
@@ -94,7 +94,9 @@ const targetEventTypes = [
{name: 'keydown', passive: false},
{name: 'keypress', passive: false},
{name: 'contextmenu', passive: false},
'pointerdown',
// We need to preventDefault on pointerdown for mouse/pen events
// that are in hit target area but not the element area.
{name: 'pointerdown', passive: false},
'pointercancel',
];
const rootEventTypes = ['keyup', 'pointerup', 'pointermove', 'scroll'];
@@ -447,15 +449,18 @@ const PressResponder = {
}
}
// Ignore emulated mouse events and mouse pressing on touch hit target
// area
if (type === 'mousedown') {
if (
state.ignoreEmulatedMouseEvents ||
isEventPositionWithinTouchHitTarget(event, context)
) {
return;
}
// Ignore emulated mouse events
if (type === 'mousedown' && state.ignoreEmulatedMouseEvents) {
return;
}
// Ignore mouse/pen pressing on touch hit target area
if (
(pointerType === 'mouse' || pointerType === 'pen') &&
isEventPositionWithinTouchHitTarget(event, context)
) {
// We need to prevent the native event to block the focus
nativeEvent.preventDefault();
return;
}
// Ignore any device buttons except left-mouse and touch/pen contact
@@ -318,7 +318,7 @@ describe('TouchHitTarget', () => {
const Test = () => (
<EventComponent>
<div>
<div style={{position: 'relative', zIndex: 0}}>
{cond ? null : (
<TouchHitTarget top={10} left={10} right={10} bottom={10} />
)}
@@ -330,14 +330,16 @@ describe('TouchHitTarget', () => {
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<div><div style="position: absolute; z-index: -1; bottom: -10px; ' +
'<div style="position: relative; z-index: 0;"><div style="position: absolute; z-index: -1; bottom: -10px; ' +
'left: -10px; right: -10px; top: -10px;"></div></div>',
);
cond = true;
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe('<div></div>');
expect(container.innerHTML).toBe(
'<div style="position: relative; z-index: 0;"></div>',
);
});
it('should render a conditional TouchHitTarget correctly (true -> false)', () => {
@@ -345,7 +347,7 @@ describe('TouchHitTarget', () => {
const Test = () => (
<EventComponent>
<div>
<div style={{position: 'relative', zIndex: 0}}>
{cond ? null : (
<TouchHitTarget top={10} left={10} right={10} bottom={10} />
)}
@@ -356,13 +358,15 @@ describe('TouchHitTarget', () => {
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe('<div></div>');
expect(container.innerHTML).toBe(
'<div style="position: relative; z-index: 0;"></div>',
);
cond = false;
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<div><div style="position: absolute; z-index: -1; bottom: -10px; ' +
'<div style="position: relative; z-index: 0;"><div style="position: absolute; z-index: -1; bottom: -10px; ' +
'left: -10px; right: -10px; top: -10px;"></div></div>',
);
});
@@ -372,7 +376,7 @@ describe('TouchHitTarget', () => {
const Test = () => (
<EventComponent>
<div>
<div style={{position: 'relative', zIndex: 0}}>
{cond ? (
<TouchHitTarget />
) : (
@@ -386,14 +390,16 @@ describe('TouchHitTarget', () => {
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<div><div style="position: absolute; z-index: -1; bottom: -10px; ' +
'<div style="position: relative; z-index: 0;"><div style="position: absolute; z-index: -1; bottom: -10px; ' +
'left: -10px; right: -10px; top: -10px;"></div></div>',
);
cond = true;
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe('<div></div>');
expect(container.innerHTML).toBe(
'<div style="position: relative; z-index: 0;"></div>',
);
});
it('should render a conditional TouchHitTarget hit slop correctly (true -> false)', () => {
@@ -401,7 +407,7 @@ describe('TouchHitTarget', () => {
const Test = () => (
<EventComponent>
<div>
<div style={{position: 'relative', zIndex: 0}}>
<span>Random span 1</span>
{cond ? (
<TouchHitTarget />
@@ -417,14 +423,15 @@ describe('TouchHitTarget', () => {
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<div><span>Random span 1</span><span>Random span 2</span></div>',
'<div style="position: relative; z-index: 0;"><span>Random span 1</span><span>Random span 2</span></div>',
);
cond = false;
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<div><span>Random span 1</span><div style="position: absolute; z-index: -1; bottom: -10px; ' +
'<div style="position: relative; z-index: 0;"><span>Random span 1</span>' +
'<div style="position: absolute; z-index: -1; bottom: -10px; ' +
'left: -10px; right: -10px; top: -10px;"></div><span>Random span 2</span></div>',
);
});
@@ -434,7 +441,7 @@ describe('TouchHitTarget', () => {
const Test = () => (
<EventComponent>
<div>
<div style={{position: 'relative', zIndex: 0}}>
<span>Random span 1</span>
{cond ? (
<TouchHitTarget top={10} left={null} right={10} bottom={10} />
@@ -455,7 +462,8 @@ describe('TouchHitTarget', () => {
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<div><span>Random span 1</span><div style="position: absolute; z-index: -1; bottom: 0px; ' +
'<div style="position: relative; z-index: 0;"><span>Random span 1</span>' +
'<div style="position: absolute; z-index: -1; bottom: 0px; ' +
'left: -20px; right: 0px; top: 0px;"></div><span>Random span 2</span></div>',
);
@@ -463,7 +471,8 @@ describe('TouchHitTarget', () => {
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<div><span>Random span 1</span><div style="position: absolute; z-index: -1; bottom: 0px; ' +
'<div style="position: relative; z-index: 0;"><span>Random span 1</span>' +
'<div style="position: absolute; z-index: -1; bottom: 0px; ' +
'left: -20px; right: 0px; top: 0px;"></div><span>Random span 2</span></div>',
);
});
@@ -473,7 +482,7 @@ describe('TouchHitTarget', () => {
const Test = () => (
<EventComponent>
<div>
<div style={{position: 'relative', zIndex: 0}}>
<span>Random span 1</span>
{cond ? (
<TouchHitTarget top={10} left={null} right={10} bottom={10} />
@@ -494,7 +503,8 @@ describe('TouchHitTarget', () => {
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<div><span>Random span 1</span><div style="position: absolute; z-index: -1; bottom: -10px; ' +
'<div style="position: relative; z-index: 0;"><span>Random span 1</span>' +
'<div style="position: absolute; z-index: -1; bottom: -10px; ' +
'left: 0px; right: -10px; top: -10px;"></div><span>Random span 2</span></div>',
);
@@ -502,7 +512,8 @@ describe('TouchHitTarget', () => {
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<div><span>Random span 1</span><div style="position: absolute; z-index: -1; bottom: -10px; ' +
'<div style="position: relative; z-index: 0;"><span>Random span 1</span>' +
'<div style="position: absolute; z-index: -1; bottom: -10px; ' +
'left: 0px; right: -10px; top: -10px;"></div><span>Random span 2</span></div>',
);
});
@@ -510,14 +521,15 @@ describe('TouchHitTarget', () => {
it('should hydrate TouchHitTarget hit slop elements correcty and patch them', () => {
const Test = () => (
<EventComponent>
<div>
<div style={{position: 'relative', zIndex: 0}}>
<TouchHitTarget top={10} left={10} right={10} bottom={10} />
</div>
</EventComponent>
);
const container = document.createElement('div');
container.innerHTML = '<div></div>';
container.innerHTML =
'<div style="position: relative; z-index: 0"></div>';
expect(() => {
ReactDOM.hydrate(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
@@ -527,7 +539,7 @@ describe('TouchHitTarget', () => {
);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<div><div style="position: absolute; z-index: -1; bottom: -10px; ' +
'<div style="position: relative; z-index: 0"><div style="position: absolute; z-index: -1; bottom: -10px; ' +
'left: -10px; right: -10px; top: -10px;"></div></div>',
);
});
+35 -29
View File
@@ -595,9 +595,41 @@ function commitLifeCycles(
}
case SuspenseComponent:
case IncompleteClassComponent:
case EventTarget:
case EventComponent:
break;
return;
case EventTarget: {
if (enableEventAPI) {
const type = finishedWork.type.type;
const props = finishedWork.memoizedProps;
const instance = finishedWork.stateNode;
let parentInstance = null;
let node = finishedWork.return;
// Traverse up the fiber tree until we find the parent host node.
while (node !== null) {
if (node.tag === HostComponent) {
parentInstance = node.stateNode;
break;
} else if (node.tag === HostRoot) {
parentInstance = node.stateNode.containerInfo;
break;
}
node = node.return;
}
invariant(
parentInstance !== null,
'This should have a parent host component initialized. This error is likely ' +
'caused by a bug in React. Please file an issue.',
);
commitEventTarget(type, props, instance, parentInstance);
}
return;
}
case EventComponent: {
if (enableEventAPI) {
mountEventComponent(finishedWork.stateNode);
}
return;
}
default: {
invariant(
false,
@@ -1218,31 +1250,6 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
return;
}
case EventTarget: {
if (enableEventAPI) {
const type = finishedWork.type.type;
const props = finishedWork.memoizedProps;
const instance = finishedWork.stateNode;
let parentInstance = null;
let node = finishedWork.return;
// Traverse up the fiber tree until we find the parent host node.
while (node !== null) {
if (node.tag === HostComponent) {
parentInstance = node.stateNode;
break;
} else if (node.tag === HostRoot) {
parentInstance = node.stateNode.containerInfo;
break;
}
node = node.return;
}
invariant(
parentInstance !== null,
'This should have a parent host component initialized. This error is likely ' +
'caused by a bug in React. Please file an issue.',
);
commitEventTarget(type, props, instance, parentInstance);
}
return;
}
case HostRoot: {
@@ -1259,7 +1266,6 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
return;
}
case EventComponent: {
mountEventComponent(finishedWork.stateNode);
return;
}
default: {