Remove SyntheticEvent subtypes (#19436)

* Remove SyntheticEvent subtypes

* Code golf
This commit is contained in:
Dan Abramov
2020-07-23 01:02:59 +01:00
committed by GitHub
parent 30e3cfe406
commit 76ce685d0f
4 changed files with 140 additions and 152 deletions
+97 -118
View File
@@ -14,20 +14,15 @@ import getEventCharCode from './getEventCharCode';
* @see http://www.w3.org/TR/DOM-Level-3-Events/
*/
const EventInterface = {
type: null,
target: null,
// currentTarget is set when dispatching; no use in copying it here
currentTarget: function() {
return null;
},
eventPhase: null,
bubbles: null,
cancelable: null,
type: 0,
eventPhase: 0,
bubbles: 0,
cancelable: 0,
timeStamp: function(event) {
return event.timeStamp || Date.now();
},
defaultPrevented: null,
isTrusted: null,
defaultPrevented: 0,
isTrusted: 0,
};
function functionThatReturnsTrue() {
@@ -56,12 +51,14 @@ export function SyntheticEvent(
targetInst,
nativeEvent,
nativeEventTarget,
Interface = EventInterface,
) {
this._reactName = reactName;
this._targetInst = targetInst;
this.nativeEvent = nativeEvent;
this.target = nativeEventTarget;
this.currentTarget = null;
const Interface = this.constructor.Interface;
for (const propName in Interface) {
if (!Interface.hasOwnProperty(propName)) {
continue;
@@ -70,11 +67,7 @@ export function SyntheticEvent(
if (normalize) {
this[propName] = normalize(nativeEvent);
} else {
if (propName === 'target') {
this.target = nativeEventTarget;
} else {
this[propName] = nativeEvent[propName];
}
this[propName] = nativeEvent[propName];
}
}
@@ -144,36 +137,12 @@ Object.assign(SyntheticEvent.prototype, {
isPersistent: functionThatReturnsTrue,
});
SyntheticEvent.Interface = EventInterface;
/**
* Helper to reduce boilerplate when creating subclasses.
*/
SyntheticEvent.extend = function(Interface) {
const Super = this;
const E = function() {};
E.prototype = Super.prototype;
const prototype = new E();
function Class() {
return Super.apply(this, arguments);
}
Object.assign(prototype, Class.prototype);
Class.prototype = prototype;
Class.prototype.constructor = Class;
Class.Interface = Object.assign({}, Super.Interface, Interface);
Class.extend = Super.extend;
return Class;
export const UIEventInterface = {
...EventInterface,
view: 0,
detail: 0,
};
export const SyntheticUIEvent = SyntheticEvent.extend({
view: null,
detail: null,
});
let previousScreenX = 0;
let previousScreenY = 0;
// Use flags to signal movementX/Y has already been set
@@ -184,20 +153,21 @@ let isMovementYSet = false;
* @interface MouseEvent
* @see http://www.w3.org/TR/DOM-Level-3-Events/
*/
export const SyntheticMouseEvent = SyntheticUIEvent.extend({
screenX: null,
screenY: null,
clientX: null,
clientY: null,
pageX: null,
pageY: null,
ctrlKey: null,
shiftKey: null,
altKey: null,
metaKey: null,
export const MouseEventInterface = {
...UIEventInterface,
screenX: 0,
screenY: 0,
clientX: 0,
clientY: 0,
pageX: 0,
pageY: 0,
ctrlKey: 0,
shiftKey: 0,
altKey: 0,
metaKey: 0,
getModifierState: getEventModifierState,
button: null,
buttons: null,
button: 0,
buttons: 0,
relatedTarget: function(event) {
return (
event.relatedTarget ||
@@ -236,63 +206,67 @@ export const SyntheticMouseEvent = SyntheticUIEvent.extend({
return event.type === 'mousemove' ? event.screenY - screenY : 0;
},
});
};
/**
* @interface DragEvent
* @see http://www.w3.org/TR/DOM-Level-3-Events/
*/
export const SyntheticDragEvent = SyntheticMouseEvent.extend({
dataTransfer: null,
});
export const DragEventInterface = {
...MouseEventInterface,
dataTransfer: 0,
};
/**
* @interface FocusEvent
* @see http://www.w3.org/TR/DOM-Level-3-Events/
*/
export const SyntheticFocusEvent = SyntheticUIEvent.extend({
relatedTarget: null,
});
export const FocusEventInterface = {
...UIEventInterface,
relatedTarget: 0,
};
/**
* @interface Event
* @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface
* @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent
*/
export const SyntheticAnimationEvent = SyntheticEvent.extend({
animationName: null,
elapsedTime: null,
pseudoElement: null,
});
export const AnimationEventInterface = {
...EventInterface,
animationName: 0,
elapsedTime: 0,
pseudoElement: 0,
};
/**
* @interface Event
* @see http://www.w3.org/TR/clipboard-apis/
*/
export const SyntheticClipboardEvent = SyntheticEvent.extend({
export const ClipboardEventInterface = {
...EventInterface,
clipboardData: function(event) {
return 'clipboardData' in event
? event.clipboardData
: window.clipboardData;
},
});
};
/**
* @interface Event
* @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents
*/
export const SyntheticCompositionEvent = SyntheticEvent.extend({
data: null,
});
export const CompositionEventInterface = {
...EventInterface,
data: 0,
};
/**
* @interface Event
* @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105
* /#events-inputevents
*/
export const SyntheticInputEvent = SyntheticEvent.extend({
data: null,
});
// Happens to share the same list for now.
export const InputEventInterface = CompositionEventInterface;
/**
* Normalization of deprecated HTML5 `key` values
@@ -422,16 +396,17 @@ function getEventModifierState(nativeEvent) {
* @interface KeyboardEvent
* @see http://www.w3.org/TR/DOM-Level-3-Events/
*/
export const SyntheticKeyboardEvent = SyntheticUIEvent.extend({
export const KeyboardEventInterface = {
...UIEventInterface,
key: getEventKey,
code: null,
location: null,
ctrlKey: null,
shiftKey: null,
altKey: null,
metaKey: null,
repeat: null,
locale: null,
code: 0,
location: 0,
ctrlKey: 0,
shiftKey: 0,
altKey: 0,
metaKey: 0,
repeat: 0,
locale: 0,
getModifierState: getEventModifierState,
// Legacy Interface
charCode: function(event) {
@@ -469,56 +444,60 @@ export const SyntheticKeyboardEvent = SyntheticUIEvent.extend({
}
return 0;
},
});
};
/**
* @interface PointerEvent
* @see http://www.w3.org/TR/pointerevents/
*/
export const SyntheticPointerEvent = SyntheticMouseEvent.extend({
pointerId: null,
width: null,
height: null,
pressure: null,
tangentialPressure: null,
tiltX: null,
tiltY: null,
twist: null,
pointerType: null,
isPrimary: null,
});
export const PointerEventInterface = {
...MouseEventInterface,
pointerId: 0,
width: 0,
height: 0,
pressure: 0,
tangentialPressure: 0,
tiltX: 0,
tiltY: 0,
twist: 0,
pointerType: 0,
isPrimary: 0,
};
/**
* @interface TouchEvent
* @see http://www.w3.org/TR/touch-events/
*/
export const SyntheticTouchEvent = SyntheticUIEvent.extend({
touches: null,
targetTouches: null,
changedTouches: null,
altKey: null,
metaKey: null,
ctrlKey: null,
shiftKey: null,
export const TouchEventInterface = {
...UIEventInterface,
touches: 0,
targetTouches: 0,
changedTouches: 0,
altKey: 0,
metaKey: 0,
ctrlKey: 0,
shiftKey: 0,
getModifierState: getEventModifierState,
});
};
/**
* @interface Event
* @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events-
* @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent
*/
export const SyntheticTransitionEvent = SyntheticEvent.extend({
propertyName: null,
elapsedTime: null,
pseudoElement: null,
});
export const TransitionEventInterface = {
...EventInterface,
propertyName: 0,
elapsedTime: 0,
pseudoElement: 0,
};
/**
* @interface WheelEvent
* @see http://www.w3.org/TR/DOM-Level-3-Events/
*/
export const SyntheticWheelEvent = SyntheticMouseEvent.extend({
export const WheelEventInterface = {
...MouseEventInterface,
deltaX(event) {
return 'deltaX' in event
? event.deltaX
@@ -538,11 +517,11 @@ export const SyntheticWheelEvent = SyntheticMouseEvent.extend({
? -event.wheelDelta
: 0;
},
deltaZ: null,
deltaZ: 0,
// Browsers without "deltaMode" is reporting in raw wheel delta where one
// notch on the scroll is always +/- 120, roughly equivalent to pixels.
// A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or
// ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size.
deltaMode: null,
});
deltaMode: 0,
};
@@ -28,8 +28,9 @@ import {
reset as FallbackCompositionStateReset,
} from '../FallbackCompositionState';
import {
SyntheticCompositionEvent,
SyntheticInputEvent,
CompositionEventInterface,
InputEventInterface,
SyntheticEvent,
} from '../SyntheticEvent';
import {accumulateTwoPhaseListeners} from '../DOMPluginEventSystem';
@@ -237,11 +238,12 @@ function extractCompositionEvent(
}
}
const event = new SyntheticCompositionEvent(
const event = new SyntheticEvent(
eventType,
null,
nativeEvent,
nativeEventTarget,
CompositionEventInterface,
);
accumulateTwoPhaseListeners(targetInst, dispatchQueue, event);
@@ -407,11 +409,12 @@ function extractBeforeInputEvent(
return null;
}
const event = new SyntheticInputEvent(
const event = new SyntheticEvent(
'onBeforeInput',
null,
nativeEvent,
nativeEventTarget,
InputEventInterface,
);
accumulateTwoPhaseListeners(targetInst, dispatchQueue, event);
event.data = chars;
@@ -13,7 +13,11 @@ import {
TOP_POINTER_OVER,
} from '../DOMTopLevelEventTypes';
import {IS_REPLAYED} from 'react-dom/src/events/EventSystemFlags';
import {SyntheticMouseEvent, SyntheticPointerEvent} from '../SyntheticEvent';
import {
SyntheticEvent,
MouseEventInterface,
PointerEventInterface,
} from '../SyntheticEvent';
import {
getClosestInstanceFromNode,
getNodeFromInstance,
@@ -113,7 +117,7 @@ function extractEvents(
let eventInterface, leaveEventType, enterEventType, eventTypePrefix;
if (topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_MOUSE_OVER) {
eventInterface = SyntheticMouseEvent;
eventInterface = MouseEventInterface;
leaveEventType = 'onMouseLeave';
enterEventType = 'onMouseEnter';
eventTypePrefix = 'mouse';
@@ -121,7 +125,7 @@ function extractEvents(
topLevelType === TOP_POINTER_OUT ||
topLevelType === TOP_POINTER_OVER
) {
eventInterface = SyntheticPointerEvent;
eventInterface = PointerEventInterface;
leaveEventType = 'onPointerLeave';
enterEventType = 'onPointerEnter';
eventTypePrefix = 'pointer';
@@ -130,21 +134,23 @@ function extractEvents(
const fromNode = from == null ? win : getNodeFromInstance(from);
const toNode = to == null ? win : getNodeFromInstance(to);
const leave = new eventInterface(
const leave = new SyntheticEvent(
leaveEventType,
from,
nativeEvent,
nativeEventTarget,
eventInterface,
);
leave.type = eventTypePrefix + 'leave';
leave.target = fromNode;
leave.relatedTarget = toNode;
let enter = new eventInterface(
let enter = new SyntheticEvent(
enterEventType,
to,
nativeEvent,
nativeEventTarget,
eventInterface,
);
enter.type = eventTypePrefix + 'enter';
enter.target = toNode;
+25 -25
View File
@@ -15,17 +15,17 @@ import type {EventSystemFlags} from '../EventSystemFlags';
import {
SyntheticEvent,
SyntheticAnimationEvent,
SyntheticClipboardEvent,
SyntheticFocusEvent,
SyntheticKeyboardEvent,
SyntheticMouseEvent,
SyntheticPointerEvent,
SyntheticDragEvent,
SyntheticTouchEvent,
SyntheticTransitionEvent,
SyntheticUIEvent,
SyntheticWheelEvent,
AnimationEventInterface,
ClipboardEventInterface,
FocusEventInterface,
KeyboardEventInterface,
MouseEventInterface,
PointerEventInterface,
DragEventInterface,
TouchEventInterface,
TransitionEventInterface,
UIEventInterface,
WheelEventInterface,
} from '../../events/SyntheticEvent';
import * as DOMTopLevelEventTypes from '../DOMTopLevelEventTypes';
@@ -57,7 +57,7 @@ function extractEvents(
if (reactName === undefined) {
return;
}
let EventConstructor;
let EventInterface;
switch (topLevelType) {
case DOMTopLevelEventTypes.TOP_KEY_PRESS:
// Firefox creates a keypress event for function keys too. This removes
@@ -69,13 +69,13 @@ function extractEvents(
/* falls through */
case DOMTopLevelEventTypes.TOP_KEY_DOWN:
case DOMTopLevelEventTypes.TOP_KEY_UP:
EventConstructor = SyntheticKeyboardEvent;
EventInterface = KeyboardEventInterface;
break;
case DOMTopLevelEventTypes.TOP_FOCUS_IN:
case DOMTopLevelEventTypes.TOP_FOCUS_OUT:
case DOMTopLevelEventTypes.TOP_BEFORE_BLUR:
case DOMTopLevelEventTypes.TOP_AFTER_BLUR:
EventConstructor = SyntheticFocusEvent;
EventInterface = FocusEventInterface;
break;
case DOMTopLevelEventTypes.TOP_CLICK:
// Firefox creates a click event on right mouse clicks. This removes the
@@ -94,7 +94,7 @@ function extractEvents(
case DOMTopLevelEventTypes.TOP_MOUSE_OUT:
case DOMTopLevelEventTypes.TOP_MOUSE_OVER:
case DOMTopLevelEventTypes.TOP_CONTEXT_MENU:
EventConstructor = SyntheticMouseEvent;
EventInterface = MouseEventInterface;
break;
case DOMTopLevelEventTypes.TOP_DRAG:
case DOMTopLevelEventTypes.TOP_DRAG_END:
@@ -104,32 +104,32 @@ function extractEvents(
case DOMTopLevelEventTypes.TOP_DRAG_OVER:
case DOMTopLevelEventTypes.TOP_DRAG_START:
case DOMTopLevelEventTypes.TOP_DROP:
EventConstructor = SyntheticDragEvent;
EventInterface = DragEventInterface;
break;
case DOMTopLevelEventTypes.TOP_TOUCH_CANCEL:
case DOMTopLevelEventTypes.TOP_TOUCH_END:
case DOMTopLevelEventTypes.TOP_TOUCH_MOVE:
case DOMTopLevelEventTypes.TOP_TOUCH_START:
EventConstructor = SyntheticTouchEvent;
EventInterface = TouchEventInterface;
break;
case DOMTopLevelEventTypes.TOP_ANIMATION_END:
case DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION:
case DOMTopLevelEventTypes.TOP_ANIMATION_START:
EventConstructor = SyntheticAnimationEvent;
EventInterface = AnimationEventInterface;
break;
case DOMTopLevelEventTypes.TOP_TRANSITION_END:
EventConstructor = SyntheticTransitionEvent;
EventInterface = TransitionEventInterface;
break;
case DOMTopLevelEventTypes.TOP_SCROLL:
EventConstructor = SyntheticUIEvent;
EventInterface = UIEventInterface;
break;
case DOMTopLevelEventTypes.TOP_WHEEL:
EventConstructor = SyntheticWheelEvent;
EventInterface = WheelEventInterface;
break;
case DOMTopLevelEventTypes.TOP_COPY:
case DOMTopLevelEventTypes.TOP_CUT:
case DOMTopLevelEventTypes.TOP_PASTE:
EventConstructor = SyntheticClipboardEvent;
EventInterface = ClipboardEventInterface;
break;
case DOMTopLevelEventTypes.TOP_GOT_POINTER_CAPTURE:
case DOMTopLevelEventTypes.TOP_LOST_POINTER_CAPTURE:
@@ -139,18 +139,18 @@ function extractEvents(
case DOMTopLevelEventTypes.TOP_POINTER_OUT:
case DOMTopLevelEventTypes.TOP_POINTER_OVER:
case DOMTopLevelEventTypes.TOP_POINTER_UP:
EventConstructor = SyntheticPointerEvent;
EventInterface = PointerEventInterface;
break;
default:
// Unknown event. This is used by createEventHandle.
EventConstructor = SyntheticEvent;
break;
}
const event = new EventConstructor(
const event = new SyntheticEvent(
reactName,
null,
nativeEvent,
nativeEventTarget,
EventInterface,
);
const inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0;