@samitouri / QOS-React-2 / commits / b1a083183c

Revert legacy plugin modules (#18638)

Dominic Gannaway committed Apr 16, 2020 at 18:46 UTC b1a083183c2f834e8550b4d7437bb0db1a51fdfb
6 files changed +233 -85
packages/react-dom/src/events/DOMLegacyEventPluginSystem.js
+202
@@ -15,6 +15,7 @@ import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
15 import type {PluginModule} from 'legacy-events/PluginModuleType';
16 import type {ReactSyntheticEvent} from 'legacy-events/ReactSyntheticEventType';
17 import type {TopLevelType} from 'legacy-events/TopLevelEventTypes';
18 +import forEachAccumulated from 'legacy-events/forEachAccumulated';
19
20 import {
21 HostRoot,
@@ -45,6 +46,7 @@ import {
46 } from './DOMTopLevelEventTypes';
47 import {addTrappedEventListener} from './ReactDOMEventListener';
48 import {batchedEventUpdates} from './ReactDOMUpdateBatching';
49 +import getListener from './getListener';
50
51 /**
52 * Summary of `DOMEventPluginSystem` event handling:
@@ -396,3 +398,203 @@ export function legacyTrapCapturedEvent(
398 );
399 listenerMap.set(topLevelType, {passive: undefined, listener});
400 }
401 +
402 +function getParent(inst: Object | null): Object | null {
403 + if (!inst) {
404 + return null;
405 + }
406 + do {
407 + inst = inst.return;
408 + // TODO: If this is a HostRoot we might want to bail out.
409 + // That is depending on if we want nested subtrees (layers) to bubble
410 + // events to their parent. We could also go through parentNode on the
411 + // host node but that wouldn't work for React Native and doesn't let us
412 + // do the portal feature.
413 + } while (inst && inst.tag !== HostComponent);
414 + if (inst) {
415 + return inst;
416 + }
417 + return null;
418 +}
419 +
420 +/**
421 + * Simulates the traversal of a two-phase, capture/bubble event dispatch.
422 + */
423 +function traverseTwoPhase(
424 + inst: Object,
425 + fn: Function,
426 + arg: ReactSyntheticEvent,
427 +) {
428 + const path = [];
429 + while (inst) {
430 + path.push(inst);
431 + inst = getParent(inst);
432 + }
433 + let i;
434 + for (i = path.length; i-- > 0; ) {
435 + fn(path[i], 'captured', arg);
436 + }
437 + for (i = 0; i < path.length; i++) {
438 + fn(path[i], 'bubbled', arg);
439 + }
440 +}
441 +
442 +function listenerAtPhase(inst, event, propagationPhase) {
443 + const registrationName =
444 + event.dispatchConfig.phasedRegistrationNames[propagationPhase];
445 + return getListener(inst, registrationName);
446 +}
447 +
448 +/**
449 + * Return the lowest common ancestor of A and B, or null if they are in
450 + * different trees.
451 + */
452 +export function getLowestCommonAncestor(
453 + instA: Object,
454 + instB: Object,
455 +): Object | null {
456 + let depthA = 0;
457 + for (let tempA = instA; tempA; tempA = getParent(tempA)) {
458 + depthA++;
459 + }
460 + let depthB = 0;
461 + for (let tempB = instB; tempB; tempB = getParent(tempB)) {
462 + depthB++;
463 + }
464 +
465 + // If A is deeper, crawl up.
466 + while (depthA - depthB > 0) {
467 + instA = getParent(instA);
468 + depthA--;
469 + }
470 +
471 + // If B is deeper, crawl up.
472 + while (depthB - depthA > 0) {
473 + instB = getParent(instB);
474 + depthB--;
475 + }
476 +
477 + // Walk in lockstep until we find a match.
478 + let depth = depthA;
479 + while (depth--) {
480 + if (instA === instB || instA === instB.alternate) {
481 + return instA;
482 + }
483 + instA = getParent(instA);
484 + instB = getParent(instB);
485 + }
486 + return null;
487 +}
488 +
489 +/**
490 + * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that
491 + * should would receive a `mouseEnter` or `mouseLeave` event.
492 + *
493 + * Does not invoke the callback on the nearest common ancestor because nothing
494 + * "entered" or "left" that element.
495 + */
496 +export function traverseEnterLeave(
497 + from: Object,
498 + to: Object,
499 + fn: Function,
500 + argFrom: ReactSyntheticEvent,
501 + argTo: ReactSyntheticEvent,
502 +) {
503 + const common = from && to ? getLowestCommonAncestor(from, to) : null;
504 + const pathFrom = [];
505 + while (true) {
506 + if (!from) {
507 + break;
508 + }
509 + if (from === common) {
510 + break;
511 + }
512 + const alternate = from.alternate;
513 + if (alternate !== null && alternate === common) {
514 + break;
515 + }
516 + pathFrom.push(from);
517 + from = getParent(from);
518 + }
519 + const pathTo = [];
520 + while (true) {
521 + if (!to) {
522 + break;
523 + }
524 + if (to === common) {
525 + break;
526 + }
527 + const alternate = to.alternate;
528 + if (alternate !== null && alternate === common) {
529 + break;
530 + }
531 + pathTo.push(to);
532 + to = getParent(to);
533 + }
534 + for (let i = 0; i < pathFrom.length; i++) {
535 + fn(pathFrom[i], 'bubbled', argFrom);
536 + }
537 + for (let i = pathTo.length; i-- > 0; ) {
538 + fn(pathTo[i], 'captured', argTo);
539 + }
540 +}
541 +
542 +function accumulateDirectionalDispatches(inst, phase, event) {
543 + if (__DEV__) {
544 + if (!inst) {
545 + console.error('Dispatching inst must not be null');
546 + }
547 + }
548 + const listener = listenerAtPhase(inst, event, phase);
549 + if (listener) {
550 + event._dispatchListeners = accumulateInto(
551 + event._dispatchListeners,
552 + listener,
553 + );
554 + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
555 + }
556 +}
557 +
558 +function accumulateTwoPhaseDispatchesSingle(event) {
559 + if (event && event.dispatchConfig.phasedRegistrationNames) {
560 + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event);
561 + }
562 +}
563 +
564 +/**
565 + * Accumulates without regard to direction, does not look for phased
566 + * registration names. Same as `accumulateDirectDispatchesSingle` but without
567 + * requiring that the `dispatchMarker` be the same as the dispatched ID.
568 + */
569 +function accumulateDispatches(
570 + inst: Object,
571 + ignoredDirection: ?boolean,
572 + event: Object,
573 +): void {
574 + if (inst && event && event.dispatchConfig.registrationName) {
575 + const registrationName = event.dispatchConfig.registrationName;
576 + const listener = getListener(inst, registrationName);
577 + if (listener) {
578 + event._dispatchListeners = accumulateInto(
579 + event._dispatchListeners,
580 + listener,
581 + );
582 + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
583 + }
584 + }
585 +}
586 +
587 +export function accumulateTwoPhaseDispatches(
588 + events: ReactSyntheticEvent | Array<ReactSyntheticEvent>,
589 +): void {
590 + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
591 +}
592 +
593 +export function accumulateEnterLeaveDispatches(
594 + leave: ReactSyntheticEvent,
595 + enter: ReactSyntheticEvent,
596 + from: Fiber,
597 + to: Fiber,
598 +) {
599 + traverseEnterLeave(from, to, accumulateDispatches, leave, enter);
600 +}
packages/react-dom/src/events/plugins/LegacyBeforeInputEventPlugin.js
+3 -3
@@ -28,7 +28,7 @@ import {
28 } from '../FallbackCompositionState';
29 import SyntheticCompositionEvent from '../SyntheticCompositionEvent';
30 import SyntheticInputEvent from '../SyntheticInputEvent';
31 -import accumulateTwoPhaseListeners from '../accumulateTwoPhaseListeners';
31 +import {accumulateTwoPhaseDispatches} from '../DOMLegacyEventPluginSystem';
32
33 const END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
34 const START_KEYCODE = 229;
@@ -276,7 +276,7 @@ function extractCompositionEvent(
276 }
277 }
278
279 - accumulateTwoPhaseListeners(event);
279 + accumulateTwoPhaseDispatches(event);
280 return event;
281 }
282
@@ -437,7 +437,7 @@ function extractBeforeInputEvent(
437 );
438
439 event.data = chars;
440 - accumulateTwoPhaseListeners(event);
440 + accumulateTwoPhaseDispatches(event);
441 return event;
442 }
443
packages/react-dom/src/events/plugins/LegacyChangeEventPlugin.js
+4 -12
@@ -27,13 +27,9 @@ import {updateValueIfChanged} from '../../client/inputValueTracking';
27 import {setDefaultValue} from '../../client/ReactDOMInput';
28 import {enqueueStateRestore} from '../ReactDOMControlledComponent';
29
30 -import {
31 - disableInputAttributeSyncing,
32 - enableModernEventSystem,
33 -} from 'shared/ReactFeatureFlags';
34 -import accumulateTwoPhaseListeners from '../accumulateTwoPhaseListeners';
30 +import {disableInputAttributeSyncing} from 'shared/ReactFeatureFlags';
31 import {batchedUpdates} from '../ReactDOMUpdateBatching';
36 -import {dispatchEventsInBatch} from '../DOMModernPluginEventSystem';
32 +import {accumulateTwoPhaseDispatches} from '../DOMLegacyEventPluginSystem';
33
34 const eventTypes = {
35 change: {
@@ -64,7 +60,7 @@ function createAndAccumulateChangeEvent(inst, nativeEvent, target) {
60 event.type = 'change';
61 // Flag this event loop as needing state restore.
62 enqueueStateRestore(target);
67 - accumulateTwoPhaseListeners(event);
63 + accumulateTwoPhaseDispatches(event);
64 return event;
65 }
66 /**
@@ -105,11 +101,7 @@ function manualDispatchChangeEvent(nativeEvent) {
101 }
102
103 function runEventInBatch(event) {
108 - if (enableModernEventSystem) {
109 - dispatchEventsInBatch([event]);
110 - } else {
111 - runEventsInBatch(event);
112 - }
104 + runEventsInBatch(event);
105 }
106
107 function getInstIfValueChanged(targetInst) {
packages/react-dom/src/events/plugins/LegacyEnterLeaveEventPlugin.js
+17 -30
@@ -23,8 +23,7 @@ import {
23 } from '../../client/ReactDOMComponentTree';
24 import {HostComponent, HostText} from 'react-reconciler/src/ReactWorkTags';
25 import {getNearestMountedFiber} from 'react-reconciler/src/ReactFiberTreeReflection';
26 -import {enableModernEventSystem} from 'shared/ReactFeatureFlags';
27 -import accumulateEnterLeaveListeners from '../accumulateEnterLeaveListeners';
26 +import {accumulateEnterLeaveDispatches} from '../DOMLegacyEventPluginSystem';
27
28 const eventTypes = {
29 mouseEnter: {
@@ -67,26 +66,16 @@ const EnterLeaveEventPlugin = {
66 const isOutEvent =
67 topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_POINTER_OUT;
68
70 - if (isOverEvent && (eventSystemFlags & IS_REPLAYED) === 0) {
71 - const related = nativeEvent.relatedTarget || nativeEvent.fromElement;
72 - if (related) {
73 - if (enableModernEventSystem) {
74 - // Due to the fact we don't add listeners to the document with the
75 - // modern event system and instead attach listeners to roots, we
76 - // need to handle the over event case. To ensure this, we just need to
77 - // make sure the node that we're coming from is managed by React.
78 - const inst = getClosestInstanceFromNode(related);
79 - if (inst !== null) {
80 - return null;
81 - }
82 - } else {
83 - // If this is an over event with a target, then we've already dispatched
84 - // the event in the out event of the other target. If this is replayed,
85 - // then it's because we couldn't dispatch against this target previously
86 - // so we have to do it now instead.
87 - return null;
88 - }
89 - }
69 + if (
70 + isOverEvent &&
71 + (eventSystemFlags & IS_REPLAYED) === 0 &&
72 + (nativeEvent.relatedTarget || nativeEvent.fromElement)
73 + ) {
74 + // If this is an over event with a target, then we've already dispatched
75 + // the event in the out event of the other target. If this is replayed,
76 + // then it's because we couldn't dispatch against this target previously
77 + // so we have to do it now instead.
78 + return null;
79 }
80
81 if (!isOutEvent && !isOverEvent) {
@@ -174,15 +163,13 @@ const EnterLeaveEventPlugin = {
163 enter.target = toNode;
164 enter.relatedTarget = fromNode;
165
177 - accumulateEnterLeaveListeners(leave, enter, from, to);
166 + accumulateEnterLeaveDispatches(leave, enter, from, to);
167
179 - if (!enableModernEventSystem) {
180 - // If we are not processing the first ancestor, then we
181 - // should not process the same nativeEvent again, as we
182 - // will have already processed it in the first ancestor.
183 - if ((eventSystemFlags & IS_FIRST_ANCESTOR) === 0) {
184 - return [leave];
185 - }
168 + // If we are not processing the first ancestor, then we
169 + // should not process the same nativeEvent again, as we
170 + // will have already processed it in the first ancestor.
171 + if ((eventSystemFlags & IS_FIRST_ANCESTOR) === 0) {
172 + return [leave];
173 }
174
175 return [leave, enter];
packages/react-dom/src/events/plugins/LegacySelectEventPlugin.js
+4 -9
@@ -26,7 +26,7 @@ import {getNodeFromInstance} from '../../client/ReactDOMComponentTree';
26 import {hasSelectionCapabilities} from '../../client/ReactInputSelection';
27 import {DOCUMENT_NODE} from '../../shared/HTMLNodeType';
28 import {isListeningToAllDependencies} from '../DOMEventListenerMap';
29 -import accumulateTwoPhaseListeners from '../accumulateTwoPhaseListeners';
29 +import {accumulateTwoPhaseDispatches} from '../DOMLegacyEventPluginSystem';
30
31 const skipSelectionChangeEvent =
32 canUseDOM && 'documentMode' in document && document.documentMode <= 11;
@@ -135,7 +135,7 @@ function constructSelectEvent(nativeEvent, nativeEventTarget) {
135 syntheticEvent.type = 'select';
136 syntheticEvent.target = activeElement;
137
138 - accumulateTwoPhaseListeners(syntheticEvent);
138 + accumulateTwoPhaseDispatches(syntheticEvent);
139
140 return syntheticEvent;
141 }
@@ -166,16 +166,11 @@ const SelectEventPlugin = {
166 nativeEvent,
167 nativeEventTarget,
168 eventSystemFlags,
169 - container,
169 ) {
171 - const containerOrDoc =
172 - container || getEventTargetDocument(nativeEventTarget);
170 + const doc = getEventTargetDocument(nativeEventTarget);
171 // Track whether all listeners exists for this plugin. If none exist, we do
172 // not extract events. See #3639.
175 - if (
176 - !containerOrDoc ||
177 - !isListeningToAllDependencies('onSelect', containerOrDoc)
178 - ) {
173 + if (!doc || !isListeningToAllDependencies('onSelect', doc)) {
174 return null;
175 }
176
packages/react-dom/src/events/plugins/LegacySimpleEventPlugin.js
+3 -31
@@ -14,10 +14,8 @@ import type {
14 import type {ReactSyntheticEvent} from 'legacy-events/ReactSyntheticEventType';
15 import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
16 import type {PluginModule} from 'legacy-events/PluginModuleType';
17 -import type {EventSystemFlags} from '../EventSystemFlags';
17
18 import SyntheticEvent from 'legacy-events/SyntheticEvent';
20 -import {IS_TARGET_PHASE_ONLY} from '../EventSystemFlags';
19
20 import * as DOMTopLevelEventTypes from '../DOMTopLevelEventTypes';
21 import {
@@ -37,10 +35,7 @@ import SyntheticTransitionEvent from '../SyntheticTransitionEvent';
35 import SyntheticUIEvent from '../SyntheticUIEvent';
36 import SyntheticWheelEvent from '../SyntheticWheelEvent';
37 import getEventCharCode from '../getEventCharCode';
40 -import accumulateTwoPhaseListeners from '../accumulateTwoPhaseListeners';
41 -import accumulateEventTargetListeners from '../accumulateEventTargetListeners';
42 -
43 -import {enableUseEventAPI} from 'shared/ReactFeatureFlags';
38 +import {accumulateTwoPhaseDispatches} from '../DOMLegacyEventPluginSystem';
39
40 // Only used in DEV for exhaustiveness validation.
41 const knownHTMLTopLevelTypes: Array<DOMTopLevelEventType> = [
@@ -86,8 +81,6 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
81 targetInst: null | Fiber,
82 nativeEvent: MouseEvent,
83 nativeEventTarget: null | EventTarget,
89 - eventSystemFlags?: EventSystemFlags,
90 - targetContainer?: null | EventTarget,
84 ): null | ReactSyntheticEvent {
85 const dispatchConfig = topLevelEventsToDispatchConfig.get(topLevelType);
86 if (!dispatchConfig) {
@@ -109,8 +102,6 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
102 break;
103 case DOMTopLevelEventTypes.TOP_BLUR:
104 case DOMTopLevelEventTypes.TOP_FOCUS:
112 - case DOMTopLevelEventTypes.TOP_BEFORE_BLUR:
113 - case DOMTopLevelEventTypes.TOP_AFTER_BLUR:
105 EventConstructor = SyntheticFocusEvent;
106 break;
107 case DOMTopLevelEventTypes.TOP_CLICK:
@@ -179,10 +170,7 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
170 break;
171 default:
172 if (__DEV__) {
182 - if (
183 - knownHTMLTopLevelTypes.indexOf(topLevelType) === -1 &&
184 - dispatchConfig.customEvent !== true
185 - ) {
173 + if (knownHTMLTopLevelTypes.indexOf(topLevelType) === -1) {
174 console.error(
175 'SimpleEventPlugin: Unhandled event type, `%s`. This warning ' +
176 'is likely caused by a bug in React. Please file an issue.',
@@ -201,23 +189,7 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
189 nativeEvent,
190 nativeEventTarget,
191 );
204 -
205 - // For TargetEvent only accumulation, we do not traverse through
206 - // the React tree looking for managed React DOM elements that have
207 - // events. Instead we only check the EventTarget Store Map to see
208 - // if the container has listeners for the particular phase we're
209 - // interested in. This is because we attach the native event listener
210 - // only in the given phase.
211 - if (
212 - enableUseEventAPI &&
213 - eventSystemFlags !== undefined &&
214 - eventSystemFlags & IS_TARGET_PHASE_ONLY &&
215 - targetContainer != null
216 - ) {
217 - accumulateEventTargetListeners(event, targetContainer);
218 - } else {
219 - accumulateTwoPhaseListeners(event, true);
220 - }
192 + accumulateTwoPhaseDispatches(event);
193 return event;
194 },
195 };