Separate SyntheticEvent constructors to prevent deopts (#19907)
* Remove arguments from hot path * Make SyntheticEvent subtypes monomorphic * Maybe fix Flow?
Dan Abramov committed
Sep 25, 2020 at 11:31 UTC
1890159a5d362e76ee949dfcace1ccb9677abc45
4 files changed
+191
-172
packages/react-dom/src/events/SyntheticEvent.js
+156
-127
@@ -15,21 +15,6 @@ type EventInterfaceType = {
15
[propName: string]: 0 | ((event: {[propName: string]: mixed}) => mixed),
16
};
17
18
-/**
19
- * @interface Event
20
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
21
- */
22
-const EventInterface: EventInterfaceType = {
23
- eventPhase: 0,
24
- bubbles: 0,
25
- cancelable: 0,
26
- timeStamp: function(event) {
27
- return event.timeStamp || Date.now();
28
- },
29
- defaultPrevented: 0,
30
- isTrusted: 0,
31
-};
32
-
18
function functionThatReturnsTrue() {
19
return true;
20
}
@@ -38,119 +23,140 @@ function functionThatReturnsFalse() {
23
return false;
24
}
25
41
-/**
42
- * Synthetic events are dispatched by event plugins, typically in response to a
43
- * top-level event delegation handler.
44
- *
45
- * These systems should generally use pooling to reduce the frequency of garbage
46
- * collection. The system should check `isPersistent` to determine whether the
47
- * event should be released into the pool after being dispatched. Users that
48
- * need a persisted event should invoke `persist`.
49
- *
50
- * Synthetic events (and subclasses) implement the DOM Level 3 Events API by
51
- * normalizing browser quirks. Subclasses do not necessarily have to implement a
52
- * DOM interface; custom application-specific events can also subclass this.
53
- */
54
-export function SyntheticEvent(
55
- reactName: string | null,
56
- reactEventType: string,
57
- targetInst: Fiber,
58
- nativeEvent: {[propName: string]: mixed},
59
- nativeEventTarget: null | EventTarget,
60
- Interface: EventInterfaceType = EventInterface,
61
-) {
62
- this._reactName = reactName;
63
- this._targetInst = targetInst;
64
- this.type = reactEventType;
65
- this.nativeEvent = nativeEvent;
66
- this.target = nativeEventTarget;
67
- this.currentTarget = null;
68
-
69
- for (const propName in Interface) {
70
- if (!Interface.hasOwnProperty(propName)) {
71
- continue;
26
+// This is intentionally a factory so that we have different returned constructors.
27
+// If we had a single constructor, it would be megamorphic and engines would deopt.
28
+function createSyntheticEvent(Interface: EventInterfaceType) {
29
+ /**
30
+ * Synthetic events are dispatched by event plugins, typically in response to a
31
+ * top-level event delegation handler.
32
+ *
33
+ * These systems should generally use pooling to reduce the frequency of garbage
34
+ * collection. The system should check `isPersistent` to determine whether the
35
+ * event should be released into the pool after being dispatched. Users that
36
+ * need a persisted event should invoke `persist`.
37
+ *
38
+ * Synthetic events (and subclasses) implement the DOM Level 3 Events API by
39
+ * normalizing browser quirks. Subclasses do not necessarily have to implement a
40
+ * DOM interface; custom application-specific events can also subclass this.
41
+ */
42
+ function SyntheticBaseEvent(
43
+ reactName: string | null,
44
+ reactEventType: string,
45
+ targetInst: Fiber,
46
+ nativeEvent: {[propName: string]: mixed},
47
+ nativeEventTarget: null | EventTarget,
48
+ ) {
49
+ this._reactName = reactName;
50
+ this._targetInst = targetInst;
51
+ this.type = reactEventType;
52
+ this.nativeEvent = nativeEvent;
53
+ this.target = nativeEventTarget;
54
+ this.currentTarget = null;
55
+
56
+ for (const propName in Interface) {
57
+ if (!Interface.hasOwnProperty(propName)) {
58
+ continue;
59
+ }
60
+ const normalize = Interface[propName];
61
+ if (normalize) {
62
+ this[propName] = normalize(nativeEvent);
63
+ } else {
64
+ this[propName] = nativeEvent[propName];
65
+ }
66
}
73
- const normalize = Interface[propName];
74
- if (normalize) {
75
- this[propName] = normalize(nativeEvent);
67
+
68
+ const defaultPrevented =
69
+ nativeEvent.defaultPrevented != null
70
+ ? nativeEvent.defaultPrevented
71
+ : nativeEvent.returnValue === false;
72
+ if (defaultPrevented) {
73
+ this.isDefaultPrevented = functionThatReturnsTrue;
74
} else {
77
- this[propName] = nativeEvent[propName];
75
+ this.isDefaultPrevented = functionThatReturnsFalse;
76
}
77
+ this.isPropagationStopped = functionThatReturnsFalse;
78
+ return this;
79
}
80
81
- const defaultPrevented =
82
- nativeEvent.defaultPrevented != null
83
- ? nativeEvent.defaultPrevented
84
- : nativeEvent.returnValue === false;
85
- if (defaultPrevented) {
86
- this.isDefaultPrevented = functionThatReturnsTrue;
87
- } else {
88
- this.isDefaultPrevented = functionThatReturnsFalse;
89
- }
90
- this.isPropagationStopped = functionThatReturnsFalse;
91
- return this;
81
+ Object.assign(SyntheticBaseEvent.prototype, {
82
+ preventDefault: function() {
83
+ this.defaultPrevented = true;
84
+ const event = this.nativeEvent;
85
+ if (!event) {
86
+ return;
87
+ }
88
+
89
+ if (event.preventDefault) {
90
+ event.preventDefault();
91
+ // $FlowFixMe - flow is not aware of `unknown` in IE
92
+ } else if (typeof event.returnValue !== 'unknown') {
93
+ event.returnValue = false;
94
+ }
95
+ this.isDefaultPrevented = functionThatReturnsTrue;
96
+ },
97
+
98
+ stopPropagation: function() {
99
+ const event = this.nativeEvent;
100
+ if (!event) {
101
+ return;
102
+ }
103
+
104
+ if (event.stopPropagation) {
105
+ event.stopPropagation();
106
+ // $FlowFixMe - flow is not aware of `unknown` in IE
107
+ } else if (typeof event.cancelBubble !== 'unknown') {
108
+ // The ChangeEventPlugin registers a "propertychange" event for
109
+ // IE. This event does not support bubbling or cancelling, and
110
+ // any references to cancelBubble throw "Member not found". A
111
+ // typeof check of "unknown" circumvents this issue (and is also
112
+ // IE specific).
113
+ event.cancelBubble = true;
114
+ }
115
+
116
+ this.isPropagationStopped = functionThatReturnsTrue;
117
+ },
118
+
119
+ /**
120
+ * We release all dispatched `SyntheticEvent`s after each event loop, adding
121
+ * them back into the pool. This allows a way to hold onto a reference that
122
+ * won't be added back into the pool.
123
+ */
124
+ persist: function() {
125
+ // Modern event system doesn't use pooling.
126
+ },
127
+
128
+ /**
129
+ * Checks if this event should be released back into the pool.
130
+ *
131
+ * @return {boolean} True if this should not be released, false otherwise.
132
+ */
133
+ isPersistent: functionThatReturnsTrue,
134
+ });
135
+ return SyntheticBaseEvent;
136
}
137
94
-Object.assign(SyntheticEvent.prototype, {
95
- preventDefault: function() {
96
- this.defaultPrevented = true;
97
- const event = this.nativeEvent;
98
- if (!event) {
99
- return;
100
- }
101
-
102
- if (event.preventDefault) {
103
- event.preventDefault();
104
- // $FlowFixMe - flow is not aware of `unknown` in IE
105
- } else if (typeof event.returnValue !== 'unknown') {
106
- event.returnValue = false;
107
- }
108
- this.isDefaultPrevented = functionThatReturnsTrue;
109
- },
110
-
111
- stopPropagation: function() {
112
- const event = this.nativeEvent;
113
- if (!event) {
114
- return;
115
- }
116
-
117
- if (event.stopPropagation) {
118
- event.stopPropagation();
119
- // $FlowFixMe - flow is not aware of `unknown` in IE
120
- } else if (typeof event.cancelBubble !== 'unknown') {
121
- // The ChangeEventPlugin registers a "propertychange" event for
122
- // IE. This event does not support bubbling or cancelling, and
123
- // any references to cancelBubble throw "Member not found". A
124
- // typeof check of "unknown" circumvents this issue (and is also
125
- // IE specific).
126
- event.cancelBubble = true;
127
- }
128
-
129
- this.isPropagationStopped = functionThatReturnsTrue;
130
- },
131
-
132
- /**
133
- * We release all dispatched `SyntheticEvent`s after each event loop, adding
134
- * them back into the pool. This allows a way to hold onto a reference that
135
- * won't be added back into the pool.
136
- */
137
- persist: function() {
138
- // Modern event system doesn't use pooling.
138
+/**
139
+ * @interface Event
140
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
141
+ */
142
+const EventInterface = {
143
+ eventPhase: 0,
144
+ bubbles: 0,
145
+ cancelable: 0,
146
+ timeStamp: function(event) {
147
+ return event.timeStamp || Date.now();
148
},
149
+ defaultPrevented: 0,
150
+ isTrusted: 0,
151
+};
152
+export const SyntheticEvent = createSyntheticEvent(EventInterface);
153
141
- /**
142
- * Checks if this event should be released back into the pool.
143
- *
144
- * @return {boolean} True if this should not be released, false otherwise.
145
- */
146
- isPersistent: functionThatReturnsTrue,
147
-});
148
-
149
-export const UIEventInterface: EventInterfaceType = {
154
+const UIEventInterface: EventInterfaceType = {
155
...EventInterface,
156
view: 0,
157
detail: 0,
158
};
159
+export const SyntheticUIEvent = createSyntheticEvent(UIEventInterface);
160
161
let lastMovementX;
162
let lastMovementY;
@@ -173,7 +179,7 @@ function updateMouseMovementPolyfillState(event) {
179
* @interface MouseEvent
180
* @see http://www.w3.org/TR/DOM-Level-3-Events/
181
*/
176
-export const MouseEventInterface: EventInterfaceType = {
182
+const MouseEventInterface: EventInterfaceType = {
183
...UIEventInterface,
184
screenX: 0,
185
screenY: 0,
@@ -213,42 +219,48 @@ export const MouseEventInterface: EventInterfaceType = {
219
return lastMovementY;
220
},
221
};
222
+export const SyntheticMouseEvent = createSyntheticEvent(MouseEventInterface);
223
224
/**
225
* @interface DragEvent
226
* @see http://www.w3.org/TR/DOM-Level-3-Events/
227
*/
221
-export const DragEventInterface: EventInterfaceType = {
228
+const DragEventInterface: EventInterfaceType = {
229
...MouseEventInterface,
230
dataTransfer: 0,
231
};
232
+export const SyntheticDragEvent = createSyntheticEvent(DragEventInterface);
233
234
/**
235
* @interface FocusEvent
236
* @see http://www.w3.org/TR/DOM-Level-3-Events/
237
*/
230
-export const FocusEventInterface: EventInterfaceType = {
238
+const FocusEventInterface: EventInterfaceType = {
239
...UIEventInterface,
240
relatedTarget: 0,
241
};
242
+export const SyntheticFocusEvent = createSyntheticEvent(FocusEventInterface);
243
244
/**
245
* @interface Event
246
* @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface
247
* @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent
248
*/
240
-export const AnimationEventInterface: EventInterfaceType = {
249
+const AnimationEventInterface: EventInterfaceType = {
250
...EventInterface,
251
animationName: 0,
252
elapsedTime: 0,
253
pseudoElement: 0,
254
};
255
+export const SyntheticAnimationEvent = createSyntheticEvent(
256
+ AnimationEventInterface,
257
+);
258
259
/**
260
* @interface Event
261
* @see http://www.w3.org/TR/clipboard-apis/
262
*/
251
-export const ClipboardEventInterface: EventInterfaceType = {
263
+const ClipboardEventInterface: EventInterfaceType = {
264
...EventInterface,
265
clipboardData: function(event) {
266
return 'clipboardData' in event
@@ -256,15 +268,21 @@ export const ClipboardEventInterface: EventInterfaceType = {
268
: window.clipboardData;
269
},
270
};
271
+export const SyntheticClipboardEvent = createSyntheticEvent(
272
+ ClipboardEventInterface,
273
+);
274
275
/**
276
* @interface Event
277
* @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents
278
*/
264
-export const CompositionEventInterface: EventInterfaceType = {
279
+const CompositionEventInterface: EventInterfaceType = {
280
...EventInterface,
281
data: 0,
282
};
283
+export const SyntheticCompositionEvent = createSyntheticEvent(
284
+ CompositionEventInterface,
285
+);
286
287
/**
288
* @interface Event
@@ -272,7 +290,7 @@ export const CompositionEventInterface: EventInterfaceType = {
290
* /#events-inputevents
291
*/
292
// Happens to share the same list for now.
275
-export const InputEventInterface: EventInterfaceType = CompositionEventInterface;
293
+export const SyntheticInputEvent = SyntheticCompositionEvent;
294
295
/**
296
* Normalization of deprecated HTML5 `key` values
@@ -402,7 +420,7 @@ function getEventModifierState(nativeEvent) {
420
* @interface KeyboardEvent
421
* @see http://www.w3.org/TR/DOM-Level-3-Events/
422
*/
405
-export const KeyboardEventInterface = {
423
+const KeyboardEventInterface = {
424
...UIEventInterface,
425
key: getEventKey,
426
code: 0,
@@ -451,12 +469,15 @@ export const KeyboardEventInterface = {
469
return 0;
470
},
471
};
472
+export const SyntheticKeyboardEvent = createSyntheticEvent(
473
+ KeyboardEventInterface,
474
+);
475
476
/**
477
* @interface PointerEvent
478
* @see http://www.w3.org/TR/pointerevents/
479
*/
459
-export const PointerEventInterface = {
480
+const PointerEventInterface = {
481
...MouseEventInterface,
482
pointerId: 0,
483
width: 0,
@@ -469,12 +490,15 @@ export const PointerEventInterface = {
490
pointerType: 0,
491
isPrimary: 0,
492
};
493
+export const SyntheticPointerEvent = createSyntheticEvent(
494
+ PointerEventInterface,
495
+);
496
497
/**
498
* @interface TouchEvent
499
* @see http://www.w3.org/TR/touch-events/
500
*/
477
-export const TouchEventInterface = {
501
+const TouchEventInterface = {
502
...UIEventInterface,
503
touches: 0,
504
targetTouches: 0,
@@ -485,24 +509,28 @@ export const TouchEventInterface = {
509
shiftKey: 0,
510
getModifierState: getEventModifierState,
511
};
512
+export const SyntheticTouchEvent = createSyntheticEvent(TouchEventInterface);
513
514
/**
515
* @interface Event
516
* @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events-
517
* @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent
518
*/
494
-export const TransitionEventInterface = {
519
+const TransitionEventInterface = {
520
...EventInterface,
521
propertyName: 0,
522
elapsedTime: 0,
523
pseudoElement: 0,
524
};
525
+export const SyntheticTransitionEvent = createSyntheticEvent(
526
+ TransitionEventInterface,
527
+);
528
529
/**
530
* @interface WheelEvent
531
* @see http://www.w3.org/TR/DOM-Level-3-Events/
532
*/
505
-export const WheelEventInterface = {
533
+const WheelEventInterface = {
534
...MouseEventInterface,
535
deltaX(event) {
536
return 'deltaX' in event
@@ -531,3 +559,4 @@ export const WheelEventInterface = {
559
// ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size.
560
deltaMode: 0,
561
};
562
+export const SyntheticWheelEvent = createSyntheticEvent(WheelEventInterface);
packages/react-dom/src/events/plugins/BeforeInputEventPlugin.js
+4
-7
@@ -22,9 +22,8 @@ import {
22
reset as FallbackCompositionStateReset,
23
} from '../FallbackCompositionState';
24
import {
25
- CompositionEventInterface,
26
- InputEventInterface,
27
- SyntheticEvent,
25
+ SyntheticCompositionEvent,
26
+ SyntheticInputEvent,
27
} from '../SyntheticEvent';
28
import {accumulateTwoPhaseListeners} from '../DOMPluginEventSystem';
29
@@ -227,13 +226,12 @@ function extractCompositionEvent(
226
}
227
}
228
230
- const event = new SyntheticEvent(
229
+ const event = new SyntheticCompositionEvent(
230
eventType,
231
domEventName,
232
null,
233
nativeEvent,
234
nativeEventTarget,
236
- CompositionEventInterface,
235
);
236
accumulateTwoPhaseListeners(targetInst, dispatchQueue, event);
237
@@ -396,13 +394,12 @@ function extractBeforeInputEvent(
394
return null;
395
}
396
399
- const event = new SyntheticEvent(
397
+ const event = new SyntheticInputEvent(
398
'onBeforeInput',
399
'beforeinput',
400
null,
401
nativeEvent,
402
nativeEventTarget,
405
- InputEventInterface,
403
);
404
accumulateTwoPhaseListeners(targetInst, dispatchQueue, event);
405
event.data = chars;
packages/react-dom/src/events/plugins/EnterLeaveEventPlugin.js
+5
-11
@@ -14,11 +14,7 @@ import type {EventSystemFlags} from '../EventSystemFlags';
14
15
import {registerDirectEvent} from '../EventRegistry';
16
import {IS_REPLAYED} from 'react-dom/src/events/EventSystemFlags';
17
-import {
18
- SyntheticEvent,
19
- MouseEventInterface,
20
- PointerEventInterface,
21
-} from '../SyntheticEvent';
17
+import {SyntheticMouseEvent, SyntheticPointerEvent} from '../SyntheticEvent';
18
import {
19
getClosestInstanceFromNode,
20
getNodeFromInstance,
@@ -123,12 +119,12 @@ function extractEvents(
119
return;
120
}
121
126
- let eventInterface = MouseEventInterface;
122
+ let SyntheticEventCtor = SyntheticMouseEvent;
123
let leaveEventType = 'onMouseLeave';
124
let enterEventType = 'onMouseEnter';
125
let eventTypePrefix = 'mouse';
126
if (domEventName === 'pointerout' || domEventName === 'pointerover') {
131
- eventInterface = PointerEventInterface;
127
+ SyntheticEventCtor = SyntheticPointerEvent;
128
leaveEventType = 'onPointerLeave';
129
enterEventType = 'onPointerEnter';
130
eventTypePrefix = 'pointer';
@@ -137,13 +133,12 @@ function extractEvents(
133
const fromNode = from == null ? win : getNodeFromInstance(from);
134
const toNode = to == null ? win : getNodeFromInstance(to);
135
140
- const leave = new SyntheticEvent(
136
+ const leave = new SyntheticEventCtor(
137
leaveEventType,
138
eventTypePrefix + 'leave',
139
from,
140
nativeEvent,
141
nativeEventTarget,
146
- eventInterface,
142
);
143
leave.target = fromNode;
144
leave.relatedTarget = toNode;
@@ -154,13 +149,12 @@ function extractEvents(
149
// the first ancestor. Next time, we will ignore the event.
150
const nativeTargetInst = getClosestInstanceFromNode((nativeEventTarget: any));
151
if (nativeTargetInst === targetInst) {
157
- const enterEvent: KnownReactSyntheticEvent = new SyntheticEvent(
152
+ const enterEvent: KnownReactSyntheticEvent = new SyntheticEventCtor(
153
enterEventType,
154
eventTypePrefix + 'enter',
155
to,
156
nativeEvent,
157
nativeEventTarget,
163
- eventInterface,
158
);
159
enterEvent.target = toNode;
160
enterEvent.relatedTarget = fromNode;
packages/react-dom/src/events/plugins/SimpleEventPlugin.js
+26
-27
@@ -15,17 +15,17 @@ import type {EventSystemFlags} from '../EventSystemFlags';
15
16
import {
17
SyntheticEvent,
18
- AnimationEventInterface,
19
- ClipboardEventInterface,
20
- FocusEventInterface,
21
- KeyboardEventInterface,
22
- MouseEventInterface,
23
- PointerEventInterface,
24
- DragEventInterface,
25
- TouchEventInterface,
26
- TransitionEventInterface,
27
- UIEventInterface,
28
- WheelEventInterface,
18
+ SyntheticKeyboardEvent,
19
+ SyntheticFocusEvent,
20
+ SyntheticMouseEvent,
21
+ SyntheticDragEvent,
22
+ SyntheticTouchEvent,
23
+ SyntheticAnimationEvent,
24
+ SyntheticTransitionEvent,
25
+ SyntheticUIEvent,
26
+ SyntheticWheelEvent,
27
+ SyntheticClipboardEvent,
28
+ SyntheticPointerEvent,
29
} from '../../events/SyntheticEvent';
30
31
import {
@@ -62,7 +62,7 @@ function extractEvents(
62
if (reactName === undefined) {
63
return;
64
}
65
- let EventInterface;
65
+ let SyntheticEventCtor = SyntheticEvent;
66
let reactEventType = domEventName;
67
switch (domEventName) {
68
case 'keypress':
@@ -75,19 +75,19 @@ function extractEvents(
75
/* falls through */
76
case 'keydown':
77
case 'keyup':
78
- EventInterface = KeyboardEventInterface;
78
+ SyntheticEventCtor = SyntheticKeyboardEvent;
79
break;
80
case 'focusin':
81
reactEventType = 'focus';
82
- EventInterface = FocusEventInterface;
82
+ SyntheticEventCtor = SyntheticFocusEvent;
83
break;
84
case 'focusout':
85
reactEventType = 'blur';
86
- EventInterface = FocusEventInterface;
86
+ SyntheticEventCtor = SyntheticFocusEvent;
87
break;
88
case 'beforeblur':
89
case 'afterblur':
90
- EventInterface = FocusEventInterface;
90
+ SyntheticEventCtor = SyntheticFocusEvent;
91
break;
92
case 'click':
93
// Firefox creates a click event on right mouse clicks. This removes the
@@ -106,7 +106,7 @@ function extractEvents(
106
case 'mouseout':
107
case 'mouseover':
108
case 'contextmenu':
109
- EventInterface = MouseEventInterface;
109
+ SyntheticEventCtor = SyntheticMouseEvent;
110
break;
111
case 'drag':
112
case 'dragend':
@@ -116,32 +116,32 @@ function extractEvents(
116
case 'dragover':
117
case 'dragstart':
118
case 'drop':
119
- EventInterface = DragEventInterface;
119
+ SyntheticEventCtor = SyntheticDragEvent;
120
break;
121
case 'touchcancel':
122
case 'touchend':
123
case 'touchmove':
124
case 'touchstart':
125
- EventInterface = TouchEventInterface;
125
+ SyntheticEventCtor = SyntheticTouchEvent;
126
break;
127
case ANIMATION_END:
128
case ANIMATION_ITERATION:
129
case ANIMATION_START:
130
- EventInterface = AnimationEventInterface;
130
+ SyntheticEventCtor = SyntheticAnimationEvent;
131
break;
132
case TRANSITION_END:
133
- EventInterface = TransitionEventInterface;
133
+ SyntheticEventCtor = SyntheticTransitionEvent;
134
break;
135
case 'scroll':
136
- EventInterface = UIEventInterface;
136
+ SyntheticEventCtor = SyntheticUIEvent;
137
break;
138
case 'wheel':
139
- EventInterface = WheelEventInterface;
139
+ SyntheticEventCtor = SyntheticWheelEvent;
140
break;
141
case 'copy':
142
case 'cut':
143
case 'paste':
144
- EventInterface = ClipboardEventInterface;
144
+ SyntheticEventCtor = SyntheticClipboardEvent;
145
break;
146
case 'gotpointercapture':
147
case 'lostpointercapture':
@@ -151,19 +151,18 @@ function extractEvents(
151
case 'pointerout':
152
case 'pointerover':
153
case 'pointerup':
154
- EventInterface = PointerEventInterface;
154
+ SyntheticEventCtor = SyntheticPointerEvent;
155
break;
156
default:
157
// Unknown event. This is used by createEventHandle.
158
break;
159
}
160
- const event = new SyntheticEvent(
160
+ const event = new SyntheticEventCtor(
161
reactName,
162
reactEventType,
163
null,
164
nativeEvent,
165
nativeEventTarget,
166
- EventInterface,
166
);
167
168
const inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0;