Remove SyntheticEvent subtypes (#19436)
* Remove SyntheticEvent subtypes * Code golf
Dan Abramov committed
Jul 23, 2020 at 01:02 UTC
76ce685d0fc7821a6c8be486d7cbb2c3d22f6fb7
4 files changed
+140
-152
packages/react-dom/src/events/SyntheticEvent.js
+97
-118
@@ -14,20 +14,15 @@ import getEventCharCode from './getEventCharCode';
14
* @see http://www.w3.org/TR/DOM-Level-3-Events/
15
*/
16
const EventInterface = {
17
- type: null,
18
- target: null,
19
- // currentTarget is set when dispatching; no use in copying it here
20
- currentTarget: function() {
21
- return null;
22
- },
23
- eventPhase: null,
24
- bubbles: null,
25
- cancelable: null,
17
+ type: 0,
18
+ eventPhase: 0,
19
+ bubbles: 0,
20
+ cancelable: 0,
21
timeStamp: function(event) {
22
return event.timeStamp || Date.now();
23
},
29
- defaultPrevented: null,
30
- isTrusted: null,
24
+ defaultPrevented: 0,
25
+ isTrusted: 0,
26
};
27
28
function functionThatReturnsTrue() {
@@ -56,12 +51,14 @@ export function SyntheticEvent(
51
targetInst,
52
nativeEvent,
53
nativeEventTarget,
54
+ Interface = EventInterface,
55
) {
56
this._reactName = reactName;
57
this._targetInst = targetInst;
58
this.nativeEvent = nativeEvent;
59
+ this.target = nativeEventTarget;
60
+ this.currentTarget = null;
61
64
- const Interface = this.constructor.Interface;
62
for (const propName in Interface) {
63
if (!Interface.hasOwnProperty(propName)) {
64
continue;
@@ -70,11 +67,7 @@ export function SyntheticEvent(
67
if (normalize) {
68
this[propName] = normalize(nativeEvent);
69
} else {
73
- if (propName === 'target') {
74
- this.target = nativeEventTarget;
75
- } else {
76
- this[propName] = nativeEvent[propName];
77
- }
70
+ this[propName] = nativeEvent[propName];
71
}
72
}
73
@@ -144,36 +137,12 @@ Object.assign(SyntheticEvent.prototype, {
137
isPersistent: functionThatReturnsTrue,
138
});
139
147
-SyntheticEvent.Interface = EventInterface;
148
-
149
-/**
150
- * Helper to reduce boilerplate when creating subclasses.
151
- */
152
-SyntheticEvent.extend = function(Interface) {
153
- const Super = this;
154
-
155
- const E = function() {};
156
- E.prototype = Super.prototype;
157
- const prototype = new E();
158
-
159
- function Class() {
160
- return Super.apply(this, arguments);
161
- }
162
- Object.assign(prototype, Class.prototype);
163
- Class.prototype = prototype;
164
- Class.prototype.constructor = Class;
165
-
166
- Class.Interface = Object.assign({}, Super.Interface, Interface);
167
- Class.extend = Super.extend;
168
-
169
- return Class;
140
+export const UIEventInterface = {
141
+ ...EventInterface,
142
+ view: 0,
143
+ detail: 0,
144
};
145
172
-export const SyntheticUIEvent = SyntheticEvent.extend({
173
- view: null,
174
- detail: null,
175
-});
176
-
146
let previousScreenX = 0;
147
let previousScreenY = 0;
148
// Use flags to signal movementX/Y has already been set
@@ -184,20 +153,21 @@ let isMovementYSet = false;
153
* @interface MouseEvent
154
* @see http://www.w3.org/TR/DOM-Level-3-Events/
155
*/
187
-export const SyntheticMouseEvent = SyntheticUIEvent.extend({
188
- screenX: null,
189
- screenY: null,
190
- clientX: null,
191
- clientY: null,
192
- pageX: null,
193
- pageY: null,
194
- ctrlKey: null,
195
- shiftKey: null,
196
- altKey: null,
197
- metaKey: null,
156
+export const MouseEventInterface = {
157
+ ...UIEventInterface,
158
+ screenX: 0,
159
+ screenY: 0,
160
+ clientX: 0,
161
+ clientY: 0,
162
+ pageX: 0,
163
+ pageY: 0,
164
+ ctrlKey: 0,
165
+ shiftKey: 0,
166
+ altKey: 0,
167
+ metaKey: 0,
168
getModifierState: getEventModifierState,
199
- button: null,
200
- buttons: null,
169
+ button: 0,
170
+ buttons: 0,
171
relatedTarget: function(event) {
172
return (
173
event.relatedTarget ||
@@ -236,63 +206,67 @@ export const SyntheticMouseEvent = SyntheticUIEvent.extend({
206
207
return event.type === 'mousemove' ? event.screenY - screenY : 0;
208
},
239
-});
209
+};
210
211
/**
212
* @interface DragEvent
213
* @see http://www.w3.org/TR/DOM-Level-3-Events/
214
*/
245
-export const SyntheticDragEvent = SyntheticMouseEvent.extend({
246
- dataTransfer: null,
247
-});
215
+export const DragEventInterface = {
216
+ ...MouseEventInterface,
217
+ dataTransfer: 0,
218
+};
219
220
/**
221
* @interface FocusEvent
222
* @see http://www.w3.org/TR/DOM-Level-3-Events/
223
*/
253
-export const SyntheticFocusEvent = SyntheticUIEvent.extend({
254
- relatedTarget: null,
255
-});
224
+export const FocusEventInterface = {
225
+ ...UIEventInterface,
226
+ relatedTarget: 0,
227
+};
228
229
/**
230
* @interface Event
231
* @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface
232
* @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent
233
*/
262
-export const SyntheticAnimationEvent = SyntheticEvent.extend({
263
- animationName: null,
264
- elapsedTime: null,
265
- pseudoElement: null,
266
-});
234
+export const AnimationEventInterface = {
235
+ ...EventInterface,
236
+ animationName: 0,
237
+ elapsedTime: 0,
238
+ pseudoElement: 0,
239
+};
240
241
/**
242
* @interface Event
243
* @see http://www.w3.org/TR/clipboard-apis/
244
*/
272
-export const SyntheticClipboardEvent = SyntheticEvent.extend({
245
+export const ClipboardEventInterface = {
246
+ ...EventInterface,
247
clipboardData: function(event) {
248
return 'clipboardData' in event
249
? event.clipboardData
250
: window.clipboardData;
251
},
278
-});
252
+};
253
254
/**
255
* @interface Event
256
* @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents
257
*/
284
-export const SyntheticCompositionEvent = SyntheticEvent.extend({
285
- data: null,
286
-});
258
+export const CompositionEventInterface = {
259
+ ...EventInterface,
260
+ data: 0,
261
+};
262
263
/**
264
* @interface Event
265
* @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105
266
* /#events-inputevents
267
*/
293
-export const SyntheticInputEvent = SyntheticEvent.extend({
294
- data: null,
295
-});
268
+// Happens to share the same list for now.
269
+export const InputEventInterface = CompositionEventInterface;
270
271
/**
272
* Normalization of deprecated HTML5 `key` values
@@ -422,16 +396,17 @@ function getEventModifierState(nativeEvent) {
396
* @interface KeyboardEvent
397
* @see http://www.w3.org/TR/DOM-Level-3-Events/
398
*/
425
-export const SyntheticKeyboardEvent = SyntheticUIEvent.extend({
399
+export const KeyboardEventInterface = {
400
+ ...UIEventInterface,
401
key: getEventKey,
427
- code: null,
428
- location: null,
429
- ctrlKey: null,
430
- shiftKey: null,
431
- altKey: null,
432
- metaKey: null,
433
- repeat: null,
434
- locale: null,
402
+ code: 0,
403
+ location: 0,
404
+ ctrlKey: 0,
405
+ shiftKey: 0,
406
+ altKey: 0,
407
+ metaKey: 0,
408
+ repeat: 0,
409
+ locale: 0,
410
getModifierState: getEventModifierState,
411
// Legacy Interface
412
charCode: function(event) {
@@ -469,56 +444,60 @@ export const SyntheticKeyboardEvent = SyntheticUIEvent.extend({
444
}
445
return 0;
446
},
472
-});
447
+};
448
449
/**
450
* @interface PointerEvent
451
* @see http://www.w3.org/TR/pointerevents/
452
*/
478
-export const SyntheticPointerEvent = SyntheticMouseEvent.extend({
479
- pointerId: null,
480
- width: null,
481
- height: null,
482
- pressure: null,
483
- tangentialPressure: null,
484
- tiltX: null,
485
- tiltY: null,
486
- twist: null,
487
- pointerType: null,
488
- isPrimary: null,
489
-});
453
+export const PointerEventInterface = {
454
+ ...MouseEventInterface,
455
+ pointerId: 0,
456
+ width: 0,
457
+ height: 0,
458
+ pressure: 0,
459
+ tangentialPressure: 0,
460
+ tiltX: 0,
461
+ tiltY: 0,
462
+ twist: 0,
463
+ pointerType: 0,
464
+ isPrimary: 0,
465
+};
466
467
/**
468
* @interface TouchEvent
469
* @see http://www.w3.org/TR/touch-events/
470
*/
495
-export const SyntheticTouchEvent = SyntheticUIEvent.extend({
496
- touches: null,
497
- targetTouches: null,
498
- changedTouches: null,
499
- altKey: null,
500
- metaKey: null,
501
- ctrlKey: null,
502
- shiftKey: null,
471
+export const TouchEventInterface = {
472
+ ...UIEventInterface,
473
+ touches: 0,
474
+ targetTouches: 0,
475
+ changedTouches: 0,
476
+ altKey: 0,
477
+ metaKey: 0,
478
+ ctrlKey: 0,
479
+ shiftKey: 0,
480
getModifierState: getEventModifierState,
504
-});
481
+};
482
483
/**
484
* @interface Event
485
* @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events-
486
* @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent
487
*/
511
-export const SyntheticTransitionEvent = SyntheticEvent.extend({
512
- propertyName: null,
513
- elapsedTime: null,
514
- pseudoElement: null,
515
-});
488
+export const TransitionEventInterface = {
489
+ ...EventInterface,
490
+ propertyName: 0,
491
+ elapsedTime: 0,
492
+ pseudoElement: 0,
493
+};
494
495
/**
496
* @interface WheelEvent
497
* @see http://www.w3.org/TR/DOM-Level-3-Events/
498
*/
521
-export const SyntheticWheelEvent = SyntheticMouseEvent.extend({
499
+export const WheelEventInterface = {
500
+ ...MouseEventInterface,
501
deltaX(event) {
502
return 'deltaX' in event
503
? event.deltaX
@@ -538,11 +517,11 @@ export const SyntheticWheelEvent = SyntheticMouseEvent.extend({
517
? -event.wheelDelta
518
: 0;
519
},
541
- deltaZ: null,
520
+ deltaZ: 0,
521
522
// Browsers without "deltaMode" is reporting in raw wheel delta where one
523
// notch on the scroll is always +/- 120, roughly equivalent to pixels.
524
// A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or
525
// ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size.
547
- deltaMode: null,
548
-});
526
+ deltaMode: 0,
527
+};
packages/react-dom/src/events/plugins/BeforeInputEventPlugin.js
+7
-4
@@ -28,8 +28,9 @@ import {
28
reset as FallbackCompositionStateReset,
29
} from '../FallbackCompositionState';
30
import {
31
- SyntheticCompositionEvent,
32
- SyntheticInputEvent,
31
+ CompositionEventInterface,
32
+ InputEventInterface,
33
+ SyntheticEvent,
34
} from '../SyntheticEvent';
35
import {accumulateTwoPhaseListeners} from '../DOMPluginEventSystem';
36
@@ -237,11 +238,12 @@ function extractCompositionEvent(
238
}
239
}
240
240
- const event = new SyntheticCompositionEvent(
241
+ const event = new SyntheticEvent(
242
eventType,
243
null,
244
nativeEvent,
245
nativeEventTarget,
246
+ CompositionEventInterface,
247
);
248
accumulateTwoPhaseListeners(targetInst, dispatchQueue, event);
249
@@ -407,11 +409,12 @@ function extractBeforeInputEvent(
409
return null;
410
}
411
410
- const event = new SyntheticInputEvent(
412
+ const event = new SyntheticEvent(
413
'onBeforeInput',
414
null,
415
nativeEvent,
416
nativeEventTarget,
417
+ InputEventInterface,
418
);
419
accumulateTwoPhaseListeners(targetInst, dispatchQueue, event);
420
event.data = chars;
packages/react-dom/src/events/plugins/EnterLeaveEventPlugin.js
+11
-5
@@ -13,7 +13,11 @@ import {
13
TOP_POINTER_OVER,
14
} from '../DOMTopLevelEventTypes';
15
import {IS_REPLAYED} from 'react-dom/src/events/EventSystemFlags';
16
-import {SyntheticMouseEvent, SyntheticPointerEvent} from '../SyntheticEvent';
16
+import {
17
+ SyntheticEvent,
18
+ MouseEventInterface,
19
+ PointerEventInterface,
20
+} from '../SyntheticEvent';
21
import {
22
getClosestInstanceFromNode,
23
getNodeFromInstance,
@@ -113,7 +117,7 @@ function extractEvents(
117
let eventInterface, leaveEventType, enterEventType, eventTypePrefix;
118
119
if (topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_MOUSE_OVER) {
116
- eventInterface = SyntheticMouseEvent;
120
+ eventInterface = MouseEventInterface;
121
leaveEventType = 'onMouseLeave';
122
enterEventType = 'onMouseEnter';
123
eventTypePrefix = 'mouse';
@@ -121,7 +125,7 @@ function extractEvents(
125
topLevelType === TOP_POINTER_OUT ||
126
topLevelType === TOP_POINTER_OVER
127
) {
124
- eventInterface = SyntheticPointerEvent;
128
+ eventInterface = PointerEventInterface;
129
leaveEventType = 'onPointerLeave';
130
enterEventType = 'onPointerEnter';
131
eventTypePrefix = 'pointer';
@@ -130,21 +134,23 @@ function extractEvents(
134
const fromNode = from == null ? win : getNodeFromInstance(from);
135
const toNode = to == null ? win : getNodeFromInstance(to);
136
133
- const leave = new eventInterface(
137
+ const leave = new SyntheticEvent(
138
leaveEventType,
139
from,
140
nativeEvent,
141
nativeEventTarget,
142
+ eventInterface,
143
);
144
leave.type = eventTypePrefix + 'leave';
145
leave.target = fromNode;
146
leave.relatedTarget = toNode;
147
143
- let enter = new eventInterface(
148
+ let enter = new SyntheticEvent(
149
enterEventType,
150
to,
151
nativeEvent,
152
nativeEventTarget,
153
+ eventInterface,
154
);
155
enter.type = eventTypePrefix + 'enter';
156
enter.target = toNode;
packages/react-dom/src/events/plugins/SimpleEventPlugin.js
+25
-25
@@ -15,17 +15,17 @@ import type {EventSystemFlags} from '../EventSystemFlags';
15
16
import {
17
SyntheticEvent,
18
- SyntheticAnimationEvent,
19
- SyntheticClipboardEvent,
20
- SyntheticFocusEvent,
21
- SyntheticKeyboardEvent,
22
- SyntheticMouseEvent,
23
- SyntheticPointerEvent,
24
- SyntheticDragEvent,
25
- SyntheticTouchEvent,
26
- SyntheticTransitionEvent,
27
- SyntheticUIEvent,
28
- SyntheticWheelEvent,
18
+ AnimationEventInterface,
19
+ ClipboardEventInterface,
20
+ FocusEventInterface,
21
+ KeyboardEventInterface,
22
+ MouseEventInterface,
23
+ PointerEventInterface,
24
+ DragEventInterface,
25
+ TouchEventInterface,
26
+ TransitionEventInterface,
27
+ UIEventInterface,
28
+ WheelEventInterface,
29
} from '../../events/SyntheticEvent';
30
31
import * as DOMTopLevelEventTypes from '../DOMTopLevelEventTypes';
@@ -57,7 +57,7 @@ function extractEvents(
57
if (reactName === undefined) {
58
return;
59
}
60
- let EventConstructor;
60
+ let EventInterface;
61
switch (topLevelType) {
62
case DOMTopLevelEventTypes.TOP_KEY_PRESS:
63
// Firefox creates a keypress event for function keys too. This removes
@@ -69,13 +69,13 @@ function extractEvents(
69
/* falls through */
70
case DOMTopLevelEventTypes.TOP_KEY_DOWN:
71
case DOMTopLevelEventTypes.TOP_KEY_UP:
72
- EventConstructor = SyntheticKeyboardEvent;
72
+ EventInterface = KeyboardEventInterface;
73
break;
74
case DOMTopLevelEventTypes.TOP_FOCUS_IN:
75
case DOMTopLevelEventTypes.TOP_FOCUS_OUT:
76
case DOMTopLevelEventTypes.TOP_BEFORE_BLUR:
77
case DOMTopLevelEventTypes.TOP_AFTER_BLUR:
78
- EventConstructor = SyntheticFocusEvent;
78
+ EventInterface = FocusEventInterface;
79
break;
80
case DOMTopLevelEventTypes.TOP_CLICK:
81
// Firefox creates a click event on right mouse clicks. This removes the
@@ -94,7 +94,7 @@ function extractEvents(
94
case DOMTopLevelEventTypes.TOP_MOUSE_OUT:
95
case DOMTopLevelEventTypes.TOP_MOUSE_OVER:
96
case DOMTopLevelEventTypes.TOP_CONTEXT_MENU:
97
- EventConstructor = SyntheticMouseEvent;
97
+ EventInterface = MouseEventInterface;
98
break;
99
case DOMTopLevelEventTypes.TOP_DRAG:
100
case DOMTopLevelEventTypes.TOP_DRAG_END:
@@ -104,32 +104,32 @@ function extractEvents(
104
case DOMTopLevelEventTypes.TOP_DRAG_OVER:
105
case DOMTopLevelEventTypes.TOP_DRAG_START:
106
case DOMTopLevelEventTypes.TOP_DROP:
107
- EventConstructor = SyntheticDragEvent;
107
+ EventInterface = DragEventInterface;
108
break;
109
case DOMTopLevelEventTypes.TOP_TOUCH_CANCEL:
110
case DOMTopLevelEventTypes.TOP_TOUCH_END:
111
case DOMTopLevelEventTypes.TOP_TOUCH_MOVE:
112
case DOMTopLevelEventTypes.TOP_TOUCH_START:
113
- EventConstructor = SyntheticTouchEvent;
113
+ EventInterface = TouchEventInterface;
114
break;
115
case DOMTopLevelEventTypes.TOP_ANIMATION_END:
116
case DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION:
117
case DOMTopLevelEventTypes.TOP_ANIMATION_START:
118
- EventConstructor = SyntheticAnimationEvent;
118
+ EventInterface = AnimationEventInterface;
119
break;
120
case DOMTopLevelEventTypes.TOP_TRANSITION_END:
121
- EventConstructor = SyntheticTransitionEvent;
121
+ EventInterface = TransitionEventInterface;
122
break;
123
case DOMTopLevelEventTypes.TOP_SCROLL:
124
- EventConstructor = SyntheticUIEvent;
124
+ EventInterface = UIEventInterface;
125
break;
126
case DOMTopLevelEventTypes.TOP_WHEEL:
127
- EventConstructor = SyntheticWheelEvent;
127
+ EventInterface = WheelEventInterface;
128
break;
129
case DOMTopLevelEventTypes.TOP_COPY:
130
case DOMTopLevelEventTypes.TOP_CUT:
131
case DOMTopLevelEventTypes.TOP_PASTE:
132
- EventConstructor = SyntheticClipboardEvent;
132
+ EventInterface = ClipboardEventInterface;
133
break;
134
case DOMTopLevelEventTypes.TOP_GOT_POINTER_CAPTURE:
135
case DOMTopLevelEventTypes.TOP_LOST_POINTER_CAPTURE:
@@ -139,18 +139,18 @@ function extractEvents(
139
case DOMTopLevelEventTypes.TOP_POINTER_OUT:
140
case DOMTopLevelEventTypes.TOP_POINTER_OVER:
141
case DOMTopLevelEventTypes.TOP_POINTER_UP:
142
- EventConstructor = SyntheticPointerEvent;
142
+ EventInterface = PointerEventInterface;
143
break;
144
default:
145
// Unknown event. This is used by createEventHandle.
146
- EventConstructor = SyntheticEvent;
146
break;
147
}
149
- const event = new EventConstructor(
148
+ const event = new SyntheticEvent(
149
reactName,
150
null,
151
nativeEvent,
152
nativeEventTarget,
153
+ EventInterface,
154
);
155
156
const inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0;