Skip to content

Commit 6a1e6b2

Browse files
authored
Experimental event API: loosen EventTarget constraints and warnings (#15292)
* Remove warning for event targets being direct children of event component * Addressed feedback and added more test coverage + warnings
1 parent f243dea commit 6a1e6b2

File tree

14 files changed

+577
-309
lines changed

14 files changed

+577
-309
lines changed

packages/react-art/src/ReactARTHostConfig.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,11 @@ export function getChildHostContext() {
340340
return NO_CONTEXT;
341341
}
342342

343-
export function getChildHostContextForEvent() {
343+
export function getChildHostContextForEventComponent() {
344+
return NO_CONTEXT;
345+
}
346+
347+
export function getChildHostContextForEventTarget() {
344348
return NO_CONTEXT;
345349
}
346350

@@ -446,6 +450,7 @@ export function handleEventComponent(
446450
export function handleEventTarget(
447451
type: Symbol | number,
448452
props: Props,
453+
parentInstance: Container,
449454
internalInstanceHandle: Object,
450455
) {
451456
// TODO: add handleEventTarget implementation

packages/react-dom/src/client/ReactDOMHostConfig.js

Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,7 @@ import dangerousStyleValue from '../shared/dangerousStyleValue';
4545

4646
import type {DOMContainer} from './ReactDOM';
4747
import type {ReactEventResponder} from 'shared/ReactTypes';
48-
import {
49-
REACT_EVENT_COMPONENT_TYPE,
50-
REACT_EVENT_TARGET_TYPE,
51-
REACT_EVENT_TARGET_TOUCH_HIT,
52-
} from 'shared/ReactSymbols';
53-
import getElementFromTouchHitTarget from 'shared/getElementFromTouchHitTarget';
48+
import {REACT_EVENT_TARGET_TOUCH_HIT} from 'shared/ReactSymbols';
5449

5550
export type Type = string;
5651
export type Props = {
@@ -75,6 +70,7 @@ type HostContextDev = {
7570
eventData: null | {|
7671
isEventComponent?: boolean,
7772
isEventTarget?: boolean,
73+
eventTargetType?: null | Symbol | number,
7874
|},
7975
};
8076
type HostContextProd = string;
@@ -180,36 +176,46 @@ export function getChildHostContext(
180176
return getChildNamespace(parentNamespace, type);
181177
}
182178

183-
export function getChildHostContextForEvent(
179+
export function getChildHostContextForEventComponent(
184180
parentHostContext: HostContext,
185-
type: Symbol | number,
186181
): HostContext {
187182
if (__DEV__) {
188183
const parentHostContextDev = ((parentHostContext: any): HostContextDev);
189184
const {namespace, ancestorInfo} = parentHostContextDev;
190-
let eventData = null;
185+
warning(
186+
parentHostContextDev.eventData === null ||
187+
!parentHostContextDev.eventData.isEventTarget,
188+
'validateDOMNesting: React event targets must not have event components as children.',
189+
);
190+
const eventData = {
191+
isEventComponent: true,
192+
isEventTarget: false,
193+
eventTargetType: null,
194+
};
195+
return {namespace, ancestorInfo, eventData};
196+
}
197+
return parentHostContext;
198+
}
191199

192-
if (type === REACT_EVENT_COMPONENT_TYPE) {
193-
warning(
194-
parentHostContextDev.eventData === null ||
195-
!parentHostContextDev.eventData.isEventTarget,
196-
'validateDOMNesting: React event targets must not have event components as children.',
197-
);
198-
eventData = {
199-
isEventComponent: true,
200-
isEventTarget: false,
201-
};
202-
} else if (type === REACT_EVENT_TARGET_TYPE) {
203-
warning(
204-
parentHostContextDev.eventData !== null &&
205-
parentHostContextDev.eventData.isEventComponent,
206-
'validateDOMNesting: React event targets must be direct children of event components.',
207-
);
208-
eventData = {
209-
isEventComponent: false,
210-
isEventTarget: true,
211-
};
212-
}
200+
export function getChildHostContextForEventTarget(
201+
parentHostContext: HostContext,
202+
type: Symbol | number,
203+
): HostContext {
204+
if (__DEV__) {
205+
const parentHostContextDev = ((parentHostContext: any): HostContextDev);
206+
const {namespace, ancestorInfo} = parentHostContextDev;
207+
warning(
208+
parentHostContextDev.eventData === null ||
209+
!parentHostContextDev.eventData.isEventComponent ||
210+
type !== REACT_EVENT_TARGET_TOUCH_HIT,
211+
'validateDOMNesting: <TouchHitTarget> cannot not be a direct child of an event component. ' +
212+
'Ensure <TouchHitTarget> is a direct child of a DOM element.',
213+
);
214+
const eventData = {
215+
isEventComponent: false,
216+
isEventTarget: true,
217+
eventTargetType: type,
218+
};
213219
return {namespace, ancestorInfo, eventData};
214220
}
215221
return parentHostContext;
@@ -243,6 +249,16 @@ export function createInstance(
243249
if (__DEV__) {
244250
// TODO: take namespace into account when validating.
245251
const hostContextDev = ((hostContext: any): HostContextDev);
252+
if (enableEventAPI) {
253+
const eventData = hostContextDev.eventData;
254+
if (eventData !== null) {
255+
warning(
256+
!eventData.isEventTarget ||
257+
eventData.eventTargetType !== REACT_EVENT_TARGET_TOUCH_HIT,
258+
'Warning: validateDOMNesting: <TouchHitTarget> must not have any children.',
259+
);
260+
}
261+
}
246262
validateDOMNesting(type, null, hostContextDev.ancestorInfo);
247263
if (
248264
typeof props.children === 'string' ||
@@ -349,14 +365,21 @@ export function createTextInstance(
349365
if (enableEventAPI) {
350366
const eventData = hostContextDev.eventData;
351367
if (eventData !== null) {
368+
warning(
369+
eventData === null ||
370+
!eventData.isEventTarget ||
371+
eventData.eventTargetType !== REACT_EVENT_TARGET_TOUCH_HIT,
372+
'Warning: validateDOMNesting: <TouchHitTarget> must not have any children.',
373+
);
352374
warning(
353375
!eventData.isEventComponent,
354376
'validateDOMNesting: React event components cannot have text DOM nodes as children. ' +
355377
'Wrap the child text "%s" in an element.',
356378
text,
357379
);
358380
warning(
359-
!eventData.isEventTarget,
381+
!eventData.isEventTarget ||
382+
eventData.eventTargetType === REACT_EVENT_TARGET_TOUCH_HIT,
360383
'validateDOMNesting: React event targets cannot have text DOM nodes as children. ' +
361384
'Wrap the child text "%s" in an element.',
362385
text,
@@ -879,25 +902,13 @@ export function handleEventComponent(
879902
export function handleEventTarget(
880903
type: Symbol | number,
881904
props: Props,
905+
parentInstance: Container,
882906
internalInstanceHandle: Object,
883907
): void {
884908
if (enableEventAPI) {
885909
// Touch target hit slop handling
886910
if (type === REACT_EVENT_TARGET_TOUCH_HIT) {
887-
// Validates that there is a single element
888-
const element = getElementFromTouchHitTarget(internalInstanceHandle);
889-
if (element !== null) {
890-
// We update the event target state node to be that of the element.
891-
// We can then diff this entry to determine if we need to add the
892-
// hit slop element, or change the dimensions of the hit slop.
893-
const lastElement = internalInstanceHandle.stateNode;
894-
if (lastElement !== element) {
895-
internalInstanceHandle.stateNode = element;
896-
// TODO: Create the hit slop element and attach it to the element
897-
} else {
898-
// TODO: Diff the left, top, right, bottom props
899-
}
900-
}
911+
// TODO
901912
}
902913
}
903914
}

0 commit comments

Comments
 (0)