@samitouri / QOS-React-2 / commits / 30cee2f4c7

Modern Event System: register onMouseEnter for portals (#18720)

Dominic Gannaway committed Apr 23, 2020 at 20:57 UTC 30cee2f4c7eb9e4097f4dc55555f4682f79f2f1d
10 files changed +63
packages/react-art/src/ReactARTHostConfig.js
+4
@@ -500,3 +500,7 @@ export function beforeActiveInstanceBlur() {
500 export function afterActiveInstanceBlur() {
501 // noop
502 }
503 +
504 +export function preparePortalMount(portalInstance: any): void {
505 + // noop
506 +}
packages/react-dom/src/client/ReactDOMHostConfig.js
+8
@@ -64,8 +64,10 @@ import {
64 enableSuspenseServerRenderer,
65 enableDeprecatedFlareAPI,
66 enableFundamentalAPI,
67 + enableModernEventSystem,
68 } from 'shared/ReactFeatureFlags';
69 import {TOP_BEFORE_BLUR, TOP_AFTER_BLUR} from '../events/DOMTopLevelEventTypes';
70 +import {listenToEvent} from '../events/DOMModernPluginEventSystem';
71
72 export type Type = string;
73 export type Props = {
@@ -1098,3 +1100,9 @@ export function makeOpaqueHydratingObject(
1100 valueOf: attemptToReadValue,
1101 };
1102 }
1103 +
1104 +export function preparePortalMount(portalInstance: Instance): void {
1105 + if (enableModernEventSystem) {
1106 + listenToEvent('onMouseEnter', portalInstance);
1107 + }
1108 +}
packages/react-dom/src/events/plugins/__tests__/ModernEnterLeaveEventPlugin-test.internal.js
+26
@@ -239,4 +239,30 @@ describe('EnterLeaveEventPlugin', () => {
239
240 ReactDOM.render(<Parent />, container);
241 });
242 +
243 + it('should work with portals outside of the root', () => {
244 + const divRef = React.createRef();
245 + const onMouseLeave = jest.fn();
246 +
247 + function Component() {
248 + return (
249 + <div onMouseLeave={onMouseLeave}>
250 + {ReactDOM.createPortal(<div ref={divRef} />, document.body)}
251 + </div>
252 + );
253 + }
254 +
255 + ReactDOM.render(<Component />, container);
256 +
257 + // Leave from the portal div
258 + divRef.current.dispatchEvent(
259 + new MouseEvent('mouseout', {
260 + bubbles: true,
261 + cancelable: true,
262 + relatedTarget: document.body,
263 + }),
264 + );
265 +
266 + expect(onMouseLeave).toHaveBeenCalledTimes(1);
267 + });
268 });
packages/react-native-renderer/src/ReactFabricHostConfig.js
+4
@@ -514,3 +514,7 @@ export function beforeActiveInstanceBlur() {
514 export function afterActiveInstanceBlur() {
515 // noop
516 }
517 +
518 +export function preparePortalMount(portalInstance: Instance): void {
519 + // noop
520 +}
packages/react-native-renderer/src/ReactNativeHostConfig.js
+4
@@ -562,3 +562,7 @@ export function beforeActiveInstanceBlur() {
562 export function afterActiveInstanceBlur() {
563 // noop
564 }
565 +
566 +export function preparePortalMount(portalInstance: Instance): void {
567 + // noop
568 +}
packages/react-noop-renderer/src/createReactNoop.js
+4
@@ -449,6 +449,10 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
449 afterActiveInstanceBlur() {
450 // NO-OP
451 },
452 +
453 + preparePortalMount() {
454 + // NO-OP
455 + },
456 };
457
458 const hostConfig = useMutation
packages/react-reconciler/src/ReactFiberCompleteWork.new.js
+4
@@ -82,6 +82,7 @@ import {
82 mountFundamentalComponent,
83 cloneFundamentalInstance,
84 shouldUpdateFundamentalComponent,
85 + preparePortalMount,
86 } from './ReactFiberHostConfig';
87 import {
88 getRootHostContainer,
@@ -973,6 +974,9 @@ function completeWork(
974 case HostPortal:
975 popHostContainer(workInProgress);
976 updateHostContainer(workInProgress);
977 + if (current === null) {
978 + preparePortalMount(workInProgress.stateNode.containerInfo);
979 + }
980 return null;
981 case ContextProvider:
982 // Pop provider fiber
packages/react-reconciler/src/ReactFiberCompleteWork.old.js
+4
@@ -82,6 +82,7 @@ import {
82 mountFundamentalComponent,
83 cloneFundamentalInstance,
84 shouldUpdateFundamentalComponent,
85 + preparePortalMount,
86 } from './ReactFiberHostConfig';
87 import {
88 getRootHostContainer,
@@ -973,6 +974,9 @@ function completeWork(
974 case HostPortal:
975 popHostContainer(workInProgress);
976 updateHostContainer(workInProgress);
977 + if (current === null) {
978 + preparePortalMount(workInProgress.stateNode.containerInfo);
979 + }
980 return null;
981 case ContextProvider:
982 // Pop provider fiber
packages/react-reconciler/src/forks/ReactFiberHostConfig.custom.js
+1
@@ -83,6 +83,7 @@ export const makeClientIdInDEV = $$$hostConfig.makeClientIdInDEV;
83 export const makeServerId = $$$hostConfig.makeServerId;
84 export const beforeActiveInstanceBlur = $$$hostConfig.beforeActiveInstanceBlur;
85 export const afterActiveInstanceBlur = $$$hostConfig.afterActiveInstanceBlur;
86 +export const preparePortalMount = $$$hostConfig.preparePortalMount;
87
88 // -------------------
89 // Mutation
packages/react-test-renderer/src/ReactTestHostConfig.js
+4
@@ -435,3 +435,7 @@ export function beforeActiveInstanceBlur() {
435 export function afterActiveInstanceBlur() {
436 // noop
437 }
438 +
439 +export function preparePortalMount(portalInstance: Instance): void {
440 + // noop
441 +}