mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Add flow to SyntheticEvent (#19564)
* Add flow to SyntheticEvent * Minimal implementation of known and unknown synthetic events * less casting * Update EnterLeaveEventPlugin.js Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
This commit is contained in:
co-authored by
Dan Abramov
parent
b8fa09e9e2
commit
87b3e2d257
+7
-7
@@ -15,7 +15,10 @@ import {
|
||||
SHOULD_NOT_PROCESS_POLYFILL_EVENT_PLUGINS,
|
||||
} from './EventSystemFlags';
|
||||
import type {AnyNativeEvent} from './PluginModuleType';
|
||||
import type {ReactSyntheticEvent} from './ReactSyntheticEventType';
|
||||
import type {
|
||||
KnownReactSyntheticEvent,
|
||||
ReactSyntheticEvent,
|
||||
} from './ReactSyntheticEventType';
|
||||
import type {ElementListenerMapEntry} from '../client/ReactDOMComponentTree';
|
||||
import type {EventPriority} from 'shared/ReactTypes';
|
||||
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
|
||||
@@ -917,15 +920,12 @@ function getLowestCommonAncestor(instA: Fiber, instB: Fiber): Fiber | null {
|
||||
|
||||
function accumulateEnterLeaveListenersForEvent(
|
||||
dispatchQueue: DispatchQueue,
|
||||
event: ReactSyntheticEvent,
|
||||
event: KnownReactSyntheticEvent,
|
||||
target: Fiber,
|
||||
common: Fiber | null,
|
||||
inCapturePhase: boolean,
|
||||
): void {
|
||||
const registrationName = event._reactName;
|
||||
if (registrationName === undefined) {
|
||||
return;
|
||||
}
|
||||
const listeners: Array<DispatchListener> = [];
|
||||
|
||||
let instance = target;
|
||||
@@ -969,8 +969,8 @@ function accumulateEnterLeaveListenersForEvent(
|
||||
// phase event listeners.
|
||||
export function accumulateEnterLeaveTwoPhaseListeners(
|
||||
dispatchQueue: DispatchQueue,
|
||||
leaveEvent: ReactSyntheticEvent,
|
||||
enterEvent: null | ReactSyntheticEvent,
|
||||
leaveEvent: KnownReactSyntheticEvent,
|
||||
enterEvent: null | KnownReactSyntheticEvent,
|
||||
from: Fiber | null,
|
||||
to: Fiber | null,
|
||||
): void {
|
||||
|
||||
+15
-3
@@ -22,14 +22,26 @@ export type DispatchConfig = {|
|
||||
eventPriority?: EventPriority,
|
||||
|};
|
||||
|
||||
export type ReactSyntheticEvent = {|
|
||||
type BaseSyntheticEvent = {
|
||||
isPersistent: () => boolean,
|
||||
isPropagationStopped: () => boolean,
|
||||
_dispatchInstances?: null | Array<Fiber | null> | Fiber,
|
||||
_dispatchListeners?: null | Array<Function> | Function,
|
||||
_reactName: string,
|
||||
_targetInst: Fiber,
|
||||
nativeEvent: Event,
|
||||
target?: mixed,
|
||||
relatedTarget?: mixed,
|
||||
type: string,
|
||||
currentTarget: null | EventTarget,
|
||||
|};
|
||||
};
|
||||
|
||||
export type KnownReactSyntheticEvent = BaseSyntheticEvent & {
|
||||
_reactName: string,
|
||||
};
|
||||
export type UnknownReactSyntheticEvent = BaseSyntheticEvent & {
|
||||
_reactName: null,
|
||||
};
|
||||
|
||||
export type ReactSyntheticEvent =
|
||||
| KnownReactSyntheticEvent
|
||||
| UnknownReactSyntheticEvent;
|
||||
|
||||
+23
-15
@@ -3,17 +3,23 @@
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/* eslint valid-typeof: 0 */
|
||||
|
||||
import getEventCharCode from './getEventCharCode';
|
||||
|
||||
type EventInterfaceType = {
|
||||
[propName: string]: 0 | ((event: {[propName: string]: mixed}) => mixed),
|
||||
};
|
||||
|
||||
/**
|
||||
* @interface Event
|
||||
* @see http://www.w3.org/TR/DOM-Level-3-Events/
|
||||
*/
|
||||
const EventInterface = {
|
||||
const EventInterface: EventInterfaceType = {
|
||||
eventPhase: 0,
|
||||
bubbles: 0,
|
||||
cancelable: 0,
|
||||
@@ -46,12 +52,12 @@ function functionThatReturnsFalse() {
|
||||
* DOM interface; custom application-specific events can also subclass this.
|
||||
*/
|
||||
export function SyntheticEvent(
|
||||
reactName,
|
||||
reactEventType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
Interface = EventInterface,
|
||||
reactName: string | null,
|
||||
reactEventType: string,
|
||||
targetInst: Fiber,
|
||||
nativeEvent: {[propName: string]: mixed},
|
||||
nativeEventTarget: null | EventTarget,
|
||||
Interface: EventInterfaceType = EventInterface,
|
||||
) {
|
||||
this._reactName = reactName;
|
||||
this._targetInst = targetInst;
|
||||
@@ -95,6 +101,7 @@ Object.assign(SyntheticEvent.prototype, {
|
||||
|
||||
if (event.preventDefault) {
|
||||
event.preventDefault();
|
||||
// $FlowFixMe - flow is not aware of `unknown` in IE
|
||||
} else if (typeof event.returnValue !== 'unknown') {
|
||||
event.returnValue = false;
|
||||
}
|
||||
@@ -109,6 +116,7 @@ Object.assign(SyntheticEvent.prototype, {
|
||||
|
||||
if (event.stopPropagation) {
|
||||
event.stopPropagation();
|
||||
// $FlowFixMe - flow is not aware of `unknown` in IE
|
||||
} else if (typeof event.cancelBubble !== 'unknown') {
|
||||
// The ChangeEventPlugin registers a "propertychange" event for
|
||||
// IE. This event does not support bubbling or cancelling, and
|
||||
@@ -138,7 +146,7 @@ Object.assign(SyntheticEvent.prototype, {
|
||||
isPersistent: functionThatReturnsTrue,
|
||||
});
|
||||
|
||||
export const UIEventInterface = {
|
||||
export const UIEventInterface: EventInterfaceType = {
|
||||
...EventInterface,
|
||||
view: 0,
|
||||
detail: 0,
|
||||
@@ -154,7 +162,7 @@ let isMovementYSet = false;
|
||||
* @interface MouseEvent
|
||||
* @see http://www.w3.org/TR/DOM-Level-3-Events/
|
||||
*/
|
||||
export const MouseEventInterface = {
|
||||
export const MouseEventInterface: EventInterfaceType = {
|
||||
...UIEventInterface,
|
||||
screenX: 0,
|
||||
screenY: 0,
|
||||
@@ -213,7 +221,7 @@ export const MouseEventInterface = {
|
||||
* @interface DragEvent
|
||||
* @see http://www.w3.org/TR/DOM-Level-3-Events/
|
||||
*/
|
||||
export const DragEventInterface = {
|
||||
export const DragEventInterface: EventInterfaceType = {
|
||||
...MouseEventInterface,
|
||||
dataTransfer: 0,
|
||||
};
|
||||
@@ -222,7 +230,7 @@ export const DragEventInterface = {
|
||||
* @interface FocusEvent
|
||||
* @see http://www.w3.org/TR/DOM-Level-3-Events/
|
||||
*/
|
||||
export const FocusEventInterface = {
|
||||
export const FocusEventInterface: EventInterfaceType = {
|
||||
...UIEventInterface,
|
||||
relatedTarget: 0,
|
||||
};
|
||||
@@ -232,7 +240,7 @@ export const FocusEventInterface = {
|
||||
* @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent
|
||||
*/
|
||||
export const AnimationEventInterface = {
|
||||
export const AnimationEventInterface: EventInterfaceType = {
|
||||
...EventInterface,
|
||||
animationName: 0,
|
||||
elapsedTime: 0,
|
||||
@@ -243,7 +251,7 @@ export const AnimationEventInterface = {
|
||||
* @interface Event
|
||||
* @see http://www.w3.org/TR/clipboard-apis/
|
||||
*/
|
||||
export const ClipboardEventInterface = {
|
||||
export const ClipboardEventInterface: EventInterfaceType = {
|
||||
...EventInterface,
|
||||
clipboardData: function(event) {
|
||||
return 'clipboardData' in event
|
||||
@@ -256,7 +264,7 @@ export const ClipboardEventInterface = {
|
||||
* @interface Event
|
||||
* @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents
|
||||
*/
|
||||
export const CompositionEventInterface = {
|
||||
export const CompositionEventInterface: EventInterfaceType = {
|
||||
...EventInterface,
|
||||
data: 0,
|
||||
};
|
||||
@@ -267,7 +275,7 @@ export const CompositionEventInterface = {
|
||||
* /#events-inputevents
|
||||
*/
|
||||
// Happens to share the same list for now.
|
||||
export const InputEventInterface = CompositionEventInterface;
|
||||
export const InputEventInterface: EventInterfaceType = CompositionEventInterface;
|
||||
|
||||
/**
|
||||
* Normalization of deprecated HTML5 `key` values
|
||||
|
||||
+16
-15
@@ -25,6 +25,7 @@ import {
|
||||
isContainerMarkedAsRoot,
|
||||
} from '../../client/ReactDOMComponentTree';
|
||||
import {accumulateEnterLeaveTwoPhaseListeners} from '../DOMPluginEventSystem';
|
||||
import type {KnownReactSyntheticEvent} from '../ReactSyntheticEventType';
|
||||
|
||||
import {HostComponent, HostText} from 'react-reconciler/src/ReactWorkTags';
|
||||
import {getNearestMountedFiber} from 'react-reconciler/src/ReactFiberTreeReflection';
|
||||
@@ -147,23 +148,23 @@ function extractEvents(
|
||||
leave.target = fromNode;
|
||||
leave.relatedTarget = toNode;
|
||||
|
||||
let enter = new SyntheticEvent(
|
||||
enterEventType,
|
||||
eventTypePrefix + 'enter',
|
||||
to,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventInterface,
|
||||
);
|
||||
enter.target = toNode;
|
||||
enter.relatedTarget = fromNode;
|
||||
let enter: KnownReactSyntheticEvent | null = null;
|
||||
|
||||
// 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.
|
||||
// We should only process this nativeEvent if we are processing
|
||||
// the first ancestor. Next time, we will ignore the event.
|
||||
const nativeTargetInst = getClosestInstanceFromNode((nativeEventTarget: any));
|
||||
if (nativeTargetInst !== targetInst) {
|
||||
enter = null;
|
||||
if (nativeTargetInst === targetInst) {
|
||||
const enterEvent: KnownReactSyntheticEvent = new SyntheticEvent(
|
||||
enterEventType,
|
||||
eventTypePrefix + 'enter',
|
||||
to,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
eventInterface,
|
||||
);
|
||||
enterEvent.target = toNode;
|
||||
enterEvent.relatedTarget = fromNode;
|
||||
enter = enterEvent;
|
||||
}
|
||||
|
||||
accumulateEnterLeaveTwoPhaseListeners(dispatchQueue, leave, enter, from, to);
|
||||
|
||||
Reference in New Issue
Block a user