From 30cee2f4c7eb9e4097f4dc55555f4682f79f2f1d Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Thu, 23 Apr 2020 20:57:52 +0100 Subject: [PATCH] Modern Event System: register onMouseEnter for portals (#18720) --- packages/react-art/src/ReactARTHostConfig.js | 4 +++ .../src/client/ReactDOMHostConfig.js | 8 ++++++ ...dernEnterLeaveEventPlugin-test.internal.js | 26 +++++++++++++++++++ .../src/ReactFabricHostConfig.js | 4 +++ .../src/ReactNativeHostConfig.js | 4 +++ .../src/createReactNoop.js | 4 +++ .../src/ReactFiberCompleteWork.new.js | 4 +++ .../src/ReactFiberCompleteWork.old.js | 4 +++ .../src/forks/ReactFiberHostConfig.custom.js | 1 + .../src/ReactTestHostConfig.js | 4 +++ 10 files changed, 63 insertions(+) diff --git a/packages/react-art/src/ReactARTHostConfig.js b/packages/react-art/src/ReactARTHostConfig.js index d1a4145ff3..7086dcccb5 100644 --- a/packages/react-art/src/ReactARTHostConfig.js +++ b/packages/react-art/src/ReactARTHostConfig.js @@ -500,3 +500,7 @@ export function beforeActiveInstanceBlur() { export function afterActiveInstanceBlur() { // noop } + +export function preparePortalMount(portalInstance: any): void { + // noop +} diff --git a/packages/react-dom/src/client/ReactDOMHostConfig.js b/packages/react-dom/src/client/ReactDOMHostConfig.js index 15a317b1f6..dd7ac44686 100644 --- a/packages/react-dom/src/client/ReactDOMHostConfig.js +++ b/packages/react-dom/src/client/ReactDOMHostConfig.js @@ -64,8 +64,10 @@ import { enableSuspenseServerRenderer, enableDeprecatedFlareAPI, enableFundamentalAPI, + enableModernEventSystem, } from 'shared/ReactFeatureFlags'; import {TOP_BEFORE_BLUR, TOP_AFTER_BLUR} from '../events/DOMTopLevelEventTypes'; +import {listenToEvent} from '../events/DOMModernPluginEventSystem'; export type Type = string; export type Props = { @@ -1098,3 +1100,9 @@ export function makeOpaqueHydratingObject( valueOf: attemptToReadValue, }; } + +export function preparePortalMount(portalInstance: Instance): void { + if (enableModernEventSystem) { + listenToEvent('onMouseEnter', portalInstance); + } +} diff --git a/packages/react-dom/src/events/plugins/__tests__/ModernEnterLeaveEventPlugin-test.internal.js b/packages/react-dom/src/events/plugins/__tests__/ModernEnterLeaveEventPlugin-test.internal.js index beda6392b1..81809ff7fa 100644 --- a/packages/react-dom/src/events/plugins/__tests__/ModernEnterLeaveEventPlugin-test.internal.js +++ b/packages/react-dom/src/events/plugins/__tests__/ModernEnterLeaveEventPlugin-test.internal.js @@ -239,4 +239,30 @@ describe('EnterLeaveEventPlugin', () => { ReactDOM.render(, container); }); + + it('should work with portals outside of the root', () => { + const divRef = React.createRef(); + const onMouseLeave = jest.fn(); + + function Component() { + return ( +
+ {ReactDOM.createPortal(
, document.body)} +
+ ); + } + + ReactDOM.render(, container); + + // Leave from the portal div + divRef.current.dispatchEvent( + new MouseEvent('mouseout', { + bubbles: true, + cancelable: true, + relatedTarget: document.body, + }), + ); + + expect(onMouseLeave).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/react-native-renderer/src/ReactFabricHostConfig.js b/packages/react-native-renderer/src/ReactFabricHostConfig.js index 714c81d7dd..fa3b25103f 100644 --- a/packages/react-native-renderer/src/ReactFabricHostConfig.js +++ b/packages/react-native-renderer/src/ReactFabricHostConfig.js @@ -514,3 +514,7 @@ export function beforeActiveInstanceBlur() { export function afterActiveInstanceBlur() { // noop } + +export function preparePortalMount(portalInstance: Instance): void { + // noop +} diff --git a/packages/react-native-renderer/src/ReactNativeHostConfig.js b/packages/react-native-renderer/src/ReactNativeHostConfig.js index 8acf509953..fd9b08cf4b 100644 --- a/packages/react-native-renderer/src/ReactNativeHostConfig.js +++ b/packages/react-native-renderer/src/ReactNativeHostConfig.js @@ -562,3 +562,7 @@ export function beforeActiveInstanceBlur() { export function afterActiveInstanceBlur() { // noop } + +export function preparePortalMount(portalInstance: Instance): void { + // noop +} diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js index 7d26eb47bb..d8b5b72806 100644 --- a/packages/react-noop-renderer/src/createReactNoop.js +++ b/packages/react-noop-renderer/src/createReactNoop.js @@ -449,6 +449,10 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { afterActiveInstanceBlur() { // NO-OP }, + + preparePortalMount() { + // NO-OP + }, }; const hostConfig = useMutation diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js index d364336ec8..87f57ff58b 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js @@ -82,6 +82,7 @@ import { mountFundamentalComponent, cloneFundamentalInstance, shouldUpdateFundamentalComponent, + preparePortalMount, } from './ReactFiberHostConfig'; import { getRootHostContainer, @@ -973,6 +974,9 @@ function completeWork( case HostPortal: popHostContainer(workInProgress); updateHostContainer(workInProgress); + if (current === null) { + preparePortalMount(workInProgress.stateNode.containerInfo); + } return null; case ContextProvider: // Pop provider fiber diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.old.js b/packages/react-reconciler/src/ReactFiberCompleteWork.old.js index efe0ef63ff..ee12b05bfd 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.old.js @@ -82,6 +82,7 @@ import { mountFundamentalComponent, cloneFundamentalInstance, shouldUpdateFundamentalComponent, + preparePortalMount, } from './ReactFiberHostConfig'; import { getRootHostContainer, @@ -973,6 +974,9 @@ function completeWork( case HostPortal: popHostContainer(workInProgress); updateHostContainer(workInProgress); + if (current === null) { + preparePortalMount(workInProgress.stateNode.containerInfo); + } return null; case ContextProvider: // Pop provider fiber diff --git a/packages/react-reconciler/src/forks/ReactFiberHostConfig.custom.js b/packages/react-reconciler/src/forks/ReactFiberHostConfig.custom.js index 3d2544b5b2..6bc1c38daf 100644 --- a/packages/react-reconciler/src/forks/ReactFiberHostConfig.custom.js +++ b/packages/react-reconciler/src/forks/ReactFiberHostConfig.custom.js @@ -83,6 +83,7 @@ export const makeClientIdInDEV = $$$hostConfig.makeClientIdInDEV; export const makeServerId = $$$hostConfig.makeServerId; export const beforeActiveInstanceBlur = $$$hostConfig.beforeActiveInstanceBlur; export const afterActiveInstanceBlur = $$$hostConfig.afterActiveInstanceBlur; +export const preparePortalMount = $$$hostConfig.preparePortalMount; // ------------------- // Mutation diff --git a/packages/react-test-renderer/src/ReactTestHostConfig.js b/packages/react-test-renderer/src/ReactTestHostConfig.js index bcf31c04b0..296bdcf56d 100644 --- a/packages/react-test-renderer/src/ReactTestHostConfig.js +++ b/packages/react-test-renderer/src/ReactTestHostConfig.js @@ -435,3 +435,7 @@ export function beforeActiveInstanceBlur() { export function afterActiveInstanceBlur() { // noop } + +export function preparePortalMount(portalInstance: Instance): void { + // noop +}