[Flare] Remove event targets including TouchHitTarget (#16011)

This commit is contained in:
Dominic Gannaway 2019-06-27 23:58:48 +01:00 committed by GitHub
parent f11540926d
commit 8b88ac2592
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 18 additions and 1789 deletions

View File

@ -333,10 +333,6 @@ export function getChildHostContextForEventComponent() {
return NO_CONTEXT;
}
export function getChildHostContextForEventTarget() {
return NO_CONTEXT;
}
export const scheduleTimeout = setTimeout;
export const cancelTimeout = clearTimeout;
export const noTimeout = -1;

View File

@ -97,7 +97,6 @@ let didWarnShadyDOM = false;
const DANGEROUSLY_SET_INNER_HTML = 'dangerouslySetInnerHTML';
const SUPPRESS_CONTENT_EDITABLE_WARNING = 'suppressContentEditableWarning';
const SUPPRESS_HYDRATION_WARNING = 'suppressHydrationWarning';
const HYDRATE_TOUCH_HIT_TARGET = 'hydrateTouchHitTarget';
const AUTOFOCUS = 'autoFocus';
const CHILDREN = 'children';
const STYLE = 'style';
@ -1034,8 +1033,6 @@ export function diffHydratedProperties(
}
ensureListeningTo(rootContainerElement, propKey);
}
} else if (enableEventAPI && propKey === HYDRATE_TOUCH_HIT_TARGET) {
updatePayload = [STYLE, rawProps.style];
} else if (
__DEV__ &&
// Convince Flow we've calculated it (it's DEV-only in this method.)

View File

@ -31,7 +31,7 @@ import {
isEnabled as ReactBrowserEventEmitterIsEnabled,
setEnabled as ReactBrowserEventEmitterSetEnabled,
} from '../events/ReactBrowserEventEmitter';
import {Namespaces, getChildNamespace} from '../shared/DOMNamespaces';
import {getChildNamespace} from '../shared/DOMNamespaces';
import {addRootEventTypesForComponentInstance} from '../events/DOMEventResponderSystem';
import {
ELEMENT_NODE,
@ -51,8 +51,6 @@ import {
mountEventResponder,
unmountEventResponder,
} from '../events/DOMEventResponderSystem';
import {REACT_EVENT_TARGET_TOUCH_HIT} from 'shared/ReactSymbols';
import {canUseDOM} from 'shared/ExecutionEnvironment';
export type Type = string;
export type Props = {
@ -93,7 +91,6 @@ type HostContextDev = {
ancestorInfo: mixed,
eventData: null | {|
isEventComponent?: boolean,
isEventTarget?: boolean,
|},
};
type HostContextProd = string;
@ -109,8 +106,6 @@ import {
} from 'shared/ReactFeatureFlags';
import warning from 'shared/warning';
const {html: HTML_NAMESPACE} = Namespaces;
let SUPPRESS_HYDRATION_WARNING;
if (__DEV__) {
SUPPRESS_HYDRATION_WARNING = 'suppressHydrationWarning';
@ -196,45 +191,8 @@ export function getChildHostContextForEventComponent(
if (__DEV__) {
const parentHostContextDev = ((parentHostContext: any): HostContextDev);
const {namespace, ancestorInfo} = parentHostContextDev;
warning(
parentHostContextDev.eventData === null ||
!parentHostContextDev.eventData.isEventTarget,
'validateDOMNesting: React event targets must not have event components as children.',
);
const eventData = {
isEventComponent: true,
isEventTarget: false,
};
return {namespace, ancestorInfo, eventData};
}
return parentHostContext;
}
export function getChildHostContextForEventTarget(
parentHostContext: HostContext,
type: Symbol | number,
): HostContext {
if (__DEV__) {
const parentHostContextDev = ((parentHostContext: any): HostContextDev);
const {namespace, ancestorInfo} = parentHostContextDev;
if (type === REACT_EVENT_TARGET_TOUCH_HIT) {
warning(
parentHostContextDev.eventData === null ||
!parentHostContextDev.eventData.isEventComponent,
'validateDOMNesting: <TouchHitTarget> cannot not be a direct child of an event component. ' +
'Ensure <TouchHitTarget> is a direct child of a DOM element.',
);
const parentNamespace = parentHostContextDev.namespace;
if (parentNamespace !== HTML_NAMESPACE) {
throw new Error(
'<TouchHitTarget> was used in an unsupported DOM namespace. ' +
'Ensure the <TouchHitTarget> is used in an HTML namespace.',
);
}
}
const eventData = {
isEventComponent: false,
isEventTarget: true,
};
return {namespace, ancestorInfo, eventData};
}
@ -924,85 +882,3 @@ export function unmountEventComponent(
unmountEventResponder(eventComponentInstance);
}
}
export function getEventTargetChildElement(
type: Symbol | number,
props: Props,
): null | EventTargetChildElement {
if (enableEventAPI) {
if (type === REACT_EVENT_TARGET_TOUCH_HIT) {
const {bottom, left, right, top} = props;
if (!bottom && !left && !right && !top) {
return null;
}
return {
type: 'div',
props: {
style: {
position: 'absolute',
zIndex: -1,
pointerEvents: null,
bottom: bottom ? `-${bottom}px` : '0px',
left: left ? `-${left}px` : '0px',
right: right ? `-${right}px` : '0px',
top: top ? `-${top}px` : '0px',
},
hydrateTouchHitTarget: true,
suppressHydrationWarning: true,
},
};
}
}
return null;
}
export function handleEventTarget(
type: Symbol | number,
props: Props,
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;
}
export function commitEventTarget(
type: Symbol | number,
props: Props,
instance: Instance,
parentInstance: Instance,
): void {
if (enableEventAPI) {
if (type === REACT_EVENT_TARGET_TOUCH_HIT) {
if (__DEV__ && canUseDOM) {
// This is done at DEV time because getComputedStyle will
// typically force a style recalculation and force a layout,
// reflow - both of which are sync are expensive.
const computedStyles = window.getComputedStyle(parentInstance);
const position = computedStyles.getPropertyValue('position');
warning(
position !== '' && position !== 'static',
'<TouchHitTarget> inserts an empty absolutely positioned <div>. ' +
'This requires its parent DOM node to be positioned too, but the ' +
'parent DOM node was found to have the style "position" set to ' +
'either no value, or a value of "static". Try using a "position" ' +
'value of "relative".',
);
warning(
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" 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.',
);
}
}
}
}

View File

@ -14,7 +14,6 @@ import {
import type {AnyNativeEvent} from 'events/PluginModuleType';
import {
EventComponent,
EventTarget as EventTargetWorkTag,
HostComponent,
FunctionComponent,
} from 'shared/ReactWorkTags';
@ -182,35 +181,6 @@ const eventResponderContext: ReactDOMResponderContext = {
eventListeners.set(eventObject, listener);
eventQueue.events.push(eventObject);
},
isEventWithinTouchHitTarget(event: ReactDOMResponderEvent): boolean {
validateResponderContext();
const target = event.target;
const nativeEvent = event.nativeEvent;
// We should always be dealing with a mouse event or touch event here.
// If we are not, these won't exist and we can early return.
const x = (nativeEvent: any).clientX;
const y = (nativeEvent: any).clientY;
if (x === undefined || y === undefined) {
return false;
}
const childFiber = getClosestInstanceFromNode(target);
if (childFiber === null) {
return false;
}
const parentFiber = childFiber.return;
if (parentFiber !== null && parentFiber.tag === EventTargetWorkTag) {
const parentNode = ((target.parentNode: any): Element);
// TODO find another way to do this without using the
// expensive getBoundingClientRect.
const {left, top, right, bottom} = parentNode.getBoundingClientRect();
// Check if the co-ords intersect with the target element's rect.
if (x > left && y > top && x < right && y < bottom) {
return false;
}
return true;
}
return false;
},
isTargetWithinEventComponent(target: Element | Document): boolean {
validateResponderContext();
if (target != null) {

View File

@ -39,8 +39,6 @@ import {
REACT_LAZY_TYPE,
REACT_MEMO_TYPE,
REACT_EVENT_COMPONENT_TYPE,
REACT_EVENT_TARGET_TYPE,
REACT_EVENT_TARGET_TOUCH_HIT,
} from 'shared/ReactSymbols';
import {
@ -1168,32 +1166,8 @@ class ReactDOMServerRenderer {
this.stack.push(frame);
return '';
}
case REACT_EVENT_COMPONENT_TYPE:
case REACT_EVENT_TARGET_TYPE: {
case REACT_EVENT_COMPONENT_TYPE: {
if (enableEventAPI) {
if (
elementType.$$typeof === REACT_EVENT_TARGET_TYPE &&
elementType.type === REACT_EVENT_TARGET_TOUCH_HIT
) {
const props = nextElement.props;
const bottom = props.bottom || 0;
const left = props.left || 0;
const right = props.right || 0;
const top = props.top || 0;
if (bottom === 0 && left === 0 && right === 0 && top === 0) {
return '';
}
let topString = top ? `-${top}px` : '0px';
let leftString = left ? `-${left}px` : '0px';
let rightString = right ? `-${right}px` : '0x';
let bottomString = bottom ? `-${bottom}px` : '0px';
return (
`<div style="position:absolute;pointer-events:none;z-index:-1;bottom:` +
`${bottomString};left:${leftString};right:${rightString};top:${topString}"></div>`
);
}
const nextChildren = toArray(
((nextChild: any): ReactElement).props.children,
);

View File

@ -219,7 +219,6 @@ const properties = {};
'suppressContentEditableWarning',
'suppressHydrationWarning',
'style',
'hydrateTouchHitTarget',
].forEach(name => {
properties[name] = new PropertyInfoRecord(
name,

View File

@ -12,8 +12,6 @@ import warning from 'shared/warning';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import voidElementTags from './voidElementTags';
import {enableEventAPI} from 'shared/ReactFeatureFlags';
import {REACT_EVENT_TARGET_TYPE} from 'shared/ReactSymbols';
const HTML = '__html';
@ -29,11 +27,7 @@ function assertValidProps(tag: string, props: ?Object) {
// Note the use of `==` which checks for null or undefined.
if (voidElementTags[tag]) {
invariant(
(props.children == null ||
(enableEventAPI &&
props.children.type &&
props.children.type.$$typeof === REACT_EVENT_TARGET_TYPE)) &&
props.dangerouslySetInnerHTML == null,
props.children == null && props.dangerouslySetInnerHTML == null,
'%s is a void element tag and must neither have `children` nor ' +
'use `dangerouslySetInnerHTML`.%s',
tag,

View File

@ -121,10 +121,6 @@ Component instance.
Returns `true` if the instance has taken ownership of the responder.
### isEventWithinTouchHitTarget(event: ResponderEvent): boolean
Returns `true` if the global coordinates lie within the TouchHitTarget.
### isTargetWithinElement(target: Element, element: Element): boolean
Returns `true` if `target` is a child of `element`.

View File

@ -119,7 +119,7 @@ Determines whether calling `onPress` should be cancelled if `onLongPress` or
Called immediately after a press is released, unless either 1) the press is
released outside the hit bounds of the element (accounting for
`pressRetentionOffset` and `TouchHitTarget`), or 2) the press was a long press,
`pressRetentionOffset`), or 2) the press was a long press,
and `onLongPress` or `onLongPressChange` props are provided, and
`onLongPressCancelsPress()` is `true`.

View File

@ -1,12 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
'use strict';
export * from './src/ReactEvents';

View File

@ -1,7 +0,0 @@
'use strict';
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react-events.production.min.js');
} else {
module.exports = require('./cjs/react-events.development.js');
}

View File

@ -19,7 +19,6 @@
"drag.js",
"scroll.js",
"focus-scope.js",
"index.js",
"build-info.json",
"cjs/",
"umd/"

View File

@ -1,19 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import {
REACT_EVENT_TARGET_TYPE,
REACT_EVENT_TARGET_TOUCH_HIT,
} from 'shared/ReactSymbols';
import type {ReactEventTarget} from 'shared/ReactTypes';
export const TouchHitTarget: ReactEventTarget = {
$$typeof: REACT_EVENT_TARGET_TYPE,
type: REACT_EVENT_TARGET_TOUCH_HIT,
};

View File

@ -31,7 +31,6 @@ type HoverState = {
hoverTarget: null | Element | Document,
isActiveHovered: boolean,
isHovered: boolean,
isOverTouchHitTarget: boolean,
isTouched: boolean,
hoverStartTimeout: null | number,
hoverEndTimeout: null | number,
@ -228,8 +227,6 @@ function dispatchHoverEndEvents(
if (props.onHoverChange) {
dispatchHoverChangeEvent(event, context, props, state);
}
state.isOverTouchHitTarget = false;
state.hoverTarget = null;
state.ignoreEmulatedMouseEvents = false;
state.isTouched = false;
@ -281,7 +278,6 @@ const HoverResponder: ReactDOMEventResponder = {
return {
isActiveHovered: false,
isHovered: false,
isOverTouchHitTarget: false,
isTouched: false,
hoverStartTimeout: null,
hoverEndTimeout: null,
@ -325,11 +321,6 @@ const HoverResponder: ReactDOMEventResponder = {
if (isEmulatedMouseEvent(event, state)) {
return;
}
if (context.isEventWithinTouchHitTarget(event)) {
state.isOverTouchHitTarget = true;
return;
}
state.hoverTarget = context.getEventCurrentTarget(event);
state.ignoreEmulatedMouseEvents = true;
dispatchHoverStartEvents(event, context, props, state);
@ -342,34 +333,18 @@ const HoverResponder: ReactDOMEventResponder = {
case 'mousemove': {
if (state.isHovered && !isEmulatedMouseEvent(event, state)) {
if (state.isHovered) {
if (state.isOverTouchHitTarget) {
// If we were moving over the TouchHitTarget and have now moved
// over the Responder target
if (!context.isEventWithinTouchHitTarget(event)) {
dispatchHoverStartEvents(event, context, props, state);
state.isOverTouchHitTarget = false;
}
} else {
// If we were moving over the Responder target and have now moved
// over the TouchHitTarget
if (context.isEventWithinTouchHitTarget(event)) {
dispatchHoverEndEvents(event, context, props, state);
state.isOverTouchHitTarget = true;
} else {
if (props.onHoverMove && state.hoverTarget !== null) {
const syntheticEvent = createHoverEvent(
event,
context,
'hovermove',
state.hoverTarget,
);
context.dispatchEvent(
syntheticEvent,
props.onHoverMove,
UserBlockingEvent,
);
}
}
if (props.onHoverMove && state.hoverTarget !== null) {
const syntheticEvent = createHoverEvent(
event,
context,
'hovermove',
state.hoverTarget,
);
context.dispatchEvent(
syntheticEvent,
props.onHoverMove,
UserBlockingEvent,
);
}
}
}

View File

@ -671,7 +671,6 @@ const PressResponder: ReactDOMEventResponder = {
const isPointerEvent = type === 'pointerdown';
const isKeyboardEvent = pointerType === 'keyboard';
const isMouseEvent = pointerType === 'mouse';
const isPenEvent = pointerType === 'pen';
if (isPointerEvent || isTouchEvent) {
state.ignoreEmulatedMouseEvents = true;
@ -684,16 +683,6 @@ const PressResponder: ReactDOMEventResponder = {
return;
}
}
// Ignore mouse/pen pressing on touch hit target area
if (
(isMouseEvent || isPenEvent) &&
context.isEventWithinTouchHitTarget(event)
) {
// We need to prevent the native event to block the focus
removeRootEventTypes(context, state);
nativeEvent.preventDefault();
return;
}
// We set these here, before the button check so we have this
// data around for handling of the context menu

View File

@ -1,649 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
let React;
let ReactNoop;
let Scheduler;
let ReactFeatureFlags;
let EventComponent;
let ReactTestRenderer;
let ReactDOM;
let ReactDOMServer;
let ReactSymbols;
let ReactEvents;
let TouchHitTarget;
const noOpResponder = {
targetEventTypes: [],
onEvent() {},
};
function createReactEventComponent() {
return {
$$typeof: ReactSymbols.REACT_EVENT_COMPONENT_TYPE,
props: null,
responder: noOpResponder,
};
}
function init() {
jest.resetModules();
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.enableEventAPI = true;
React = require('react');
Scheduler = require('scheduler');
ReactSymbols = require('shared/ReactSymbols');
ReactEvents = require('react-events');
}
function initNoopRenderer() {
init();
ReactNoop = require('react-noop-renderer');
}
function initTestRenderer() {
init();
ReactTestRenderer = require('react-test-renderer');
}
function initReactDOM() {
init();
ReactDOM = require('react-dom');
}
function initReactDOMServer() {
init();
ReactDOMServer = require('react-dom/server');
}
describe('TouchHitTarget', () => {
describe('NoopRenderer', () => {
beforeEach(() => {
initNoopRenderer();
EventComponent = createReactEventComponent();
TouchHitTarget = ReactEvents.TouchHitTarget;
});
it('should not warn when a TouchHitTarget is used correctly', () => {
const Test = () => (
<EventComponent>
<div>
<TouchHitTarget />
</div>
</EventComponent>
);
ReactNoop.render(<Test />);
expect(Scheduler).toFlushWithoutYielding();
expect(ReactNoop).toMatchRenderedOutput(<div />);
});
it('should warn when a TouchHitTarget has children', () => {
const Test = () => (
<EventComponent>
<div>
<TouchHitTarget>
<span>Child 1</span>
</TouchHitTarget>
</div>
</EventComponent>
);
expect(() => {
ReactNoop.render(<Test />);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
const Test2 = () => (
<EventComponent>
<div>
<TouchHitTarget>Child 1</TouchHitTarget>
</div>
</EventComponent>
);
expect(() => {
ReactNoop.render(<Test2 />);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
// Should render without warnings
const Test3 = () => (
<EventComponent>
<div>
<TouchHitTarget />
</div>
</EventComponent>
);
ReactNoop.render(<Test3 />);
expect(Scheduler).toFlushWithoutYielding();
expect(ReactNoop).toMatchRenderedOutput(<div />);
});
it('should warn when a TouchHitTarget is a direct child of an event component', () => {
const Test = () => (
<EventComponent>
<TouchHitTarget />
</EventComponent>
);
expect(() => {
ReactNoop.render(<Test />);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev(
'Warning: validateDOMNesting: <TouchHitTarget> cannot not be a direct child of an event component. ' +
'Ensure <TouchHitTarget> is a direct child of a DOM element.',
);
});
});
describe('TestRenderer', () => {
beforeEach(() => {
initTestRenderer();
EventComponent = createReactEventComponent();
TouchHitTarget = ReactEvents.TouchHitTarget;
});
it('should not warn when a TouchHitTarget is used correctly', () => {
const Test = () => (
<EventComponent>
<div>
<TouchHitTarget />
</div>
</EventComponent>
);
const root = ReactTestRenderer.create(null);
root.update(<Test />);
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput(<div />);
});
it('should warn when a TouchHitTarget has children', () => {
const Test = () => (
<EventComponent>
<div>
<TouchHitTarget>
<span>Child 1</span>
</TouchHitTarget>
</div>
</EventComponent>
);
const root = ReactTestRenderer.create(null);
expect(() => {
root.update(<Test />);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
const Test2 = () => (
<EventComponent>
<div>
<TouchHitTarget>Child 1</TouchHitTarget>
</div>
</EventComponent>
);
expect(() => {
root.update(<Test2 />);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
// Should render without warnings
const Test3 = () => (
<EventComponent>
<div>
<TouchHitTarget />
</div>
</EventComponent>
);
root.update(<Test3 />);
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput(<div />);
});
it('should warn when a TouchHitTarget is a direct child of an event component', () => {
const Test = () => (
<EventComponent>
<TouchHitTarget />
</EventComponent>
);
const root = ReactTestRenderer.create(null);
expect(() => {
root.update(<Test />);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev(
'Warning: validateDOMNesting: <TouchHitTarget> cannot not be a direct child of an event component. ' +
'Ensure <TouchHitTarget> is a direct child of a DOM element.',
);
});
});
describe('ReactDOM', () => {
beforeEach(() => {
initReactDOM();
EventComponent = createReactEventComponent();
TouchHitTarget = ReactEvents.TouchHitTarget;
});
it('should not warn when a TouchHitTarget is used correctly', () => {
const Test = () => (
<EventComponent>
<div>
<TouchHitTarget />
</div>
</EventComponent>
);
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe('<div></div>');
});
it('should warn when a TouchHitTarget has children', () => {
const Test = () => (
<EventComponent>
<div>
<TouchHitTarget>
<span>Child 1</span>
</TouchHitTarget>
</div>
</EventComponent>
);
const container = document.createElement('div');
expect(() => {
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
const Test2 = () => (
<EventComponent>
<div>
<TouchHitTarget>Child 1</TouchHitTarget>
</div>
</EventComponent>
);
expect(() => {
ReactDOM.render(<Test2 />, container);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
// Should render without warnings
const Test3 = () => (
<EventComponent>
<div>
<TouchHitTarget />
</div>
</EventComponent>
);
ReactDOM.render(<Test3 />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe('<div></div>');
});
it('should warn when a TouchHitTarget is a direct child of an event component', () => {
const Test = () => (
<EventComponent>
<TouchHitTarget />
</EventComponent>
);
const container = document.createElement('div');
expect(() => {
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev(
'Warning: validateDOMNesting: <TouchHitTarget> cannot not be a direct child of an event component. ' +
'Ensure <TouchHitTarget> is a direct child of a DOM element.',
);
});
it('should render a conditional TouchHitTarget correctly (false -> true)', () => {
let cond = false;
const Test = () => (
<EventComponent>
<div style={{position: 'relative', zIndex: 0}}>
{cond ? null : (
<TouchHitTarget top={10} left={10} right={10} bottom={10} />
)}
</div>
</EventComponent>
);
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<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 style="position: relative; z-index: 0;"></div>',
);
});
it('should render a conditional TouchHitTarget correctly (true -> false)', () => {
let cond = true;
const Test = () => (
<EventComponent>
<div style={{position: 'relative', zIndex: 0}}>
{cond ? null : (
<TouchHitTarget top={10} left={10} right={10} bottom={10} />
)}
</div>
</EventComponent>
);
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
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 style="position: relative; z-index: 0;"><div style="position: absolute; z-index: -1; bottom: -10px; ' +
'left: -10px; right: -10px; top: -10px;"></div></div>',
);
});
it('should render a conditional TouchHitTarget hit slop correctly (false -> true)', () => {
let cond = false;
const Test = () => (
<EventComponent>
<div style={{position: 'relative', zIndex: 0}}>
{cond ? (
<TouchHitTarget />
) : (
<TouchHitTarget top={10} left={10} right={10} bottom={10} />
)}
</div>
</EventComponent>
);
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<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 style="position: relative; z-index: 0;"></div>',
);
});
it('should render a conditional TouchHitTarget hit slop correctly (true -> false)', () => {
let cond = true;
const Test = () => (
<EventComponent>
<div style={{position: 'relative', zIndex: 0}}>
<span>Random span 1</span>
{cond ? (
<TouchHitTarget />
) : (
<TouchHitTarget top={10} left={10} right={10} bottom={10} />
)}
<span>Random span 2</span>
</div>
</EventComponent>
);
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<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 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>',
);
});
it('should update TouchHitTarget hit slop values correctly (false -> true)', () => {
let cond = false;
const Test = () => (
<EventComponent>
<div style={{position: 'relative', zIndex: 0}}>
<span>Random span 1</span>
{cond ? (
<TouchHitTarget top={10} left={null} right={10} bottom={10} />
) : (
<TouchHitTarget
top={undefined}
left={20}
right={null}
bottom={0}
/>
)}
<span>Random span 2</span>
</div>
</EventComponent>
);
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<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>',
);
cond = true;
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<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>',
);
});
it('should update TouchHitTarget hit slop values correctly (true -> false)', () => {
let cond = true;
const Test = () => (
<EventComponent>
<div style={{position: 'relative', zIndex: 0}}>
<span>Random span 1</span>
{cond ? (
<TouchHitTarget top={10} left={null} right={10} bottom={10} />
) : (
<TouchHitTarget
top={undefined}
left={20}
right={null}
bottom={0}
/>
)}
<span>Random span 2</span>
</div>
</EventComponent>
);
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<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>',
);
cond = false;
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<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>',
);
});
it('should hydrate TouchHitTarget hit slop elements correcty', () => {
const Test = () => (
<EventComponent>
<div style={{position: 'relative', zIndex: 0}}>
<TouchHitTarget />
</div>
</EventComponent>
);
const container = document.createElement('div');
container.innerHTML = '<div style="position:relative;z-index:0"></div>';
ReactDOM.hydrate(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<div style="position:relative;z-index:0"></div>',
);
const Test2 = () => (
<EventComponent>
<div style={{position: 'relative', zIndex: 0}}>
<TouchHitTarget top={10} left={10} right={10} bottom={10} />
</div>
</EventComponent>
);
const container2 = document.createElement('div');
container2.innerHTML =
'<div style="position:relative;z-index:0"><div style="position:absolute;pointer-events:none;z-index:-1;' +
'bottom:-10px;left:-10px;right:-10px;top:-10px"></div></div>';
ReactDOM.hydrate(<Test2 />, container2);
expect(Scheduler).toFlushWithoutYielding();
expect(container2.innerHTML).toBe(
'<div style="position:relative;z-index:0"><div style="position: absolute; z-index: -1; ' +
'bottom: -10px; left: -10px; right: -10px; top: -10px;"></div></div>',
);
});
it('should hydrate TouchHitTarget hit slop elements correcty and patch them', () => {
const Test = () => (
<EventComponent>
<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 style="position: relative; z-index: 0"></div>';
expect(() => {
ReactDOM.hydrate(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev(
'Warning: Expected server HTML to contain a matching <div> in <div>.',
{withoutStack: true},
);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe(
'<div style="position: relative; z-index: 0"><div style="position: absolute; z-index: -1; bottom: -10px; ' +
'left: -10px; right: -10px; top: -10px;"></div></div>',
);
});
});
describe('ReactDOMServer', () => {
beforeEach(() => {
initReactDOMServer();
EventComponent = createReactEventComponent();
TouchHitTarget = ReactEvents.TouchHitTarget;
});
it('should not warn when a TouchHitTarget is used correctly', () => {
const Test = () => (
<EventComponent>
<div>
<TouchHitTarget />
</div>
</EventComponent>
);
const output = ReactDOMServer.renderToString(<Test />);
expect(output).toBe('<div></div>');
});
it('should render a TouchHitTarget with hit slop values', () => {
const Test = () => (
<EventComponent>
<div>
<TouchHitTarget top={10} left={10} right={10} bottom={10} />
</div>
</EventComponent>
);
let output = ReactDOMServer.renderToString(<Test />);
expect(output).toBe(
'<div><div style="position:absolute;pointer-events:none;z-index:-1;' +
'bottom:-10px;left:-10px;right:-10px;top:-10px"></div></div>',
);
const Test2 = () => (
<EventComponent>
<div>
<TouchHitTarget top={null} left={undefined} right={0} bottom={10} />
</div>
</EventComponent>
);
output = ReactDOMServer.renderToString(<Test2 />);
expect(output).toBe(
'<div><div style="position:absolute;pointer-events:none;z-index:-1;' +
'bottom:-10px;left:0px;right:0x;top:0px"></div></div>',
);
const Test3 = () => (
<EventComponent>
<div>
<TouchHitTarget top={1} left={2} right={3} bottom={4} />
</div>
</EventComponent>
);
output = ReactDOMServer.renderToString(<Test3 />);
expect(output).toBe(
'<div><div style="position:absolute;pointer-events:none;z-index:-1;' +
'bottom:-4px;left:-2px;right:-3px;top:-1px"></div></div>',
);
});
});
});

View File

@ -291,14 +291,6 @@ export function getChildHostContextForEventComponent(
return parentHostContext;
}
export function getChildHostContextForEventTarget(
parentHostContext: HostContext,
type: Symbol | number,
) {
// TODO: add getChildHostContextForEventTarget implementation
return parentHostContext;
}
export function getPublicInstance(instance: Instance): * {
return instance.canonical;
}

View File

@ -216,14 +216,6 @@ export function getChildHostContextForEventComponent(
return parentHostContext;
}
export function getChildHostContextForEventTarget(
parentHostContext: HostContext,
type: Symbol | number,
) {
// TODO: add getChildHostContextForEventTarget implementation
return parentHostContext;
}
export function getPublicInstance(instance: Instance): * {
return instance;
}

View File

@ -23,11 +23,7 @@ import type {RootTag} from 'shared/ReactRootTags';
import * as Scheduler from 'scheduler/unstable_mock';
import {createPortal} from 'shared/ReactPortal';
import expect from 'expect';
import {
REACT_FRAGMENT_TYPE,
REACT_ELEMENT_TYPE,
REACT_EVENT_TARGET_TOUCH_HIT,
} from 'shared/ReactSymbols';
import {REACT_FRAGMENT_TYPE, REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
import warning from 'shared/warning';
import enqueueTask from 'shared/enqueueTask';
import ReactSharedInternals from 'shared/ReactSharedInternals';
@ -38,18 +34,6 @@ import {
} from 'shared/ReactFeatureFlags';
import {ConcurrentRoot, BatchedRoot, LegacyRoot} from 'shared/ReactRootTags';
type EventTargetChildElement = {
type: string,
props: null | {
style?: {
position?: string,
bottom?: string,
left?: string,
right?: string,
top?: string,
},
},
};
type Container = {
rootID: string,
children: Array<Instance | TextInstance>,
@ -86,8 +70,6 @@ const {ReactCurrentActingRendererSigil} = ReactSharedInternals;
const NO_CONTEXT = {};
const UPPERCASE_CONTEXT = {};
const EVENT_COMPONENT_CONTEXT = {};
const EVENT_TARGET_CONTEXT = {};
const EVENT_TOUCH_HIT_TARGET_CONTEXT = {};
const UPDATE_SIGNAL = {};
if (__DEV__) {
Object.freeze(NO_CONTEXT);
@ -286,34 +268,11 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
getChildHostContextForEventComponent(parentHostContext: HostContext) {
if (__DEV__ && enableEventAPI) {
warning(
parentHostContext !== EVENT_TARGET_CONTEXT &&
parentHostContext !== EVENT_TOUCH_HIT_TARGET_CONTEXT,
'validateDOMNesting: React event targets must not have event components as children.',
);
return EVENT_COMPONENT_CONTEXT;
}
return parentHostContext;
},
getChildHostContextForEventTarget(
parentHostContext: HostContext,
type: Symbol | number,
) {
if (__DEV__ && enableEventAPI) {
if (type === REACT_EVENT_TARGET_TOUCH_HIT) {
warning(
parentHostContext !== EVENT_COMPONENT_CONTEXT,
'validateDOMNesting: <TouchHitTarget> cannot not be a direct child of an event component. ' +
'Ensure <TouchHitTarget> is a direct child of a DOM element.',
);
return EVENT_TOUCH_HIT_TARGET_CONTEXT;
}
return EVENT_TARGET_CONTEXT;
}
return parentHostContext;
},
getPublicInstance(instance) {
return instance;
},
@ -448,53 +407,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
unmountEventComponent(): void {
// NO-OP
},
getEventTargetChildElement(
type: Symbol | number,
props: Props,
): null | EventTargetChildElement {
if (enableEventAPI) {
if (type === REACT_EVENT_TARGET_TOUCH_HIT) {
const {bottom, left, right, top} = props;
if (!bottom && !left && !right && !top) {
return null;
}
return {
type: 'div',
props: {
style: {
position: 'absolute',
zIndex: -1,
bottom: bottom ? `-${bottom}px` : '0px',
left: left ? `-${left}px` : '0px',
right: right ? `-${right}px` : '0px',
top: top ? `-${top}px` : '0px',
},
},
};
}
}
return null;
},
handleEventTarget(
type: Symbol | number,
props: Props,
rootContainerInstance: Container,
internalInstanceHandle: Object,
): boolean {
return false;
},
commitEventTarget(
type: Symbol | number,
props: Props,
instance: Instance,
parentInstance: Instance,
): void {
// NO-OP
},
};
const hostConfig = useMutation

View File

@ -13,7 +13,6 @@ import type {
ReactPortal,
RefObject,
ReactEventComponent,
ReactEventTarget,
} from 'shared/ReactTypes';
import type {RootTag} from 'shared/ReactRootTags';
import type {WorkTag} from 'shared/ReactWorkTags';
@ -50,7 +49,6 @@ import {
SimpleMemoComponent,
LazyComponent,
EventComponent,
EventTarget,
} from 'shared/ReactWorkTags';
import getComponentName from 'shared/getComponentName';
@ -81,7 +79,6 @@ import {
REACT_MEMO_TYPE,
REACT_LAZY_TYPE,
REACT_EVENT_COMPONENT_TYPE,
REACT_EVENT_TARGET_TYPE,
} from 'shared/ReactSymbols';
let hasBadMapPolyfill;
@ -592,17 +589,6 @@ export function createFiberFromTypeAndProps(
);
}
break;
case REACT_EVENT_TARGET_TYPE:
if (enableEventAPI) {
return createFiberFromEventTarget(
type,
pendingProps,
mode,
expirationTime,
key,
);
}
break;
}
}
let info = '';
@ -695,24 +681,6 @@ export function createFiberFromEventComponent(
return fiber;
}
export function createFiberFromEventTarget(
eventTarget: ReactEventTarget,
pendingProps: any,
mode: TypeOfMode,
expirationTime: ExpirationTime,
key: null | string,
): Fiber {
const fiber = createFiber(EventTarget, pendingProps, key, mode);
fiber.elementType = eventTarget;
fiber.type = eventTarget;
fiber.expirationTime = expirationTime;
// Store latest props
fiber.stateNode = {
props: pendingProps,
};
return fiber;
}
function createFiberFromProfiler(
pendingProps: any,
mode: TypeOfMode,

View File

@ -41,7 +41,6 @@ import {
LazyComponent,
IncompleteClassComponent,
EventComponent,
EventTarget,
} from 'shared/ReactWorkTags';
import {
NoEffect,
@ -108,13 +107,11 @@ import {
registerSuspenseInstanceRetry,
} from './ReactFiberHostConfig';
import type {SuspenseInstance} from './ReactFiberHostConfig';
import {getEventTargetChildElement} from './ReactFiberHostConfig';
import {shouldSuspend} from './ReactFiberReconciler';
import {
pushHostContext,
pushHostContainer,
pushHostContextForEventComponent,
pushHostContextForEventTarget,
} from './ReactFiberHostContext';
import {
suspenseStackCursor,
@ -2412,38 +2409,6 @@ function updateEventComponent(current, workInProgress, renderExpirationTime) {
return workInProgress.child;
}
function updateEventTarget(current, workInProgress, renderExpirationTime) {
const type = workInProgress.type.type;
const nextProps = workInProgress.pendingProps;
const eventTargetChild = getEventTargetChildElement(type, nextProps);
if (__DEV__) {
warning(
nextProps.children == null,
'Event targets should not have children.',
);
}
if (eventTargetChild !== null) {
const child = (workInProgress.child = createFiberFromTypeAndProps(
eventTargetChild.type,
null,
eventTargetChild.props,
null,
workInProgress.mode,
renderExpirationTime,
));
child.return = workInProgress;
if (current === null || current.child === null) {
child.effectTag = Placement;
}
} else {
reconcileChildren(current, workInProgress, null, renderExpirationTime);
}
pushHostContextForEventTarget(workInProgress);
return workInProgress.child;
}
export function markWorkInProgressReceivedUpdate() {
didReceiveUpdate = true;
}
@ -2711,12 +2676,6 @@ function beginWork(
pushHostContextForEventComponent(workInProgress);
}
break;
case EventTarget: {
if (enableEventAPI) {
pushHostContextForEventTarget(workInProgress);
}
break;
}
}
return bailoutOnAlreadyFinishedWork(
current,
@ -2912,12 +2871,6 @@ function beginWork(
}
break;
}
case EventTarget: {
if (enableEventAPI) {
return updateEventTarget(current, workInProgress, renderExpirationTime);
}
break;
}
}
invariant(
false,

View File

@ -45,7 +45,6 @@ import {
MemoComponent,
SimpleMemoComponent,
EventComponent,
EventTarget,
SuspenseListComponent,
} from 'shared/ReactWorkTags';
import {
@ -94,7 +93,6 @@ import {
unhideInstance,
unhideTextInstance,
unmountEventComponent,
commitEventTarget,
mountEventComponent,
} from './ReactFiberHostConfig';
import {
@ -305,7 +303,6 @@ function commitBeforeMutationLifeCycles(
case HostText:
case HostPortal:
case IncompleteClassComponent:
case EventTarget:
// Nothing to do for these component types
return;
default: {
@ -594,34 +591,6 @@ function commitLifeCycles(
case SuspenseListComponent:
case IncompleteClassComponent:
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);
@ -869,7 +838,6 @@ function commitContainer(finishedWork: Fiber) {
case ClassComponent:
case HostComponent:
case HostText:
case EventTarget:
case EventComponent: {
return;
}
@ -1254,9 +1222,6 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
commitTextUpdate(textInstance, oldText, newText);
return;
}
case EventTarget: {
return;
}
case HostRoot: {
return;
}

View File

@ -48,7 +48,6 @@ import {
LazyComponent,
IncompleteClassComponent,
EventComponent,
EventTarget,
} from 'shared/ReactWorkTags';
import {NoMode, BatchedMode} from './ReactTypeOfMode';
import {
@ -76,7 +75,6 @@ import {
appendChildToContainerChildSet,
finalizeContainerChildren,
updateEventComponent,
handleEventTarget,
} from './ReactFiberHostConfig';
import {
getRootHostContainer,
@ -1085,26 +1083,6 @@ function completeWork(
}
break;
}
case EventTarget: {
if (enableEventAPI) {
popHostContext(workInProgress);
const type = workInProgress.type.type;
const rootContainerInstance = getRootHostContainer();
const shouldUpdate = handleEventTarget(
type,
newProps,
rootContainerInstance,
workInProgress,
);
// Update the latest props on the stateNode. This is used
// during the event phase to find the most current props.
workInProgress.stateNode.props = newProps;
if (shouldUpdate) {
markUpdate(workInProgress);
}
}
break;
}
default:
invariant(
false,

View File

@ -17,7 +17,6 @@ import {
getChildHostContext,
getRootHostContext,
getChildHostContextForEventComponent,
getChildHostContextForEventTarget,
} from './ReactFiberHostConfig';
import {createCursor, push, pop} from './ReactFiberStack';
@ -112,25 +111,6 @@ function pushHostContextForEventComponent(fiber: Fiber): void {
push(contextStackCursor, nextContext, fiber);
}
function pushHostContextForEventTarget(fiber: Fiber): void {
const context: HostContext = requiredContext(contextStackCursor.current);
const eventTargetType = fiber.type.type;
const nextContext = getChildHostContextForEventTarget(
context,
eventTargetType,
);
// Don't push this Fiber's context unless it's unique.
if (context === nextContext) {
return;
}
// Track the context and the Fiber that provided it.
// This enables us to pop only Fibers that provide unique contexts.
push(contextFiberStackCursor, fiber, fiber);
push(contextStackCursor, nextContext, fiber);
}
function popHostContext(fiber: Fiber): void {
// Do not pop unless this Fiber provided the current context.
// pushHostContext() only pushes Fibers that provide unique contexts.
@ -150,5 +130,4 @@ export {
pushHostContainer,
pushHostContext,
pushHostContextForEventComponent,
pushHostContextForEventTarget,
};

View File

@ -20,7 +20,6 @@ import {
SuspenseListComponent,
DehydratedSuspenseComponent,
EventComponent,
EventTarget,
} from 'shared/ReactWorkTags';
import {DidCapture, NoEffect, ShouldCapture} from 'shared/ReactSideEffectTags';
import {
@ -109,7 +108,6 @@ function unwindWork(
popProvider(workInProgress);
return null;
case EventComponent:
case EventTarget:
if (enableEventAPI) {
popHostContext(workInProgress);
}
@ -156,7 +154,6 @@ function unwindInterruptedWork(interruptedWork: Fiber) {
popProvider(interruptedWork);
break;
case EventComponent:
case EventTarget:
if (enableEventAPI) {
popHostContext(interruptedWork);
}

View File

@ -18,7 +18,6 @@ let ReactTestRenderer;
let ReactDOM;
let ReactDOMServer;
let ReactTestUtils;
let EventTarget;
let ReactSymbols;
const noOpResponder = {
@ -35,14 +34,6 @@ function createReactEventComponent() {
};
}
function createReactEventTarget() {
return {
$$typeof: ReactSymbols.REACT_EVENT_TARGET_TYPE,
displayName: 'TestEventTarget',
type: Symbol.for('react.event_target.test'),
};
}
function init() {
jest.resetModules();
ReactFeatureFlags = require('shared/ReactFeatureFlags');
@ -80,7 +71,6 @@ describe('ReactFiberEvents', () => {
beforeEach(() => {
initNoopRenderer();
EventComponent = createReactEventComponent();
EventTarget = createReactEventTarget();
});
it('should render a simple event component with a single child', () => {
@ -124,85 +114,6 @@ describe('ReactFiberEvents', () => {
);
});
it('should render a simple event component with a single event target', () => {
const Test = () => (
<EventComponent>
<div>
Hello world<EventTarget />
</div>
</EventComponent>
);
ReactNoop.render(<Test />);
expect(Scheduler).toFlushWithoutYielding();
expect(ReactNoop).toMatchRenderedOutput(<div>Hello world</div>);
});
it('should warn when an event target has a direct text child', () => {
const Test = () => (
<EventComponent>
<EventTarget>Hello world</EventTarget>
</EventComponent>
);
expect(() => {
ReactNoop.render(<Test />);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
});
it('should warn when an event target has a direct text child #2', () => {
const ChildWrapper = () => 'Hello world';
const Test = () => (
<EventComponent>
<EventTarget>
<ChildWrapper />
</EventTarget>
</EventComponent>
);
expect(() => {
ReactNoop.render(<Test />);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
});
it('should not warn if an event target is not a direct child of an event component', () => {
const Test = () => (
<EventComponent>
<div>
<EventTarget />
<span>Child 1</span>
</div>
</EventComponent>
);
ReactNoop.render(<Test />);
expect(Scheduler).toFlushWithoutYielding();
expect(ReactNoop).toMatchRenderedOutput(
<div>
<span>Child 1</span>
</div>,
);
});
it('should warn if an event target has an event component as a child', () => {
const Test = () => (
<EventComponent>
<EventTarget>
<EventComponent>
<span>Child 1</span>
</EventComponent>
</EventTarget>
</EventComponent>
);
expect(() => {
ReactNoop.render(<Test />);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
});
it('should handle event components correctly with error boundaries', () => {
function ErrorComponent() {
throw new Error('Failed!');
@ -331,51 +242,6 @@ describe('ReactFiberEvents', () => {
);
});
it('should handle re-renders where there is a bail-out in a parent and an error occurs #2', () => {
let _updateCounter;
function Child() {
const [counter, updateCounter] = React.useState(0);
_updateCounter = updateCounter;
if (counter === 1) {
return <EventTarget>123</EventTarget>;
}
return (
<div>
<span>Child - {counter}</span>
</div>
);
}
const Parent = () => (
<div>
<EventComponent>
<Child />
</EventComponent>
</div>
);
ReactNoop.render(<Parent />);
expect(Scheduler).toFlushWithoutYielding();
expect(ReactNoop).toMatchRenderedOutput(
<div>
<div>
<span>Child - 0</span>
</div>
</div>,
);
expect(() => {
ReactNoop.act(() => {
_updateCounter(counter => counter + 1);
});
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
});
it('should error with a component stack contains the names of the event components and event targets', () => {
let componentStackMessage;
@ -426,7 +292,6 @@ describe('ReactFiberEvents', () => {
beforeEach(() => {
initTestRenderer();
EventComponent = createReactEventComponent();
EventTarget = createReactEventTarget();
});
it('should render a simple event component with a single child', () => {
@ -473,101 +338,6 @@ describe('ReactFiberEvents', () => {
);
});
it('should render a simple event component with a single event target', () => {
const Test = () => (
<EventComponent>
<div>
Hello world<EventTarget />
</div>
</EventComponent>
);
const root = ReactTestRenderer.create(null);
root.update(<Test />);
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput(<div>Hello world</div>);
const Test2 = () => (
<EventComponent>
<EventTarget />
<span>I am now a span</span>
</EventComponent>
);
root.update(<Test2 />);
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput(<span>I am now a span</span>);
});
it('should warn when an event target has a direct text child', () => {
const Test = () => (
<EventComponent>
<EventTarget>Hello world</EventTarget>
</EventComponent>
);
const root = ReactTestRenderer.create(null);
expect(() => {
root.update(<Test />);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
});
it('should warn when an event target has a direct text child #2', () => {
const ChildWrapper = () => 'Hello world';
const Test = () => (
<EventComponent>
<EventTarget>
<ChildWrapper />
</EventTarget>
</EventComponent>
);
const root = ReactTestRenderer.create(null);
expect(() => {
root.update(<Test />);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
});
it('should not warn if an event target is not a direct child of an event component', () => {
const Test = () => (
<EventComponent>
<div>
<EventTarget />
<span>Child 1</span>
</div>
</EventComponent>
);
const root = ReactTestRenderer.create(null);
root.update(<Test />);
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput(
<div>
<span>Child 1</span>
</div>,
);
});
it('should warn if an event target has an event component as a child', () => {
const Test = () => (
<EventComponent>
<EventTarget>
<EventComponent>
<span>Child 1</span>
</EventComponent>
</EventTarget>
</EventComponent>
);
const root = ReactTestRenderer.create(null);
expect(() => {
root.update(<Test />);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
});
it('should handle event components correctly with error boundaries', () => {
function ErrorComponent() {
throw new Error('Failed!');
@ -697,52 +467,6 @@ describe('ReactFiberEvents', () => {
);
});
it('should handle re-renders where there is a bail-out in a parent and an error occurs #2', () => {
let _updateCounter;
function Child() {
const [counter, updateCounter] = React.useState(0);
_updateCounter = updateCounter;
if (counter === 1) {
return <EventTarget>123</EventTarget>;
}
return (
<div>
<span>Child - {counter}</span>
</div>
);
}
const Parent = () => (
<div>
<EventComponent>
<Child />
</EventComponent>
</div>
);
const root = ReactTestRenderer.create(null);
root.update(<Parent />);
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput(
<div>
<div>
<span>Child - 0</span>
</div>
</div>,
);
expect(() => {
ReactTestRenderer.act(() => {
_updateCounter(counter => counter + 1);
});
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
});
it('should error with a component stack contains the names of the event components and event targets', () => {
let componentStackMessage;
@ -831,7 +555,6 @@ describe('ReactFiberEvents', () => {
beforeEach(() => {
initReactDOM();
EventComponent = createReactEventComponent();
EventTarget = createReactEventTarget();
});
it('should render a simple event component with a single child', () => {
@ -877,97 +600,6 @@ describe('ReactFiberEvents', () => {
);
});
it('should render a simple event component with a single event target', () => {
const Test = () => (
<EventComponent>
<div>
Hello world<EventTarget />
</div>
</EventComponent>
);
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe('<div>Hello world</div>');
const Test2 = () => (
<EventComponent>
<EventTarget />
<span>I am now a span</span>
</EventComponent>
);
ReactDOM.render(<Test2 />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe('<span>I am now a span</span>');
});
it('should warn when an event target has a direct text child', () => {
const Test = () => (
<EventComponent>
<EventTarget>Hello world</EventTarget>
</EventComponent>
);
expect(() => {
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
});
it('should warn when an event target has a direct text child #2', () => {
const ChildWrapper = () => 'Hello world';
const Test = () => (
<EventComponent>
<EventTarget>
<ChildWrapper />
</EventTarget>
</EventComponent>
);
expect(() => {
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
});
it('should not warn if an event target is not a direct child of an event component', () => {
const Test = () => (
<EventComponent>
<div>
<EventTarget />
<span>Child 1</span>
</div>
</EventComponent>
);
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe('<div><span>Child 1</span></div>');
});
it('should warn if an event target has an event component as a child', () => {
const Test = () => (
<EventComponent>
<EventTarget>
<EventComponent>
<span>Child 1</span>
</EventComponent>
</EventTarget>
</EventComponent>
);
expect(() => {
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
});
it('should handle event components correctly with error boundaries', () => {
function ErrorComponent() {
throw new Error('Failed!');
@ -1084,47 +716,6 @@ describe('ReactFiberEvents', () => {
);
});
it('should handle re-renders where there is a bail-out in a parent and an error occurs #2', () => {
let _updateCounter;
function Child() {
const [counter, updateCounter] = React.useState(0);
_updateCounter = updateCounter;
if (counter === 1) {
return <EventTarget>123</EventTarget>;
}
return (
<div>
<span>Child - {counter}</span>
</div>
);
}
const Parent = () => (
<div>
<EventComponent>
<Child />
</EventComponent>
</div>
);
const container = document.createElement('div');
ReactDOM.render(<Parent />, container);
expect(container.innerHTML).toBe(
'<div><div><span>Child - 0</span></div></div>',
);
expect(() => {
ReactTestUtils.act(() => {
_updateCounter(counter => counter + 1);
});
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev('Warning: Event targets should not have children.');
});
it('should error with a component stack contains the names of the event components and event targets', () => {
let componentStackMessage;
@ -1175,7 +766,6 @@ describe('ReactFiberEvents', () => {
beforeEach(() => {
initReactDOMServer();
EventComponent = createReactEventComponent();
EventTarget = createReactEventTarget();
});
it('should render a simple event component with a single child', () => {
@ -1187,29 +777,5 @@ describe('ReactFiberEvents', () => {
const output = ReactDOMServer.renderToString(<Test />);
expect(output).toBe('<div>Hello world</div>');
});
it('should render a simple event component with a single event target', () => {
const Test = () => (
<EventComponent>
<div>
Hello world<EventTarget />
</div>
</EventComponent>
);
let output = ReactDOMServer.renderToString(<Test />);
expect(output).toBe('<div>Hello world</div>');
const Test2 = () => (
<EventComponent>
<EventTarget>
<span>I am now a span</span>
</EventTarget>
</EventComponent>
);
output = ReactDOMServer.renderToString(<Test2 />);
expect(output).toBe('<span>I am now a span</span>');
});
});
});

View File

@ -36,9 +36,6 @@ describe('ReactFiberHostContext', () => {
getChildHostContextForEventComponent: function() {
return null;
},
getChildHostContextForEventTarget: function() {
return null;
},
shouldSetTextContent: function() {
return false;
},

View File

@ -44,8 +44,6 @@ export const getRootHostContext = $$$hostConfig.getRootHostContext;
export const getChildHostContext = $$$hostConfig.getChildHostContext;
export const getChildHostContextForEventComponent =
$$$hostConfig.getChildHostContextForEventComponent;
export const getChildHostContextForEventTarget =
$$$hostConfig.getChildHostContextForEventTarget;
export const prepareForCommit = $$$hostConfig.prepareForCommit;
export const resetAfterCommit = $$$hostConfig.resetAfterCommit;
export const createInstance = $$$hostConfig.createInstance;
@ -90,8 +88,6 @@ export const hideTextInstance = $$$hostConfig.hideTextInstance;
export const unhideInstance = $$$hostConfig.unhideInstance;
export const unhideTextInstance = $$$hostConfig.unhideTextInstance;
export const unmountEventComponent = $$$hostConfig.unmountEventComponent;
export const commitTouchHitTargetUpdate =
$$$hostConfig.commitTouchHitTargetUpdate;
export const commitEventTarget = $$$hostConfig.commitEventTarget;
// -------------------

View File

@ -10,22 +10,9 @@
import warning from 'shared/warning';
import type {ReactEventComponentInstance} from 'shared/ReactTypes';
import {REACT_EVENT_TARGET_TOUCH_HIT} from 'shared/ReactSymbols';
import {enableEventAPI} from 'shared/ReactFeatureFlags';
type EventTargetChildElement = {
type: string,
props: null | {
style?: {
position?: string,
bottom?: string,
left?: string,
right?: string,
top?: string,
},
},
};
export type Type = string;
export type Props = Object;
export type Container = {|
@ -59,8 +46,6 @@ export * from 'shared/HostConfigWithNoPersistence';
export * from 'shared/HostConfigWithNoHydration';
const EVENT_COMPONENT_CONTEXT = {};
const EVENT_TARGET_CONTEXT = {};
const EVENT_TOUCH_HIT_TARGET_CONTEXT = {};
const NO_CONTEXT = {};
const UPDATE_SIGNAL = {};
if (__DEV__) {
@ -140,34 +125,11 @@ export function getChildHostContextForEventComponent(
parentHostContext: HostContext,
): HostContext {
if (__DEV__ && enableEventAPI) {
warning(
parentHostContext !== EVENT_TARGET_CONTEXT &&
parentHostContext !== EVENT_TOUCH_HIT_TARGET_CONTEXT,
'validateDOMNesting: React event targets must not have event components as children.',
);
return EVENT_COMPONENT_CONTEXT;
}
return NO_CONTEXT;
}
export function getChildHostContextForEventTarget(
parentHostContext: HostContext,
type: Symbol | number,
): HostContext {
if (__DEV__ && enableEventAPI) {
if (type === REACT_EVENT_TARGET_TOUCH_HIT) {
warning(
parentHostContext !== EVENT_COMPONENT_CONTEXT,
'validateDOMNesting: <TouchHitTarget> cannot not be a direct child of an event component. ' +
'Ensure <TouchHitTarget> is a direct child of a DOM element.',
);
return EVENT_TOUCH_HIT_TARGET_CONTEXT;
}
return EVENT_TARGET_CONTEXT;
}
return NO_CONTEXT;
}
export function prepareForCommit(containerInfo: Container): void {
// noop
}
@ -246,12 +208,6 @@ export function createTextInstance(
'Wrap the child text "%s" in an element.',
text,
);
warning(
hostContext !== EVENT_TARGET_CONTEXT,
'validateDOMNesting: React event targets cannot have text DOM nodes as children. ' +
'Wrap the child text "%s" in an element.',
text,
);
}
return {
text,
@ -346,59 +302,3 @@ export function unmountEventComponent(
): void {
// noop
}
export function getEventTargetChildElement(
type: Symbol | number,
props: Props,
): null | EventTargetChildElement {
if (enableEventAPI) {
if (type === REACT_EVENT_TARGET_TOUCH_HIT) {
const {bottom, left, right, top} = props;
if (!bottom && !left && !right && !top) {
return null;
}
return {
type: 'div',
props: {
style: {
position: 'absolute',
zIndex: -1,
bottom: bottom ? `-${bottom}px` : '0px',
left: left ? `-${left}px` : '0px',
right: right ? `-${right}px` : '0px',
top: top ? `-${top}px` : '0px',
},
},
};
}
}
return null;
}
export function handleEventTarget(
type: Symbol | number,
props: Props,
rootContainerInstance: Container,
internalInstanceHandle: Object,
): boolean {
if (enableEventAPI) {
if (type === REACT_EVENT_TARGET_TOUCH_HIT) {
// In DEV we do a computed style check on the position to ensure
// the parent host component is correctly position in the document.
if (__DEV__) {
return true;
}
}
}
return false;
}
export function commitEventTarget(
type: Symbol | number,
props: Props,
instance: Instance,
parentInstance: Instance,
): void {
// noop
}

View File

@ -47,5 +47,3 @@ export const didNotFindHydratableContainerSuspenseInstance = shim;
export const didNotFindHydratableInstance = shim;
export const didNotFindHydratableTextInstance = shim;
export const didNotFindHydratableSuspenseInstance = shim;
export const canHydrateTouchHitTargetInstance = shim;
export const hydrateTouchHitTargetInstance = shim;

View File

@ -30,4 +30,3 @@ export const finalizeContainerChildren = shim;
export const replaceContainerChildren = shim;
export const cloneHiddenInstance = shim;
export const cloneHiddenTextInstance = shim;
export const cloneHiddenTouchHitTargetInstance = shim;

View File

@ -61,7 +61,6 @@ export type ReactDOMResponderContext = {
) => boolean,
isTargetWithinEventComponent: (Element | Document) => boolean,
isTargetWithinEventResponderScope: (Element | Document) => boolean,
isEventWithinTouchHitTarget: (event: ReactDOMResponderEvent) => boolean,
addRootEventTypes: (
rootEventTypes: Array<ReactDOMEventResponderEventType>,
) => void,

View File

@ -54,14 +54,6 @@ export const REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4;
export const REACT_EVENT_COMPONENT_TYPE = hasSymbol
? Symbol.for('react.event_component')
: 0xead5;
export const REACT_EVENT_TARGET_TYPE = hasSymbol
? Symbol.for('react.event_target')
: 0xead6;
// React event targets
export const REACT_EVENT_TARGET_TOUCH_HIT = hasSymbol
? Symbol.for('react.event_target.touch_hit')
: 0xead7;
const MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
const FAUX_ITERATOR_SYMBOL = '@@iterator';

View File

@ -23,11 +23,8 @@ import {
REACT_SUSPENSE_LIST_TYPE,
REACT_LAZY_TYPE,
REACT_EVENT_COMPONENT_TYPE,
REACT_EVENT_TARGET_TYPE,
REACT_EVENT_TARGET_TOUCH_HIT,
} from 'shared/ReactSymbols';
import {refineResolvedLazyComponent} from 'shared/ReactLazyComponent';
import type {ReactEventTarget} from 'shared/ReactTypes';
import {enableEventAPI} from './ReactFeatureFlags';
@ -101,18 +98,6 @@ function getComponentName(type: mixed): string | null {
}
break;
}
case REACT_EVENT_TARGET_TYPE: {
if (enableEventAPI) {
const eventTarget = ((type: any): ReactEventTarget);
if (eventTarget.type === REACT_EVENT_TARGET_TOUCH_HIT) {
return 'TouchHitTarget';
}
const displayName = eventTarget.displayName;
if (displayName !== undefined) {
return displayName;
}
}
}
}
}
return null;

View File

@ -20,7 +20,6 @@ import {
REACT_MEMO_TYPE,
REACT_LAZY_TYPE,
REACT_EVENT_COMPONENT_TYPE,
REACT_EVENT_TARGET_TYPE,
} from 'shared/ReactSymbols';
export default function isValidElementType(type: mixed) {
@ -41,7 +40,6 @@ export default function isValidElementType(type: mixed) {
type.$$typeof === REACT_PROVIDER_TYPE ||
type.$$typeof === REACT_CONTEXT_TYPE ||
type.$$typeof === REACT_FORWARD_REF_TYPE ||
type.$$typeof === REACT_EVENT_COMPONENT_TYPE ||
type.$$typeof === REACT_EVENT_TARGET_TYPE))
type.$$typeof === REACT_EVENT_COMPONENT_TYPE))
);
}

View File

@ -438,21 +438,6 @@ const bundles = [
},
/******* React Events (experimental) *******/
{
bundleTypes: [
UMD_DEV,
UMD_PROD,
NODE_DEV,
NODE_PROD,
FB_WWW_DEV,
FB_WWW_PROD,
],
moduleType: ISOMORPHIC,
entry: 'react-events',
global: 'ReactEvents',
externals: [],
},
{
bundleTypes: [
UMD_DEV,