@samitouri / QOS-React / commits / 76ce685d0f

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;