Skip to content

Commit

Permalink
Experimental event API: adds context.isTargetDirectlyWithinEventCompo…
Browse files Browse the repository at this point in the history
…nent (#15481)
  • Loading branch information
trueadm committed Apr 24, 2019
1 parent d3af2f2 commit fa2fa35
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 7 deletions.
16 changes: 16 additions & 0 deletions packages/react-dom/src/events/DOMEventResponderSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,22 @@ const eventResponderContext: ReactResponderContext = {
}
return false;
},
isTargetDirectlyWithinEventComponent(target: Element | Document): boolean {
validateResponderContext();
if (target != null) {
let fiber = getClosestInstanceFromNode(target);
while (fiber !== null) {
if (fiber.stateNode === currentInstance) {
return true;
}
if (fiber.tag === EventComponent) {
return false;
}
fiber = fiber.return;
}
}
return false;
},
isTargetWithinElement(
childTarget: Element | Document,
parentTarget: Element | Document,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -948,4 +948,52 @@ describe('DOMEventResponderSystem', () => {
},
]);
});

it('isTargetDirectlyWithinEventComponent works', () => {
const buttonRef = React.createRef();
const divRef = React.createRef();
const log = [];

const EventComponent = createReactEventComponent(
['pointerout'],
undefined,
undefined,
(event, context) => {
const isWithin = context.isTargetDirectlyWithinEventComponent(
event.nativeEvent.relatedTarget,
);
log.push(isWithin);
},
);

const Test = () => (
<EventComponent>
<div ref={divRef} />
<EventComponent>
<button ref={buttonRef}>Click me!</button>
</EventComponent>
</EventComponent>
);
ReactDOM.render(<Test />, container);

const createEvent = (type, data) => {
const event = document.createEvent('CustomEvent');
event.initCustomEvent(type, true, true);
if (data != null) {
Object.entries(data).forEach(([key, value]) => {
event[key] = value;
});
}
return event;
};

buttonRef.current.dispatchEvent(
createEvent('pointerout', {relatedTarget: divRef.current}),
);
divRef.current.dispatchEvent(
createEvent('pointerout', {relatedTarget: buttonRef.current}),
);

expect(log).toEqual([false, true, false]);
});
});
8 changes: 6 additions & 2 deletions packages/react-events/src/Hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ function dispatchHoverStartEvents(
if (event !== null) {
const {nativeEvent} = event;
if (
context.isTargetWithinEventComponent((nativeEvent: any).relatedTarget)
context.isTargetDirectlyWithinEventComponent(
(nativeEvent: any).relatedTarget,
)
) {
return;
}
Expand Down Expand Up @@ -156,7 +158,9 @@ function dispatchHoverEndEvents(
if (event !== null) {
const {nativeEvent} = event;
if (
context.isTargetWithinEventComponent((nativeEvent: any).relatedTarget)
context.isTargetDirectlyWithinEventComponent(
(nativeEvent: any).relatedTarget,
)
) {
return;
}
Expand Down
9 changes: 4 additions & 5 deletions packages/react-events/src/__tests__/Hover-test.internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -443,18 +443,17 @@ describe('Hover event responder', () => {
createPointerEvent('pointerover', {relatedTarget: innerRef.current}),
);
outerRef.current.dispatchEvent(createPointerEvent('pointerout'));
// TODO: correct result should include commented events
expect(events).toEqual([
'outer: onHoverStart',
'outer: onHoverChange',
// 'outer: onHoverEnd',
// 'outer: onHoverChange',
'outer: onHoverEnd',
'outer: onHoverChange',
'inner: onHoverStart',
'inner: onHoverChange',
'inner: onHoverEnd',
'inner: onHoverChange',
// 'outer: onHoverStart',
// 'outer: onHoverChange',
'outer: onHoverStart',
'outer: onHoverChange',
'outer: onHoverEnd',
'outer: onHoverChange',
]);
Expand Down
1 change: 1 addition & 0 deletions packages/shared/ReactTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export type ReactResponderContext = {
parentTarget: Element | Document,
) => boolean,
isTargetWithinEventComponent: (Element | Document) => boolean,
isTargetDirectlyWithinEventComponent: (Element | Document) => boolean,
isPositionWithinTouchHitTarget: (
doc: Document,
x: number,
Expand Down

0 comments on commit fa2fa35

Please sign in to comment.