mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Revert legacy plugin modules (#18638)
This commit is contained in:
@@ -15,6 +15,7 @@ import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
|
||||
import type {PluginModule} from 'legacy-events/PluginModuleType';
|
||||
import type {ReactSyntheticEvent} from 'legacy-events/ReactSyntheticEventType';
|
||||
import type {TopLevelType} from 'legacy-events/TopLevelEventTypes';
|
||||
import forEachAccumulated from 'legacy-events/forEachAccumulated';
|
||||
|
||||
import {
|
||||
HostRoot,
|
||||
@@ -45,6 +46,7 @@ import {
|
||||
} from './DOMTopLevelEventTypes';
|
||||
import {addTrappedEventListener} from './ReactDOMEventListener';
|
||||
import {batchedEventUpdates} from './ReactDOMUpdateBatching';
|
||||
import getListener from './getListener';
|
||||
|
||||
/**
|
||||
* Summary of `DOMEventPluginSystem` event handling:
|
||||
@@ -396,3 +398,203 @@ export function legacyTrapCapturedEvent(
|
||||
);
|
||||
listenerMap.set(topLevelType, {passive: undefined, listener});
|
||||
}
|
||||
|
||||
function getParent(inst: Object | null): Object | null {
|
||||
if (!inst) {
|
||||
return null;
|
||||
}
|
||||
do {
|
||||
inst = inst.return;
|
||||
// TODO: If this is a HostRoot we might want to bail out.
|
||||
// That is depending on if we want nested subtrees (layers) to bubble
|
||||
// events to their parent. We could also go through parentNode on the
|
||||
// host node but that wouldn't work for React Native and doesn't let us
|
||||
// do the portal feature.
|
||||
} while (inst && inst.tag !== HostComponent);
|
||||
if (inst) {
|
||||
return inst;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates the traversal of a two-phase, capture/bubble event dispatch.
|
||||
*/
|
||||
function traverseTwoPhase(
|
||||
inst: Object,
|
||||
fn: Function,
|
||||
arg: ReactSyntheticEvent,
|
||||
) {
|
||||
const path = [];
|
||||
while (inst) {
|
||||
path.push(inst);
|
||||
inst = getParent(inst);
|
||||
}
|
||||
let i;
|
||||
for (i = path.length; i-- > 0; ) {
|
||||
fn(path[i], 'captured', arg);
|
||||
}
|
||||
for (i = 0; i < path.length; i++) {
|
||||
fn(path[i], 'bubbled', arg);
|
||||
}
|
||||
}
|
||||
|
||||
function listenerAtPhase(inst, event, propagationPhase) {
|
||||
const registrationName =
|
||||
event.dispatchConfig.phasedRegistrationNames[propagationPhase];
|
||||
return getListener(inst, registrationName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the lowest common ancestor of A and B, or null if they are in
|
||||
* different trees.
|
||||
*/
|
||||
export function getLowestCommonAncestor(
|
||||
instA: Object,
|
||||
instB: Object,
|
||||
): Object | null {
|
||||
let depthA = 0;
|
||||
for (let tempA = instA; tempA; tempA = getParent(tempA)) {
|
||||
depthA++;
|
||||
}
|
||||
let depthB = 0;
|
||||
for (let tempB = instB; tempB; tempB = getParent(tempB)) {
|
||||
depthB++;
|
||||
}
|
||||
|
||||
// If A is deeper, crawl up.
|
||||
while (depthA - depthB > 0) {
|
||||
instA = getParent(instA);
|
||||
depthA--;
|
||||
}
|
||||
|
||||
// If B is deeper, crawl up.
|
||||
while (depthB - depthA > 0) {
|
||||
instB = getParent(instB);
|
||||
depthB--;
|
||||
}
|
||||
|
||||
// Walk in lockstep until we find a match.
|
||||
let depth = depthA;
|
||||
while (depth--) {
|
||||
if (instA === instB || instA === instB.alternate) {
|
||||
return instA;
|
||||
}
|
||||
instA = getParent(instA);
|
||||
instB = getParent(instB);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that
|
||||
* should would receive a `mouseEnter` or `mouseLeave` event.
|
||||
*
|
||||
* Does not invoke the callback on the nearest common ancestor because nothing
|
||||
* "entered" or "left" that element.
|
||||
*/
|
||||
export function traverseEnterLeave(
|
||||
from: Object,
|
||||
to: Object,
|
||||
fn: Function,
|
||||
argFrom: ReactSyntheticEvent,
|
||||
argTo: ReactSyntheticEvent,
|
||||
) {
|
||||
const common = from && to ? getLowestCommonAncestor(from, to) : null;
|
||||
const pathFrom = [];
|
||||
while (true) {
|
||||
if (!from) {
|
||||
break;
|
||||
}
|
||||
if (from === common) {
|
||||
break;
|
||||
}
|
||||
const alternate = from.alternate;
|
||||
if (alternate !== null && alternate === common) {
|
||||
break;
|
||||
}
|
||||
pathFrom.push(from);
|
||||
from = getParent(from);
|
||||
}
|
||||
const pathTo = [];
|
||||
while (true) {
|
||||
if (!to) {
|
||||
break;
|
||||
}
|
||||
if (to === common) {
|
||||
break;
|
||||
}
|
||||
const alternate = to.alternate;
|
||||
if (alternate !== null && alternate === common) {
|
||||
break;
|
||||
}
|
||||
pathTo.push(to);
|
||||
to = getParent(to);
|
||||
}
|
||||
for (let i = 0; i < pathFrom.length; i++) {
|
||||
fn(pathFrom[i], 'bubbled', argFrom);
|
||||
}
|
||||
for (let i = pathTo.length; i-- > 0; ) {
|
||||
fn(pathTo[i], 'captured', argTo);
|
||||
}
|
||||
}
|
||||
|
||||
function accumulateDirectionalDispatches(inst, phase, event) {
|
||||
if (__DEV__) {
|
||||
if (!inst) {
|
||||
console.error('Dispatching inst must not be null');
|
||||
}
|
||||
}
|
||||
const listener = listenerAtPhase(inst, event, phase);
|
||||
if (listener) {
|
||||
event._dispatchListeners = accumulateInto(
|
||||
event._dispatchListeners,
|
||||
listener,
|
||||
);
|
||||
event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
|
||||
}
|
||||
}
|
||||
|
||||
function accumulateTwoPhaseDispatchesSingle(event) {
|
||||
if (event && event.dispatchConfig.phasedRegistrationNames) {
|
||||
traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulates without regard to direction, does not look for phased
|
||||
* registration names. Same as `accumulateDirectDispatchesSingle` but without
|
||||
* requiring that the `dispatchMarker` be the same as the dispatched ID.
|
||||
*/
|
||||
function accumulateDispatches(
|
||||
inst: Object,
|
||||
ignoredDirection: ?boolean,
|
||||
event: Object,
|
||||
): void {
|
||||
if (inst && event && event.dispatchConfig.registrationName) {
|
||||
const registrationName = event.dispatchConfig.registrationName;
|
||||
const listener = getListener(inst, registrationName);
|
||||
if (listener) {
|
||||
event._dispatchListeners = accumulateInto(
|
||||
event._dispatchListeners,
|
||||
listener,
|
||||
);
|
||||
event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function accumulateTwoPhaseDispatches(
|
||||
events: ReactSyntheticEvent | Array<ReactSyntheticEvent>,
|
||||
): void {
|
||||
forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
|
||||
}
|
||||
|
||||
export function accumulateEnterLeaveDispatches(
|
||||
leave: ReactSyntheticEvent,
|
||||
enter: ReactSyntheticEvent,
|
||||
from: Fiber,
|
||||
to: Fiber,
|
||||
) {
|
||||
traverseEnterLeave(from, to, accumulateDispatches, leave, enter);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
} from '../FallbackCompositionState';
|
||||
import SyntheticCompositionEvent from '../SyntheticCompositionEvent';
|
||||
import SyntheticInputEvent from '../SyntheticInputEvent';
|
||||
import accumulateTwoPhaseListeners from '../accumulateTwoPhaseListeners';
|
||||
import {accumulateTwoPhaseDispatches} from '../DOMLegacyEventPluginSystem';
|
||||
|
||||
const END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
|
||||
const START_KEYCODE = 229;
|
||||
@@ -276,7 +276,7 @@ function extractCompositionEvent(
|
||||
}
|
||||
}
|
||||
|
||||
accumulateTwoPhaseListeners(event);
|
||||
accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
@@ -437,7 +437,7 @@ function extractBeforeInputEvent(
|
||||
);
|
||||
|
||||
event.data = chars;
|
||||
accumulateTwoPhaseListeners(event);
|
||||
accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,13 +27,9 @@ import {updateValueIfChanged} from '../../client/inputValueTracking';
|
||||
import {setDefaultValue} from '../../client/ReactDOMInput';
|
||||
import {enqueueStateRestore} from '../ReactDOMControlledComponent';
|
||||
|
||||
import {
|
||||
disableInputAttributeSyncing,
|
||||
enableModernEventSystem,
|
||||
} from 'shared/ReactFeatureFlags';
|
||||
import accumulateTwoPhaseListeners from '../accumulateTwoPhaseListeners';
|
||||
import {disableInputAttributeSyncing} from 'shared/ReactFeatureFlags';
|
||||
import {batchedUpdates} from '../ReactDOMUpdateBatching';
|
||||
import {dispatchEventsInBatch} from '../DOMModernPluginEventSystem';
|
||||
import {accumulateTwoPhaseDispatches} from '../DOMLegacyEventPluginSystem';
|
||||
|
||||
const eventTypes = {
|
||||
change: {
|
||||
@@ -64,7 +60,7 @@ function createAndAccumulateChangeEvent(inst, nativeEvent, target) {
|
||||
event.type = 'change';
|
||||
// Flag this event loop as needing state restore.
|
||||
enqueueStateRestore(target);
|
||||
accumulateTwoPhaseListeners(event);
|
||||
accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
}
|
||||
/**
|
||||
@@ -105,11 +101,7 @@ function manualDispatchChangeEvent(nativeEvent) {
|
||||
}
|
||||
|
||||
function runEventInBatch(event) {
|
||||
if (enableModernEventSystem) {
|
||||
dispatchEventsInBatch([event]);
|
||||
} else {
|
||||
runEventsInBatch(event);
|
||||
}
|
||||
runEventsInBatch(event);
|
||||
}
|
||||
|
||||
function getInstIfValueChanged(targetInst) {
|
||||
|
||||
@@ -23,8 +23,7 @@ import {
|
||||
} from '../../client/ReactDOMComponentTree';
|
||||
import {HostComponent, HostText} from 'react-reconciler/src/ReactWorkTags';
|
||||
import {getNearestMountedFiber} from 'react-reconciler/src/ReactFiberTreeReflection';
|
||||
import {enableModernEventSystem} from 'shared/ReactFeatureFlags';
|
||||
import accumulateEnterLeaveListeners from '../accumulateEnterLeaveListeners';
|
||||
import {accumulateEnterLeaveDispatches} from '../DOMLegacyEventPluginSystem';
|
||||
|
||||
const eventTypes = {
|
||||
mouseEnter: {
|
||||
@@ -67,26 +66,16 @@ const EnterLeaveEventPlugin = {
|
||||
const isOutEvent =
|
||||
topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_POINTER_OUT;
|
||||
|
||||
if (isOverEvent && (eventSystemFlags & IS_REPLAYED) === 0) {
|
||||
const related = nativeEvent.relatedTarget || nativeEvent.fromElement;
|
||||
if (related) {
|
||||
if (enableModernEventSystem) {
|
||||
// Due to the fact we don't add listeners to the document with the
|
||||
// modern event system and instead attach listeners to roots, we
|
||||
// need to handle the over event case. To ensure this, we just need to
|
||||
// make sure the node that we're coming from is managed by React.
|
||||
const inst = getClosestInstanceFromNode(related);
|
||||
if (inst !== null) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
// If this is an over event with a target, then we've already dispatched
|
||||
// the event in the out event of the other target. If this is replayed,
|
||||
// then it's because we couldn't dispatch against this target previously
|
||||
// so we have to do it now instead.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (
|
||||
isOverEvent &&
|
||||
(eventSystemFlags & IS_REPLAYED) === 0 &&
|
||||
(nativeEvent.relatedTarget || nativeEvent.fromElement)
|
||||
) {
|
||||
// If this is an over event with a target, then we've already dispatched
|
||||
// the event in the out event of the other target. If this is replayed,
|
||||
// then it's because we couldn't dispatch against this target previously
|
||||
// so we have to do it now instead.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isOutEvent && !isOverEvent) {
|
||||
@@ -174,15 +163,13 @@ const EnterLeaveEventPlugin = {
|
||||
enter.target = toNode;
|
||||
enter.relatedTarget = fromNode;
|
||||
|
||||
accumulateEnterLeaveListeners(leave, enter, from, to);
|
||||
accumulateEnterLeaveDispatches(leave, enter, from, to);
|
||||
|
||||
if (!enableModernEventSystem) {
|
||||
// If we are not processing the first ancestor, then we
|
||||
// should not process the same nativeEvent again, as we
|
||||
// will have already processed it in the first ancestor.
|
||||
if ((eventSystemFlags & IS_FIRST_ANCESTOR) === 0) {
|
||||
return [leave];
|
||||
}
|
||||
// If we are not processing the first ancestor, then we
|
||||
// should not process the same nativeEvent again, as we
|
||||
// will have already processed it in the first ancestor.
|
||||
if ((eventSystemFlags & IS_FIRST_ANCESTOR) === 0) {
|
||||
return [leave];
|
||||
}
|
||||
|
||||
return [leave, enter];
|
||||
|
||||
@@ -26,7 +26,7 @@ import {getNodeFromInstance} from '../../client/ReactDOMComponentTree';
|
||||
import {hasSelectionCapabilities} from '../../client/ReactInputSelection';
|
||||
import {DOCUMENT_NODE} from '../../shared/HTMLNodeType';
|
||||
import {isListeningToAllDependencies} from '../DOMEventListenerMap';
|
||||
import accumulateTwoPhaseListeners from '../accumulateTwoPhaseListeners';
|
||||
import {accumulateTwoPhaseDispatches} from '../DOMLegacyEventPluginSystem';
|
||||
|
||||
const skipSelectionChangeEvent =
|
||||
canUseDOM && 'documentMode' in document && document.documentMode <= 11;
|
||||
@@ -135,7 +135,7 @@ function constructSelectEvent(nativeEvent, nativeEventTarget) {
|
||||
syntheticEvent.type = 'select';
|
||||
syntheticEvent.target = activeElement;
|
||||
|
||||
accumulateTwoPhaseListeners(syntheticEvent);
|
||||
accumulateTwoPhaseDispatches(syntheticEvent);
|
||||
|
||||
return syntheticEvent;
|
||||
}
|
||||
@@ -166,16 +166,11 @@ const SelectEventPlugin = {
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
container,
|
||||
) {
|
||||
const containerOrDoc =
|
||||
container || getEventTargetDocument(nativeEventTarget);
|
||||
const doc = getEventTargetDocument(nativeEventTarget);
|
||||
// Track whether all listeners exists for this plugin. If none exist, we do
|
||||
// not extract events. See #3639.
|
||||
if (
|
||||
!containerOrDoc ||
|
||||
!isListeningToAllDependencies('onSelect', containerOrDoc)
|
||||
) {
|
||||
if (!doc || !isListeningToAllDependencies('onSelect', doc)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,8 @@ import type {
|
||||
import type {ReactSyntheticEvent} from 'legacy-events/ReactSyntheticEventType';
|
||||
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
|
||||
import type {PluginModule} from 'legacy-events/PluginModuleType';
|
||||
import type {EventSystemFlags} from '../EventSystemFlags';
|
||||
|
||||
import SyntheticEvent from 'legacy-events/SyntheticEvent';
|
||||
import {IS_TARGET_PHASE_ONLY} from '../EventSystemFlags';
|
||||
|
||||
import * as DOMTopLevelEventTypes from '../DOMTopLevelEventTypes';
|
||||
import {
|
||||
@@ -37,10 +35,7 @@ import SyntheticTransitionEvent from '../SyntheticTransitionEvent';
|
||||
import SyntheticUIEvent from '../SyntheticUIEvent';
|
||||
import SyntheticWheelEvent from '../SyntheticWheelEvent';
|
||||
import getEventCharCode from '../getEventCharCode';
|
||||
import accumulateTwoPhaseListeners from '../accumulateTwoPhaseListeners';
|
||||
import accumulateEventTargetListeners from '../accumulateEventTargetListeners';
|
||||
|
||||
import {enableUseEventAPI} from 'shared/ReactFeatureFlags';
|
||||
import {accumulateTwoPhaseDispatches} from '../DOMLegacyEventPluginSystem';
|
||||
|
||||
// Only used in DEV for exhaustiveness validation.
|
||||
const knownHTMLTopLevelTypes: Array<DOMTopLevelEventType> = [
|
||||
@@ -86,8 +81,6 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
|
||||
targetInst: null | Fiber,
|
||||
nativeEvent: MouseEvent,
|
||||
nativeEventTarget: null | EventTarget,
|
||||
eventSystemFlags?: EventSystemFlags,
|
||||
targetContainer?: null | EventTarget,
|
||||
): null | ReactSyntheticEvent {
|
||||
const dispatchConfig = topLevelEventsToDispatchConfig.get(topLevelType);
|
||||
if (!dispatchConfig) {
|
||||
@@ -109,8 +102,6 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_BLUR:
|
||||
case DOMTopLevelEventTypes.TOP_FOCUS:
|
||||
case DOMTopLevelEventTypes.TOP_BEFORE_BLUR:
|
||||
case DOMTopLevelEventTypes.TOP_AFTER_BLUR:
|
||||
EventConstructor = SyntheticFocusEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_CLICK:
|
||||
@@ -179,10 +170,7 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
|
||||
break;
|
||||
default:
|
||||
if (__DEV__) {
|
||||
if (
|
||||
knownHTMLTopLevelTypes.indexOf(topLevelType) === -1 &&
|
||||
dispatchConfig.customEvent !== true
|
||||
) {
|
||||
if (knownHTMLTopLevelTypes.indexOf(topLevelType) === -1) {
|
||||
console.error(
|
||||
'SimpleEventPlugin: Unhandled event type, `%s`. This warning ' +
|
||||
'is likely caused by a bug in React. Please file an issue.',
|
||||
@@ -201,23 +189,7 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
|
||||
// For TargetEvent only accumulation, we do not traverse through
|
||||
// the React tree looking for managed React DOM elements that have
|
||||
// events. Instead we only check the EventTarget Store Map to see
|
||||
// if the container has listeners for the particular phase we're
|
||||
// interested in. This is because we attach the native event listener
|
||||
// only in the given phase.
|
||||
if (
|
||||
enableUseEventAPI &&
|
||||
eventSystemFlags !== undefined &&
|
||||
eventSystemFlags & IS_TARGET_PHASE_ONLY &&
|
||||
targetContainer != null
|
||||
) {
|
||||
accumulateEventTargetListeners(event, targetContainer);
|
||||
} else {
|
||||
accumulateTwoPhaseListeners(event, true);
|
||||
}
|
||||
accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user