Skip to content

Commit fa2fa35

Browse files
authored
Experimental event API: adds context.isTargetDirectlyWithinEventComponent (#15481)
1 parent d3af2f2 commit fa2fa35

File tree

5 files changed

+75
-7
lines changed

5 files changed

+75
-7
lines changed

packages/react-dom/src/events/DOMEventResponderSystem.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,22 @@ const eventResponderContext: ReactResponderContext = {
170170
}
171171
return false;
172172
},
173+
isTargetDirectlyWithinEventComponent(target: Element | Document): boolean {
174+
validateResponderContext();
175+
if (target != null) {
176+
let fiber = getClosestInstanceFromNode(target);
177+
while (fiber !== null) {
178+
if (fiber.stateNode === currentInstance) {
179+
return true;
180+
}
181+
if (fiber.tag === EventComponent) {
182+
return false;
183+
}
184+
fiber = fiber.return;
185+
}
186+
}
187+
return false;
188+
},
173189
isTargetWithinElement(
174190
childTarget: Element | Document,
175191
parentTarget: Element | Document,

packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,4 +948,52 @@ describe('DOMEventResponderSystem', () => {
948948
},
949949
]);
950950
});
951+
952+
it('isTargetDirectlyWithinEventComponent works', () => {
953+
const buttonRef = React.createRef();
954+
const divRef = React.createRef();
955+
const log = [];
956+
957+
const EventComponent = createReactEventComponent(
958+
['pointerout'],
959+
undefined,
960+
undefined,
961+
(event, context) => {
962+
const isWithin = context.isTargetDirectlyWithinEventComponent(
963+
event.nativeEvent.relatedTarget,
964+
);
965+
log.push(isWithin);
966+
},
967+
);
968+
969+
const Test = () => (
970+
<EventComponent>
971+
<div ref={divRef} />
972+
<EventComponent>
973+
<button ref={buttonRef}>Click me!</button>
974+
</EventComponent>
975+
</EventComponent>
976+
);
977+
ReactDOM.render(<Test />, container);
978+
979+
const createEvent = (type, data) => {
980+
const event = document.createEvent('CustomEvent');
981+
event.initCustomEvent(type, true, true);
982+
if (data != null) {
983+
Object.entries(data).forEach(([key, value]) => {
984+
event[key] = value;
985+
});
986+
}
987+
return event;
988+
};
989+
990+
buttonRef.current.dispatchEvent(
991+
createEvent('pointerout', {relatedTarget: divRef.current}),
992+
);
993+
divRef.current.dispatchEvent(
994+
createEvent('pointerout', {relatedTarget: buttonRef.current}),
995+
);
996+
997+
expect(log).toEqual([false, true, false]);
998+
});
951999
});

packages/react-events/src/Hover.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ function dispatchHoverStartEvents(
9999
if (event !== null) {
100100
const {nativeEvent} = event;
101101
if (
102-
context.isTargetWithinEventComponent((nativeEvent: any).relatedTarget)
102+
context.isTargetDirectlyWithinEventComponent(
103+
(nativeEvent: any).relatedTarget,
104+
)
103105
) {
104106
return;
105107
}
@@ -156,7 +158,9 @@ function dispatchHoverEndEvents(
156158
if (event !== null) {
157159
const {nativeEvent} = event;
158160
if (
159-
context.isTargetWithinEventComponent((nativeEvent: any).relatedTarget)
161+
context.isTargetDirectlyWithinEventComponent(
162+
(nativeEvent: any).relatedTarget,
163+
)
160164
) {
161165
return;
162166
}

packages/react-events/src/__tests__/Hover-test.internal.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -443,18 +443,17 @@ describe('Hover event responder', () => {
443443
createPointerEvent('pointerover', {relatedTarget: innerRef.current}),
444444
);
445445
outerRef.current.dispatchEvent(createPointerEvent('pointerout'));
446-
// TODO: correct result should include commented events
447446
expect(events).toEqual([
448447
'outer: onHoverStart',
449448
'outer: onHoverChange',
450-
// 'outer: onHoverEnd',
451-
// 'outer: onHoverChange',
449+
'outer: onHoverEnd',
450+
'outer: onHoverChange',
452451
'inner: onHoverStart',
453452
'inner: onHoverChange',
454453
'inner: onHoverEnd',
455454
'inner: onHoverChange',
456-
// 'outer: onHoverStart',
457-
// 'outer: onHoverChange',
455+
'outer: onHoverStart',
456+
'outer: onHoverChange',
458457
'outer: onHoverEnd',
459458
'outer: onHoverChange',
460459
]);

packages/shared/ReactTypes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ export type ReactResponderContext = {
171171
parentTarget: Element | Document,
172172
) => boolean,
173173
isTargetWithinEventComponent: (Element | Document) => boolean,
174+
isTargetDirectlyWithinEventComponent: (Element | Document) => boolean,
174175
isPositionWithinTouchHitTarget: (
175176
doc: Document,
176177
x: number,

0 commit comments

Comments
 (0)