Make event plugin injection statically resolvable (#19234)
* Make plugins ESM * Resolve extractEvents statically * Resolve eventTypes statically * Fix flow types and inconsistent naming * Move injection into the plugin system itself * Fix Flow
This commit is contained in:
parent
67eb6ff4a8
commit
9e7f5c02ca
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
registrationNameModules,
|
||||
registrationNames,
|
||||
possibleRegistrationNames,
|
||||
} from '../events/EventPluginRegistry';
|
||||
import {canUseDOM} from 'shared/ExecutionEnvironment';
|
||||
|
@ -133,7 +133,7 @@ if (__DEV__) {
|
|||
validateARIAProperties(type, props);
|
||||
validateInputProperties(type, props);
|
||||
validateUnknownProperties(type, props, {
|
||||
registrationNameModules,
|
||||
registrationNames,
|
||||
possibleRegistrationNames,
|
||||
});
|
||||
};
|
||||
|
@ -356,7 +356,7 @@ function setInitialDOMProperties(
|
|||
// We could have excluded it in the property list instead of
|
||||
// adding a special case here, but then it wouldn't be emitted
|
||||
// on server rendering (but we *do* want to emit it in SSR).
|
||||
} else if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
} else if (registrationNames.hasOwnProperty(propKey)) {
|
||||
if (nextProp != null) {
|
||||
if (__DEV__ && typeof nextProp !== 'function') {
|
||||
warnForInvalidEventListener(propKey, nextProp);
|
||||
|
@ -694,7 +694,7 @@ export function diffProperties(
|
|||
// Noop
|
||||
} else if (propKey === AUTOFOCUS) {
|
||||
// Noop. It doesn't work on updates anyway.
|
||||
} else if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
} else if (registrationNames.hasOwnProperty(propKey)) {
|
||||
// This is a special case. If any listener updates we need to ensure
|
||||
// that the "current" fiber pointer gets updated so we need a commit
|
||||
// to update this element.
|
||||
|
@ -781,7 +781,7 @@ export function diffProperties(
|
|||
propKey === SUPPRESS_HYDRATION_WARNING
|
||||
) {
|
||||
// Noop
|
||||
} else if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
} else if (registrationNames.hasOwnProperty(propKey)) {
|
||||
if (nextProp != null) {
|
||||
// We eagerly listen to this even though we haven't committed yet.
|
||||
if (__DEV__ && typeof nextProp !== 'function') {
|
||||
|
@ -978,7 +978,7 @@ export function diffHydratedProperties(
|
|||
updatePayload = [CHILDREN, '' + nextProp];
|
||||
}
|
||||
}
|
||||
} else if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
} else if (registrationNames.hasOwnProperty(propKey)) {
|
||||
if (nextProp != null) {
|
||||
if (__DEV__ && typeof nextProp !== 'function') {
|
||||
warnForInvalidEventListener(propKey, nextProp);
|
||||
|
|
|
@ -12,6 +12,7 @@ import type {
|
|||
TopLevelType,
|
||||
DOMTopLevelEventType,
|
||||
} from '../events/TopLevelEventTypes';
|
||||
import type {EventTypes} from '../events/PluginModuleType';
|
||||
import type {
|
||||
DispatchConfig,
|
||||
CustomDispatchConfig,
|
||||
|
@ -32,7 +33,7 @@ import {enableCreateEventHandleAPI} from 'shared/ReactFeatureFlags';
|
|||
// here once. If we remove or refactor the
|
||||
// SimpleEventPlugin, we should also remove or
|
||||
// update the below line.
|
||||
export const simpleEventPluginEventTypes = {};
|
||||
export const simpleEventPluginEventTypes: EventTypes = {};
|
||||
|
||||
export const topLevelEventsToDispatchConfig: Map<
|
||||
TopLevelType,
|
||||
|
|
|
@ -7,29 +7,30 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import type {AnyNativeEvent} from '../events/PluginModuleType';
|
||||
import type {DOMTopLevelEventType} from '../events/TopLevelEventTypes';
|
||||
import type {
|
||||
ElementListenerMap,
|
||||
ElementListenerMapEntry,
|
||||
} from '../client/ReactDOMComponentTree';
|
||||
import type {TopLevelType, DOMTopLevelEventType} from './TopLevelEventTypes';
|
||||
import type {EventSystemFlags} from './EventSystemFlags';
|
||||
import type {EventPriority, ReactScopeInstance} from 'shared/ReactTypes';
|
||||
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
|
||||
import type {
|
||||
ModernPluginModule,
|
||||
AnyNativeEvent,
|
||||
DispatchQueue,
|
||||
DispatchQueueItem,
|
||||
DispatchQueueItemPhase,
|
||||
DispatchQueueItemPhaseEntry,
|
||||
} from '../events/PluginModuleType';
|
||||
} from './PluginModuleType';
|
||||
import type {
|
||||
ReactSyntheticEvent,
|
||||
CustomDispatchConfig,
|
||||
} from '../events/ReactSyntheticEventType';
|
||||
} from './ReactSyntheticEventType';
|
||||
import type {
|
||||
ElementListenerMap,
|
||||
ElementListenerMapEntry,
|
||||
} from '../client/ReactDOMComponentTree';
|
||||
import type {EventPriority, ReactScopeInstance} from 'shared/ReactTypes';
|
||||
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
|
||||
|
||||
import {registrationNameDependencies} from '../events/EventPluginRegistry';
|
||||
import {plugins} from '../events/EventPluginRegistry';
|
||||
import {
|
||||
injectEventPlugin,
|
||||
registrationNameDependencies,
|
||||
} from './EventPluginRegistry';
|
||||
import {
|
||||
PLUGIN_EVENT_SYSTEM,
|
||||
LEGACY_FB_SUPPORT,
|
||||
|
@ -113,6 +114,74 @@ import {
|
|||
} from './EventListener';
|
||||
import {removeTrappedEventListener} from './DeprecatedDOMEventResponderSystem';
|
||||
import {topLevelEventsToDispatchConfig} from './DOMEventProperties';
|
||||
import * as ModernBeforeInputEventPlugin from './plugins/ModernBeforeInputEventPlugin';
|
||||
import * as ModernChangeEventPlugin from './plugins/ModernChangeEventPlugin';
|
||||
import * as ModernEnterLeaveEventPlugin from './plugins/ModernEnterLeaveEventPlugin';
|
||||
import * as ModernSelectEventPlugin from './plugins/ModernSelectEventPlugin';
|
||||
import * as ModernSimpleEventPlugin from './plugins/ModernSimpleEventPlugin';
|
||||
|
||||
// TODO: remove top-level side effect.
|
||||
injectEventPlugin(ModernSimpleEventPlugin.eventTypes);
|
||||
injectEventPlugin(ModernEnterLeaveEventPlugin.eventTypes);
|
||||
injectEventPlugin(ModernChangeEventPlugin.eventTypes);
|
||||
injectEventPlugin(ModernSelectEventPlugin.eventTypes);
|
||||
injectEventPlugin(ModernBeforeInputEventPlugin.eventTypes);
|
||||
|
||||
function extractEvents(
|
||||
dispatchQueue: DispatchQueue,
|
||||
topLevelType: TopLevelType,
|
||||
targetInst: null | Fiber,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
nativeEventTarget: null | EventTarget,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
targetContainer: null | EventTarget,
|
||||
) {
|
||||
ModernSimpleEventPlugin.extractEvents(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
);
|
||||
ModernEnterLeaveEventPlugin.extractEvents(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
);
|
||||
ModernChangeEventPlugin.extractEvents(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
);
|
||||
ModernSelectEventPlugin.extractEvents(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
);
|
||||
ModernBeforeInputEventPlugin.extractEvents(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
);
|
||||
}
|
||||
|
||||
export const capturePhaseEvents: Set<DOMTopLevelEventType> = new Set([
|
||||
TOP_FOCUS,
|
||||
|
@ -218,22 +287,17 @@ function dispatchEventsForPlugins(
|
|||
targetInst: null | Fiber,
|
||||
targetContainer: EventTarget,
|
||||
): void {
|
||||
const modernPlugins = ((plugins: any): Array<ModernPluginModule<Event>>);
|
||||
const nativeEventTarget = getEventTarget(nativeEvent);
|
||||
const dispatchQueue: DispatchQueue = [];
|
||||
|
||||
for (let i = 0; i < modernPlugins.length; i++) {
|
||||
const plugin = modernPlugins[i];
|
||||
plugin.extractEvents(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
);
|
||||
}
|
||||
extractEvents(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
);
|
||||
dispatchEventsInBatch(dispatchQueue);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,110 +7,11 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import type {DispatchConfig} from './ReactSyntheticEventType';
|
||||
import type {
|
||||
AnyNativeEvent,
|
||||
LegacyPluginModule,
|
||||
ModernPluginModule,
|
||||
} from './PluginModuleType';
|
||||
import ModernBeforeInputEventPlugin from '../events/plugins/ModernBeforeInputEventPlugin';
|
||||
import ModernChangeEventPlugin from '../events/plugins/ModernChangeEventPlugin';
|
||||
import ModernEnterLeaveEventPlugin from '../events/plugins/ModernEnterLeaveEventPlugin';
|
||||
import ModernSelectEventPlugin from '../events/plugins/ModernSelectEventPlugin';
|
||||
import ModernSimpleEventPlugin from '../events/plugins/ModernSimpleEventPlugin';
|
||||
import type {TopLevelType} from './TopLevelEventTypes';
|
||||
import type {EventTypes} from './PluginModuleType';
|
||||
|
||||
import invariant from 'shared/invariant';
|
||||
|
||||
/**
|
||||
* Publishes an event so that it can be dispatched by the supplied plugin.
|
||||
*
|
||||
* @param {object} dispatchConfig Dispatch configuration for the event.
|
||||
* @param {object} PluginModule Plugin publishing the event.
|
||||
* @return {boolean} True if the event was successfully published.
|
||||
* @private
|
||||
*/
|
||||
function publishEventForPlugin(
|
||||
dispatchConfig: DispatchConfig,
|
||||
pluginModule:
|
||||
| LegacyPluginModule<AnyNativeEvent>
|
||||
| ModernPluginModule<AnyNativeEvent>,
|
||||
eventName: string,
|
||||
): boolean {
|
||||
invariant(
|
||||
!eventNameDispatchConfigs.hasOwnProperty(eventName),
|
||||
'EventPluginRegistry: More than one plugin attempted to publish the same ' +
|
||||
'event name, `%s`.',
|
||||
eventName,
|
||||
);
|
||||
eventNameDispatchConfigs[eventName] = dispatchConfig;
|
||||
|
||||
const phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
|
||||
if (phasedRegistrationNames) {
|
||||
for (const phaseName in phasedRegistrationNames) {
|
||||
if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
|
||||
const phasedRegistrationName = phasedRegistrationNames[phaseName];
|
||||
publishRegistrationName(
|
||||
phasedRegistrationName,
|
||||
pluginModule,
|
||||
eventName,
|
||||
);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (dispatchConfig.registrationName) {
|
||||
publishRegistrationName(
|
||||
dispatchConfig.registrationName,
|
||||
pluginModule,
|
||||
eventName,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes a registration name that is used to identify dispatched events.
|
||||
*
|
||||
* @param {string} registrationName Registration name to add.
|
||||
* @param {object} PluginModule Plugin publishing the event.
|
||||
* @private
|
||||
*/
|
||||
function publishRegistrationName(
|
||||
registrationName: string,
|
||||
pluginModule:
|
||||
| LegacyPluginModule<AnyNativeEvent>
|
||||
| ModernPluginModule<AnyNativeEvent>,
|
||||
eventName: string,
|
||||
): void {
|
||||
invariant(
|
||||
!registrationNameModules[registrationName],
|
||||
'EventPluginRegistry: More than one plugin attempted to publish the same ' +
|
||||
'registration name, `%s`.',
|
||||
registrationName,
|
||||
);
|
||||
registrationNameModules[registrationName] = pluginModule;
|
||||
registrationNameDependencies[registrationName] =
|
||||
pluginModule.eventTypes[eventName].dependencies;
|
||||
|
||||
if (__DEV__) {
|
||||
const lowerCasedName = registrationName.toLowerCase();
|
||||
possibleRegistrationNames[lowerCasedName] = registrationName;
|
||||
|
||||
if (registrationName === 'onDoubleClick') {
|
||||
possibleRegistrationNames.ondblclick = registrationName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers plugins so that they can extract and dispatch events.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Ordered list of injected plugins.
|
||||
*/
|
||||
export const plugins = [];
|
||||
|
||||
/**
|
||||
* Mapping from event name to dispatch config
|
||||
*/
|
||||
|
@ -119,7 +20,7 @@ export const eventNameDispatchConfigs = {};
|
|||
/**
|
||||
* Mapping from registration name to plugin module
|
||||
*/
|
||||
export const registrationNameModules = {};
|
||||
export const registrationNames = {};
|
||||
|
||||
/**
|
||||
* Mapping from registration name to event name
|
||||
|
@ -135,17 +36,66 @@ export const registrationNameDependencies = {};
|
|||
export const possibleRegistrationNames = __DEV__ ? {} : (null: any);
|
||||
// Trust the developer to only use possibleRegistrationNames in __DEV__
|
||||
|
||||
function injectEventPlugin(pluginModule: ModernPluginModule<any>): void {
|
||||
plugins.push(pluginModule);
|
||||
const publishedEvents = pluginModule.eventTypes;
|
||||
for (const eventName in publishedEvents) {
|
||||
publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName);
|
||||
function publishEventForPlugin(
|
||||
eventTypes: EventTypes,
|
||||
eventName: string,
|
||||
): boolean {
|
||||
invariant(
|
||||
!eventNameDispatchConfigs.hasOwnProperty(eventName),
|
||||
'EventPluginRegistry: More than one plugin attempted to publish the same ' +
|
||||
'event name, `%s`.',
|
||||
eventName,
|
||||
);
|
||||
const dispatchConfig = eventTypes[eventName];
|
||||
eventNameDispatchConfigs[eventName] = dispatchConfig;
|
||||
|
||||
const phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
|
||||
if (phasedRegistrationNames) {
|
||||
for (const phaseName in phasedRegistrationNames) {
|
||||
if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
|
||||
const phasedRegistrationName = phasedRegistrationNames[phaseName];
|
||||
publishRegistrationName(
|
||||
phasedRegistrationName,
|
||||
eventTypes[eventName].dependencies,
|
||||
);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (dispatchConfig.registrationName) {
|
||||
publishRegistrationName(
|
||||
dispatchConfig.registrationName,
|
||||
eventTypes[eventName].dependencies,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function publishRegistrationName(
|
||||
registrationName: string,
|
||||
dependencies: ?Array<TopLevelType>,
|
||||
): void {
|
||||
invariant(
|
||||
!registrationNames[registrationName],
|
||||
'EventPluginRegistry: More than one plugin attempted to publish the same ' +
|
||||
'registration name, `%s`.',
|
||||
registrationName,
|
||||
);
|
||||
registrationNames[registrationName] = true;
|
||||
registrationNameDependencies[registrationName] = dependencies;
|
||||
|
||||
if (__DEV__) {
|
||||
const lowerCasedName = registrationName.toLowerCase();
|
||||
possibleRegistrationNames[lowerCasedName] = registrationName;
|
||||
|
||||
if (registrationName === 'onDoubleClick') {
|
||||
possibleRegistrationNames.ondblclick = registrationName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove top-level side effect.
|
||||
injectEventPlugin(ModernSimpleEventPlugin);
|
||||
injectEventPlugin(ModernEnterLeaveEventPlugin);
|
||||
injectEventPlugin(ModernChangeEventPlugin);
|
||||
injectEventPlugin(ModernSelectEventPlugin);
|
||||
injectEventPlugin(ModernBeforeInputEventPlugin);
|
||||
export function injectEventPlugin(eventTypes: EventTypes): void {
|
||||
for (const eventName in eventTypes) {
|
||||
publishEventForPlugin(eventTypes, eventName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import type {
|
|||
DispatchConfig,
|
||||
ReactSyntheticEvent,
|
||||
} from './ReactSyntheticEventType';
|
||||
import type {TopLevelType} from './TopLevelEventTypes';
|
||||
|
||||
export type EventTypes = {[key: string]: DispatchConfig, ...};
|
||||
|
||||
|
@ -22,19 +21,6 @@ export type PluginName = string;
|
|||
|
||||
export type EventSystemFlags = number;
|
||||
|
||||
export type LegacyPluginModule<NativeEvent> = {
|
||||
eventTypes: EventTypes,
|
||||
extractEvents: (
|
||||
topLevelType: TopLevelType,
|
||||
targetInst: null | Fiber,
|
||||
nativeTarget: NativeEvent,
|
||||
nativeEventTarget: null | EventTarget,
|
||||
eventSystemFlags?: number,
|
||||
container?: null | EventTarget,
|
||||
) => ?ReactSyntheticEvent,
|
||||
tapMoveThreshold?: number,
|
||||
};
|
||||
|
||||
export type DispatchQueueItemPhaseEntry = {|
|
||||
instance: null | Fiber,
|
||||
listener: Function,
|
||||
|
@ -50,16 +36,3 @@ export type DispatchQueueItem = {|
|
|||
|};
|
||||
|
||||
export type DispatchQueue = Array<DispatchQueueItem>;
|
||||
|
||||
export type ModernPluginModule<NativeEvent> = {
|
||||
eventTypes: EventTypes,
|
||||
extractEvents: (
|
||||
dispatchQueue: DispatchQueue,
|
||||
topLevelType: TopLevelType,
|
||||
targetInst: null | Fiber,
|
||||
nativeTarget: NativeEvent,
|
||||
nativeEventTarget: null | EventTarget,
|
||||
eventSystemFlags: number,
|
||||
container: null | EventTarget,
|
||||
) => void,
|
||||
};
|
||||
|
|
|
@ -58,7 +58,7 @@ const SPACEBAR_CODE = 32;
|
|||
const SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);
|
||||
|
||||
// Events and their corresponding property names.
|
||||
const eventTypes = {
|
||||
const eventTypes: EventTypes = {
|
||||
beforeInput: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: 'onBeforeInput',
|
||||
|
@ -457,33 +457,29 @@ function extractBeforeInputEvent(
|
|||
* allowing us to share composition fallback code for both `beforeInput` and
|
||||
* `composition` event types.
|
||||
*/
|
||||
const BeforeInputEventPlugin = {
|
||||
eventTypes: eventTypes,
|
||||
|
||||
extractEvents: function(
|
||||
function extractEvents(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
) {
|
||||
extractCompositionEvent(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
container,
|
||||
) {
|
||||
extractCompositionEvent(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
extractBeforeInputEvent(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
},
|
||||
};
|
||||
);
|
||||
extractBeforeInputEvent(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
}
|
||||
|
||||
export default BeforeInputEventPlugin;
|
||||
export {eventTypes, extractEvents};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type {AnyNativeEvent, EventTypes} from '../PluginModuleType';
|
||||
import type {TopLevelType} from '../TopLevelEventTypes';
|
||||
import type {DispatchQueue} from '../PluginModuleType';
|
||||
import type {EventSystemFlags} from '../EventSystemFlags';
|
||||
|
@ -39,7 +39,7 @@ import {
|
|||
accumulateTwoPhaseListeners,
|
||||
} from '../DOMModernPluginEventSystem';
|
||||
|
||||
const eventTypes = {
|
||||
const eventTypes: EventTypes = {
|
||||
change: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: 'onChange',
|
||||
|
@ -271,58 +271,52 @@ function handleControlledInputBlur(node: HTMLInputElement) {
|
|||
* - textarea
|
||||
* - select
|
||||
*/
|
||||
const ChangeEventPlugin = {
|
||||
eventTypes: eventTypes,
|
||||
function extractEvents(
|
||||
dispatchQueue: DispatchQueue,
|
||||
topLevelType: TopLevelType,
|
||||
targetInst: null | Fiber,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
nativeEventTarget: null | EventTarget,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
targetContainer: null | EventTarget,
|
||||
) {
|
||||
const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
|
||||
|
||||
_isInputEventSupported: isInputEventSupported,
|
||||
|
||||
extractEvents: function(
|
||||
dispatchQueue: DispatchQueue,
|
||||
topLevelType: TopLevelType,
|
||||
targetInst: null | Fiber,
|
||||
nativeEvent: MouseEvent,
|
||||
nativeEventTarget: null | EventTarget,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
targetContainer: null | EventTarget,
|
||||
) {
|
||||
const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
|
||||
|
||||
let getTargetInstFunc, handleEventFunc;
|
||||
if (shouldUseChangeEvent(targetNode)) {
|
||||
getTargetInstFunc = getTargetInstForChangeEvent;
|
||||
} else if (isTextInputElement(((targetNode: any): HTMLElement))) {
|
||||
if (isInputEventSupported) {
|
||||
getTargetInstFunc = getTargetInstForInputOrChangeEvent;
|
||||
} else {
|
||||
getTargetInstFunc = getTargetInstForInputEventPolyfill;
|
||||
handleEventFunc = handleEventsForInputEventPolyfill;
|
||||
}
|
||||
} else if (shouldUseClickEvent(targetNode)) {
|
||||
getTargetInstFunc = getTargetInstForClickEvent;
|
||||
let getTargetInstFunc, handleEventFunc;
|
||||
if (shouldUseChangeEvent(targetNode)) {
|
||||
getTargetInstFunc = getTargetInstForChangeEvent;
|
||||
} else if (isTextInputElement(((targetNode: any): HTMLElement))) {
|
||||
if (isInputEventSupported) {
|
||||
getTargetInstFunc = getTargetInstForInputOrChangeEvent;
|
||||
} else {
|
||||
getTargetInstFunc = getTargetInstForInputEventPolyfill;
|
||||
handleEventFunc = handleEventsForInputEventPolyfill;
|
||||
}
|
||||
} else if (shouldUseClickEvent(targetNode)) {
|
||||
getTargetInstFunc = getTargetInstForClickEvent;
|
||||
}
|
||||
|
||||
if (getTargetInstFunc) {
|
||||
const inst = getTargetInstFunc(topLevelType, targetInst);
|
||||
if (inst) {
|
||||
createAndAccumulateChangeEvent(
|
||||
dispatchQueue,
|
||||
inst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (getTargetInstFunc) {
|
||||
const inst = getTargetInstFunc(topLevelType, targetInst);
|
||||
if (inst) {
|
||||
createAndAccumulateChangeEvent(
|
||||
dispatchQueue,
|
||||
inst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (handleEventFunc) {
|
||||
handleEventFunc(topLevelType, targetNode, targetInst);
|
||||
}
|
||||
if (handleEventFunc) {
|
||||
handleEventFunc(topLevelType, targetNode, targetInst);
|
||||
}
|
||||
|
||||
// When blurring, set the value attribute for number inputs
|
||||
if (topLevelType === TOP_BLUR) {
|
||||
handleControlledInputBlur(((targetNode: any): HTMLInputElement));
|
||||
}
|
||||
},
|
||||
};
|
||||
// When blurring, set the value attribute for number inputs
|
||||
if (topLevelType === TOP_BLUR) {
|
||||
handleControlledInputBlur(((targetNode: any): HTMLInputElement));
|
||||
}
|
||||
}
|
||||
|
||||
export default ChangeEventPlugin;
|
||||
export {eventTypes, extractEvents};
|
||||
|
|
|
@ -23,7 +23,7 @@ import {accumulateEnterLeaveListeners} from '../DOMModernPluginEventSystem';
|
|||
import {HostComponent, HostText} from 'react-reconciler/src/ReactWorkTags';
|
||||
import {getNearestMountedFiber} from 'react-reconciler/src/ReactFiberTreeReflection';
|
||||
|
||||
const eventTypes = {
|
||||
const eventTypes: EventTypes = {
|
||||
mouseEnter: {
|
||||
registrationName: 'onMouseEnter',
|
||||
dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER],
|
||||
|
@ -42,139 +42,135 @@ const eventTypes = {
|
|||
},
|
||||
};
|
||||
|
||||
const EnterLeaveEventPlugin = {
|
||||
eventTypes: eventTypes,
|
||||
/**
|
||||
* For almost every interaction we care about, there will be both a top-level
|
||||
* `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
|
||||
* we do not extract duplicate events. However, moving the mouse into the
|
||||
* browser from outside will not fire a `mouseout` event. In this case, we use
|
||||
* the `mouseover` top-level event.
|
||||
*/
|
||||
function extractEvents(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
) {
|
||||
const isOverEvent =
|
||||
topLevelType === TOP_MOUSE_OVER || topLevelType === TOP_POINTER_OVER;
|
||||
const isOutEvent =
|
||||
topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_POINTER_OUT;
|
||||
|
||||
/**
|
||||
* For almost every interaction we care about, there will be both a top-level
|
||||
* `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
|
||||
* we do not extract duplicate events. However, moving the mouse into the
|
||||
* browser from outside will not fire a `mouseout` event. In this case, we use
|
||||
* the `mouseover` top-level event.
|
||||
*/
|
||||
extractEvents: function(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
if (isOverEvent && (eventSystemFlags & IS_REPLAYED) === 0) {
|
||||
const related = nativeEvent.relatedTarget || nativeEvent.fromElement;
|
||||
if (related) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isOutEvent && !isOverEvent) {
|
||||
// Must not be a mouse or pointer in or out - ignoring.
|
||||
return;
|
||||
}
|
||||
|
||||
let win;
|
||||
if (nativeEventTarget.window === nativeEventTarget) {
|
||||
// `nativeEventTarget` is probably a window object.
|
||||
win = nativeEventTarget;
|
||||
} else {
|
||||
// TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
|
||||
const doc = nativeEventTarget.ownerDocument;
|
||||
if (doc) {
|
||||
win = doc.defaultView || doc.parentWindow;
|
||||
} else {
|
||||
win = window;
|
||||
}
|
||||
}
|
||||
|
||||
let from;
|
||||
let to;
|
||||
if (isOutEvent) {
|
||||
const related = nativeEvent.relatedTarget || nativeEvent.toElement;
|
||||
from = targetInst;
|
||||
to = related ? getClosestInstanceFromNode(related) : null;
|
||||
if (to !== null) {
|
||||
const nearestMounted = getNearestMountedFiber(to);
|
||||
if (
|
||||
to !== nearestMounted ||
|
||||
(to.tag !== HostComponent && to.tag !== HostText)
|
||||
) {
|
||||
to = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Moving to a node from outside the window.
|
||||
from = null;
|
||||
to = targetInst;
|
||||
}
|
||||
|
||||
if (from === to) {
|
||||
// Nothing pertains to our managed components.
|
||||
return;
|
||||
}
|
||||
|
||||
let eventInterface, leaveEventType, enterEventType, eventTypePrefix;
|
||||
|
||||
if (topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_MOUSE_OVER) {
|
||||
eventInterface = SyntheticMouseEvent;
|
||||
leaveEventType = eventTypes.mouseLeave;
|
||||
enterEventType = eventTypes.mouseEnter;
|
||||
eventTypePrefix = 'mouse';
|
||||
} else if (
|
||||
topLevelType === TOP_POINTER_OUT ||
|
||||
topLevelType === TOP_POINTER_OVER
|
||||
) {
|
||||
eventInterface = SyntheticPointerEvent;
|
||||
leaveEventType = eventTypes.pointerLeave;
|
||||
enterEventType = eventTypes.pointerEnter;
|
||||
eventTypePrefix = 'pointer';
|
||||
}
|
||||
|
||||
const fromNode = from == null ? win : getNodeFromInstance(from);
|
||||
const toNode = to == null ? win : getNodeFromInstance(to);
|
||||
|
||||
const leave = new eventInterface(
|
||||
leaveEventType,
|
||||
from,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
container,
|
||||
) {
|
||||
const isOverEvent =
|
||||
topLevelType === TOP_MOUSE_OVER || topLevelType === TOP_POINTER_OVER;
|
||||
const isOutEvent =
|
||||
topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_POINTER_OUT;
|
||||
);
|
||||
leave.type = eventTypePrefix + 'leave';
|
||||
leave.target = fromNode;
|
||||
leave.relatedTarget = toNode;
|
||||
|
||||
if (isOverEvent && (eventSystemFlags & IS_REPLAYED) === 0) {
|
||||
const related = nativeEvent.relatedTarget || nativeEvent.fromElement;
|
||||
if (related) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
let enter = new eventInterface(
|
||||
enterEventType,
|
||||
to,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
enter.type = eventTypePrefix + 'enter';
|
||||
enter.target = toNode;
|
||||
enter.relatedTarget = fromNode;
|
||||
|
||||
if (!isOutEvent && !isOverEvent) {
|
||||
// Must not be a mouse or pointer in or out - ignoring.
|
||||
return;
|
||||
}
|
||||
// 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.
|
||||
const nativeTargetInst = getClosestInstanceFromNode(nativeEventTarget);
|
||||
if (nativeTargetInst !== targetInst) {
|
||||
enter = null;
|
||||
}
|
||||
|
||||
let win;
|
||||
if (nativeEventTarget.window === nativeEventTarget) {
|
||||
// `nativeEventTarget` is probably a window object.
|
||||
win = nativeEventTarget;
|
||||
} else {
|
||||
// TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
|
||||
const doc = nativeEventTarget.ownerDocument;
|
||||
if (doc) {
|
||||
win = doc.defaultView || doc.parentWindow;
|
||||
} else {
|
||||
win = window;
|
||||
}
|
||||
}
|
||||
accumulateEnterLeaveListeners(dispatchQueue, leave, enter, from, to);
|
||||
}
|
||||
|
||||
let from;
|
||||
let to;
|
||||
if (isOutEvent) {
|
||||
const related = nativeEvent.relatedTarget || nativeEvent.toElement;
|
||||
from = targetInst;
|
||||
to = related ? getClosestInstanceFromNode(related) : null;
|
||||
if (to !== null) {
|
||||
const nearestMounted = getNearestMountedFiber(to);
|
||||
if (
|
||||
to !== nearestMounted ||
|
||||
(to.tag !== HostComponent && to.tag !== HostText)
|
||||
) {
|
||||
to = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Moving to a node from outside the window.
|
||||
from = null;
|
||||
to = targetInst;
|
||||
}
|
||||
|
||||
if (from === to) {
|
||||
// Nothing pertains to our managed components.
|
||||
return;
|
||||
}
|
||||
|
||||
let eventInterface, leaveEventType, enterEventType, eventTypePrefix;
|
||||
|
||||
if (topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_MOUSE_OVER) {
|
||||
eventInterface = SyntheticMouseEvent;
|
||||
leaveEventType = eventTypes.mouseLeave;
|
||||
enterEventType = eventTypes.mouseEnter;
|
||||
eventTypePrefix = 'mouse';
|
||||
} else if (
|
||||
topLevelType === TOP_POINTER_OUT ||
|
||||
topLevelType === TOP_POINTER_OVER
|
||||
) {
|
||||
eventInterface = SyntheticPointerEvent;
|
||||
leaveEventType = eventTypes.pointerLeave;
|
||||
enterEventType = eventTypes.pointerEnter;
|
||||
eventTypePrefix = 'pointer';
|
||||
}
|
||||
|
||||
const fromNode = from == null ? win : getNodeFromInstance(from);
|
||||
const toNode = to == null ? win : getNodeFromInstance(to);
|
||||
|
||||
const leave = new eventInterface(
|
||||
leaveEventType,
|
||||
from,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
leave.type = eventTypePrefix + 'leave';
|
||||
leave.target = fromNode;
|
||||
leave.relatedTarget = toNode;
|
||||
|
||||
let enter = new eventInterface(
|
||||
enterEventType,
|
||||
to,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
enter.type = eventTypePrefix + 'enter';
|
||||
enter.target = toNode;
|
||||
enter.relatedTarget = fromNode;
|
||||
|
||||
// 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.
|
||||
const nativeTargetInst = getClosestInstanceFromNode(nativeEventTarget);
|
||||
if (nativeTargetInst !== targetInst) {
|
||||
enter = null;
|
||||
}
|
||||
|
||||
accumulateEnterLeaveListeners(dispatchQueue, leave, enter, from, to);
|
||||
},
|
||||
};
|
||||
|
||||
export default EnterLeaveEventPlugin;
|
||||
export {eventTypes, extractEvents};
|
||||
|
|
|
@ -48,7 +48,7 @@ const rootTargetDependencies = [
|
|||
TOP_MOUSE_UP,
|
||||
];
|
||||
|
||||
const eventTypes = {
|
||||
const eventTypes: EventTypes = {
|
||||
select: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: 'onSelect',
|
||||
|
@ -176,6 +176,84 @@ function isListeningToEvent(
|
|||
return listenerMap.has(listenerMapKey);
|
||||
}
|
||||
|
||||
function extractEvents(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
) {
|
||||
const doc = getEventTargetDocument(nativeEventTarget);
|
||||
// Track whether all listeners exists for this plugin. If none exist, we do
|
||||
// not extract events. See #3639.
|
||||
if (
|
||||
// We only listen to TOP_SELECTION_CHANGE on the document, never the
|
||||
// root.
|
||||
!isListeningToEvent(TOP_SELECTION_CHANGE, doc) ||
|
||||
// If we are handling TOP_SELECTION_CHANGE, then we don't need to
|
||||
// check for the other dependencies, as TOP_SELECTION_CHANGE is only
|
||||
// event attached from the onChange plugin and we don't expose an
|
||||
// onSelectionChange event from React.
|
||||
(topLevelType !== TOP_SELECTION_CHANGE &&
|
||||
!isListeningToEvents(rootTargetDependencies, targetContainer))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
|
||||
|
||||
switch (topLevelType) {
|
||||
// Track the input node that has focus.
|
||||
case TOP_FOCUS:
|
||||
if (
|
||||
isTextInputElement(targetNode) ||
|
||||
targetNode.contentEditable === 'true'
|
||||
) {
|
||||
activeElement = targetNode;
|
||||
activeElementInst = targetInst;
|
||||
lastSelection = null;
|
||||
}
|
||||
break;
|
||||
case TOP_BLUR:
|
||||
activeElement = null;
|
||||
activeElementInst = null;
|
||||
lastSelection = null;
|
||||
break;
|
||||
// Don't fire the event while the user is dragging. This matches the
|
||||
// semantics of the native select event.
|
||||
case TOP_MOUSE_DOWN:
|
||||
mouseDown = true;
|
||||
break;
|
||||
case TOP_CONTEXT_MENU:
|
||||
case TOP_MOUSE_UP:
|
||||
case TOP_DRAG_END:
|
||||
mouseDown = false;
|
||||
constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget);
|
||||
break;
|
||||
// Chrome and IE fire non-standard event when selection is changed (and
|
||||
// sometimes when it hasn't). IE's event fires out of order with respect
|
||||
// to key and input events on deletion, so we discard it.
|
||||
//
|
||||
// Firefox doesn't support selectionchange, so check selection status
|
||||
// after each key entry. The selection changes after keydown and before
|
||||
// keyup, but we check on keydown as well in the case of holding down a
|
||||
// key, when multiple keydown events are fired but only one keyup is.
|
||||
// This is also our approach for IE handling, for the reason above.
|
||||
case TOP_SELECTION_CHANGE:
|
||||
if (skipSelectionChangeEvent) {
|
||||
break;
|
||||
}
|
||||
// falls through
|
||||
case TOP_KEY_DOWN:
|
||||
case TOP_KEY_UP:
|
||||
constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* This plugin creates an `onSelect` event that normalizes select events
|
||||
* across form elements.
|
||||
|
@ -190,86 +268,4 @@ function isListeningToEvent(
|
|||
* - Fires for collapsed selection.
|
||||
* - Fires after user input.
|
||||
*/
|
||||
const SelectEventPlugin = {
|
||||
eventTypes: eventTypes,
|
||||
|
||||
extractEvents: function(
|
||||
dispatchQueue,
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventSystemFlags,
|
||||
container,
|
||||
) {
|
||||
const doc = getEventTargetDocument(nativeEventTarget);
|
||||
// Track whether all listeners exists for this plugin. If none exist, we do
|
||||
// not extract events. See #3639.
|
||||
if (
|
||||
// We only listen to TOP_SELECTION_CHANGE on the document, never the
|
||||
// root.
|
||||
!isListeningToEvent(TOP_SELECTION_CHANGE, doc) ||
|
||||
// If we are handling TOP_SELECTION_CHANGE, then we don't need to
|
||||
// check for the other dependencies, as TOP_SELECTION_CHANGE is only
|
||||
// event attached from the onChange plugin and we don't expose an
|
||||
// onSelectionChange event from React.
|
||||
(topLevelType !== TOP_SELECTION_CHANGE &&
|
||||
!isListeningToEvents(rootTargetDependencies, container))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
|
||||
|
||||
switch (topLevelType) {
|
||||
// Track the input node that has focus.
|
||||
case TOP_FOCUS:
|
||||
if (
|
||||
isTextInputElement(targetNode) ||
|
||||
targetNode.contentEditable === 'true'
|
||||
) {
|
||||
activeElement = targetNode;
|
||||
activeElementInst = targetInst;
|
||||
lastSelection = null;
|
||||
}
|
||||
break;
|
||||
case TOP_BLUR:
|
||||
activeElement = null;
|
||||
activeElementInst = null;
|
||||
lastSelection = null;
|
||||
break;
|
||||
// Don't fire the event while the user is dragging. This matches the
|
||||
// semantics of the native select event.
|
||||
case TOP_MOUSE_DOWN:
|
||||
mouseDown = true;
|
||||
break;
|
||||
case TOP_CONTEXT_MENU:
|
||||
case TOP_MOUSE_UP:
|
||||
case TOP_DRAG_END:
|
||||
mouseDown = false;
|
||||
constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget);
|
||||
break;
|
||||
// Chrome and IE fire non-standard event when selection is changed (and
|
||||
// sometimes when it hasn't). IE's event fires out of order with respect
|
||||
// to key and input events on deletion, so we discard it.
|
||||
//
|
||||
// Firefox doesn't support selectionchange, so check selection status
|
||||
// after each key entry. The selection changes after keydown and before
|
||||
// keyup, but we check on keydown as well in the case of holding down a
|
||||
// key, when multiple keydown events are fired but only one keyup is.
|
||||
// This is also our approach for IE handling, for the reason above.
|
||||
case TOP_SELECTION_CHANGE:
|
||||
if (skipSelectionChangeEvent) {
|
||||
break;
|
||||
}
|
||||
// falls through
|
||||
case TOP_KEY_DOWN:
|
||||
case TOP_KEY_UP:
|
||||
constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
export default SelectEventPlugin;
|
||||
export {eventTypes, extractEvents};
|
||||
|
|
|
@ -13,7 +13,7 @@ import type {
|
|||
} from '../../events/TopLevelEventTypes';
|
||||
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
|
||||
import type {
|
||||
ModernPluginModule,
|
||||
AnyNativeEvent,
|
||||
DispatchQueue,
|
||||
} from '../../events/PluginModuleType';
|
||||
import type {EventSystemFlags} from '../EventSystemFlags';
|
||||
|
@ -81,144 +81,144 @@ const knownHTMLTopLevelTypes: Array<DOMTopLevelEventType> = [
|
|||
DOMTopLevelEventTypes.TOP_WAITING,
|
||||
];
|
||||
|
||||
const SimpleEventPlugin: ModernPluginModule<MouseEvent> = {
|
||||
function extractEvents(
|
||||
dispatchQueue: DispatchQueue,
|
||||
topLevelType: TopLevelType,
|
||||
targetInst: null | Fiber,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
nativeEventTarget: null | EventTarget,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
targetContainer: null | EventTarget,
|
||||
): void {
|
||||
const dispatchConfig = topLevelEventsToDispatchConfig.get(topLevelType);
|
||||
if (!dispatchConfig) {
|
||||
return;
|
||||
}
|
||||
let EventConstructor;
|
||||
switch (topLevelType) {
|
||||
case DOMTopLevelEventTypes.TOP_KEY_PRESS:
|
||||
// Firefox creates a keypress event for function keys too. This removes
|
||||
// the unwanted keypress events. Enter is however both printable and
|
||||
// non-printable. One would expect Tab to be as well (but it isn't).
|
||||
if (getEventCharCode(nativeEvent) === 0) {
|
||||
return;
|
||||
}
|
||||
/* falls through */
|
||||
case DOMTopLevelEventTypes.TOP_KEY_DOWN:
|
||||
case DOMTopLevelEventTypes.TOP_KEY_UP:
|
||||
EventConstructor = SyntheticKeyboardEvent;
|
||||
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:
|
||||
// Firefox creates a click event on right mouse clicks. This removes the
|
||||
// unwanted click events.
|
||||
if (nativeEvent.button === 2) {
|
||||
return;
|
||||
}
|
||||
/* falls through */
|
||||
case DOMTopLevelEventTypes.TOP_AUX_CLICK:
|
||||
case DOMTopLevelEventTypes.TOP_DOUBLE_CLICK:
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_DOWN:
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_MOVE:
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_UP:
|
||||
// TODO: Disabled elements should not respond to mouse events
|
||||
/* falls through */
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_OUT:
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_OVER:
|
||||
case DOMTopLevelEventTypes.TOP_CONTEXT_MENU:
|
||||
EventConstructor = SyntheticMouseEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_DRAG:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_END:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_ENTER:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_EXIT:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_LEAVE:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_OVER:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_START:
|
||||
case DOMTopLevelEventTypes.TOP_DROP:
|
||||
EventConstructor = SyntheticDragEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_TOUCH_CANCEL:
|
||||
case DOMTopLevelEventTypes.TOP_TOUCH_END:
|
||||
case DOMTopLevelEventTypes.TOP_TOUCH_MOVE:
|
||||
case DOMTopLevelEventTypes.TOP_TOUCH_START:
|
||||
EventConstructor = SyntheticTouchEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_ANIMATION_END:
|
||||
case DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION:
|
||||
case DOMTopLevelEventTypes.TOP_ANIMATION_START:
|
||||
EventConstructor = SyntheticAnimationEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_TRANSITION_END:
|
||||
EventConstructor = SyntheticTransitionEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_SCROLL:
|
||||
EventConstructor = SyntheticUIEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_WHEEL:
|
||||
EventConstructor = SyntheticWheelEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_COPY:
|
||||
case DOMTopLevelEventTypes.TOP_CUT:
|
||||
case DOMTopLevelEventTypes.TOP_PASTE:
|
||||
EventConstructor = SyntheticClipboardEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_GOT_POINTER_CAPTURE:
|
||||
case DOMTopLevelEventTypes.TOP_LOST_POINTER_CAPTURE:
|
||||
case DOMTopLevelEventTypes.TOP_POINTER_CANCEL:
|
||||
case DOMTopLevelEventTypes.TOP_POINTER_DOWN:
|
||||
case DOMTopLevelEventTypes.TOP_POINTER_MOVE:
|
||||
case DOMTopLevelEventTypes.TOP_POINTER_OUT:
|
||||
case DOMTopLevelEventTypes.TOP_POINTER_OVER:
|
||||
case DOMTopLevelEventTypes.TOP_POINTER_UP:
|
||||
EventConstructor = SyntheticPointerEvent;
|
||||
break;
|
||||
default:
|
||||
if (__DEV__) {
|
||||
if (
|
||||
knownHTMLTopLevelTypes.indexOf(topLevelType) === -1 &&
|
||||
dispatchConfig.customEvent !== true
|
||||
) {
|
||||
console.error(
|
||||
'SimpleEventPlugin: Unhandled event type, `%s`. This warning ' +
|
||||
'is likely caused by a bug in React. Please file an issue.',
|
||||
topLevelType,
|
||||
);
|
||||
}
|
||||
}
|
||||
// HTML Events
|
||||
// @see http://www.w3.org/TR/html5/index.html#events-0
|
||||
EventConstructor = SyntheticEvent;
|
||||
break;
|
||||
}
|
||||
const event = new EventConstructor(
|
||||
dispatchConfig,
|
||||
null,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
|
||||
if (
|
||||
enableCreateEventHandleAPI &&
|
||||
eventSystemFlags !== undefined &&
|
||||
eventSystemFlags & IS_TARGET_PHASE_ONLY &&
|
||||
targetContainer != null
|
||||
) {
|
||||
accumulateEventTargetListeners(dispatchQueue, event, targetContainer);
|
||||
} else {
|
||||
accumulateTwoPhaseListeners(targetInst, dispatchQueue, event, true);
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
export {
|
||||
// simpleEventPluginEventTypes gets populated from
|
||||
// the DOMEventProperties module.
|
||||
eventTypes: simpleEventPluginEventTypes,
|
||||
extractEvents: function(
|
||||
dispatchQueue: DispatchQueue,
|
||||
topLevelType: TopLevelType,
|
||||
targetInst: null | Fiber,
|
||||
nativeEvent: MouseEvent,
|
||||
nativeEventTarget: null | EventTarget,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
targetContainer: null | EventTarget,
|
||||
): void {
|
||||
const dispatchConfig = topLevelEventsToDispatchConfig.get(topLevelType);
|
||||
if (!dispatchConfig) {
|
||||
return;
|
||||
}
|
||||
let EventConstructor;
|
||||
switch (topLevelType) {
|
||||
case DOMTopLevelEventTypes.TOP_KEY_PRESS:
|
||||
// Firefox creates a keypress event for function keys too. This removes
|
||||
// the unwanted keypress events. Enter is however both printable and
|
||||
// non-printable. One would expect Tab to be as well (but it isn't).
|
||||
if (getEventCharCode(nativeEvent) === 0) {
|
||||
return;
|
||||
}
|
||||
/* falls through */
|
||||
case DOMTopLevelEventTypes.TOP_KEY_DOWN:
|
||||
case DOMTopLevelEventTypes.TOP_KEY_UP:
|
||||
EventConstructor = SyntheticKeyboardEvent;
|
||||
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:
|
||||
// Firefox creates a click event on right mouse clicks. This removes the
|
||||
// unwanted click events.
|
||||
if (nativeEvent.button === 2) {
|
||||
return;
|
||||
}
|
||||
/* falls through */
|
||||
case DOMTopLevelEventTypes.TOP_AUX_CLICK:
|
||||
case DOMTopLevelEventTypes.TOP_DOUBLE_CLICK:
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_DOWN:
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_MOVE:
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_UP:
|
||||
// TODO: Disabled elements should not respond to mouse events
|
||||
/* falls through */
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_OUT:
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_OVER:
|
||||
case DOMTopLevelEventTypes.TOP_CONTEXT_MENU:
|
||||
EventConstructor = SyntheticMouseEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_DRAG:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_END:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_ENTER:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_EXIT:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_LEAVE:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_OVER:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_START:
|
||||
case DOMTopLevelEventTypes.TOP_DROP:
|
||||
EventConstructor = SyntheticDragEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_TOUCH_CANCEL:
|
||||
case DOMTopLevelEventTypes.TOP_TOUCH_END:
|
||||
case DOMTopLevelEventTypes.TOP_TOUCH_MOVE:
|
||||
case DOMTopLevelEventTypes.TOP_TOUCH_START:
|
||||
EventConstructor = SyntheticTouchEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_ANIMATION_END:
|
||||
case DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION:
|
||||
case DOMTopLevelEventTypes.TOP_ANIMATION_START:
|
||||
EventConstructor = SyntheticAnimationEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_TRANSITION_END:
|
||||
EventConstructor = SyntheticTransitionEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_SCROLL:
|
||||
EventConstructor = SyntheticUIEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_WHEEL:
|
||||
EventConstructor = SyntheticWheelEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_COPY:
|
||||
case DOMTopLevelEventTypes.TOP_CUT:
|
||||
case DOMTopLevelEventTypes.TOP_PASTE:
|
||||
EventConstructor = SyntheticClipboardEvent;
|
||||
break;
|
||||
case DOMTopLevelEventTypes.TOP_GOT_POINTER_CAPTURE:
|
||||
case DOMTopLevelEventTypes.TOP_LOST_POINTER_CAPTURE:
|
||||
case DOMTopLevelEventTypes.TOP_POINTER_CANCEL:
|
||||
case DOMTopLevelEventTypes.TOP_POINTER_DOWN:
|
||||
case DOMTopLevelEventTypes.TOP_POINTER_MOVE:
|
||||
case DOMTopLevelEventTypes.TOP_POINTER_OUT:
|
||||
case DOMTopLevelEventTypes.TOP_POINTER_OVER:
|
||||
case DOMTopLevelEventTypes.TOP_POINTER_UP:
|
||||
EventConstructor = SyntheticPointerEvent;
|
||||
break;
|
||||
default:
|
||||
if (__DEV__) {
|
||||
if (
|
||||
knownHTMLTopLevelTypes.indexOf(topLevelType) === -1 &&
|
||||
dispatchConfig.customEvent !== true
|
||||
) {
|
||||
console.error(
|
||||
'SimpleEventPlugin: Unhandled event type, `%s`. This warning ' +
|
||||
'is likely caused by a bug in React. Please file an issue.',
|
||||
topLevelType,
|
||||
);
|
||||
}
|
||||
}
|
||||
// HTML Events
|
||||
// @see http://www.w3.org/TR/html5/index.html#events-0
|
||||
EventConstructor = SyntheticEvent;
|
||||
break;
|
||||
}
|
||||
const event = new EventConstructor(
|
||||
dispatchConfig,
|
||||
null,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
|
||||
if (
|
||||
enableCreateEventHandleAPI &&
|
||||
eventSystemFlags !== undefined &&
|
||||
eventSystemFlags & IS_TARGET_PHASE_ONLY &&
|
||||
targetContainer != null
|
||||
) {
|
||||
accumulateEventTargetListeners(dispatchQueue, event, targetContainer);
|
||||
} else {
|
||||
accumulateTwoPhaseListeners(targetInst, dispatchQueue, event, true);
|
||||
}
|
||||
return event;
|
||||
},
|
||||
simpleEventPluginEventTypes as eventTypes,
|
||||
extractEvents,
|
||||
};
|
||||
|
||||
export default SimpleEventPlugin;
|
||||
|
|
|
@ -43,11 +43,8 @@ if (__DEV__) {
|
|||
|
||||
// We can't rely on the event system being injected on the server.
|
||||
if (eventRegistry != null) {
|
||||
const {
|
||||
registrationNameModules,
|
||||
possibleRegistrationNames,
|
||||
} = eventRegistry;
|
||||
if (registrationNameModules.hasOwnProperty(name)) {
|
||||
const {registrationNames, possibleRegistrationNames} = eventRegistry;
|
||||
if (registrationNames.hasOwnProperty(name)) {
|
||||
return true;
|
||||
}
|
||||
const registrationName = possibleRegistrationNames.hasOwnProperty(
|
||||
|
|
Loading…
Reference in New Issue