Enable modern event system and delete dead code (#19230)
Dan Abramov committed
Jul 1, 2020 at 17:43 UTC
9fba65efa50fe5f38e5664729d4aa6f85cf7be92
52 files changed
+205
-7155
packages/react-dom/src/__tests__/ReactDOM-test.js
+1
-4
@@ -357,10 +357,7 @@ describe('ReactDOM', () => {
357
ReactDOM.render(<Wrapper />, container);
358
let expected;
359
360
- if (
361
- ReactFeatureFlags.enableModernEventSystem &
362
- ReactFeatureFlags.enableLegacyFBSupport
363
- ) {
360
+ if (ReactFeatureFlags.enableLegacyFBSupport) {
361
// We expect to duplicate the 2nd handler because this test is
362
// not really designed around how the legacy FB support system works.
363
// This is because the above test sync fires a click() event
packages/react-dom/src/__tests__/ReactDOMComponent-test.js
+1
-4
@@ -2719,10 +2719,7 @@ describe('ReactDOMComponent', () => {
2719
// might depend on this.
2720
//
2721
// @see https://github.com/facebook/react/pull/12919#issuecomment-395224674
2722
- if (
2723
- ReactFeatureFlags.enableModernEventSystem &
2724
- ReactFeatureFlags.enableLegacyFBSupport
2725
- ) {
2722
+ if (ReactFeatureFlags.enableLegacyFBSupport) {
2723
// The order will change here, as the legacy FB support adds
2724
// the event listener onto the document after the one above has.
2725
expect(eventOrder).toEqual([
packages/react-dom/src/__tests__/ReactDOMEventListener-test.js
+22
-67
@@ -12,7 +12,6 @@
12
describe('ReactDOMEventListener', () => {
13
let React;
14
let ReactDOM;
15
- const ReactFeatureFlags = require('shared/ReactFeatureFlags');
15
16
beforeEach(() => {
17
jest.resetModules();
@@ -20,34 +19,6 @@ describe('ReactDOMEventListener', () => {
19
ReactDOM = require('react-dom');
20
});
21
23
- // We attached events to roots with the modern system,
24
- // so this test is no longer valid.
25
- if (!ReactFeatureFlags.enableModernEventSystem) {
26
- it('should dispatch events from outside React tree', () => {
27
- const mock = jest.fn();
28
-
29
- const container = document.createElement('div');
30
- const node = ReactDOM.render(<div onMouseEnter={mock} />, container);
31
- const otherNode = document.createElement('h1');
32
- document.body.appendChild(container);
33
- document.body.appendChild(otherNode);
34
-
35
- try {
36
- otherNode.dispatchEvent(
37
- new MouseEvent('mouseout', {
38
- bubbles: true,
39
- cancelable: true,
40
- relatedTarget: node,
41
- }),
42
- );
43
- expect(mock).toBeCalled();
44
- } finally {
45
- document.body.removeChild(container);
46
- document.body.removeChild(otherNode);
47
- }
48
- });
49
- }
50
-
22
describe('Propagation', () => {
23
it('should propagate events one level down', () => {
24
const mouseOut = jest.fn();
@@ -194,25 +165,19 @@ describe('ReactDOMEventListener', () => {
165
// The first call schedules a render of '1' into the 'Child'.
166
// However, we're batching so it isn't flushed yet.
167
expect(mock.mock.calls[0][0]).toBe('Child');
197
- if (ReactFeatureFlags.enableModernEventSystem) {
198
- // As we have two roots, it means we have two event listeners.
199
- // This also means we enter the event batching phase twice,
200
- // flushing the child to be 1.
201
-
202
- // We don't have any good way of knowing if another event will
203
- // occur because another event handler might invoke
204
- // stopPropagation() along the way. After discussions internally
205
- // with Sebastian, it seems that for now over-flushing should
206
- // be fine, especially as the new event system is a breaking
207
- // change anyway. We can maybe revisit this later as part of
208
- // the work to refine this in the scheduler (maybe by leveraging
209
- // isInputPending?).
210
- expect(mock.mock.calls[1][0]).toBe('1');
211
- } else {
212
- // The first call schedules a render of '2' into the 'Child'.
213
- // We're still batching so it isn't flushed yet either.
214
- expect(mock.mock.calls[1][0]).toBe('Child');
215
- }
168
+ // As we have two roots, it means we have two event listeners.
169
+ // This also means we enter the event batching phase twice,
170
+ // flushing the child to be 1.
171
+
172
+ // We don't have any good way of knowing if another event will
173
+ // occur because another event handler might invoke
174
+ // stopPropagation() along the way. After discussions internally
175
+ // with Sebastian, it seems that for now over-flushing should
176
+ // be fine, especially as the new event system is a breaking
177
+ // change anyway. We can maybe revisit this later as part of
178
+ // the work to refine this in the scheduler (maybe by leveraging
179
+ // isInputPending?).
180
+ expect(mock.mock.calls[1][0]).toBe('1');
181
// By the time we leave the handler, the second update is flushed.
182
expect(childNode.textContent).toBe('2');
183
} finally {
@@ -383,25 +348,15 @@ describe('ReactDOMEventListener', () => {
348
bubbles: false,
349
}),
350
);
386
- if (ReactFeatureFlags.enableModernEventSystem) {
387
- // As of the modern event system refactor, we now support
388
- // this on <img>. The reason for this, is because we now
389
- // attach all media events to the "root" or "portal" in the
390
- // capture phase, rather than the bubble phase. This allows
391
- // us to assign less event listeners to individual elements,
392
- // which also nicely allows us to support more without needing
393
- // to add more individual code paths to support various
394
- // events that do not bubble.
395
- expect(handleImgLoadStart).toHaveBeenCalledTimes(1);
396
- } else {
397
- // Historically, we happened to not support onLoadStart
398
- // on <img>, and this test documents that lack of support.
399
- // If we decide to support it in the future, we should change
400
- // this line to expect 1 call. Note that fixing this would
401
- // be simple but would require attaching a handler to each
402
- // <img>. So far nobody asked us for it.
403
- expect(handleImgLoadStart).toHaveBeenCalledTimes(0);
404
- }
351
+ // As of the modern event system refactor, we now support
352
+ // this on <img>. The reason for this, is because we now
353
+ // attach all media events to the "root" or "portal" in the
354
+ // capture phase, rather than the bubble phase. This allows
355
+ // us to assign less event listeners to individual elements,
356
+ // which also nicely allows us to support more without needing
357
+ // to add more individual code paths to support various
358
+ // events that do not bubble.
359
+ expect(handleImgLoadStart).toHaveBeenCalledTimes(1);
360
361
videoRef.current.dispatchEvent(
362
new ProgressEvent('loadstart', {
packages/react-dom/src/__tests__/ReactTestUtils-test.js
-94
@@ -15,8 +15,6 @@ import * as ReactDOM from 'react-dom';
15
import * as ReactDOMServer from 'react-dom/server';
16
import * as ReactTestUtils from 'react-dom/test-utils';
17
18
-const ReactFeatureFlags = require('shared/ReactFeatureFlags');
19
-
18
function getTestDocument(markup) {
19
const doc = document.implementation.createHTMLDocument('');
20
doc.open();
@@ -33,98 +31,6 @@ describe('ReactTestUtils', () => {
31
expect(Object.keys(ReactTestUtils.Simulate).sort()).toMatchSnapshot();
32
});
33
36
- if (!ReactFeatureFlags.enableModernEventSystem) {
37
- // SimulateNative API has been removed in the modern event system
38
- it('SimulateNative should have locally attached media events', () => {
39
- expect(Object.keys(ReactTestUtils.SimulateNative).sort()).toEqual([
40
- 'abort',
41
- 'animationEnd',
42
- 'animationIteration',
43
- 'animationStart',
44
- 'blur',
45
- 'canPlay',
46
- 'canPlayThrough',
47
- 'cancel',
48
- 'change',
49
- 'click',
50
- 'close',
51
- 'compositionEnd',
52
- 'compositionStart',
53
- 'compositionUpdate',
54
- 'contextMenu',
55
- 'copy',
56
- 'cut',
57
- 'doubleClick',
58
- 'drag',
59
- 'dragEnd',
60
- 'dragEnter',
61
- 'dragExit',
62
- 'dragLeave',
63
- 'dragOver',
64
- 'dragStart',
65
- 'drop',
66
- 'durationChange',
67
- 'emptied',
68
- 'encrypted',
69
- 'ended',
70
- 'error',
71
- 'focus',
72
- 'input',
73
- 'keyDown',
74
- 'keyPress',
75
- 'keyUp',
76
- 'load',
77
- 'loadStart',
78
- 'loadedData',
79
- 'loadedMetadata',
80
- 'mouseDown',
81
- 'mouseMove',
82
- 'mouseOut',
83
- 'mouseOver',
84
- 'mouseUp',
85
- 'paste',
86
- 'pause',
87
- 'play',
88
- 'playing',
89
- 'progress',
90
- 'rateChange',
91
- 'scroll',
92
- 'seeked',
93
- 'seeking',
94
- 'selectionChange',
95
- 'stalled',
96
- 'suspend',
97
- 'textInput',
98
- 'timeUpdate',
99
- 'toggle',
100
- 'touchCancel',
101
- 'touchEnd',
102
- 'touchMove',
103
- 'touchStart',
104
- 'transitionEnd',
105
- 'volumeChange',
106
- 'waiting',
107
- 'wheel',
108
- ]);
109
- });
110
-
111
- it('SimulateNative should warn about deprecation', () => {
112
- const container = document.createElement('div');
113
- const node = ReactDOM.render(<div />, container);
114
- expect(() =>
115
- ReactTestUtils.SimulateNative.click(node),
116
- ).toWarnDev(
117
- 'ReactTestUtils.SimulateNative is an undocumented API that does not match ' +
118
- 'how the browser dispatches events, and will be removed in a future major ' +
119
- 'version of React. If you rely on it for testing, consider attaching the root ' +
120
- 'DOM container to the document during the test, and then dispatching native browser ' +
121
- 'events by calling `node.dispatchEvent()` on the DOM nodes. Make sure to set ' +
122
- 'the `bubbles` flag to `true` when creating the native browser event.',
123
- {withoutStack: true},
124
- );
125
- });
126
- }
127
-
34
it('gives Jest mocks a passthrough implementation with mockComponent()', () => {
35
class MockedComponent extends React.Component {
36
render() {
packages/react-dom/src/__tests__/ReactTreeTraversal-test.js
+37
-83
@@ -11,7 +11,6 @@
11
12
let React;
13
let ReactDOM;
14
-const ReactFeatureFlags = require('shared/ReactFeatureFlags');
14
15
const ChildComponent = ({id, eventHandler}) => (
16
<div
@@ -204,89 +203,44 @@ describe('ReactTreeTraversal', () => {
203
expect(mockFn.mock.calls).toEqual(expectedCalls);
204
});
205
207
- // This will not work with the modern event system that
208
- // attaches event listeners to roots as the event below
209
- // is being triggered on a node that React does not listen
206
+ // The modern event system attaches event listeners to roots so the
207
+ // event below is being triggered on a node that React does not listen
208
// to any more. Instead we should fire mouseover.
211
- if (ReactFeatureFlags.enableModernEventSystem) {
212
- it('should enter from the window', () => {
213
- const enterNode = document.getElementById('P_P1_C1__DIV');
214
-
215
- const expectedCalls = [
216
- ['P', 'mouseenter'],
217
- ['P_P1', 'mouseenter'],
218
- ['P_P1_C1__DIV', 'mouseenter'],
219
- ];
220
-
221
- enterNode.dispatchEvent(
222
- new MouseEvent('mouseover', {
223
- bubbles: true,
224
- cancelable: true,
225
- relatedTarget: outerNode1,
226
- }),
227
- );
228
-
229
- expect(mockFn.mock.calls).toEqual(expectedCalls);
230
- });
231
- } else {
232
- it('should enter from the window', () => {
233
- const enterNode = document.getElementById('P_P1_C1__DIV');
234
-
235
- const expectedCalls = [
236
- ['P', 'mouseenter'],
237
- ['P_P1', 'mouseenter'],
238
- ['P_P1_C1__DIV', 'mouseenter'],
239
- ];
240
-
241
- outerNode1.dispatchEvent(
242
- new MouseEvent('mouseout', {
243
- bubbles: true,
244
- cancelable: true,
245
- relatedTarget: enterNode,
246
- }),
247
- );
248
-
249
- expect(mockFn.mock.calls).toEqual(expectedCalls);
250
- });
251
- }
252
-
253
- // This will not work with the modern event system that
254
- // attaches event listeners to roots as the event below
255
- // is being triggered on a node that React does not listen
256
- // to any more. Instead we should fire mouseover.
257
- if (ReactFeatureFlags.enableModernEventSystem) {
258
- it('should enter from the window to the shallowest', () => {
259
- const enterNode = document.getElementById('P');
260
-
261
- const expectedCalls = [['P', 'mouseenter']];
262
-
263
- enterNode.dispatchEvent(
264
- new MouseEvent('mouseover', {
265
- bubbles: true,
266
- cancelable: true,
267
- relatedTarget: outerNode1,
268
- }),
269
- );
270
-
271
- expect(mockFn.mock.calls).toEqual(expectedCalls);
272
- });
273
- } else {
274
- it('should enter from the window to the shallowest', () => {
275
- const enterNode = document.getElementById('P');
276
-
277
- const expectedCalls = [['P', 'mouseenter']];
278
-
279
- outerNode1.dispatchEvent(
280
- new MouseEvent('mouseout', {
281
- bubbles: true,
282
- cancelable: true,
283
- relatedTarget: enterNode,
284
- }),
285
- );
286
-
287
- expect(mockFn.mock.calls).toEqual(expectedCalls);
288
- });
289
- }
209
+ it('should enter from the window', () => {
210
+ const enterNode = document.getElementById('P_P1_C1__DIV');
211
+
212
+ const expectedCalls = [
213
+ ['P', 'mouseenter'],
214
+ ['P_P1', 'mouseenter'],
215
+ ['P_P1_C1__DIV', 'mouseenter'],
216
+ ];
217
+
218
+ enterNode.dispatchEvent(
219
+ new MouseEvent('mouseover', {
220
+ bubbles: true,
221
+ cancelable: true,
222
+ relatedTarget: outerNode1,
223
+ }),
224
+ );
225
+
226
+ expect(mockFn.mock.calls).toEqual(expectedCalls);
227
+ });
228
+
229
+ it('should enter from the window to the shallowest', () => {
230
+ const enterNode = document.getElementById('P');
231
+
232
+ const expectedCalls = [['P', 'mouseenter']];
233
+
234
+ enterNode.dispatchEvent(
235
+ new MouseEvent('mouseover', {
236
+ bubbles: true,
237
+ cancelable: true,
238
+ relatedTarget: outerNode1,
239
+ }),
240
+ );
241
+
242
+ expect(mockFn.mock.calls).toEqual(expectedCalls);
243
+ });
244
245
it('should leave to the window', () => {
246
const leaveNode = document.getElementById('P_P1_C1__DIV');
packages/react-dom/src/client/ReactDOMClientInjection.js
+9
-67
@@ -5,19 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import {setComponentTree} from '../legacy-events/EventPluginUtils';
9
-
10
-import {
11
- getFiberCurrentPropsFromNode,
12
- getInstanceFromNode,
13
- getNodeFromInstance,
14
-} from './ReactDOMComponentTree';
15
-
16
-import LegacyBeforeInputEventPlugin from '../events/plugins/LegacyBeforeInputEventPlugin';
17
-import LegacyChangeEventPlugin from '../events/plugins/LegacyChangeEventPlugin';
18
-import LegacyEnterLeaveEventPlugin from '../events/plugins/LegacyEnterLeaveEventPlugin';
19
-import LegacySelectEventPlugin from '../events/plugins/LegacySelectEventPlugin';
20
-import LegacySimpleEventPlugin from '../events/plugins/LegacySimpleEventPlugin';
8
+// TODO: remove this injection altogether.
9
10
import ModernBeforeInputEventPlugin from '../events/plugins/ModernBeforeInputEventPlugin';
11
import ModernChangeEventPlugin from '../events/plugins/ModernChangeEventPlugin';
@@ -25,58 +13,12 @@ import ModernEnterLeaveEventPlugin from '../events/plugins/ModernEnterLeaveEvent
13
import ModernSelectEventPlugin from '../events/plugins/ModernSelectEventPlugin';
14
import ModernSimpleEventPlugin from '../events/plugins/ModernSimpleEventPlugin';
15
28
-import {
29
- injectEventPluginOrder,
30
- injectEventPluginsByName,
31
- injectEventPlugins,
32
-} from '../legacy-events/EventPluginRegistry';
33
-import {enableModernEventSystem} from 'shared/ReactFeatureFlags';
34
-
35
-if (enableModernEventSystem) {
36
- injectEventPlugins([
37
- ModernSimpleEventPlugin,
38
- ModernEnterLeaveEventPlugin,
39
- ModernChangeEventPlugin,
40
- ModernSelectEventPlugin,
41
- ModernBeforeInputEventPlugin,
42
- ]);
43
-} else {
44
- /**
45
- * Specifies a deterministic ordering of `EventPlugin`s. A convenient way to
46
- * reason about plugins, without having to package every one of them. This
47
- * is better than having plugins be ordered in the same order that they
48
- * are injected because that ordering would be influenced by the packaging order.
49
- * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that
50
- * preventing default on events is convenient in `SimpleEventPlugin` handlers.
51
- */
52
- const DOMEventPluginOrder = [
53
- 'ResponderEventPlugin',
54
- 'SimpleEventPlugin',
55
- 'EnterLeaveEventPlugin',
56
- 'ChangeEventPlugin',
57
- 'SelectEventPlugin',
58
- 'BeforeInputEventPlugin',
59
- ];
60
-
61
- /**
62
- * Inject modules for resolving DOM hierarchy and plugin ordering.
63
- */
64
- injectEventPluginOrder(DOMEventPluginOrder);
65
- setComponentTree(
66
- getFiberCurrentPropsFromNode,
67
- getInstanceFromNode,
68
- getNodeFromInstance,
69
- );
16
+import {injectEventPlugins} from '../legacy-events/EventPluginRegistry';
17
71
- /**
72
- * Some important event plugins included by default (without having to require
73
- * them).
74
- */
75
- injectEventPluginsByName({
76
- SimpleEventPlugin: LegacySimpleEventPlugin,
77
- EnterLeaveEventPlugin: LegacyEnterLeaveEventPlugin,
78
- ChangeEventPlugin: LegacyChangeEventPlugin,
79
- SelectEventPlugin: LegacySelectEventPlugin,
80
- BeforeInputEventPlugin: LegacyBeforeInputEventPlugin,
81
- });
82
-}
18
+injectEventPlugins([
19
+ ModernSimpleEventPlugin,
20
+ ModernEnterLeaveEventPlugin,
21
+ ModernChangeEventPlugin,
22
+ ModernSelectEventPlugin,
23
+ ModernBeforeInputEventPlugin,
24
+]);
packages/react-dom/src/client/ReactDOMComponent.js
+16
-123
@@ -51,15 +51,6 @@ import {
51
import {track} from './inputValueTracking';
52
import setInnerHTML from './setInnerHTML';
53
import setTextContent from './setTextContent';
54
-import {
55
- TOP_ERROR,
56
- TOP_INVALID,
57
- TOP_LOAD,
58
- TOP_RESET,
59
- TOP_SUBMIT,
60
- TOP_TOGGLE,
61
-} from '../events/DOMTopLevelEventTypes';
62
-import {mediaEventTypes} from '../events/DOMTopLevelEventTypes';
54
import {
55
createDangerousStringForStyles,
56
setValueForStyles,
@@ -74,7 +65,6 @@ import {
65
import assertValidProps from '../shared/assertValidProps';
66
import {
67
DOCUMENT_NODE,
77
- DOCUMENT_FRAGMENT_NODE,
68
ELEMENT_NODE,
69
COMMENT_NODE,
70
} from '../shared/HTMLNodeType';
@@ -88,12 +78,7 @@ import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols';
78
import {
79
enableDeprecatedFlareAPI,
80
enableTrustedTypesIntegration,
91
- enableModernEventSystem,
81
} from 'shared/ReactFeatureFlags';
93
-import {
94
- legacyListenToEvent,
95
- legacyTrapBubbledEvent,
96
-} from '../events/DOMLegacyEventPluginSystem';
82
import {listenToEvent} from '../events/DOMModernPluginEventSystem';
83
import {getEventListenerMap} from './ReactDOMComponentTree';
84
@@ -273,33 +258,22 @@ export function ensureListeningTo(
258
rootContainerInstance: Element | Node,
259
registrationName: string,
260
): void {
276
- if (enableModernEventSystem) {
277
- // If we have a comment node, then use the parent node,
278
- // which should be an element.
279
- const rootContainerElement =
280
- rootContainerInstance.nodeType === COMMENT_NODE
281
- ? rootContainerInstance.parentNode
282
- : rootContainerInstance;
283
- // Containers should only ever be element nodes. We do not
284
- // want to register events to document fragments or documents
285
- // with the modern plugin event system.
286
- invariant(
287
- rootContainerElement != null &&
288
- rootContainerElement.nodeType === ELEMENT_NODE,
289
- 'ensureListeningTo(): received a container that was not an element node. ' +
290
- 'This is likely a bug in React.',
291
- );
292
- listenToEvent(registrationName, ((rootContainerElement: any): Element));
293
- } else {
294
- // Legacy plugin event system path
295
- const isDocumentOrFragment =
296
- rootContainerInstance.nodeType === DOCUMENT_NODE ||
297
- rootContainerInstance.nodeType === DOCUMENT_FRAGMENT_NODE;
298
- const doc = isDocumentOrFragment
299
- ? rootContainerInstance
300
- : rootContainerInstance.ownerDocument;
301
- legacyListenToEvent(registrationName, ((doc: any): Document));
302
- }
261
+ // If we have a comment node, then use the parent node,
262
+ // which should be an element.
263
+ const rootContainerElement =
264
+ rootContainerInstance.nodeType === COMMENT_NODE
265
+ ? rootContainerInstance.parentNode
266
+ : rootContainerInstance;
267
+ // Containers should only ever be element nodes. We do not
268
+ // want to register events to document fragments or documents
269
+ // with the modern plugin event system.
270
+ invariant(
271
+ rootContainerElement != null &&
272
+ rootContainerElement.nodeType === ELEMENT_NODE,
273
+ 'ensureListeningTo(): received a container that was not an element node. ' +
274
+ 'This is likely a bug in React.',
275
+ );
276
+ listenToEvent(registrationName, ((rootContainerElement: any): Element));
277
}
278
279
function getOwnerDocumentFromRootContainer(
@@ -544,55 +518,29 @@ export function setInitialProperties(
518
case 'iframe':
519
case 'object':
520
case 'embed':
547
- if (!enableModernEventSystem) {
548
- legacyTrapBubbledEvent(TOP_LOAD, domElement);
549
- }
521
props = rawProps;
522
break;
523
case 'video':
524
case 'audio':
554
- if (!enableModernEventSystem) {
555
- // Create listener for each media event
556
- for (let i = 0; i < mediaEventTypes.length; i++) {
557
- legacyTrapBubbledEvent(mediaEventTypes[i], domElement);
558
- }
559
- }
525
props = rawProps;
526
break;
527
case 'source':
563
- if (!enableModernEventSystem) {
564
- legacyTrapBubbledEvent(TOP_ERROR, domElement);
565
- }
528
props = rawProps;
529
break;
530
case 'img':
531
case 'image':
532
case 'link':
571
- if (!enableModernEventSystem) {
572
- legacyTrapBubbledEvent(TOP_ERROR, domElement);
573
- legacyTrapBubbledEvent(TOP_LOAD, domElement);
574
- }
533
props = rawProps;
534
break;
535
case 'form':
578
- if (!enableModernEventSystem) {
579
- legacyTrapBubbledEvent(TOP_RESET, domElement);
580
- legacyTrapBubbledEvent(TOP_SUBMIT, domElement);
581
- }
536
props = rawProps;
537
break;
538
case 'details':
585
- if (!enableModernEventSystem) {
586
- legacyTrapBubbledEvent(TOP_TOGGLE, domElement);
587
- }
539
props = rawProps;
540
break;
541
case 'input':
542
ReactDOMInputInitWrapperState(domElement, rawProps);
543
props = ReactDOMInputGetHostProps(domElement, rawProps);
593
- if (!enableModernEventSystem) {
594
- legacyTrapBubbledEvent(TOP_INVALID, domElement);
595
- }
544
// For controlled components we always need to ensure we're listening
545
// to onChange. Even if there is no listener.
546
ensureListeningTo(rootContainerElement, 'onChange');
@@ -604,9 +552,6 @@ export function setInitialProperties(
552
case 'select':
553
ReactDOMSelectInitWrapperState(domElement, rawProps);
554
props = ReactDOMSelectGetHostProps(domElement, rawProps);
607
- if (!enableModernEventSystem) {
608
- legacyTrapBubbledEvent(TOP_INVALID, domElement);
609
- }
555
// For controlled components we always need to ensure we're listening
556
// to onChange. Even if there is no listener.
557
ensureListeningTo(rootContainerElement, 'onChange');
@@ -614,9 +559,6 @@ export function setInitialProperties(
559
case 'textarea':
560
ReactDOMTextareaInitWrapperState(domElement, rawProps);
561
props = ReactDOMTextareaGetHostProps(domElement, rawProps);
617
- if (!enableModernEventSystem) {
618
- legacyTrapBubbledEvent(TOP_INVALID, domElement);
619
- }
562
// For controlled components we always need to ensure we're listening
563
// to onChange. Even if there is no listener.
564
ensureListeningTo(rootContainerElement, 'onChange');
@@ -949,51 +891,8 @@ export function diffHydratedProperties(
891
892
// TODO: Make sure that we check isMounted before firing any of these events.
893
switch (tag) {
952
- case 'iframe':
953
- case 'object':
954
- case 'embed':
955
- if (!enableModernEventSystem) {
956
- legacyTrapBubbledEvent(TOP_LOAD, domElement);
957
- }
958
- break;
959
- case 'video':
960
- case 'audio':
961
- if (!enableModernEventSystem) {
962
- // Create listener for each media event
963
- for (let i = 0; i < mediaEventTypes.length; i++) {
964
- legacyTrapBubbledEvent(mediaEventTypes[i], domElement);
965
- }
966
- }
967
- break;
968
- case 'source':
969
- if (!enableModernEventSystem) {
970
- legacyTrapBubbledEvent(TOP_ERROR, domElement);
971
- }
972
- break;
973
- case 'img':
974
- case 'image':
975
- case 'link':
976
- if (!enableModernEventSystem) {
977
- legacyTrapBubbledEvent(TOP_ERROR, domElement);
978
- legacyTrapBubbledEvent(TOP_LOAD, domElement);
979
- }
980
- break;
981
- case 'form':
982
- if (!enableModernEventSystem) {
983
- legacyTrapBubbledEvent(TOP_RESET, domElement);
984
- legacyTrapBubbledEvent(TOP_SUBMIT, domElement);
985
- }
986
- break;
987
- case 'details':
988
- if (!enableModernEventSystem) {
989
- legacyTrapBubbledEvent(TOP_TOGGLE, domElement);
990
- }
991
- break;
894
case 'input':
895
ReactDOMInputInitWrapperState(domElement, rawProps);
994
- if (!enableModernEventSystem) {
995
- legacyTrapBubbledEvent(TOP_INVALID, domElement);
996
- }
896
// For controlled components we always need to ensure we're listening
897
// to onChange. Even if there is no listener.
898
ensureListeningTo(rootContainerElement, 'onChange');
@@ -1003,18 +902,12 @@ export function diffHydratedProperties(
902
break;
903
case 'select':
904
ReactDOMSelectInitWrapperState(domElement, rawProps);
1006
- if (!enableModernEventSystem) {
1007
- legacyTrapBubbledEvent(TOP_INVALID, domElement);
1008
- }
905
// For controlled components we always need to ensure we're listening
906
// to onChange. Even if there is no listener.
907
ensureListeningTo(rootContainerElement, 'onChange');
908
break;
909
case 'textarea':
910
ReactDOMTextareaInitWrapperState(domElement, rawProps);
1015
- if (!enableModernEventSystem) {
1016
- legacyTrapBubbledEvent(TOP_INVALID, domElement);
1017
- }
911
// For controlled components we always need to ensure we're listening
912
// to onChange. Even if there is no listener.
913
ensureListeningTo(rootContainerElement, 'onChange');
packages/react-dom/src/client/ReactDOMHostConfig.js
+1
-4
@@ -75,7 +75,6 @@ import {
75
enableSuspenseServerRenderer,
76
enableDeprecatedFlareAPI,
77
enableFundamentalAPI,
78
- enableModernEventSystem,
78
enableCreateEventHandleAPI,
79
enableScopeAPI,
80
} from 'shared/ReactFeatureFlags';
@@ -1123,9 +1122,7 @@ export function makeOpaqueHydratingObject(
1122
}
1123
1124
export function preparePortalMount(portalInstance: Instance): void {
1126
- if (enableModernEventSystem) {
1127
- listenToEvent('onMouseEnter', portalInstance);
1128
- }
1125
+ listenToEvent('onMouseEnter', portalInstance);
1126
}
1127
1128
export function prepareScopeUpdate(
packages/react-dom/src/client/ReactDOMRoot.js
-3
@@ -57,8 +57,6 @@ import {
57
LegacyRoot,
58
} from 'react-reconciler/src/ReactRootTags';
59
60
-import {enableModernEventSystem} from 'shared/ReactFeatureFlags';
61
-
60
function ReactDOMRoot(container: Container, options: void | RootOptions) {
61
this._internalRoot = createRootImpl(container, ConcurrentRoot, options);
62
}
@@ -144,7 +142,6 @@ function createRootImpl(
142
// hoist it to reduce code-size.
143
eagerlyTrapReplayableEvents(container, ((doc: any): Document));
144
} else if (
147
- enableModernEventSystem &&
145
containerNodeType !== DOCUMENT_FRAGMENT_NODE &&
146
containerNodeType !== DOCUMENT_NODE
147
) {
packages/react-dom/src/events/DOMLegacyEventPluginSystem.js
deleted
-622
@@ -1,622 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @flow
8
- */
9
-
10
-import type {AnyNativeEvent} from '../legacy-events/PluginModuleType';
11
-import type {DOMTopLevelEventType} from '../legacy-events/TopLevelEventTypes';
12
-import type {ElementListenerMap} from '../client/ReactDOMComponentTree';
13
-import type {EventSystemFlags} from './EventSystemFlags';
14
-import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
15
-import type {LegacyPluginModule} from '../legacy-events/PluginModuleType';
16
-import type {ReactSyntheticEvent} from '../legacy-events/ReactSyntheticEventType';
17
-import type {TopLevelType} from '../legacy-events/TopLevelEventTypes';
18
-import forEachAccumulated from '../legacy-events/forEachAccumulated';
19
-
20
-import {
21
- HostRoot,
22
- HostComponent,
23
- HostText,
24
-} from 'react-reconciler/src/ReactWorkTags';
25
-import {IS_FIRST_ANCESTOR, PLUGIN_EVENT_SYSTEM} from './EventSystemFlags';
26
-import {runEventsInBatch} from '../legacy-events/EventBatching';
27
-import {plugins} from '../legacy-events/EventPluginRegistry';
28
-import accumulateInto from '../legacy-events/accumulateInto';
29
-import {registrationNameDependencies} from '../legacy-events/EventPluginRegistry';
30
-
31
-import getEventTarget from './getEventTarget';
32
-import {
33
- getClosestInstanceFromNode,
34
- getEventListenerMap,
35
-} from '../client/ReactDOMComponentTree';
36
-import isEventSupported from './isEventSupported';
37
-import {
38
- TOP_BLUR,
39
- TOP_CANCEL,
40
- TOP_CLOSE,
41
- TOP_FOCUS,
42
- TOP_INVALID,
43
- TOP_RESET,
44
- TOP_SCROLL,
45
- TOP_SUBMIT,
46
- getRawEventName,
47
- mediaEventTypes,
48
-} from './DOMTopLevelEventTypes';
49
-import {createEventListenerWrapperWithPriority} from './ReactDOMEventListener';
50
-import {batchedEventUpdates} from './ReactDOMUpdateBatching';
51
-import getListener from './getListener';
52
-import {addEventCaptureListener, addEventBubbleListener} from './EventListener';
53
-
54
-/**
55
- * Summary of `DOMEventPluginSystem` event handling:
56
- *
57
- * - Top-level delegation is used to trap most native browser events. This
58
- * may only occur in the main thread and is the responsibility of
59
- * ReactDOMEventListener, which is injected and can therefore support
60
- * pluggable event sources. This is the only work that occurs in the main
61
- * thread.
62
- *
63
- * - We normalize and de-duplicate events to account for browser quirks. This
64
- * may be done in the worker thread.
65
- *
66
- * - Forward these native events (with the associated top-level type used to
67
- * trap it) to `EventPluginRegistry`, which in turn will ask plugins if they want
68
- * to extract any synthetic events.
69
- *
70
- * - The `EventPluginRegistry` will then process each event by annotating them with
71
- * "dispatches", a sequence of listeners and IDs that care about that event.
72
- *
73
- * - The `EventPluginRegistry` then dispatches the events.
74
- *
75
- * Overview of React and the event system:
76
- *
77
- * +------------+ .
78
- * | DOM | .
79
- * +------------+ .
80
- * | .
81
- * v .
82
- * +------------+ .
83
- * | ReactEvent | .
84
- * | Listener | .
85
- * +------------+ . +-----------+
86
- * | . +--------+|SimpleEvent|
87
- * | . | |Plugin |
88
- * +-----|------+ . v +-----------+
89
- * | | | . +--------------+ +------------+
90
- * | +-----------.--->|PluginRegistry| | Event |
91
- * | | . | | +-----------+ | Propagators|
92
- * | ReactEvent | . | | |TapEvent | |------------|
93
- * | Emitter | . | |<---+|Plugin | |other plugin|
94
- * | | . | | +-----------+ | utilities |
95
- * | +-----------.--->| | +------------+
96
- * | | | . +--------------+
97
- * +-----|------+ . ^ +-----------+
98
- * | . | |Enter/Leave|
99
- * + . +-------+|Plugin |
100
- * +-------------+ . +-----------+
101
- * | application | .
102
- * |-------------| .
103
- * | | .
104
- * | | .
105
- * +-------------+ .
106
- * .
107
- * React Core . General Purpose Event Plugin System
108
- */
109
-
110
-const CALLBACK_BOOKKEEPING_POOL_SIZE = 10;
111
-const callbackBookkeepingPool = [];
112
-
113
-type BookKeepingInstance = {|
114
- topLevelType: DOMTopLevelEventType | null,
115
- eventSystemFlags: EventSystemFlags,
116
- nativeEvent: AnyNativeEvent | null,
117
- targetInst: Fiber | null,
118
- ancestors: Array<Fiber | null>,
119
-|};
120
-
121
-function releaseTopLevelCallbackBookKeeping(
122
- instance: BookKeepingInstance,
123
-): void {
124
- instance.topLevelType = null;
125
- instance.nativeEvent = null;
126
- instance.targetInst = null;
127
- instance.ancestors.length = 0;
128
- if (callbackBookkeepingPool.length < CALLBACK_BOOKKEEPING_POOL_SIZE) {
129
- callbackBookkeepingPool.push(instance);
130
- }
131
-}
132
-
133
-// Used to store ancestor hierarchy in top level callback
134
-function getTopLevelCallbackBookKeeping(
135
- topLevelType: DOMTopLevelEventType,
136
- nativeEvent: AnyNativeEvent,
137
- targetInst: Fiber | null,
138
- eventSystemFlags: EventSystemFlags,
139
-): BookKeepingInstance {
140
- if (callbackBookkeepingPool.length) {
141
- const instance = callbackBookkeepingPool.pop();
142
- instance.topLevelType = topLevelType;
143
- instance.eventSystemFlags = eventSystemFlags;
144
- instance.nativeEvent = nativeEvent;
145
- instance.targetInst = targetInst;
146
- return instance;
147
- }
148
- return {
149
- topLevelType,
150
- eventSystemFlags,
151
- nativeEvent,
152
- targetInst,
153
- ancestors: [],
154
- };
155
-}
156
-
157
-/**
158
- * Find the deepest React component completely containing the root of the
159
- * passed-in instance (for use when entire React trees are nested within each
160
- * other). If React trees are not nested, returns null.
161
- */
162
-function findRootContainerNode(inst) {
163
- if (inst.tag === HostRoot) {
164
- return inst.stateNode.containerInfo;
165
- }
166
- // TODO: It may be a good idea to cache this to prevent unnecessary DOM
167
- // traversal, but caching is difficult to do correctly without using a
168
- // mutation observer to listen for all DOM changes.
169
- while (inst.return) {
170
- inst = inst.return;
171
- }
172
- if (inst.tag !== HostRoot) {
173
- // This can happen if we're in a detached tree.
174
- return null;
175
- }
176
- return inst.stateNode.containerInfo;
177
-}
178
-
179
-/**
180
- * Allows registered plugins an opportunity to extract events from top-level
181
- * native browser events.
182
- *
183
- * @return {*} An accumulation of synthetic events.
184
- * @internal
185
- */
186
-function extractPluginEvents(
187
- topLevelType: TopLevelType,
188
- targetInst: null | Fiber,
189
- nativeEvent: AnyNativeEvent,
190
- nativeEventTarget: null | EventTarget,
191
- eventSystemFlags: EventSystemFlags,
192
-): Array<ReactSyntheticEvent> | ReactSyntheticEvent | null {
193
- let events = null;
194
- const legacyPlugins = ((plugins: any): Array<LegacyPluginModule<Event>>);
195
- for (let i = 0; i < legacyPlugins.length; i++) {
196
- // Not every plugin in the ordering may be loaded at runtime.
197
- const possiblePlugin = legacyPlugins[i];
198
- if (possiblePlugin) {
199
- const extractedEvents = possiblePlugin.extractEvents(
200
- topLevelType,
201
- targetInst,
202
- nativeEvent,
203
- nativeEventTarget,
204
- eventSystemFlags,
205
- );
206
- if (extractedEvents) {
207
- events = accumulateInto(events, extractedEvents);
208
- }
209
- }
210
- }
211
- return events;
212
-}
213
-
214
-function runExtractedPluginEventsInBatch(
215
- topLevelType: TopLevelType,
216
- targetInst: null | Fiber,
217
- nativeEvent: AnyNativeEvent,
218
- nativeEventTarget: null | EventTarget,
219
- eventSystemFlags: EventSystemFlags,
220
-) {
221
- const events = extractPluginEvents(
222
- topLevelType,
223
- targetInst,
224
- nativeEvent,
225
- nativeEventTarget,
226
- eventSystemFlags,
227
- );
228
- runEventsInBatch(events);
229
-}
230
-
231
-function handleTopLevel(bookKeeping: BookKeepingInstance) {
232
- let targetInst = bookKeeping.targetInst;
233
-
234
- // Loop through the hierarchy, in case there's any nested components.
235
- // It's important that we build the array of ancestors before calling any
236
- // event handlers, because event handlers can modify the DOM, leading to
237
- // inconsistencies with ReactMount's node cache. See #1105.
238
- let ancestor = targetInst;
239
- do {
240
- if (!ancestor) {
241
- const ancestors = bookKeeping.ancestors;
242
- ((ancestors: any): Array<Fiber | null>).push(ancestor);
243
- break;
244
- }
245
- const root = findRootContainerNode(ancestor);
246
- if (!root) {
247
- break;
248
- }
249
- const tag = ancestor.tag;
250
- if (tag === HostComponent || tag === HostText) {
251
- bookKeeping.ancestors.push(ancestor);
252
- }
253
- ancestor = getClosestInstanceFromNode(root);
254
- } while (ancestor);
255
-
256
- for (let i = 0; i < bookKeeping.ancestors.length; i++) {
257
- targetInst = bookKeeping.ancestors[i];
258
- const eventTarget = getEventTarget(bookKeeping.nativeEvent);
259
- const topLevelType = ((bookKeeping.topLevelType: any): DOMTopLevelEventType);
260
- const nativeEvent = ((bookKeeping.nativeEvent: any): AnyNativeEvent);
261
- let eventSystemFlags = bookKeeping.eventSystemFlags;
262
-
263
- // If this is the first ancestor, we mark it on the system flags
264
- if (i === 0) {
265
- eventSystemFlags |= IS_FIRST_ANCESTOR;
266
- }
267
-
268
- runExtractedPluginEventsInBatch(
269
- topLevelType,
270
- targetInst,
271
- nativeEvent,
272
- eventTarget,
273
- eventSystemFlags,
274
- );
275
- }
276
-}
277
-
278
-export function dispatchEventForLegacyPluginEventSystem(
279
- topLevelType: DOMTopLevelEventType,
280
- eventSystemFlags: EventSystemFlags,
281
- nativeEvent: AnyNativeEvent,
282
- targetInst: null | Fiber,
283
-): void {
284
- const bookKeeping = getTopLevelCallbackBookKeeping(
285
- topLevelType,
286
- nativeEvent,
287
- targetInst,
288
- eventSystemFlags,
289
- );
290
-
291
- try {
292
- // Event queue being processed in the same cycle allows
293
- // `preventDefault`.
294
- batchedEventUpdates(handleTopLevel, bookKeeping);
295
- } finally {
296
- releaseTopLevelCallbackBookKeeping(bookKeeping);
297
- }
298
-}
299
-
300
-/**
301
- * We listen for bubbled touch events on the document object.
302
- *
303
- * Firefox v8.01 (and possibly others) exhibited strange behavior when
304
- * mounting `onmousemove` events at some node that was not the document
305
- * element. The symptoms were that if your mouse is not moving over something
306
- * contained within that mount point (for example on the background) the
307
- * top-level listeners for `onmousemove` won't be called. However, if you
308
- * register the `mousemove` on the document object, then it will of course
309
- * catch all `mousemove`s. This along with iOS quirks, justifies restricting
310
- * top-level listeners to the document object only, at least for these
311
- * movement types of events and possibly all events.
312
- *
313
- * @see https://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
314
- *
315
- * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but
316
- * they bubble to document.
317
- *
318
- * @param {string} registrationName Name of listener (e.g. `onClick`).
319
- * @param {object} mountAt Container where to mount the listener
320
- */
321
-export function legacyListenToEvent(
322
- registrationName: string,
323
- mountAt: Document | Element,
324
-): void {
325
- const listenerMap = getEventListenerMap(mountAt);
326
- const dependencies = registrationNameDependencies[registrationName];
327
-
328
- for (let i = 0; i < dependencies.length; i++) {
329
- const dependency = dependencies[i];
330
- legacyListenToTopLevelEvent(dependency, mountAt, listenerMap);
331
- }
332
-}
333
-
334
-export function legacyListenToTopLevelEvent(
335
- topLevelType: DOMTopLevelEventType,
336
- mountAt: Document | Element,
337
- listenerMap: ElementListenerMap,
338
-): void {
339
- if (!listenerMap.has(topLevelType)) {
340
- switch (topLevelType) {
341
- case TOP_SCROLL: {
342
- legacyTrapCapturedEvent(TOP_SCROLL, mountAt, listenerMap);
343
- break;
344
- }
345
- case TOP_FOCUS:
346
- case TOP_BLUR:
347
- legacyTrapCapturedEvent(TOP_FOCUS, mountAt, listenerMap);
348
- legacyTrapCapturedEvent(TOP_BLUR, mountAt, listenerMap);
349
- break;
350
- case TOP_CANCEL:
351
- case TOP_CLOSE: {
352
- if (isEventSupported(getRawEventName(topLevelType))) {
353
- legacyTrapCapturedEvent(topLevelType, mountAt, listenerMap);
354
- }
355
- break;
356
- }
357
- case TOP_INVALID:
358
- case TOP_SUBMIT:
359
- case TOP_RESET:
360
- // We listen to them on the target DOM elements.
361
- // Some of them bubble so we don't want them to fire twice.
362
- break;
363
- default: {
364
- // By default, listen on the top level to all non-media events.
365
- // Media events don't bubble so adding the listener wouldn't do anything.
366
- const isMediaEvent = mediaEventTypes.indexOf(topLevelType) !== -1;
367
- if (!isMediaEvent) {
368
- legacyTrapBubbledEvent(topLevelType, mountAt, listenerMap);
369
- }
370
- break;
371
- }
372
- }
373
- }
374
-}
375
-
376
-export function legacyTrapBubbledEvent(
377
- topLevelType: DOMTopLevelEventType,
378
- element: Document | Element,
379
- listenerMap?: ElementListenerMap,
380
-): void {
381
- const listener = addTrappedEventListener(
382
- element,
383
- topLevelType,
384
- PLUGIN_EVENT_SYSTEM,
385
- false,
386
- );
387
- if (listenerMap) {
388
- listenerMap.set(topLevelType, {passive: undefined, listener});
389
- }
390
-}
391
-
392
-export function legacyTrapCapturedEvent(
393
- topLevelType: DOMTopLevelEventType,
394
- element: Document | Element,
395
- listenerMap: ElementListenerMap,
396
-): void {
397
- const listener = addTrappedEventListener(
398
- element,
399
- topLevelType,
400
- PLUGIN_EVENT_SYSTEM,
401
- true,
402
- );
403
- listenerMap.set(topLevelType, {passive: undefined, listener});
404
-}
405
-
406
-function addTrappedEventListener(
407
- targetContainer: EventTarget,
408
- topLevelType: DOMTopLevelEventType,
409
- eventSystemFlags: EventSystemFlags,
410
- capture: boolean,
411
-): any => void {
412
- const rawEventName = getRawEventName(topLevelType);
413
- const listener = createEventListenerWrapperWithPriority(
414
- targetContainer,
415
- topLevelType,
416
- eventSystemFlags,
417
- );
418
- const unsubscribeListener = capture
419
- ? addEventCaptureListener(targetContainer, rawEventName, listener)
420
- : addEventBubbleListener(targetContainer, rawEventName, listener);
421
- return unsubscribeListener;
422
-}
423
-
424
-function getParent(inst: Object | null): Object | null {
425
- if (!inst) {
426
- return null;
427
- }
428
- do {
429
- inst = inst.return;
430
- // TODO: If this is a HostRoot we might want to bail out.
431
- // That is depending on if we want nested subtrees (layers) to bubble
432
- // events to their parent. We could also go through parentNode on the
433
- // host node but that wouldn't work for React Native and doesn't let us
434
- // do the portal feature.
435
- } while (inst && inst.tag !== HostComponent);
436
- if (inst) {
437
- return inst;
438
- }
439
- return null;
440
-}
441
-
442
-/**
443
- * Simulates the traversal of a two-phase, capture/bubble event dispatch.
444
- */
445
-function traverseTwoPhase(
446
- inst: Object,
447
- fn: Function,
448
- arg: ReactSyntheticEvent,
449
-) {
450
- const path = [];
451
- while (inst) {
452
- path.push(inst);
453
- inst = getParent(inst);
454
- }
455
- let i;
456
- for (i = path.length; i-- > 0; ) {
457
- fn(path[i], 'captured', arg);
458
- }
459
- for (i = 0; i < path.length; i++) {
460
- fn(path[i], 'bubbled', arg);
461
- }
462
-}
463
-
464
-function listenerAtPhase(inst, event, propagationPhase) {
465
- const registrationName =
466
- event.dispatchConfig.phasedRegistrationNames[propagationPhase];
467
- return getListener(inst, registrationName);
468
-}
469
-
470
-/**
471
- * Return the lowest common ancestor of A and B, or null if they are in
472
- * different trees.
473
- */
474
-export function getLowestCommonAncestor(
475
- instA: Object,
476
- instB: Object,
477
-): Object | null {
478
- let depthA = 0;
479
- for (let tempA = instA; tempA; tempA = getParent(tempA)) {
480
- depthA++;
481
- }
482
- let depthB = 0;
483
- for (let tempB = instB; tempB; tempB = getParent(tempB)) {
484
- depthB++;
485
- }
486
-
487
- // If A is deeper, crawl up.
488
- while (depthA - depthB > 0) {
489
- instA = getParent(instA);
490
- depthA--;
491
- }
492
-
493
- // If B is deeper, crawl up.
494
- while (depthB - depthA > 0) {
495
- instB = getParent(instB);
496
- depthB--;
497
- }
498
-
499
- // Walk in lockstep until we find a match.
500
- let depth = depthA;
501
- while (depth--) {
502
- if (instA === instB || instA === instB.alternate) {
503
- return instA;
504
- }
505
- instA = getParent(instA);
506
- instB = getParent(instB);
507
- }
508
- return null;
509
-}
510
-
511
-/**
512
- * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that
513
- * should would receive a `mouseEnter` or `mouseLeave` event.
514
- *
515
- * Does not invoke the callback on the nearest common ancestor because nothing
516
- * "entered" or "left" that element.
517
- */
518
-export function traverseEnterLeave(
519
- from: Object,
520
- to: Object,
521
- fn: Function,
522
- argFrom: ReactSyntheticEvent,
523
- argTo: ReactSyntheticEvent,
524
-) {
525
- const common = from && to ? getLowestCommonAncestor(from, to) : null;
526
- const pathFrom = [];
527
- while (true) {
528
- if (!from) {
529
- break;
530
- }
531
- if (from === common) {
532
- break;
533
- }
534
- const alternate = from.alternate;
535
- if (alternate !== null && alternate === common) {
536
- break;
537
- }
538
- pathFrom.push(from);
539
- from = getParent(from);
540
- }
541
- const pathTo = [];
542
- while (true) {
543
- if (!to) {
544
- break;
545
- }
546
- if (to === common) {
547
- break;
548
- }
549
- const alternate = to.alternate;
550
- if (alternate !== null && alternate === common) {
551
- break;
552
- }
553
- pathTo.push(to);
554
- to = getParent(to);
555
- }
556
- for (let i = 0; i < pathFrom.length; i++) {
557
- fn(pathFrom[i], 'bubbled', argFrom);
558
- }
559
- for (let i = pathTo.length; i-- > 0; ) {
560
- fn(pathTo[i], 'captured', argTo);
561
- }
562
-}
563
-
564
-function accumulateDirectionalDispatches(inst, phase, event) {
565
- if (__DEV__) {
566
- if (!inst) {
567
- console.error('Dispatching inst must not be null');
568
- }
569
- }
570
- const listener = listenerAtPhase(inst, event, phase);
571
- if (listener) {
572
- event._dispatchListeners = accumulateInto(
573
- event._dispatchListeners,
574
- listener,
575
- );
576
- event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
577
- }
578
-}
579
-
580
-function accumulateTwoPhaseDispatchesSingle(event) {
581
- if (event && event.dispatchConfig.phasedRegistrationNames) {
582
- traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event);
583
- }
584
-}
585
-
586
-/**
587
- * Accumulates without regard to direction, does not look for phased
588
- * registration names. Same as `accumulateDirectDispatchesSingle` but without
589
- * requiring that the `dispatchMarker` be the same as the dispatched ID.
590
- */
591
-function accumulateDispatches(
592
- inst: Object,
593
- ignoredDirection: ?boolean,
594
- event: Object,
595
-): void {
596
- if (inst && event && event.dispatchConfig.registrationName) {
597
- const registrationName = event.dispatchConfig.registrationName;
598
- const listener = getListener(inst, registrationName);
599
- if (listener) {
600
- event._dispatchListeners = accumulateInto(
601
- event._dispatchListeners,
602
- listener,
603
- );
604
- event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
605
- }
606
- }
607
-}
608
-
609
-export function accumulateTwoPhaseDispatches(
610
- events: ReactSyntheticEvent | Array<ReactSyntheticEvent>,
611
-): void {
612
- forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
613
-}
614
-
615
-export function accumulateEnterLeaveDispatches(
616
- leave: ReactSyntheticEvent,
617
- enter: ReactSyntheticEvent,
618
- from: Fiber,
619
- to: Fiber,
620
-) {
621
- traverseEnterLeave(from, to, accumulateDispatches, leave, enter);
622
-}
packages/react-dom/src/events/ReactDOMEventListener.js
+28
-66
@@ -43,7 +43,6 @@ import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
43
44
import {
45
enableDeprecatedFlareAPI,
46
- enableModernEventSystem,
46
enableLegacyFBSupport,
47
} from 'shared/ReactFeatureFlags';
48
import {
@@ -52,7 +51,6 @@ import {
51
DiscreteEvent,
52
} from 'shared/ReactTypes';
53
import {getEventPriorityForPluginSystem} from './DOMEventProperties';
55
-import {dispatchEventForLegacyPluginEventSystem} from './DOMLegacyEventPluginSystem';
54
import {dispatchEventForPluginEventSystem} from './DOMModernPluginEventSystem';
55
import {
56
flushDiscreteUpdatesIfNeeded,
@@ -230,22 +228,13 @@ export function dispatchEvent(
228
// in case the event system needs to trace it.
229
if (enableDeprecatedFlareAPI) {
230
if (eventSystemFlags & PLUGIN_EVENT_SYSTEM) {
233
- if (enableModernEventSystem) {
234
- dispatchEventForPluginEventSystem(
235
- topLevelType,
236
- eventSystemFlags,
237
- nativeEvent,
238
- null,
239
- targetContainer,
240
- );
241
- } else {
242
- dispatchEventForLegacyPluginEventSystem(
243
- topLevelType,
244
- eventSystemFlags,
245
- nativeEvent,
246
- null,
247
- );
248
- }
231
+ dispatchEventForPluginEventSystem(
232
+ topLevelType,
233
+ eventSystemFlags,
234
+ nativeEvent,
235
+ null,
236
+ targetContainer,
237
+ );
238
}
239
if (eventSystemFlags & RESPONDER_EVENT_SYSTEM) {
240
// React Flare event system
@@ -258,22 +247,13 @@ export function dispatchEvent(
247
);
248
}
249
} else {
261
- if (enableModernEventSystem) {
262
- dispatchEventForPluginEventSystem(
263
- topLevelType,
264
- eventSystemFlags,
265
- nativeEvent,
266
- null,
267
- targetContainer,
268
- );
269
- } else {
270
- dispatchEventForLegacyPluginEventSystem(
271
- topLevelType,
272
- eventSystemFlags,
273
- nativeEvent,
274
- null,
275
- );
276
- }
250
+ dispatchEventForPluginEventSystem(
251
+ topLevelType,
252
+ eventSystemFlags,
253
+ nativeEvent,
254
+ null,
255
+ targetContainer,
256
+ );
257
}
258
}
259
@@ -329,22 +309,13 @@ export function attemptToDispatchEvent(
309
310
if (enableDeprecatedFlareAPI) {
311
if (eventSystemFlags & PLUGIN_EVENT_SYSTEM) {
332
- if (enableModernEventSystem) {
333
- dispatchEventForPluginEventSystem(
334
- topLevelType,
335
- eventSystemFlags,
336
- nativeEvent,
337
- targetInst,
338
- targetContainer,
339
- );
340
- } else {
341
- dispatchEventForLegacyPluginEventSystem(
342
- topLevelType,
343
- eventSystemFlags,
344
- nativeEvent,
345
- targetInst,
346
- );
347
- }
312
+ dispatchEventForPluginEventSystem(
313
+ topLevelType,
314
+ eventSystemFlags,
315
+ nativeEvent,
316
+ targetInst,
317
+ targetContainer,
318
+ );
319
}
320
if (eventSystemFlags & RESPONDER_EVENT_SYSTEM) {
321
// React Flare event system
@@ -357,22 +328,13 @@ export function attemptToDispatchEvent(
328
);
329
}
330
} else {
360
- if (enableModernEventSystem) {
361
- dispatchEventForPluginEventSystem(
362
- topLevelType,
363
- eventSystemFlags,
364
- nativeEvent,
365
- targetInst,
366
- targetContainer,
367
- );
368
- } else {
369
- dispatchEventForLegacyPluginEventSystem(
370
- topLevelType,
371
- eventSystemFlags,
372
- nativeEvent,
373
- targetInst,
374
- );
375
- }
331
+ dispatchEventForPluginEventSystem(
332
+ topLevelType,
333
+ eventSystemFlags,
334
+ nativeEvent,
335
+ targetInst,
336
+ targetContainer,
337
+ );
338
}
339
// We're not blocked on anything.
340
return null;
packages/react-dom/src/events/ReactDOMEventReplaying.js
+11
-23
@@ -17,7 +17,6 @@ import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
17
import {
18
enableDeprecatedFlareAPI,
19
enableSelectiveHydration,
20
- enableModernEventSystem,
20
} from 'shared/ReactFeatureFlags';
21
import {
22
unstable_runWithPriority as runWithPriority,
@@ -116,7 +115,6 @@ import {
115
TOP_BLUR,
116
} from './DOMTopLevelEventTypes';
117
import {IS_REPLAYED, PLUGIN_EVENT_SYSTEM} from './EventSystemFlags';
119
-import {legacyListenToTopLevelEvent} from './DOMLegacyEventPluginSystem';
118
import {listenToTopLevelEvent} from './DOMModernPluginEventSystem';
119
import {addResponderEventSystemEvent} from './DeprecatedDOMEventResponderSystem';
120
@@ -230,9 +228,6 @@ function trapReplayableEventForDocument(
228
document: Document,
229
listenerMap: ElementListenerMap,
230
) {
233
- if (!enableModernEventSystem) {
234
- legacyListenToTopLevelEvent(topLevelType, document, listenerMap);
235
- }
231
if (enableDeprecatedFlareAPI) {
232
// Trap events for the responder system.
233
const topLevelTypeString = unsafeCastDOMTopLevelTypeToString(topLevelType);
@@ -257,30 +252,23 @@ export function eagerlyTrapReplayableEvents(
252
document: Document,
253
) {
254
const listenerMapForDoc = getEventListenerMap(document);
260
- let listenerMapForContainer;
261
- if (enableModernEventSystem) {
262
- listenerMapForContainer = getEventListenerMap(container);
263
- }
255
+ const listenerMapForContainer = getEventListenerMap(container);
256
// Discrete
257
discreteReplayableEvents.forEach(topLevelType => {
266
- if (enableModernEventSystem) {
267
- trapReplayableEventForContainer(
268
- topLevelType,
269
- container,
270
- listenerMapForContainer,
271
- );
272
- }
258
+ trapReplayableEventForContainer(
259
+ topLevelType,
260
+ container,
261
+ listenerMapForContainer,
262
+ );
263
trapReplayableEventForDocument(topLevelType, document, listenerMapForDoc);
264
});
265
// Continuous
266
continuousReplayableEvents.forEach(topLevelType => {
277
- if (enableModernEventSystem) {
278
- trapReplayableEventForContainer(
279
- topLevelType,
280
- container,
281
- listenerMapForContainer,
282
- );
283
- }
267
+ trapReplayableEventForContainer(
268
+ topLevelType,
269
+ container,
270
+ listenerMapForContainer,
271
+ );
272
trapReplayableEventForDocument(topLevelType, document, listenerMapForDoc);
273
});
274
}
packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js
-3
@@ -60,7 +60,6 @@ describe('DOMModernPluginEventSystem', () => {
60
beforeEach(() => {
61
jest.resetModules();
62
ReactFeatureFlags = require('shared/ReactFeatureFlags');
63
- ReactFeatureFlags.enableModernEventSystem = true;
63
ReactFeatureFlags.enableLegacyFBSupport = enableLegacyFBSupport;
64
65
React = require('react');
@@ -1197,7 +1196,6 @@ describe('DOMModernPluginEventSystem', () => {
1196
jest.resetModules();
1197
ReactFeatureFlags = require('shared/ReactFeatureFlags');
1198
ReactFeatureFlags.enableLegacyFBSupport = enableLegacyFBSupport;
1200
- ReactFeatureFlags.enableModernEventSystem = true;
1199
ReactFeatureFlags.enableCreateEventHandleAPI = true;
1200
1201
React = require('react');
@@ -2555,7 +2553,6 @@ describe('DOMModernPluginEventSystem', () => {
2553
beforeEach(() => {
2554
jest.resetModules();
2555
ReactFeatureFlags = require('shared/ReactFeatureFlags');
2558
- ReactFeatureFlags.enableModernEventSystem = true;
2556
ReactFeatureFlags.enableCreateEventHandleAPI = true;
2557
ReactFeatureFlags.enableScopeAPI = true;
2558
packages/react-dom/src/events/__tests__/SyntheticClipboardEvent-test.js
-40
@@ -11,7 +11,6 @@
11
12
let React;
13
let ReactDOM;
14
-const ReactFeatureFlags = require('shared/ReactFeatureFlags');
14
15
describe('SyntheticClipboardEvent', () => {
16
let container;
@@ -117,44 +116,5 @@ describe('SyntheticClipboardEvent', () => {
116
117
expect(expectedCount).toBe(3);
118
});
120
-
121
- if (!ReactFeatureFlags.enableModernEventSystem) {
122
- it('is able to `persist`', () => {
123
- const persistentEvents = [];
124
- const eventHandler = event => {
125
- expect(event.isPersistent()).toBe(false);
126
- event.persist();
127
- expect(event.isPersistent()).toBe(true);
128
- persistentEvents.push(event);
129
- };
130
-
131
- const div = ReactDOM.render(
132
- <div
133
- onCopy={eventHandler}
134
- onCut={eventHandler}
135
- onPaste={eventHandler}
136
- />,
137
- container,
138
- );
139
-
140
- let event;
141
- event = document.createEvent('Event');
142
- event.initEvent('copy', true, true);
143
- div.dispatchEvent(event);
144
-
145
- event = document.createEvent('Event');
146
- event.initEvent('cut', true, true);
147
- div.dispatchEvent(event);
148
-
149
- event = document.createEvent('Event');
150
- event.initEvent('paste', true, true);
151
- div.dispatchEvent(event);
152
-
153
- expect(persistentEvents.length).toBe(3);
154
- expect(persistentEvents[0].type).toBe('copy');
155
- expect(persistentEvents[1].type).toBe('cut');
156
- expect(persistentEvents[2].type).toBe('paste');
157
- });
158
- }
119
});
120
});
packages/react-dom/src/events/__tests__/SyntheticEvent-test.js
-253
@@ -11,7 +11,6 @@
11
12
let React;
13
let ReactDOM;
14
-const ReactFeatureFlags = require('shared/ReactFeatureFlags');
14
15
describe('SyntheticEvent', () => {
16
let container;
@@ -99,256 +98,4 @@ describe('SyntheticEvent', () => {
98
99
expect(expectedCount).toBe(1);
100
});
102
-
103
- if (!ReactFeatureFlags.enableModernEventSystem) {
104
- it('should be able to `persist`', () => {
105
- let expectedCount = 0;
106
- let syntheticEvent;
107
-
108
- const eventHandler = e => {
109
- expect(e.isPersistent()).toBe(false);
110
- e.persist();
111
- syntheticEvent = e;
112
- expect(e.isPersistent()).toBe(true);
113
-
114
- expectedCount++;
115
- };
116
- const node = ReactDOM.render(<div onClick={eventHandler} />, container);
117
-
118
- const event = document.createEvent('Event');
119
- event.initEvent('click', true, true);
120
- node.dispatchEvent(event);
121
-
122
- expect(syntheticEvent.type).toBe('click');
123
- expect(syntheticEvent.bubbles).toBe(true);
124
- expect(syntheticEvent.cancelable).toBe(true);
125
- expect(expectedCount).toBe(1);
126
- });
127
-
128
- it('should be nullified and log warnings if the synthetic event has not been persisted', () => {
129
- let expectedCount = 0;
130
- let syntheticEvent;
131
-
132
- const eventHandler = e => {
133
- syntheticEvent = e;
134
-
135
- expectedCount++;
136
- };
137
- const node = ReactDOM.render(<div onClick={eventHandler} />, container);
138
-
139
- const event = document.createEvent('Event');
140
- event.initEvent('click', true, true);
141
- node.dispatchEvent(event);
142
-
143
- const getExpectedWarning = property =>
144
- 'Warning: This synthetic event is reused for performance reasons. If ' +
145
- `you're seeing this, you're accessing the property \`${property}\` on a ` +
146
- 'released/nullified synthetic event. This is set to null. If you must ' +
147
- 'keep the original synthetic event around, use event.persist(). ' +
148
- 'See https://fb.me/react-event-pooling for more information.';
149
-
150
- // once for each property accessed
151
- expect(() =>
152
- expect(syntheticEvent.type).toBe(null),
153
- ).toErrorDev(getExpectedWarning('type'), {withoutStack: true});
154
- expect(() =>
155
- expect(syntheticEvent.nativeEvent).toBe(null),
156
- ).toErrorDev(getExpectedWarning('nativeEvent'), {withoutStack: true});
157
- expect(() =>
158
- expect(syntheticEvent.target).toBe(null),
159
- ).toErrorDev(getExpectedWarning('target'), {withoutStack: true});
160
-
161
- expect(expectedCount).toBe(1);
162
- });
163
-
164
- it('should warn when setting properties of a synthetic event that has not been persisted', () => {
165
- let expectedCount = 0;
166
- let syntheticEvent;
167
-
168
- const eventHandler = e => {
169
- syntheticEvent = e;
170
-
171
- expectedCount++;
172
- };
173
- const node = ReactDOM.render(<div onClick={eventHandler} />, container);
174
-
175
- const event = document.createEvent('Event');
176
- event.initEvent('click', true, true);
177
- node.dispatchEvent(event);
178
-
179
- expect(() => {
180
- syntheticEvent.type = 'MouseEvent';
181
- }).toErrorDev(
182
- 'Warning: This synthetic event is reused for performance reasons. If ' +
183
- "you're seeing this, you're setting the property `type` on a " +
184
- 'released/nullified synthetic event. This is effectively a no-op. If you must ' +
185
- 'keep the original synthetic event around, use event.persist(). ' +
186
- 'See https://fb.me/react-event-pooling for more information.',
187
- {withoutStack: true},
188
- );
189
- expect(expectedCount).toBe(1);
190
- });
191
-
192
- it('should warn when calling `preventDefault` if the synthetic event has not been persisted', () => {
193
- let expectedCount = 0;
194
- let syntheticEvent;
195
-
196
- const eventHandler = e => {
197
- syntheticEvent = e;
198
- expectedCount++;
199
- };
200
- const node = ReactDOM.render(<div onClick={eventHandler} />, container);
201
-
202
- const event = document.createEvent('Event');
203
- event.initEvent('click', true, true);
204
- node.dispatchEvent(event);
205
-
206
- expect(() =>
207
- syntheticEvent.preventDefault(),
208
- ).toErrorDev(
209
- 'Warning: This synthetic event is reused for performance reasons. If ' +
210
- "you're seeing this, you're accessing the method `preventDefault` on a " +
211
- 'released/nullified synthetic event. This is a no-op function. If you must ' +
212
- 'keep the original synthetic event around, use event.persist(). ' +
213
- 'See https://fb.me/react-event-pooling for more information.',
214
- {withoutStack: true},
215
- );
216
- expect(expectedCount).toBe(1);
217
- });
218
-
219
- it('should warn when calling `stopPropagation` if the synthetic event has not been persisted', () => {
220
- let expectedCount = 0;
221
- let syntheticEvent;
222
-
223
- const eventHandler = e => {
224
- syntheticEvent = e;
225
- expectedCount++;
226
- };
227
- const node = ReactDOM.render(<div onClick={eventHandler} />, container);
228
-
229
- const event = document.createEvent('Event');
230
- event.initEvent('click', true, true);
231
-
232
- node.dispatchEvent(event);
233
-
234
- expect(() =>
235
- syntheticEvent.stopPropagation(),
236
- ).toErrorDev(
237
- 'Warning: This synthetic event is reused for performance reasons. If ' +
238
- "you're seeing this, you're accessing the method `stopPropagation` on a " +
239
- 'released/nullified synthetic event. This is a no-op function. If you must ' +
240
- 'keep the original synthetic event around, use event.persist(). ' +
241
- 'See https://fb.me/react-event-pooling for more information.',
242
- {withoutStack: true},
243
- );
244
- expect(expectedCount).toBe(1);
245
- });
246
-
247
- it('should warn when calling `isPropagationStopped` if the synthetic event has not been persisted', () => {
248
- let expectedCount = 0;
249
- let syntheticEvent;
250
-
251
- const eventHandler = e => {
252
- syntheticEvent = e;
253
- expectedCount++;
254
- };
255
- const node = ReactDOM.render(<div onClick={eventHandler} />, container);
256
-
257
- const event = document.createEvent('Event');
258
- event.initEvent('click', true, true);
259
- node.dispatchEvent(event);
260
-
261
- expect(() =>
262
- expect(syntheticEvent.isPropagationStopped()).toBe(false),
263
- ).toErrorDev(
264
- 'Warning: This synthetic event is reused for performance reasons. If ' +
265
- "you're seeing this, you're accessing the method `isPropagationStopped` on a " +
266
- 'released/nullified synthetic event. This is a no-op function. If you must ' +
267
- 'keep the original synthetic event around, use event.persist(). ' +
268
- 'See https://fb.me/react-event-pooling for more information.',
269
- {withoutStack: true},
270
- );
271
- expect(expectedCount).toBe(1);
272
- });
273
-
274
- it('should warn when calling `isDefaultPrevented` if the synthetic event has not been persisted', () => {
275
- let expectedCount = 0;
276
- let syntheticEvent;
277
-
278
- const eventHandler = e => {
279
- syntheticEvent = e;
280
- expectedCount++;
281
- };
282
- const node = ReactDOM.render(<div onClick={eventHandler} />, container);
283
-
284
- const event = document.createEvent('Event');
285
- event.initEvent('click', true, true);
286
- node.dispatchEvent(event);
287
-
288
- expect(() =>
289
- expect(syntheticEvent.isDefaultPrevented()).toBe(false),
290
- ).toErrorDev(
291
- 'Warning: This synthetic event is reused for performance reasons. If ' +
292
- "you're seeing this, you're accessing the method `isDefaultPrevented` on a " +
293
- 'released/nullified synthetic event. This is a no-op function. If you must ' +
294
- 'keep the original synthetic event around, use event.persist(). ' +
295
- 'See https://fb.me/react-event-pooling for more information.',
296
- {withoutStack: true},
297
- );
298
- expect(expectedCount).toBe(1);
299
- });
300
-
301
- it('should properly log warnings when events simulated with rendered components', () => {
302
- let event;
303
- function assignEvent(e) {
304
- event = e;
305
- }
306
- const node = ReactDOM.render(<div onClick={assignEvent} />, container);
307
- node.click();
308
-
309
- // access a property to cause the warning
310
- expect(() => {
311
- event.nativeEvent; // eslint-disable-line no-unused-expressions
312
- }).toErrorDev(
313
- 'Warning: This synthetic event is reused for performance reasons. If ' +
314
- "you're seeing this, you're accessing the property `nativeEvent` on a " +
315
- 'released/nullified synthetic event. This is set to null. If you must ' +
316
- 'keep the original synthetic event around, use event.persist(). ' +
317
- 'See https://fb.me/react-event-pooling for more information.',
318
- {withoutStack: true},
319
- );
320
- });
321
- }
322
-
323
- // TODO: we might want to re-add a warning like this in the future,
324
- // but it shouldn't use Proxies because they make debugging difficult.
325
- // Or we might disallow this pattern altogether:
326
- // https://github.com/facebook/react/issues/13224
327
- xit('should warn if a property is added to the synthetic event', () => {
328
- let expectedCount = 0;
329
- let syntheticEvent;
330
-
331
- const eventHandler = e => {
332
- expect(() => {
333
- e.foo = 'bar';
334
- }).toErrorDev(
335
- 'Warning: This synthetic event is reused for performance reasons. If ' +
336
- "you're seeing this, you're adding a new property in the synthetic " +
337
- 'event object. The property is never released. ' +
338
- 'See https://fb.me/react-event-pooling for more information.',
339
- {withoutStack: true},
340
- );
341
- syntheticEvent = e;
342
- expectedCount++;
343
- };
344
- const node = ReactDOM.render(<div onClick={eventHandler} />, container);
345
-
346
- const event = document.createEvent('Event');
347
- event.initEvent('click', true, true);
348
-
349
- node.dispatchEvent(event);
350
-
351
- expect(syntheticEvent.foo).toBe('bar');
352
- expect(expectedCount).toBe(1);
353
- });
101
});
packages/react-dom/src/events/__tests__/SyntheticKeyboardEvent-test.js
-48
@@ -11,7 +11,6 @@
11
12
let React;
13
let ReactDOM;
14
-const ReactFeatureFlags = require('shared/ReactFeatureFlags');
14
15
describe('SyntheticKeyboardEvent', () => {
16
let container;
@@ -547,52 +546,5 @@ describe('SyntheticKeyboardEvent', () => {
546
);
547
expect(expectedCount).toBe(3);
548
});
550
-
551
- if (!ReactFeatureFlags.enableModernEventSystem) {
552
- it('is able to `persist`', () => {
553
- const persistentEvents = [];
554
- const eventHandler = event => {
555
- expect(event.isPersistent()).toBe(false);
556
- event.persist();
557
- expect(event.isPersistent()).toBe(true);
558
- persistentEvents.push(event);
559
- };
560
- const div = ReactDOM.render(
561
- <div
562
- onKeyDown={eventHandler}
563
- onKeyUp={eventHandler}
564
- onKeyPress={eventHandler}
565
- />,
566
- container,
567
- );
568
-
569
- div.dispatchEvent(
570
- new KeyboardEvent('keydown', {
571
- keyCode: 40,
572
- bubbles: true,
573
- cancelable: true,
574
- }),
575
- );
576
- div.dispatchEvent(
577
- new KeyboardEvent('keyup', {
578
- keyCode: 40,
579
- bubbles: true,
580
- cancelable: true,
581
- }),
582
- );
583
- div.dispatchEvent(
584
- new KeyboardEvent('keypress', {
585
- charCode: 40,
586
- keyCode: 40,
587
- bubbles: true,
588
- cancelable: true,
589
- }),
590
- );
591
- expect(persistentEvents.length).toBe(3);
592
- expect(persistentEvents[0].type).toBe('keydown');
593
- expect(persistentEvents[1].type).toBe('keyup');
594
- expect(persistentEvents[2].type).toBe('keypress');
595
- });
596
- }
549
});
550
});
packages/react-dom/src/events/__tests__/SyntheticWheelEvent-test.js
-23
@@ -11,7 +11,6 @@
11
12
let React;
13
let ReactDOM;
14
-const ReactFeatureFlags = require('shared/ReactFeatureFlags');
14
15
describe('SyntheticWheelEvent', () => {
16
let container;
@@ -113,26 +112,4 @@ describe('SyntheticWheelEvent', () => {
112
113
expect(events.length).toBe(2);
114
});
116
-
117
- if (!ReactFeatureFlags.enableModernEventSystem) {
118
- it('should be able to `persist`', () => {
119
- const events = [];
120
- const onWheel = event => {
121
- expect(event.isPersistent()).toBe(false);
122
- event.persist();
123
- expect(event.isPersistent()).toBe(true);
124
- events.push(event);
125
- };
126
- ReactDOM.render(<div onWheel={onWheel} />, container);
127
-
128
- container.firstChild.dispatchEvent(
129
- new MouseEvent('wheel', {
130
- bubbles: true,
131
- }),
132
- );
133
-
134
- expect(events.length).toBe(1);
135
- expect(events[0].type).toBe('wheel');
136
- });
137
- }
115
});
packages/react-dom/src/events/plugins/LegacyBeforeInputEventPlugin.js
deleted
-498
@@ -1,498 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-import type {TopLevelType} from '../../legacy-events/TopLevelEventTypes';
9
-
10
-import {canUseDOM} from 'shared/ExecutionEnvironment';
11
-
12
-import {
13
- TOP_BLUR,
14
- TOP_COMPOSITION_START,
15
- TOP_COMPOSITION_END,
16
- TOP_COMPOSITION_UPDATE,
17
- TOP_KEY_DOWN,
18
- TOP_KEY_PRESS,
19
- TOP_KEY_UP,
20
- TOP_MOUSE_DOWN,
21
- TOP_TEXT_INPUT,
22
- TOP_PASTE,
23
-} from '../DOMTopLevelEventTypes';
24
-import {
25
- getData as FallbackCompositionStateGetData,
26
- initialize as FallbackCompositionStateInitialize,
27
- reset as FallbackCompositionStateReset,
28
-} from '../FallbackCompositionState';
29
-import SyntheticCompositionEvent from '../SyntheticCompositionEvent';
30
-import SyntheticInputEvent from '../SyntheticInputEvent';
31
-import {accumulateTwoPhaseDispatches} from '../DOMLegacyEventPluginSystem';
32
-
33
-const END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
34
-const START_KEYCODE = 229;
35
-
36
-const canUseCompositionEvent = canUseDOM && 'CompositionEvent' in window;
37
-
38
-let documentMode = null;
39
-if (canUseDOM && 'documentMode' in document) {
40
- documentMode = document.documentMode;
41
-}
42
-
43
-// Webkit offers a very useful `textInput` event that can be used to
44
-// directly represent `beforeInput`. The IE `textinput` event is not as
45
-// useful, so we don't use it.
46
-const canUseTextInputEvent =
47
- canUseDOM && 'TextEvent' in window && !documentMode;
48
-
49
-// In IE9+, we have access to composition events, but the data supplied
50
-// by the native compositionend event may be incorrect. Japanese ideographic
51
-// spaces, for instance (\u3000) are not recorded correctly.
52
-const useFallbackCompositionData =
53
- canUseDOM &&
54
- (!canUseCompositionEvent ||
55
- (documentMode && documentMode > 8 && documentMode <= 11));
56
-
57
-const SPACEBAR_CODE = 32;
58
-const SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);
59
-
60
-// Events and their corresponding property names.
61
-const eventTypes = {
62
- beforeInput: {
63
- phasedRegistrationNames: {
64
- bubbled: 'onBeforeInput',
65
- captured: 'onBeforeInputCapture',
66
- },
67
- dependencies: [
68
- TOP_COMPOSITION_END,
69
- TOP_KEY_PRESS,
70
- TOP_TEXT_INPUT,
71
- TOP_PASTE,
72
- ],
73
- },
74
- compositionEnd: {
75
- phasedRegistrationNames: {
76
- bubbled: 'onCompositionEnd',
77
- captured: 'onCompositionEndCapture',
78
- },
79
- dependencies: [
80
- TOP_BLUR,
81
- TOP_COMPOSITION_END,
82
- TOP_KEY_DOWN,
83
- TOP_KEY_PRESS,
84
- TOP_KEY_UP,
85
- TOP_MOUSE_DOWN,
86
- ],
87
- },
88
- compositionStart: {
89
- phasedRegistrationNames: {
90
- bubbled: 'onCompositionStart',
91
- captured: 'onCompositionStartCapture',
92
- },
93
- dependencies: [
94
- TOP_BLUR,
95
- TOP_COMPOSITION_START,
96
- TOP_KEY_DOWN,
97
- TOP_KEY_PRESS,
98
- TOP_KEY_UP,
99
- TOP_MOUSE_DOWN,
100
- ],
101
- },
102
- compositionUpdate: {
103
- phasedRegistrationNames: {
104
- bubbled: 'onCompositionUpdate',
105
- captured: 'onCompositionUpdateCapture',
106
- },
107
- dependencies: [
108
- TOP_BLUR,
109
- TOP_COMPOSITION_UPDATE,
110
- TOP_KEY_DOWN,
111
- TOP_KEY_PRESS,
112
- TOP_KEY_UP,
113
- TOP_MOUSE_DOWN,
114
- ],
115
- },
116
-};
117
-
118
-// Track whether we've ever handled a keypress on the space key.
119
-let hasSpaceKeypress = false;
120
-
121
-/**
122
- * Return whether a native keypress event is assumed to be a command.
123
- * This is required because Firefox fires `keypress` events for key commands
124
- * (cut, copy, select-all, etc.) even though no character is inserted.
125
- */
126
-function isKeypressCommand(nativeEvent) {
127
- return (
128
- (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) &&
129
- // ctrlKey && altKey is equivalent to AltGr, and is not a command.
130
- !(nativeEvent.ctrlKey && nativeEvent.altKey)
131
- );
132
-}
133
-
134
-/**
135
- * Translate native top level events into event types.
136
- *
137
- * @param {string} topLevelType
138
- * @return {object}
139
- */
140
-function getCompositionEventType(topLevelType) {
141
- switch (topLevelType) {
142
- case TOP_COMPOSITION_START:
143
- return eventTypes.compositionStart;
144
- case TOP_COMPOSITION_END:
145
- return eventTypes.compositionEnd;
146
- case TOP_COMPOSITION_UPDATE:
147
- return eventTypes.compositionUpdate;
148
- }
149
-}
150
-
151
-/**
152
- * Does our fallback best-guess model think this event signifies that
153
- * composition has begun?
154
- *
155
- * @param {string} topLevelType
156
- * @param {object} nativeEvent
157
- * @return {boolean}
158
- */
159
-function isFallbackCompositionStart(topLevelType, nativeEvent) {
160
- return topLevelType === TOP_KEY_DOWN && nativeEvent.keyCode === START_KEYCODE;
161
-}
162
-
163
-/**
164
- * Does our fallback mode think that this event is the end of composition?
165
- *
166
- * @param {string} topLevelType
167
- * @param {object} nativeEvent
168
- * @return {boolean}
169
- */
170
-function isFallbackCompositionEnd(topLevelType, nativeEvent) {
171
- switch (topLevelType) {
172
- case TOP_KEY_UP:
173
- // Command keys insert or clear IME input.
174
- return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1;
175
- case TOP_KEY_DOWN:
176
- // Expect IME keyCode on each keydown. If we get any other
177
- // code we must have exited earlier.
178
- return nativeEvent.keyCode !== START_KEYCODE;
179
- case TOP_KEY_PRESS:
180
- case TOP_MOUSE_DOWN:
181
- case TOP_BLUR:
182
- // Events are not possible without cancelling IME.
183
- return true;
184
- default:
185
- return false;
186
- }
187
-}
188
-
189
-/**
190
- * Google Input Tools provides composition data via a CustomEvent,
191
- * with the `data` property populated in the `detail` object. If this
192
- * is available on the event object, use it. If not, this is a plain
193
- * composition event and we have nothing special to extract.
194
- *
195
- * @param {object} nativeEvent
196
- * @return {?string}
197
- */
198
-function getDataFromCustomEvent(nativeEvent) {
199
- const detail = nativeEvent.detail;
200
- if (typeof detail === 'object' && 'data' in detail) {
201
- return detail.data;
202
- }
203
- return null;
204
-}
205
-
206
-/**
207
- * Check if a composition event was triggered by Korean IME.
208
- * Our fallback mode does not work well with IE's Korean IME,
209
- * so just use native composition events when Korean IME is used.
210
- * Although CompositionEvent.locale property is deprecated,
211
- * it is available in IE, where our fallback mode is enabled.
212
- *
213
- * @param {object} nativeEvent
214
- * @return {boolean}
215
- */
216
-function isUsingKoreanIME(nativeEvent) {
217
- return nativeEvent.locale === 'ko';
218
-}
219
-
220
-// Track the current IME composition status, if any.
221
-let isComposing = false;
222
-
223
-/**
224
- * @return {?object} A SyntheticCompositionEvent.
225
- */
226
-function extractCompositionEvent(
227
- topLevelType,
228
- targetInst,
229
- nativeEvent,
230
- nativeEventTarget,
231
-) {
232
- let eventType;
233
- let fallbackData;
234
-
235
- if (canUseCompositionEvent) {
236
- eventType = getCompositionEventType(topLevelType);
237
- } else if (!isComposing) {
238
- if (isFallbackCompositionStart(topLevelType, nativeEvent)) {
239
- eventType = eventTypes.compositionStart;
240
- }
241
- } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) {
242
- eventType = eventTypes.compositionEnd;
243
- }
244
-
245
- if (!eventType) {
246
- return null;
247
- }
248
-
249
- if (useFallbackCompositionData && !isUsingKoreanIME(nativeEvent)) {
250
- // The current composition is stored statically and must not be
251
- // overwritten while composition continues.
252
- if (!isComposing && eventType === eventTypes.compositionStart) {
253
- isComposing = FallbackCompositionStateInitialize(nativeEventTarget);
254
- } else if (eventType === eventTypes.compositionEnd) {
255
- if (isComposing) {
256
- fallbackData = FallbackCompositionStateGetData();
257
- }
258
- }
259
- }
260
-
261
- const event = SyntheticCompositionEvent.getPooled(
262
- eventType,
263
- targetInst,
264
- nativeEvent,
265
- nativeEventTarget,
266
- );
267
-
268
- if (fallbackData) {
269
- // Inject data generated from fallback path into the synthetic event.
270
- // This matches the property of native CompositionEventInterface.
271
- event.data = fallbackData;
272
- } else {
273
- const customData = getDataFromCustomEvent(nativeEvent);
274
- if (customData !== null) {
275
- event.data = customData;
276
- }
277
- }
278
-
279
- accumulateTwoPhaseDispatches(event);
280
- return event;
281
-}
282
-
283
-/**
284
- * @param {TopLevelType} topLevelType Number from `TopLevelType`.
285
- * @param {object} nativeEvent Native browser event.
286
- * @return {?string} The string corresponding to this `beforeInput` event.
287
- */
288
-function getNativeBeforeInputChars(topLevelType: TopLevelType, nativeEvent) {
289
- switch (topLevelType) {
290
- case TOP_COMPOSITION_END:
291
- return getDataFromCustomEvent(nativeEvent);
292
- case TOP_KEY_PRESS:
293
- /**
294
- * If native `textInput` events are available, our goal is to make
295
- * use of them. However, there is a special case: the spacebar key.
296
- * In Webkit, preventing default on a spacebar `textInput` event
297
- * cancels character insertion, but it *also* causes the browser
298
- * to fall back to its default spacebar behavior of scrolling the
299
- * page.
300
- *
301
- * Tracking at:
302
- * https://code.google.com/p/chromium/issues/detail?id=355103
303
- *
304
- * To avoid this issue, use the keypress event as if no `textInput`
305
- * event is available.
306
- */
307
- const which = nativeEvent.which;
308
- if (which !== SPACEBAR_CODE) {
309
- return null;
310
- }
311
-
312
- hasSpaceKeypress = true;
313
- return SPACEBAR_CHAR;
314
-
315
- case TOP_TEXT_INPUT:
316
- // Record the characters to be added to the DOM.
317
- const chars = nativeEvent.data;
318
-
319
- // If it's a spacebar character, assume that we have already handled
320
- // it at the keypress level and bail immediately. Android Chrome
321
- // doesn't give us keycodes, so we need to ignore it.
322
- if (chars === SPACEBAR_CHAR && hasSpaceKeypress) {
323
- return null;
324
- }
325
-
326
- return chars;
327
-
328
- default:
329
- // For other native event types, do nothing.
330
- return null;
331
- }
332
-}
333
-
334
-/**
335
- * For browsers that do not provide the `textInput` event, extract the
336
- * appropriate string to use for SyntheticInputEvent.
337
- *
338
- * @param {number} topLevelType Number from `TopLevelEventTypes`.
339
- * @param {object} nativeEvent Native browser event.
340
- * @return {?string} The fallback string for this `beforeInput` event.
341
- */
342
-function getFallbackBeforeInputChars(topLevelType: TopLevelType, nativeEvent) {
343
- // If we are currently composing (IME) and using a fallback to do so,
344
- // try to extract the composed characters from the fallback object.
345
- // If composition event is available, we extract a string only at
346
- // compositionevent, otherwise extract it at fallback events.
347
- if (isComposing) {
348
- if (
349
- topLevelType === TOP_COMPOSITION_END ||
350
- (!canUseCompositionEvent &&
351
- isFallbackCompositionEnd(topLevelType, nativeEvent))
352
- ) {
353
- const chars = FallbackCompositionStateGetData();
354
- FallbackCompositionStateReset();
355
- isComposing = false;
356
- return chars;
357
- }
358
- return null;
359
- }
360
-
361
- switch (topLevelType) {
362
- case TOP_PASTE:
363
- // If a paste event occurs after a keypress, throw out the input
364
- // chars. Paste events should not lead to BeforeInput events.
365
- return null;
366
- case TOP_KEY_PRESS:
367
- /**
368
- * As of v27, Firefox may fire keypress events even when no character
369
- * will be inserted. A few possibilities:
370
- *
371
- * - `which` is `0`. Arrow keys, Esc key, etc.
372
- *
373
- * - `which` is the pressed key code, but no char is available.
374
- * Ex: 'AltGr + d` in Polish. There is no modified character for
375
- * this key combination and no character is inserted into the
376
- * document, but FF fires the keypress for char code `100` anyway.
377
- * No `input` event will occur.
378
- *
379
- * - `which` is the pressed key code, but a command combination is
380
- * being used. Ex: `Cmd+C`. No character is inserted, and no
381
- * `input` event will occur.
382
- */
383
- if (!isKeypressCommand(nativeEvent)) {
384
- // IE fires the `keypress` event when a user types an emoji via
385
- // Touch keyboard of Windows. In such a case, the `char` property
386
- // holds an emoji character like `\uD83D\uDE0A`. Because its length
387
- // is 2, the property `which` does not represent an emoji correctly.
388
- // In such a case, we directly return the `char` property instead of
389
- // using `which`.
390
- if (nativeEvent.char && nativeEvent.char.length > 1) {
391
- return nativeEvent.char;
392
- } else if (nativeEvent.which) {
393
- return String.fromCharCode(nativeEvent.which);
394
- }
395
- }
396
- return null;
397
- case TOP_COMPOSITION_END:
398
- return useFallbackCompositionData && !isUsingKoreanIME(nativeEvent)
399
- ? null
400
- : nativeEvent.data;
401
- default:
402
- return null;
403
- }
404
-}
405
-
406
-/**
407
- * Extract a SyntheticInputEvent for `beforeInput`, based on either native
408
- * `textInput` or fallback behavior.
409
- *
410
- * @return {?object} A SyntheticInputEvent.
411
- */
412
-function extractBeforeInputEvent(
413
- topLevelType,
414
- targetInst,
415
- nativeEvent,
416
- nativeEventTarget,
417
-) {
418
- let chars;
419
-
420
- if (canUseTextInputEvent) {
421
- chars = getNativeBeforeInputChars(topLevelType, nativeEvent);
422
- } else {
423
- chars = getFallbackBeforeInputChars(topLevelType, nativeEvent);
424
- }
425
-
426
- // If no characters are being inserted, no BeforeInput event should
427
- // be fired.
428
- if (!chars) {
429
- return null;
430
- }
431
-
432
- const event = SyntheticInputEvent.getPooled(
433
- eventTypes.beforeInput,
434
- targetInst,
435
- nativeEvent,
436
- nativeEventTarget,
437
- );
438
-
439
- event.data = chars;
440
- accumulateTwoPhaseDispatches(event);
441
- return event;
442
-}
443
-
444
-/**
445
- * Create an `onBeforeInput` event to match
446
- * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents.
447
- *
448
- * This event plugin is based on the native `textInput` event
449
- * available in Chrome, Safari, Opera, and IE. This event fires after
450
- * `onKeyPress` and `onCompositionEnd`, but before `onInput`.
451
- *
452
- * `beforeInput` is spec'd but not implemented in any browsers, and
453
- * the `input` event does not provide any useful information about what has
454
- * actually been added, contrary to the spec. Thus, `textInput` is the best
455
- * available event to identify the characters that have actually been inserted
456
- * into the target node.
457
- *
458
- * This plugin is also responsible for emitting `composition` events, thus
459
- * allowing us to share composition fallback code for both `beforeInput` and
460
- * `composition` event types.
461
- */
462
-const BeforeInputEventPlugin = {
463
- eventTypes: eventTypes,
464
-
465
- extractEvents: function(
466
- topLevelType,
467
- targetInst,
468
- nativeEvent,
469
- nativeEventTarget,
470
- eventSystemFlags,
471
- ) {
472
- const composition = extractCompositionEvent(
473
- topLevelType,
474
- targetInst,
475
- nativeEvent,
476
- nativeEventTarget,
477
- );
478
-
479
- const beforeInput = extractBeforeInputEvent(
480
- topLevelType,
481
- targetInst,
482
- nativeEvent,
483
- nativeEventTarget,
484
- );
485
-
486
- if (composition === null) {
487
- return beforeInput;
488
- }
489
-
490
- if (beforeInput === null) {
491
- return composition;
492
- }
493
-
494
- return [composition, beforeInput];
495
- },
496
-};
497
-
498
-export default BeforeInputEventPlugin;
packages/react-dom/src/events/plugins/LegacyChangeEventPlugin.js
deleted
-310
@@ -1,310 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-import {runEventsInBatch} from '../../legacy-events/EventBatching';
9
-import SyntheticEvent from '../../legacy-events/SyntheticEvent';
10
-import isTextInputElement from '../isTextInputElement';
11
-import {canUseDOM} from 'shared/ExecutionEnvironment';
12
-
13
-import {
14
- TOP_BLUR,
15
- TOP_CHANGE,
16
- TOP_CLICK,
17
- TOP_FOCUS,
18
- TOP_INPUT,
19
- TOP_KEY_DOWN,
20
- TOP_KEY_UP,
21
- TOP_SELECTION_CHANGE,
22
-} from '../DOMTopLevelEventTypes';
23
-import getEventTarget from '../getEventTarget';
24
-import isEventSupported from '../isEventSupported';
25
-import {getNodeFromInstance} from '../../client/ReactDOMComponentTree';
26
-import {updateValueIfChanged} from '../../client/inputValueTracking';
27
-import {setDefaultValue} from '../../client/ReactDOMInput';
28
-import {enqueueStateRestore} from '../ReactDOMControlledComponent';
29
-
30
-import {disableInputAttributeSyncing} from 'shared/ReactFeatureFlags';
31
-import {batchedUpdates} from '../ReactDOMUpdateBatching';
32
-import {accumulateTwoPhaseDispatches} from '../DOMLegacyEventPluginSystem';
33
-
34
-const eventTypes = {
35
- change: {
36
- phasedRegistrationNames: {
37
- bubbled: 'onChange',
38
- captured: 'onChangeCapture',
39
- },
40
- dependencies: [
41
- TOP_BLUR,
42
- TOP_CHANGE,
43
- TOP_CLICK,
44
- TOP_FOCUS,
45
- TOP_INPUT,
46
- TOP_KEY_DOWN,
47
- TOP_KEY_UP,
48
- TOP_SELECTION_CHANGE,
49
- ],
50
- },
51
-};
52
-
53
-function createAndAccumulateChangeEvent(inst, nativeEvent, target) {
54
- const event = SyntheticEvent.getPooled(
55
- eventTypes.change,
56
- inst,
57
- nativeEvent,
58
- target,
59
- );
60
- event.type = 'change';
61
- // Flag this event loop as needing state restore.
62
- enqueueStateRestore(target);
63
- accumulateTwoPhaseDispatches(event);
64
- return event;
65
-}
66
-/**
67
- * For IE shims
68
- */
69
-let activeElement = null;
70
-let activeElementInst = null;
71
-
72
-/**
73
- * SECTION: handle `change` event
74
- */
75
-function shouldUseChangeEvent(elem) {
76
- const nodeName = elem.nodeName && elem.nodeName.toLowerCase();
77
- return (
78
- nodeName === 'select' || (nodeName === 'input' && elem.type === 'file')
79
- );
80
-}
81
-
82
-function manualDispatchChangeEvent(nativeEvent) {
83
- const event = createAndAccumulateChangeEvent(
84
- activeElementInst,
85
- nativeEvent,
86
- getEventTarget(nativeEvent),
87
- );
88
-
89
- // If change and propertychange bubbled, we'd just bind to it like all the
90
- // other events and have it go through ReactBrowserEventEmitter. Since it
91
- // doesn't, we manually listen for the events and so we have to enqueue and
92
- // process the abstract event manually.
93
- //
94
- // Batching is necessary here in order to ensure that all event handlers run
95
- // before the next rerender (including event handlers attached to ancestor
96
- // elements instead of directly on the input). Without this, controlled
97
- // components don't work properly in conjunction with event bubbling because
98
- // the component is rerendered and the value reverted before all the event
99
- // handlers can run. See https://github.com/facebook/react/issues/708.
100
- batchedUpdates(runEventInBatch, event);
101
-}
102
-
103
-function runEventInBatch(event) {
104
- runEventsInBatch(event);
105
-}
106
-
107
-function getInstIfValueChanged(targetInst) {
108
- const targetNode = getNodeFromInstance(targetInst);
109
- if (updateValueIfChanged(targetNode)) {
110
- return targetInst;
111
- }
112
-}
113
-
114
-function getTargetInstForChangeEvent(topLevelType, targetInst) {
115
- if (topLevelType === TOP_CHANGE) {
116
- return targetInst;
117
- }
118
-}
119
-
120
-/**
121
- * SECTION: handle `input` event
122
- */
123
-let isInputEventSupported = false;
124
-if (canUseDOM) {
125
- // IE9 claims to support the input event but fails to trigger it when
126
- // deleting text, so we ignore its input events.
127
- isInputEventSupported =
128
- isEventSupported('input') &&
129
- (!document.documentMode || document.documentMode > 9);
130
-}
131
-
132
-/**
133
- * (For IE <=9) Starts tracking propertychange events on the passed-in element
134
- * and override the value property so that we can distinguish user events from
135
- * value changes in JS.
136
- */
137
-function startWatchingForValueChange(target, targetInst) {
138
- activeElement = target;
139
- activeElementInst = targetInst;
140
- activeElement.attachEvent('onpropertychange', handlePropertyChange);
141
-}
142
-
143
-/**
144
- * (For IE <=9) Removes the event listeners from the currently-tracked element,
145
- * if any exists.
146
- */
147
-function stopWatchingForValueChange() {
148
- if (!activeElement) {
149
- return;
150
- }
151
- activeElement.detachEvent('onpropertychange', handlePropertyChange);
152
- activeElement = null;
153
- activeElementInst = null;
154
-}
155
-
156
-/**
157
- * (For IE <=9) Handles a propertychange event, sending a `change` event if
158
- * the value of the active element has changed.
159
- */
160
-function handlePropertyChange(nativeEvent) {
161
- if (nativeEvent.propertyName !== 'value') {
162
- return;
163
- }
164
- if (getInstIfValueChanged(activeElementInst)) {
165
- manualDispatchChangeEvent(nativeEvent);
166
- }
167
-}
168
-
169
-function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) {
170
- if (topLevelType === TOP_FOCUS) {
171
- // In IE9, propertychange fires for most input events but is buggy and
172
- // doesn't fire when text is deleted, but conveniently, selectionchange
173
- // appears to fire in all of the remaining cases so we catch those and
174
- // forward the event if the value has changed
175
- // In either case, we don't want to call the event handler if the value
176
- // is changed from JS so we redefine a setter for `.value` that updates
177
- // our activeElementValue variable, allowing us to ignore those changes
178
- //
179
- // stopWatching() should be a noop here but we call it just in case we
180
- // missed a blur event somehow.
181
- stopWatchingForValueChange();
182
- startWatchingForValueChange(target, targetInst);
183
- } else if (topLevelType === TOP_BLUR) {
184
- stopWatchingForValueChange();
185
- }
186
-}
187
-
188
-// For IE8 and IE9.
189
-function getTargetInstForInputEventPolyfill(topLevelType, targetInst) {
190
- if (
191
- topLevelType === TOP_SELECTION_CHANGE ||
192
- topLevelType === TOP_KEY_UP ||
193
- topLevelType === TOP_KEY_DOWN
194
- ) {
195
- // On the selectionchange event, the target is just document which isn't
196
- // helpful for us so just check activeElement instead.
197
- //
198
- // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire
199
- // propertychange on the first input event after setting `value` from a
200
- // script and fires only keydown, keypress, keyup. Catching keyup usually
201
- // gets it and catching keydown lets us fire an event for the first
202
- // keystroke if user does a key repeat (it'll be a little delayed: right
203
- // before the second keystroke). Other input methods (e.g., paste) seem to
204
- // fire selectionchange normally.
205
- return getInstIfValueChanged(activeElementInst);
206
- }
207
-}
208
-
209
-/**
210
- * SECTION: handle `click` event
211
- */
212
-function shouldUseClickEvent(elem) {
213
- // Use the `click` event to detect changes to checkbox and radio inputs.
214
- // This approach works across all browsers, whereas `change` does not fire
215
- // until `blur` in IE8.
216
- const nodeName = elem.nodeName;
217
- return (
218
- nodeName &&
219
- nodeName.toLowerCase() === 'input' &&
220
- (elem.type === 'checkbox' || elem.type === 'radio')
221
- );
222
-}
223
-
224
-function getTargetInstForClickEvent(topLevelType, targetInst) {
225
- if (topLevelType === TOP_CLICK) {
226
- return getInstIfValueChanged(targetInst);
227
- }
228
-}
229
-
230
-function getTargetInstForInputOrChangeEvent(topLevelType, targetInst) {
231
- if (topLevelType === TOP_INPUT || topLevelType === TOP_CHANGE) {
232
- return getInstIfValueChanged(targetInst);
233
- }
234
-}
235
-
236
-function handleControlledInputBlur(node) {
237
- const state = node._wrapperState;
238
-
239
- if (!state || !state.controlled || node.type !== 'number') {
240
- return;
241
- }
242
-
243
- if (!disableInputAttributeSyncing) {
244
- // If controlled, assign the value attribute to the current value on blur
245
- setDefaultValue(node, 'number', node.value);
246
- }
247
-}
248
-
249
-/**
250
- * This plugin creates an `onChange` event that normalizes change events
251
- * across form elements. This event fires at a time when it's possible to
252
- * change the element's value without seeing a flicker.
253
- *
254
- * Supported elements are:
255
- * - input (see `isTextInputElement`)
256
- * - textarea
257
- * - select
258
- */
259
-const ChangeEventPlugin = {
260
- eventTypes: eventTypes,
261
-
262
- _isInputEventSupported: isInputEventSupported,
263
-
264
- extractEvents: function(
265
- topLevelType,
266
- targetInst,
267
- nativeEvent,
268
- nativeEventTarget,
269
- eventSystemFlags,
270
- ) {
271
- const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
272
-
273
- let getTargetInstFunc, handleEventFunc;
274
- if (shouldUseChangeEvent(targetNode)) {
275
- getTargetInstFunc = getTargetInstForChangeEvent;
276
- } else if (isTextInputElement(targetNode)) {
277
- if (isInputEventSupported) {
278
- getTargetInstFunc = getTargetInstForInputOrChangeEvent;
279
- } else {
280
- getTargetInstFunc = getTargetInstForInputEventPolyfill;
281
- handleEventFunc = handleEventsForInputEventPolyfill;
282
- }
283
- } else if (shouldUseClickEvent(targetNode)) {
284
- getTargetInstFunc = getTargetInstForClickEvent;
285
- }
286
-
287
- if (getTargetInstFunc) {
288
- const inst = getTargetInstFunc(topLevelType, targetInst);
289
- if (inst) {
290
- const event = createAndAccumulateChangeEvent(
291
- inst,
292
- nativeEvent,
293
- nativeEventTarget,
294
- );
295
- return event;
296
- }
297
- }
298
-
299
- if (handleEventFunc) {
300
- handleEventFunc(topLevelType, targetNode, targetInst);
301
- }
302
-
303
- // When blurring, set the value attribute for number inputs
304
- if (topLevelType === TOP_BLUR) {
305
- handleControlledInputBlur(targetNode);
306
- }
307
- },
308
-};
309
-
310
-export default ChangeEventPlugin;
packages/react-dom/src/events/plugins/LegacyEnterLeaveEventPlugin.js
deleted
-179
@@ -1,179 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-import {
9
- TOP_MOUSE_OUT,
10
- TOP_MOUSE_OVER,
11
- TOP_POINTER_OUT,
12
- TOP_POINTER_OVER,
13
-} from '../DOMTopLevelEventTypes';
14
-import {
15
- IS_REPLAYED,
16
- IS_FIRST_ANCESTOR,
17
-} from 'react-dom/src/events/EventSystemFlags';
18
-import SyntheticMouseEvent from '../SyntheticMouseEvent';
19
-import SyntheticPointerEvent from '../SyntheticPointerEvent';
20
-import {
21
- getClosestInstanceFromNode,
22
- getNodeFromInstance,
23
-} from '../../client/ReactDOMComponentTree';
24
-import {HostComponent, HostText} from 'react-reconciler/src/ReactWorkTags';
25
-import {getNearestMountedFiber} from 'react-reconciler/src/ReactFiberTreeReflection';
26
-import {accumulateEnterLeaveDispatches} from '../DOMLegacyEventPluginSystem';
27
-
28
-const eventTypes = {
29
- mouseEnter: {
30
- registrationName: 'onMouseEnter',
31
- dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER],
32
- },
33
- mouseLeave: {
34
- registrationName: 'onMouseLeave',
35
- dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER],
36
- },
37
- pointerEnter: {
38
- registrationName: 'onPointerEnter',
39
- dependencies: [TOP_POINTER_OUT, TOP_POINTER_OVER],
40
- },
41
- pointerLeave: {
42
- registrationName: 'onPointerLeave',
43
- dependencies: [TOP_POINTER_OUT, TOP_POINTER_OVER],
44
- },
45
-};
46
-
47
-const EnterLeaveEventPlugin = {
48
- eventTypes: eventTypes,
49
-
50
- /**
51
- * For almost every interaction we care about, there will be both a top-level
52
- * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
53
- * we do not extract duplicate events. However, moving the mouse into the
54
- * browser from outside will not fire a `mouseout` event. In this case, we use
55
- * the `mouseover` top-level event.
56
- */
57
- extractEvents: function(
58
- topLevelType,
59
- targetInst,
60
- nativeEvent,
61
- nativeEventTarget,
62
- eventSystemFlags,
63
- ) {
64
- const isOverEvent =
65
- topLevelType === TOP_MOUSE_OVER || topLevelType === TOP_POINTER_OVER;
66
- const isOutEvent =
67
- topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_POINTER_OUT;
68
-
69
- if (
70
- isOverEvent &&
71
- (eventSystemFlags & IS_REPLAYED) === 0 &&
72
- (nativeEvent.relatedTarget || nativeEvent.fromElement)
73
- ) {
74
- // If this is an over event with a target, then we've already dispatched
75
- // the event in the out event of the other target. If this is replayed,
76
- // then it's because we couldn't dispatch against this target previously
77
- // so we have to do it now instead.
78
- return null;
79
- }
80
-
81
- if (!isOutEvent && !isOverEvent) {
82
- // Must not be a mouse or pointer in or out - ignoring.
83
- return null;
84
- }
85
-
86
- let win;
87
- if (nativeEventTarget.window === nativeEventTarget) {
88
- // `nativeEventTarget` is probably a window object.
89
- win = nativeEventTarget;
90
- } else {
91
- // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
92
- const doc = nativeEventTarget.ownerDocument;
93
- if (doc) {
94
- win = doc.defaultView || doc.parentWindow;
95
- } else {
96
- win = window;
97
- }
98
- }
99
-
100
- let from;
101
- let to;
102
- if (isOutEvent) {
103
- from = targetInst;
104
- const related = nativeEvent.relatedTarget || nativeEvent.toElement;
105
- to = related ? getClosestInstanceFromNode(related) : null;
106
- if (to !== null) {
107
- const nearestMounted = getNearestMountedFiber(to);
108
- if (
109
- to !== nearestMounted ||
110
- (to.tag !== HostComponent && to.tag !== HostText)
111
- ) {
112
- to = null;
113
- }
114
- }
115
- } else {
116
- // Moving to a node from outside the window.
117
- from = null;
118
- to = targetInst;
119
- }
120
-
121
- if (from === to) {
122
- // Nothing pertains to our managed components.
123
- return null;
124
- }
125
-
126
- let eventInterface, leaveEventType, enterEventType, eventTypePrefix;
127
-
128
- if (topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_MOUSE_OVER) {
129
- eventInterface = SyntheticMouseEvent;
130
- leaveEventType = eventTypes.mouseLeave;
131
- enterEventType = eventTypes.mouseEnter;
132
- eventTypePrefix = 'mouse';
133
- } else if (
134
- topLevelType === TOP_POINTER_OUT ||
135
- topLevelType === TOP_POINTER_OVER
136
- ) {
137
- eventInterface = SyntheticPointerEvent;
138
- leaveEventType = eventTypes.pointerLeave;
139
- enterEventType = eventTypes.pointerEnter;
140
- eventTypePrefix = 'pointer';
141
- }
142
-
143
- const fromNode = from == null ? win : getNodeFromInstance(from);
144
- const toNode = to == null ? win : getNodeFromInstance(to);
145
-
146
- const leave = eventInterface.getPooled(
147
- leaveEventType,
148
- from,
149
- nativeEvent,
150
- nativeEventTarget,
151
- );
152
- leave.type = eventTypePrefix + 'leave';
153
- leave.target = fromNode;
154
- leave.relatedTarget = toNode;
155
-
156
- const enter = eventInterface.getPooled(
157
- enterEventType,
158
- to,
159
- nativeEvent,
160
- nativeEventTarget,
161
- );
162
- enter.type = eventTypePrefix + 'enter';
163
- enter.target = toNode;
164
- enter.relatedTarget = fromNode;
165
-
166
- accumulateEnterLeaveDispatches(leave, enter, from, to);
167
-
168
- // If we are not processing the first ancestor, then we
169
- // should not process the same nativeEvent again, as we
170
- // will have already processed it in the first ancestor.
171
- if ((eventSystemFlags & IS_FIRST_ANCESTOR) === 0) {
172
- return [leave];
173
- }
174
-
175
- return [leave, enter];
176
- },
177
-};
178
-
179
-export default EnterLeaveEventPlugin;
packages/react-dom/src/events/plugins/LegacySelectEventPlugin.js
deleted
-248
@@ -1,248 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-import {canUseDOM} from 'shared/ExecutionEnvironment';
9
-import SyntheticEvent from '../../legacy-events/SyntheticEvent';
10
-import isTextInputElement from '../isTextInputElement';
11
-import shallowEqual from 'shared/shallowEqual';
12
-
13
-import {
14
- TOP_BLUR,
15
- TOP_CONTEXT_MENU,
16
- TOP_DRAG_END,
17
- TOP_FOCUS,
18
- TOP_KEY_DOWN,
19
- TOP_KEY_UP,
20
- TOP_MOUSE_DOWN,
21
- TOP_MOUSE_UP,
22
- TOP_SELECTION_CHANGE,
23
-} from '../DOMTopLevelEventTypes';
24
-import getActiveElement from '../../client/getActiveElement';
25
-import {
26
- getNodeFromInstance,
27
- getEventListenerMap,
28
-} from '../../client/ReactDOMComponentTree';
29
-import {hasSelectionCapabilities} from '../../client/ReactInputSelection';
30
-import {DOCUMENT_NODE} from '../../shared/HTMLNodeType';
31
-import {accumulateTwoPhaseDispatches} from '../DOMLegacyEventPluginSystem';
32
-
33
-import {registrationNameDependencies} from '../../legacy-events/EventPluginRegistry';
34
-
35
-const skipSelectionChangeEvent =
36
- canUseDOM && 'documentMode' in document && document.documentMode <= 11;
37
-
38
-const eventTypes = {
39
- select: {
40
- phasedRegistrationNames: {
41
- bubbled: 'onSelect',
42
- captured: 'onSelectCapture',
43
- },
44
- dependencies: [
45
- TOP_BLUR,
46
- TOP_CONTEXT_MENU,
47
- TOP_DRAG_END,
48
- TOP_FOCUS,
49
- TOP_KEY_DOWN,
50
- TOP_KEY_UP,
51
- TOP_MOUSE_DOWN,
52
- TOP_MOUSE_UP,
53
- TOP_SELECTION_CHANGE,
54
- ],
55
- },
56
-};
57
-
58
-let activeElement = null;
59
-let activeElementInst = null;
60
-let lastSelection = null;
61
-let mouseDown = false;
62
-
63
-/**
64
- * Get an object which is a unique representation of the current selection.
65
- *
66
- * The return value will not be consistent across nodes or browsers, but
67
- * two identical selections on the same node will return identical objects.
68
- *
69
- * @param {DOMElement} node
70
- * @return {object}
71
- */
72
-function getSelection(node) {
73
- if ('selectionStart' in node && hasSelectionCapabilities(node)) {
74
- return {
75
- start: node.selectionStart,
76
- end: node.selectionEnd,
77
- };
78
- } else {
79
- const win =
80
- (node.ownerDocument && node.ownerDocument.defaultView) || window;
81
- const selection = win.getSelection();
82
- return {
83
- anchorNode: selection.anchorNode,
84
- anchorOffset: selection.anchorOffset,
85
- focusNode: selection.focusNode,
86
- focusOffset: selection.focusOffset,
87
- };
88
- }
89
-}
90
-
91
-/**
92
- * Get document associated with the event target.
93
- *
94
- * @param {object} nativeEventTarget
95
- * @return {Document}
96
- */
97
-function getEventTargetDocument(eventTarget) {
98
- return eventTarget.window === eventTarget
99
- ? eventTarget.document
100
- : eventTarget.nodeType === DOCUMENT_NODE
101
- ? eventTarget
102
- : eventTarget.ownerDocument;
103
-}
104
-
105
-/**
106
- * Poll selection to see whether it's changed.
107
- *
108
- * @param {object} nativeEvent
109
- * @param {object} nativeEventTarget
110
- * @return {?SyntheticEvent}
111
- */
112
-function constructSelectEvent(nativeEvent, nativeEventTarget) {
113
- // Ensure we have the right element, and that the user is not dragging a
114
- // selection (this matches native `select` event behavior). In HTML5, select
115
- // fires only on input and textarea thus if there's no focused element we
116
- // won't dispatch.
117
- const doc = getEventTargetDocument(nativeEventTarget);
118
-
119
- if (
120
- mouseDown ||
121
- activeElement == null ||
122
- activeElement !== getActiveElement(doc)
123
- ) {
124
- return null;
125
- }
126
-
127
- // Only fire when selection has actually changed.
128
- const currentSelection = getSelection(activeElement);
129
- if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) {
130
- lastSelection = currentSelection;
131
-
132
- const syntheticEvent = SyntheticEvent.getPooled(
133
- eventTypes.select,
134
- activeElementInst,
135
- nativeEvent,
136
- nativeEventTarget,
137
- );
138
-
139
- syntheticEvent.type = 'select';
140
- syntheticEvent.target = activeElement;
141
-
142
- accumulateTwoPhaseDispatches(syntheticEvent);
143
-
144
- return syntheticEvent;
145
- }
146
-
147
- return null;
148
-}
149
-
150
-function isListeningToAllDependencies(
151
- registrationName: string,
152
- mountAt: Document | Element,
153
-): boolean {
154
- const dependencies = registrationNameDependencies[registrationName];
155
- const listenerMap = getEventListenerMap(mountAt);
156
- for (let i = 0; i < dependencies.length; i++) {
157
- const event = dependencies[i];
158
- if (!listenerMap.has(event)) {
159
- return false;
160
- }
161
- }
162
- return true;
163
-}
164
-
165
-/**
166
- * This plugin creates an `onSelect` event that normalizes select events
167
- * across form elements.
168
- *
169
- * Supported elements are:
170
- * - input (see `isTextInputElement`)
171
- * - textarea
172
- * - contentEditable
173
- *
174
- * This differs from native browser implementations in the following ways:
175
- * - Fires on contentEditable fields as well as inputs.
176
- * - Fires for collapsed selection.
177
- * - Fires after user input.
178
- */
179
-const SelectEventPlugin = {
180
- eventTypes: eventTypes,
181
-
182
- extractEvents: function(
183
- topLevelType,
184
- targetInst,
185
- nativeEvent,
186
- nativeEventTarget,
187
- eventSystemFlags,
188
- ) {
189
- const doc = getEventTargetDocument(nativeEventTarget);
190
- // Track whether all listeners exists for this plugin. If none exist, we do
191
- // not extract events. See #3639.
192
- if (!doc || !isListeningToAllDependencies('onSelect', doc)) {
193
- return null;
194
- }
195
-
196
- const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
197
-
198
- switch (topLevelType) {
199
- // Track the input node that has focus.
200
- case TOP_FOCUS:
201
- if (
202
- isTextInputElement(targetNode) ||
203
- targetNode.contentEditable === 'true'
204
- ) {
205
- activeElement = targetNode;
206
- activeElementInst = targetInst;
207
- lastSelection = null;
208
- }
209
- break;
210
- case TOP_BLUR:
211
- activeElement = null;
212
- activeElementInst = null;
213
- lastSelection = null;
214
- break;
215
- // Don't fire the event while the user is dragging. This matches the
216
- // semantics of the native select event.
217
- case TOP_MOUSE_DOWN:
218
- mouseDown = true;
219
- break;
220
- case TOP_CONTEXT_MENU:
221
- case TOP_MOUSE_UP:
222
- case TOP_DRAG_END:
223
- mouseDown = false;
224
- return constructSelectEvent(nativeEvent, nativeEventTarget);
225
- // Chrome and IE fire non-standard event when selection is changed (and
226
- // sometimes when it hasn't). IE's event fires out of order with respect
227
- // to key and input events on deletion, so we discard it.
228
- //
229
- // Firefox doesn't support selectionchange, so check selection status
230
- // after each key entry. The selection changes after keydown and before
231
- // keyup, but we check on keydown as well in the case of holding down a
232
- // key, when multiple keydown events are fired but only one keyup is.
233
- // This is also our approach for IE handling, for the reason above.
234
- case TOP_SELECTION_CHANGE:
235
- if (skipSelectionChangeEvent) {
236
- break;
237
- }
238
- // falls through
239
- case TOP_KEY_DOWN:
240
- case TOP_KEY_UP:
241
- return constructSelectEvent(nativeEvent, nativeEventTarget);
242
- }
243
-
244
- return null;
245
- },
246
-};
247
-
248
-export default SelectEventPlugin;
packages/react-dom/src/events/plugins/LegacySimpleEventPlugin.js
deleted
-197
@@ -1,197 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @flow
8
- */
9
-
10
-import type {
11
- TopLevelType,
12
- DOMTopLevelEventType,
13
-} from '../../legacy-events/TopLevelEventTypes';
14
-import type {ReactSyntheticEvent} from '../../legacy-events/ReactSyntheticEventType';
15
-import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
16
-import type {LegacyPluginModule} from '../../legacy-events/PluginModuleType';
17
-
18
-import SyntheticEvent from '../../legacy-events/SyntheticEvent';
19
-
20
-import * as DOMTopLevelEventTypes from '../DOMTopLevelEventTypes';
21
-import {
22
- topLevelEventsToDispatchConfig,
23
- simpleEventPluginEventTypes,
24
-} from '../DOMEventProperties';
25
-
26
-import SyntheticAnimationEvent from '../SyntheticAnimationEvent';
27
-import SyntheticClipboardEvent from '../SyntheticClipboardEvent';
28
-import SyntheticFocusEvent from '../SyntheticFocusEvent';
29
-import SyntheticKeyboardEvent from '../SyntheticKeyboardEvent';
30
-import SyntheticMouseEvent from '../SyntheticMouseEvent';
31
-import SyntheticPointerEvent from '../SyntheticPointerEvent';
32
-import SyntheticDragEvent from '../SyntheticDragEvent';
33
-import SyntheticTouchEvent from '../SyntheticTouchEvent';
34
-import SyntheticTransitionEvent from '../SyntheticTransitionEvent';
35
-import SyntheticUIEvent from '../SyntheticUIEvent';
36
-import SyntheticWheelEvent from '../SyntheticWheelEvent';
37
-import getEventCharCode from '../getEventCharCode';
38
-import {accumulateTwoPhaseDispatches} from '../DOMLegacyEventPluginSystem';
39
-
40
-// Only used in DEV for exhaustiveness validation.
41
-const knownHTMLTopLevelTypes: Array<DOMTopLevelEventType> = [
42
- DOMTopLevelEventTypes.TOP_ABORT,
43
- DOMTopLevelEventTypes.TOP_CANCEL,
44
- DOMTopLevelEventTypes.TOP_CAN_PLAY,
45
- DOMTopLevelEventTypes.TOP_CAN_PLAY_THROUGH,
46
- DOMTopLevelEventTypes.TOP_CLOSE,
47
- DOMTopLevelEventTypes.TOP_DURATION_CHANGE,
48
- DOMTopLevelEventTypes.TOP_EMPTIED,
49
- DOMTopLevelEventTypes.TOP_ENCRYPTED,
50
- DOMTopLevelEventTypes.TOP_ENDED,
51
- DOMTopLevelEventTypes.TOP_ERROR,
52
- DOMTopLevelEventTypes.TOP_INPUT,
53
- DOMTopLevelEventTypes.TOP_INVALID,
54
- DOMTopLevelEventTypes.TOP_LOAD,
55
- DOMTopLevelEventTypes.TOP_LOADED_DATA,
56
- DOMTopLevelEventTypes.TOP_LOADED_METADATA,
57
- DOMTopLevelEventTypes.TOP_LOAD_START,
58
- DOMTopLevelEventTypes.TOP_PAUSE,
59
- DOMTopLevelEventTypes.TOP_PLAY,
60
- DOMTopLevelEventTypes.TOP_PLAYING,
61
- DOMTopLevelEventTypes.TOP_PROGRESS,
62
- DOMTopLevelEventTypes.TOP_RATE_CHANGE,
63
- DOMTopLevelEventTypes.TOP_RESET,
64
- DOMTopLevelEventTypes.TOP_SEEKED,
65
- DOMTopLevelEventTypes.TOP_SEEKING,
66
- DOMTopLevelEventTypes.TOP_STALLED,
67
- DOMTopLevelEventTypes.TOP_SUBMIT,
68
- DOMTopLevelEventTypes.TOP_SUSPEND,
69
- DOMTopLevelEventTypes.TOP_TIME_UPDATE,
70
- DOMTopLevelEventTypes.TOP_TOGGLE,
71
- DOMTopLevelEventTypes.TOP_VOLUME_CHANGE,
72
- DOMTopLevelEventTypes.TOP_WAITING,
73
-];
74
-
75
-const SimpleEventPlugin: LegacyPluginModule<MouseEvent> = {
76
- // simpleEventPluginEventTypes gets populated from
77
- // the DOMEventProperties module.
78
- eventTypes: simpleEventPluginEventTypes,
79
- extractEvents: function(
80
- topLevelType: TopLevelType,
81
- targetInst: null | Fiber,
82
- nativeEvent: MouseEvent,
83
- nativeEventTarget: null | EventTarget,
84
- ): null | ReactSyntheticEvent {
85
- const dispatchConfig = topLevelEventsToDispatchConfig.get(topLevelType);
86
- if (!dispatchConfig) {
87
- return null;
88
- }
89
- let EventConstructor;
90
- switch (topLevelType) {
91
- case DOMTopLevelEventTypes.TOP_KEY_PRESS:
92
- // Firefox creates a keypress event for function keys too. This removes
93
- // the unwanted keypress events. Enter is however both printable and
94
- // non-printable. One would expect Tab to be as well (but it isn't).
95
- if (getEventCharCode(nativeEvent) === 0) {
96
- return null;
97
- }
98
- /* falls through */
99
- case DOMTopLevelEventTypes.TOP_KEY_DOWN:
100
- case DOMTopLevelEventTypes.TOP_KEY_UP:
101
- EventConstructor = SyntheticKeyboardEvent;
102
- break;
103
- case DOMTopLevelEventTypes.TOP_BLUR:
104
- case DOMTopLevelEventTypes.TOP_FOCUS:
105
- EventConstructor = SyntheticFocusEvent;
106
- break;
107
- case DOMTopLevelEventTypes.TOP_CLICK:
108
- // Firefox creates a click event on right mouse clicks. This removes the
109
- // unwanted click events.
110
- if (nativeEvent.button === 2) {
111
- return null;
112
- }
113
- /* falls through */
114
- case DOMTopLevelEventTypes.TOP_AUX_CLICK:
115
- case DOMTopLevelEventTypes.TOP_DOUBLE_CLICK:
116
- case DOMTopLevelEventTypes.TOP_MOUSE_DOWN:
117
- case DOMTopLevelEventTypes.TOP_MOUSE_MOVE:
118
- case DOMTopLevelEventTypes.TOP_MOUSE_UP:
119
- // TODO: Disabled elements should not respond to mouse events
120
- /* falls through */
121
- case DOMTopLevelEventTypes.TOP_MOUSE_OUT:
122
- case DOMTopLevelEventTypes.TOP_MOUSE_OVER:
123
- case DOMTopLevelEventTypes.TOP_CONTEXT_MENU:
124
- EventConstructor = SyntheticMouseEvent;
125
- break;
126
- case DOMTopLevelEventTypes.TOP_DRAG:
127
- case DOMTopLevelEventTypes.TOP_DRAG_END:
128
- case DOMTopLevelEventTypes.TOP_DRAG_ENTER:
129
- case DOMTopLevelEventTypes.TOP_DRAG_EXIT:
130
- case DOMTopLevelEventTypes.TOP_DRAG_LEAVE:
131
- case DOMTopLevelEventTypes.TOP_DRAG_OVER:
132
- case DOMTopLevelEventTypes.TOP_DRAG_START:
133
- case DOMTopLevelEventTypes.TOP_DROP:
134
- EventConstructor = SyntheticDragEvent;
135
- break;
136
- case DOMTopLevelEventTypes.TOP_TOUCH_CANCEL:
137
- case DOMTopLevelEventTypes.TOP_TOUCH_END:
138
- case DOMTopLevelEventTypes.TOP_TOUCH_MOVE:
139
- case DOMTopLevelEventTypes.TOP_TOUCH_START:
140
- EventConstructor = SyntheticTouchEvent;
141
- break;
142
- case DOMTopLevelEventTypes.TOP_ANIMATION_END:
143
- case DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION:
144
- case DOMTopLevelEventTypes.TOP_ANIMATION_START:
145
- EventConstructor = SyntheticAnimationEvent;
146
- break;
147
- case DOMTopLevelEventTypes.TOP_TRANSITION_END:
148
- EventConstructor = SyntheticTransitionEvent;
149
- break;
150
- case DOMTopLevelEventTypes.TOP_SCROLL:
151
- EventConstructor = SyntheticUIEvent;
152
- break;
153
- case DOMTopLevelEventTypes.TOP_WHEEL:
154
- EventConstructor = SyntheticWheelEvent;
155
- break;
156
- case DOMTopLevelEventTypes.TOP_COPY:
157
- case DOMTopLevelEventTypes.TOP_CUT:
158
- case DOMTopLevelEventTypes.TOP_PASTE:
159
- EventConstructor = SyntheticClipboardEvent;
160
- break;
161
- case DOMTopLevelEventTypes.TOP_GOT_POINTER_CAPTURE:
162
- case DOMTopLevelEventTypes.TOP_LOST_POINTER_CAPTURE:
163
- case DOMTopLevelEventTypes.TOP_POINTER_CANCEL:
164
- case DOMTopLevelEventTypes.TOP_POINTER_DOWN:
165
- case DOMTopLevelEventTypes.TOP_POINTER_MOVE:
166
- case DOMTopLevelEventTypes.TOP_POINTER_OUT:
167
- case DOMTopLevelEventTypes.TOP_POINTER_OVER:
168
- case DOMTopLevelEventTypes.TOP_POINTER_UP:
169
- EventConstructor = SyntheticPointerEvent;
170
- break;
171
- default:
172
- if (__DEV__) {
173
- if (knownHTMLTopLevelTypes.indexOf(topLevelType) === -1) {
174
- console.error(
175
- 'SimpleEventPlugin: Unhandled event type, `%s`. This warning ' +
176
- 'is likely caused by a bug in React. Please file an issue.',
177
- topLevelType,
178
- );
179
- }
180
- }
181
- // HTML Events
182
- // @see http://www.w3.org/TR/html5/index.html#events-0
183
- EventConstructor = SyntheticEvent;
184
- break;
185
- }
186
- const event = EventConstructor.getPooled(
187
- dispatchConfig,
188
- targetInst,
189
- nativeEvent,
190
- nativeEventTarget,
191
- );
192
- accumulateTwoPhaseDispatches(event);
193
- return event;
194
- },
195
-};
196
-
197
-export default SimpleEventPlugin;
packages/react-dom/src/events/plugins/__tests__/LegacyChangeEventPlugin-test.js
deleted
-763
@@ -1,763 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @emails react-core
8
- */
9
-
10
-'use strict';
11
-
12
-let React = require('react');
13
-let ReactDOM = require('react-dom');
14
-let TestUtils = require('react-dom/test-utils');
15
-let ReactFeatureFlags;
16
-let Scheduler;
17
-
18
-const setUntrackedChecked = Object.getOwnPropertyDescriptor(
19
- HTMLInputElement.prototype,
20
- 'checked',
21
-).set;
22
-
23
-const setUntrackedValue = Object.getOwnPropertyDescriptor(
24
- HTMLInputElement.prototype,
25
- 'value',
26
-).set;
27
-
28
-const setUntrackedTextareaValue = Object.getOwnPropertyDescriptor(
29
- HTMLTextAreaElement.prototype,
30
- 'value',
31
-).set;
32
-
33
-describe('ChangeEventPlugin', () => {
34
- let container;
35
-
36
- beforeEach(() => {
37
- ReactFeatureFlags = require('shared/ReactFeatureFlags');
38
- // TODO pull this into helper method, reduce repetition.
39
- // mock the browser APIs which are used in schedule:
40
- // - calling 'window.postMessage' should actually fire postmessage handlers
41
- const originalAddEventListener = global.addEventListener;
42
- let postMessageCallback;
43
- global.addEventListener = function(eventName, callback, useCapture) {
44
- if (eventName === 'message') {
45
- postMessageCallback = callback;
46
- } else {
47
- originalAddEventListener(eventName, callback, useCapture);
48
- }
49
- };
50
- global.postMessage = function(messageKey, targetOrigin) {
51
- const postMessageEvent = {source: window, data: messageKey};
52
- if (postMessageCallback) {
53
- postMessageCallback(postMessageEvent);
54
- }
55
- };
56
- jest.resetModules();
57
- container = document.createElement('div');
58
- document.body.appendChild(container);
59
- });
60
-
61
- afterEach(() => {
62
- document.body.removeChild(container);
63
- container = null;
64
- });
65
-
66
- // We try to avoid firing "duplicate" React change events.
67
- // However, to tell which events are "duplicates" and should be ignored,
68
- // we are tracking the "current" input value, and only respect events
69
- // that occur after it changes. In most of these tests, we verify that we
70
- // keep track of the "current" value and only fire events when it changes.
71
- // See https://github.com/facebook/react/pull/5746.
72
-
73
- it('should consider initial text value to be current', () => {
74
- let called = 0;
75
-
76
- function cb(e) {
77
- called++;
78
- expect(e.type).toBe('change');
79
- }
80
-
81
- const node = ReactDOM.render(
82
- <input type="text" onChange={cb} defaultValue="foo" />,
83
- container,
84
- );
85
- node.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
86
- node.dispatchEvent(new Event('change', {bubbles: true, cancelable: true}));
87
-
88
- if (ReactFeatureFlags.disableInputAttributeSyncing) {
89
- // TODO: figure out why. This might be a bug.
90
- expect(called).toBe(1);
91
- } else {
92
- // There should be no React change events because the value stayed the same.
93
- expect(called).toBe(0);
94
- }
95
- });
96
-
97
- it('should consider initial checkbox checked=true to be current', () => {
98
- let called = 0;
99
-
100
- function cb(e) {
101
- called++;
102
- expect(e.type).toBe('change');
103
- }
104
-
105
- const node = ReactDOM.render(
106
- <input type="checkbox" onChange={cb} defaultChecked={true} />,
107
- container,
108
- );
109
-
110
- // Secretly, set `checked` to false, so that dispatching the `click` will
111
- // make it `true` again. Thus, at the time of the event, React should not
112
- // consider it a change from the initial `true` value.
113
- setUntrackedChecked.call(node, false);
114
- node.dispatchEvent(
115
- new MouseEvent('click', {bubbles: true, cancelable: true}),
116
- );
117
- // There should be no React change events because the value stayed the same.
118
- expect(called).toBe(0);
119
- });
120
-
121
- it('should consider initial checkbox checked=false to be current', () => {
122
- let called = 0;
123
-
124
- function cb(e) {
125
- called++;
126
- expect(e.type).toBe('change');
127
- }
128
-
129
- const node = ReactDOM.render(
130
- <input type="checkbox" onChange={cb} defaultChecked={false} />,
131
- container,
132
- );
133
-
134
- // Secretly, set `checked` to true, so that dispatching the `click` will
135
- // make it `false` again. Thus, at the time of the event, React should not
136
- // consider it a change from the initial `false` value.
137
- setUntrackedChecked.call(node, true);
138
- node.dispatchEvent(
139
- new MouseEvent('click', {bubbles: true, cancelable: true}),
140
- );
141
- // There should be no React change events because the value stayed the same.
142
- expect(called).toBe(0);
143
- });
144
-
145
- it('should fire change for checkbox input', () => {
146
- let called = 0;
147
-
148
- function cb(e) {
149
- called++;
150
- expect(e.type).toBe('change');
151
- }
152
-
153
- const node = ReactDOM.render(
154
- <input type="checkbox" onChange={cb} />,
155
- container,
156
- );
157
-
158
- expect(node.checked).toBe(false);
159
- node.dispatchEvent(
160
- new MouseEvent('click', {bubbles: true, cancelable: true}),
161
- );
162
- // Note: unlike with text input events, dispatching `click` actually
163
- // toggles the checkbox and updates its `checked` value.
164
- expect(node.checked).toBe(true);
165
- expect(called).toBe(1);
166
-
167
- expect(node.checked).toBe(true);
168
- node.dispatchEvent(
169
- new MouseEvent('click', {bubbles: true, cancelable: true}),
170
- );
171
- expect(node.checked).toBe(false);
172
- expect(called).toBe(2);
173
- });
174
-
175
- it('should not fire change setting the value programmatically', () => {
176
- let called = 0;
177
-
178
- function cb(e) {
179
- called++;
180
- expect(e.type).toBe('change');
181
- }
182
-
183
- const input = ReactDOM.render(
184
- <input type="text" defaultValue="foo" onChange={cb} />,
185
- container,
186
- );
187
-
188
- // Set it programmatically.
189
- input.value = 'bar';
190
- // Even if a DOM input event fires, React sees that the real input value now
191
- // ('bar') is the same as the "current" one we already recorded.
192
- input.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
193
- expect(input.value).toBe('bar');
194
- // In this case we don't expect to get a React event.
195
- expect(called).toBe(0);
196
-
197
- // However, we can simulate user typing by calling the underlying setter.
198
- setUntrackedValue.call(input, 'foo');
199
- // Now, when the event fires, the real input value ('foo') differs from the
200
- // "current" one we previously recorded ('bar').
201
- input.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
202
- expect(input.value).toBe('foo');
203
- // In this case React should fire an event for it.
204
- expect(called).toBe(1);
205
-
206
- // Verify again that extra events without real changes are ignored.
207
- input.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
208
- expect(called).toBe(1);
209
- });
210
-
211
- it('should not distinguish equal string and number values', () => {
212
- let called = 0;
213
-
214
- function cb(e) {
215
- called++;
216
- expect(e.type).toBe('change');
217
- }
218
-
219
- const input = ReactDOM.render(
220
- <input type="text" defaultValue="42" onChange={cb} />,
221
- container,
222
- );
223
-
224
- // When we set `value` as a property, React updates the "current" value
225
- // that it tracks internally. The "current" value is later used to determine
226
- // whether a change event is a duplicate or not.
227
- // Even though we set value to a number, we still shouldn't get a change
228
- // event because as a string, it's equal to the initial value ('42').
229
- input.value = 42;
230
- input.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
231
- expect(input.value).toBe('42');
232
- expect(called).toBe(0);
233
- });
234
-
235
- // See a similar input test above for a detailed description of why.
236
- it('should not fire change when setting checked programmatically', () => {
237
- let called = 0;
238
-
239
- function cb(e) {
240
- called++;
241
- expect(e.type).toBe('change');
242
- }
243
-
244
- const input = ReactDOM.render(
245
- <input type="checkbox" onChange={cb} defaultChecked={false} />,
246
- container,
247
- );
248
-
249
- // Set the value, updating the "current" value that React tracks to true.
250
- input.checked = true;
251
- // Under the hood, uncheck the box so that the click will "check" it again.
252
- setUntrackedChecked.call(input, false);
253
- input.click();
254
- expect(input.checked).toBe(true);
255
- // We don't expect a React event because at the time of the click, the real
256
- // checked value (true) was the same as the last recorded "current" value
257
- // (also true).
258
- expect(called).toBe(0);
259
-
260
- // However, simulating a normal click should fire a React event because the
261
- // real value (false) would have changed from the last tracked value (true).
262
- input.click();
263
- expect(called).toBe(1);
264
- });
265
-
266
- it('should unmount', () => {
267
- const input = ReactDOM.render(<input />, container);
268
-
269
- ReactDOM.unmountComponentAtNode(container);
270
- });
271
-
272
- it('should only fire change for checked radio button once', () => {
273
- let called = 0;
274
-
275
- function cb(e) {
276
- called++;
277
- expect(e.type).toBe('change');
278
- }
279
-
280
- const input = ReactDOM.render(
281
- <input type="radio" onChange={cb} />,
282
- container,
283
- );
284
-
285
- setUntrackedChecked.call(input, true);
286
- input.dispatchEvent(new Event('click', {bubbles: true, cancelable: true}));
287
- input.dispatchEvent(new Event('click', {bubbles: true, cancelable: true}));
288
- expect(called).toBe(1);
289
- });
290
-
291
- it('should track radio button cousins in a group', () => {
292
- let called1 = 0;
293
- let called2 = 0;
294
-
295
- function cb1(e) {
296
- called1++;
297
- expect(e.type).toBe('change');
298
- }
299
-
300
- function cb2(e) {
301
- called2++;
302
- expect(e.type).toBe('change');
303
- }
304
-
305
- const div = ReactDOM.render(
306
- <div>
307
- <input type="radio" name="group" onChange={cb1} />
308
- <input type="radio" name="group" onChange={cb2} />
309
- </div>,
310
- container,
311
- );
312
- const option1 = div.childNodes[0];
313
- const option2 = div.childNodes[1];
314
-
315
- // Select first option.
316
- option1.click();
317
- expect(called1).toBe(1);
318
- expect(called2).toBe(0);
319
-
320
- // Select second option.
321
- option2.click();
322
- expect(called1).toBe(1);
323
- expect(called2).toBe(1);
324
-
325
- // Select the first option.
326
- // It should receive the React change event again.
327
- option1.click();
328
- expect(called1).toBe(2);
329
- expect(called2).toBe(1);
330
- });
331
-
332
- it('should deduplicate input value change events', () => {
333
- let called = 0;
334
-
335
- function cb(e) {
336
- called++;
337
- expect(e.type).toBe('change');
338
- }
339
-
340
- let input;
341
- ['text', 'number', 'range'].forEach(type => {
342
- called = 0;
343
- input = ReactDOM.render(<input type={type} onChange={cb} />, container);
344
- // Should be ignored (no change):
345
- input.dispatchEvent(
346
- new Event('change', {bubbles: true, cancelable: true}),
347
- );
348
- setUntrackedValue.call(input, '42');
349
- input.dispatchEvent(
350
- new Event('change', {bubbles: true, cancelable: true}),
351
- );
352
- // Should be ignored (no change):
353
- input.dispatchEvent(
354
- new Event('change', {bubbles: true, cancelable: true}),
355
- );
356
- expect(called).toBe(1);
357
- ReactDOM.unmountComponentAtNode(container);
358
-
359
- called = 0;
360
- input = ReactDOM.render(<input type={type} onChange={cb} />, container);
361
- // Should be ignored (no change):
362
- input.dispatchEvent(
363
- new Event('input', {bubbles: true, cancelable: true}),
364
- );
365
- setUntrackedValue.call(input, '42');
366
- input.dispatchEvent(
367
- new Event('input', {bubbles: true, cancelable: true}),
368
- );
369
- // Should be ignored (no change):
370
- input.dispatchEvent(
371
- new Event('input', {bubbles: true, cancelable: true}),
372
- );
373
- expect(called).toBe(1);
374
- ReactDOM.unmountComponentAtNode(container);
375
-
376
- called = 0;
377
- input = ReactDOM.render(<input type={type} onChange={cb} />, container);
378
- // Should be ignored (no change):
379
- input.dispatchEvent(
380
- new Event('change', {bubbles: true, cancelable: true}),
381
- );
382
- setUntrackedValue.call(input, '42');
383
- input.dispatchEvent(
384
- new Event('input', {bubbles: true, cancelable: true}),
385
- );
386
- // Should be ignored (no change):
387
- input.dispatchEvent(
388
- new Event('change', {bubbles: true, cancelable: true}),
389
- );
390
- expect(called).toBe(1);
391
- ReactDOM.unmountComponentAtNode(container);
392
- });
393
- });
394
-
395
- it('should listen for both change and input events when supported', () => {
396
- let called = 0;
397
-
398
- function cb(e) {
399
- called++;
400
- expect(e.type).toBe('change');
401
- }
402
-
403
- const input = ReactDOM.render(
404
- <input type="range" onChange={cb} />,
405
- container,
406
- );
407
-
408
- setUntrackedValue.call(input, 10);
409
- input.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
410
-
411
- setUntrackedValue.call(input, 20);
412
- input.dispatchEvent(new Event('change', {bubbles: true, cancelable: true}));
413
-
414
- expect(called).toBe(2);
415
- });
416
-
417
- it('should only fire events when the value changes for range inputs', () => {
418
- let called = 0;
419
-
420
- function cb(e) {
421
- called++;
422
- expect(e.type).toBe('change');
423
- }
424
-
425
- const input = ReactDOM.render(
426
- <input type="range" onChange={cb} />,
427
- container,
428
- );
429
- setUntrackedValue.call(input, '40');
430
- input.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
431
- input.dispatchEvent(new Event('change', {bubbles: true, cancelable: true}));
432
-
433
- setUntrackedValue.call(input, 'foo');
434
- input.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
435
- input.dispatchEvent(new Event('change', {bubbles: true, cancelable: true}));
436
-
437
- expect(called).toBe(2);
438
- });
439
-
440
- it('does not crash for nodes with custom value property', () => {
441
- let originalCreateElement;
442
- // https://github.com/facebook/react/issues/10196
443
- try {
444
- originalCreateElement = document.createElement;
445
- document.createElement = function() {
446
- const node = originalCreateElement.apply(this, arguments);
447
- Object.defineProperty(node, 'value', {
448
- get() {},
449
- set() {},
450
- });
451
- return node;
452
- };
453
- const div = document.createElement('div');
454
- // Mount
455
- const node = ReactDOM.render(<input type="text" />, div);
456
- // Update
457
- ReactDOM.render(<input type="text" />, div);
458
- // Change
459
- node.dispatchEvent(
460
- new Event('change', {bubbles: true, cancelable: true}),
461
- );
462
- // Unmount
463
- ReactDOM.unmountComponentAtNode(div);
464
- } finally {
465
- document.createElement = originalCreateElement;
466
- }
467
- });
468
-
469
- describe('concurrent mode', () => {
470
- beforeEach(() => {
471
- jest.resetModules();
472
- ReactFeatureFlags = require('shared/ReactFeatureFlags');
473
-
474
- React = require('react');
475
- ReactDOM = require('react-dom');
476
- TestUtils = require('react-dom/test-utils');
477
- Scheduler = require('scheduler');
478
- });
479
-
480
- // @gate experimental
481
- it('text input', () => {
482
- const root = ReactDOM.unstable_createRoot(container);
483
- let input;
484
-
485
- class ControlledInput extends React.Component {
486
- state = {value: 'initial'};
487
- onChange = event => this.setState({value: event.target.value});
488
- render() {
489
- Scheduler.unstable_yieldValue(`render: ${this.state.value}`);
490
- const controlledValue =
491
- this.state.value === 'changed' ? 'changed [!]' : this.state.value;
492
- return (
493
- <input
494
- ref={el => (input = el)}
495
- type="text"
496
- value={controlledValue}
497
- onChange={this.onChange}
498
- />
499
- );
500
- }
501
- }
502
-
503
- // Initial mount. Test that this is async.
504
- root.render(<ControlledInput />);
505
- // Should not have flushed yet.
506
- expect(Scheduler).toHaveYielded([]);
507
- expect(input).toBe(undefined);
508
- // Flush callbacks.
509
- expect(Scheduler).toFlushAndYield(['render: initial']);
510
- expect(input.value).toBe('initial');
511
-
512
- // Trigger a change event.
513
- setUntrackedValue.call(input, 'changed');
514
- input.dispatchEvent(
515
- new Event('input', {bubbles: true, cancelable: true}),
516
- );
517
- // Change should synchronously flush
518
- expect(Scheduler).toHaveYielded(['render: changed']);
519
- // Value should be the controlled value, not the original one
520
- expect(input.value).toBe('changed [!]');
521
- });
522
-
523
- // @gate experimental
524
- it('checkbox input', () => {
525
- const root = ReactDOM.unstable_createRoot(container);
526
- let input;
527
-
528
- class ControlledInput extends React.Component {
529
- state = {checked: false};
530
- onChange = event => {
531
- this.setState({checked: event.target.checked});
532
- };
533
- render() {
534
- Scheduler.unstable_yieldValue(`render: ${this.state.checked}`);
535
- const controlledValue = this.props.reverse
536
- ? !this.state.checked
537
- : this.state.checked;
538
- return (
539
- <input
540
- ref={el => (input = el)}
541
- type="checkbox"
542
- checked={controlledValue}
543
- onChange={this.onChange}
544
- />
545
- );
546
- }
547
- }
548
-
549
- // Initial mount. Test that this is async.
550
- root.render(<ControlledInput reverse={false} />);
551
- // Should not have flushed yet.
552
- expect(Scheduler).toHaveYielded([]);
553
- expect(input).toBe(undefined);
554
- // Flush callbacks.
555
- expect(Scheduler).toFlushAndYield(['render: false']);
556
- expect(input.checked).toBe(false);
557
-
558
- // Trigger a change event.
559
- input.dispatchEvent(
560
- new MouseEvent('click', {bubbles: true, cancelable: true}),
561
- );
562
- // Change should synchronously flush
563
- expect(Scheduler).toHaveYielded(['render: true']);
564
- expect(input.checked).toBe(true);
565
-
566
- // Now let's make sure we're using the controlled value.
567
- root.render(<ControlledInput reverse={true} />);
568
- expect(Scheduler).toFlushAndYield(['render: true']);
569
-
570
- // Trigger another change event.
571
- input.dispatchEvent(
572
- new MouseEvent('click', {bubbles: true, cancelable: true}),
573
- );
574
- // Change should synchronously flush
575
- expect(Scheduler).toHaveYielded(['render: true']);
576
- expect(input.checked).toBe(false);
577
- });
578
-
579
- // @gate experimental
580
- it('textarea', () => {
581
- const root = ReactDOM.unstable_createRoot(container);
582
- let textarea;
583
-
584
- class ControlledTextarea extends React.Component {
585
- state = {value: 'initial'};
586
- onChange = event => this.setState({value: event.target.value});
587
- render() {
588
- Scheduler.unstable_yieldValue(`render: ${this.state.value}`);
589
- const controlledValue =
590
- this.state.value === 'changed' ? 'changed [!]' : this.state.value;
591
- return (
592
- <textarea
593
- ref={el => (textarea = el)}
594
- type="text"
595
- value={controlledValue}
596
- onChange={this.onChange}
597
- />
598
- );
599
- }
600
- }
601
-
602
- // Initial mount. Test that this is async.
603
- root.render(<ControlledTextarea />);
604
- // Should not have flushed yet.
605
- expect(Scheduler).toHaveYielded([]);
606
- expect(textarea).toBe(undefined);
607
- // Flush callbacks.
608
- expect(Scheduler).toFlushAndYield(['render: initial']);
609
- expect(textarea.value).toBe('initial');
610
-
611
- // Trigger a change event.
612
- setUntrackedTextareaValue.call(textarea, 'changed');
613
- textarea.dispatchEvent(
614
- new Event('input', {bubbles: true, cancelable: true}),
615
- );
616
- // Change should synchronously flush
617
- expect(Scheduler).toHaveYielded(['render: changed']);
618
- // Value should be the controlled value, not the original one
619
- expect(textarea.value).toBe('changed [!]');
620
- });
621
-
622
- // @gate experimental
623
- it('parent of input', () => {
624
- const root = ReactDOM.unstable_createRoot(container);
625
- let input;
626
-
627
- class ControlledInput extends React.Component {
628
- state = {value: 'initial'};
629
- onChange = event => this.setState({value: event.target.value});
630
- render() {
631
- Scheduler.unstable_yieldValue(`render: ${this.state.value}`);
632
- const controlledValue =
633
- this.state.value === 'changed' ? 'changed [!]' : this.state.value;
634
- return (
635
- <div onChange={this.onChange}>
636
- <input
637
- ref={el => (input = el)}
638
- type="text"
639
- value={controlledValue}
640
- onChange={() => {
641
- // Does nothing. Parent handler is responsible for updating.
642
- }}
643
- />
644
- </div>
645
- );
646
- }
647
- }
648
-
649
- // Initial mount. Test that this is async.
650
- root.render(<ControlledInput />);
651
- // Should not have flushed yet.
652
- expect(Scheduler).toHaveYielded([]);
653
- expect(input).toBe(undefined);
654
- // Flush callbacks.
655
- expect(Scheduler).toFlushAndYield(['render: initial']);
656
- expect(input.value).toBe('initial');
657
-
658
- // Trigger a change event.
659
- setUntrackedValue.call(input, 'changed');
660
- input.dispatchEvent(
661
- new Event('input', {bubbles: true, cancelable: true}),
662
- );
663
- // Change should synchronously flush
664
- expect(Scheduler).toHaveYielded(['render: changed']);
665
- // Value should be the controlled value, not the original one
666
- expect(input.value).toBe('changed [!]');
667
- });
668
-
669
- // @gate experimental
670
- it('is async for non-input events', () => {
671
- const root = ReactDOM.unstable_createRoot(container);
672
- let input;
673
-
674
- class ControlledInput extends React.Component {
675
- state = {value: 'initial'};
676
- onChange = event => this.setState({value: event.target.value});
677
- reset = () => {
678
- this.setState({value: ''});
679
- };
680
- render() {
681
- Scheduler.unstable_yieldValue(`render: ${this.state.value}`);
682
- const controlledValue =
683
- this.state.value === 'changed' ? 'changed [!]' : this.state.value;
684
- return (
685
- <input
686
- ref={el => (input = el)}
687
- type="text"
688
- value={controlledValue}
689
- onChange={this.onChange}
690
- onClick={this.reset}
691
- />
692
- );
693
- }
694
- }
695
-
696
- // Initial mount. Test that this is async.
697
- root.render(<ControlledInput />);
698
- // Should not have flushed yet.
699
- expect(Scheduler).toHaveYielded([]);
700
- expect(input).toBe(undefined);
701
- // Flush callbacks.
702
- expect(Scheduler).toFlushAndYield(['render: initial']);
703
- expect(input.value).toBe('initial');
704
-
705
- // Trigger a click event
706
- input.dispatchEvent(
707
- new Event('click', {bubbles: true, cancelable: true}),
708
- );
709
- // Nothing should have changed
710
- expect(Scheduler).toHaveYielded([]);
711
- expect(input.value).toBe('initial');
712
-
713
- // Flush callbacks.
714
- // Now the click update has flushed.
715
- expect(Scheduler).toFlushAndYield(['render: ']);
716
- expect(input.value).toBe('');
717
- });
718
-
719
- // @gate experimental
720
- it('mouse enter/leave should be user-blocking but not discrete', async () => {
721
- // This is currently behind a feature flag
722
- jest.resetModules();
723
- React = require('react');
724
- ReactDOM = require('react-dom');
725
- TestUtils = require('react-dom/test-utils');
726
- Scheduler = require('scheduler');
727
-
728
- const {act} = TestUtils;
729
- const {useState} = React;
730
-
731
- const root = ReactDOM.unstable_createRoot(container);
732
-
733
- const target = React.createRef(null);
734
- function Foo() {
735
- const [isHover, setHover] = useState(false);
736
- return (
737
- <div
738
- ref={target}
739
- onMouseEnter={() => setHover(true)}
740
- onMouseLeave={() => setHover(false)}>
741
- {isHover ? 'hovered' : 'not hovered'}
742
- </div>
743
- );
744
- }
745
-
746
- await act(async () => {
747
- root.render(<Foo />);
748
- });
749
- expect(container.textContent).toEqual('not hovered');
750
-
751
- await act(async () => {
752
- const mouseOverEvent = document.createEvent('MouseEvents');
753
- mouseOverEvent.initEvent('mouseover', true, true);
754
- target.current.dispatchEvent(mouseOverEvent);
755
-
756
- // 3s should be enough to expire the updates
757
- Scheduler.unstable_advanceTime(3000);
758
- expect(Scheduler).toFlushExpired([]);
759
- expect(container.textContent).toEqual('hovered');
760
- });
761
- });
762
- });
763
-});
packages/react-dom/src/events/plugins/__tests__/LegacyEnterLeaveEventPlugin-test.js
deleted
-239
@@ -1,239 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @emails react-core
8
- */
9
-
10
-'use strict';
11
-
12
-let React;
13
-let ReactDOM;
14
-
15
-describe('EnterLeaveEventPlugin', () => {
16
- let container;
17
-
18
- beforeEach(() => {
19
- jest.resetModules();
20
-
21
- React = require('react');
22
- ReactDOM = require('react-dom');
23
-
24
- // The container has to be attached for events to fire.
25
- container = document.createElement('div');
26
- document.body.appendChild(container);
27
- });
28
-
29
- afterEach(() => {
30
- document.body.removeChild(container);
31
- container = null;
32
- });
33
-
34
- it('should set onMouseLeave relatedTarget properly in iframe', () => {
35
- const iframe = document.createElement('iframe');
36
- container.appendChild(iframe);
37
- const iframeDocument = iframe.contentDocument;
38
- iframeDocument.write(
39
- '<!DOCTYPE html><html><head></head><body><div></div></body></html>',
40
- );
41
- iframeDocument.close();
42
-
43
- const leaveEvents = [];
44
- const node = ReactDOM.render(
45
- <div
46
- onMouseLeave={e => {
47
- e.persist();
48
- leaveEvents.push(e);
49
- }}
50
- />,
51
- iframeDocument.body.getElementsByTagName('div')[0],
52
- );
53
-
54
- node.dispatchEvent(
55
- new MouseEvent('mouseout', {
56
- bubbles: true,
57
- cancelable: true,
58
- relatedTarget: iframe.contentWindow,
59
- }),
60
- );
61
-
62
- expect(leaveEvents.length).toBe(1);
63
- expect(leaveEvents[0].target).toBe(node);
64
- expect(leaveEvents[0].relatedTarget).toBe(iframe.contentWindow);
65
- });
66
-
67
- it('should set onMouseEnter relatedTarget properly in iframe', () => {
68
- const iframe = document.createElement('iframe');
69
- container.appendChild(iframe);
70
- const iframeDocument = iframe.contentDocument;
71
- iframeDocument.write(
72
- '<!DOCTYPE html><html><head></head><body><div></div></body></html>',
73
- );
74
- iframeDocument.close();
75
-
76
- const enterEvents = [];
77
- const node = ReactDOM.render(
78
- <div
79
- onMouseEnter={e => {
80
- e.persist();
81
- enterEvents.push(e);
82
- }}
83
- />,
84
- iframeDocument.body.getElementsByTagName('div')[0],
85
- );
86
-
87
- node.dispatchEvent(
88
- new MouseEvent('mouseover', {
89
- bubbles: true,
90
- cancelable: true,
91
- relatedTarget: null,
92
- }),
93
- );
94
-
95
- expect(enterEvents.length).toBe(1);
96
- expect(enterEvents[0].target).toBe(node);
97
- expect(enterEvents[0].relatedTarget).toBe(iframe.contentWindow);
98
- });
99
-
100
- // Regression test for https://github.com/facebook/react/issues/10906.
101
- it('should find the common parent after updates', () => {
102
- let parentEnterCalls = 0;
103
- let childEnterCalls = 0;
104
- let parent = null;
105
-
106
- class Parent extends React.Component {
107
- render() {
108
- return (
109
- <div
110
- onMouseEnter={() => parentEnterCalls++}
111
- ref={node => (parent = node)}>
112
- {this.props.showChild && (
113
- <div onMouseEnter={() => childEnterCalls++} />
114
- )}
115
- </div>
116
- );
117
- }
118
- }
119
-
120
- ReactDOM.render(<Parent />, container);
121
- // The issue only reproduced on insertion during the first update.
122
- ReactDOM.render(<Parent showChild={true} />, container);
123
-
124
- // Enter from parent into the child.
125
- parent.dispatchEvent(
126
- new MouseEvent('mouseout', {
127
- bubbles: true,
128
- cancelable: true,
129
- relatedTarget: parent.firstChild,
130
- }),
131
- );
132
-
133
- // Entering a child should fire on the child, not on the parent.
134
- expect(childEnterCalls).toBe(1);
135
- expect(parentEnterCalls).toBe(0);
136
- });
137
-
138
- // Test for https://github.com/facebook/react/issues/16763.
139
- it('should call mouseEnter once from sibling rendered inside a rendered component', done => {
140
- const mockFn = jest.fn();
141
-
142
- class Parent extends React.Component {
143
- constructor(props) {
144
- super(props);
145
- this.parentEl = React.createRef();
146
- }
147
-
148
- componentDidMount() {
149
- ReactDOM.render(<MouseEnterDetect />, this.parentEl.current);
150
- }
151
-
152
- render() {
153
- return <div ref={this.parentEl} />;
154
- }
155
- }
156
-
157
- class MouseEnterDetect extends React.Component {
158
- constructor(props) {
159
- super(props);
160
- this.firstEl = React.createRef();
161
- this.siblingEl = React.createRef();
162
- }
163
-
164
- componentDidMount() {
165
- this.siblingEl.current.dispatchEvent(
166
- new MouseEvent('mouseout', {
167
- bubbles: true,
168
- cancelable: true,
169
- relatedTarget: this.firstEl.current,
170
- }),
171
- );
172
- expect(mockFn.mock.calls.length).toBe(1);
173
- done();
174
- }
175
-
176
- render() {
177
- return (
178
- <React.Fragment>
179
- <div ref={this.firstEl} onMouseEnter={mockFn} />
180
- <div ref={this.siblingEl} />
181
- </React.Fragment>
182
- );
183
- }
184
- }
185
-
186
- ReactDOM.render(<Parent />, container);
187
- });
188
-
189
- it('should call mouseEnter when pressing a non tracked React node', done => {
190
- const mockFn = jest.fn();
191
-
192
- class Parent extends React.Component {
193
- constructor(props) {
194
- super(props);
195
- this.parentEl = React.createRef();
196
- }
197
-
198
- componentDidMount() {
199
- ReactDOM.render(<MouseEnterDetect />, this.parentEl.current);
200
- }
201
-
202
- render() {
203
- return <div ref={this.parentEl} />;
204
- }
205
- }
206
-
207
- class MouseEnterDetect extends React.Component {
208
- constructor(props) {
209
- super(props);
210
- this.divRef = React.createRef();
211
- this.siblingEl = React.createRef();
212
- }
213
-
214
- componentDidMount() {
215
- const attachedNode = document.createElement('div');
216
- this.divRef.current.appendChild(attachedNode);
217
- attachedNode.dispatchEvent(
218
- new MouseEvent('mouseout', {
219
- bubbles: true,
220
- cancelable: true,
221
- relatedTarget: this.siblingEl.current,
222
- }),
223
- );
224
- expect(mockFn.mock.calls.length).toBe(1);
225
- done();
226
- }
227
-
228
- render() {
229
- return (
230
- <div ref={this.divRef}>
231
- <div ref={this.siblingEl} onMouseEnter={mockFn} />
232
- </div>
233
- );
234
- }
235
- }
236
-
237
- ReactDOM.render(<Parent />, container);
238
- });
239
-});
packages/react-dom/src/events/plugins/__tests__/ModernBeforeInputEventPlugin-test.internal.js
deleted
-831
@@ -1,831 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @emails react-core
8
- */
9
-
10
-'use strict';
11
-
12
-let React;
13
-let ReactDOM;
14
-let ReactFeatureFlags;
15
-
16
-describe('BeforeInputEventPlugin', () => {
17
- let container;
18
-
19
- function loadReactDOM(envSimulator) {
20
- jest.resetModules();
21
- if (envSimulator) {
22
- envSimulator();
23
- }
24
- ReactFeatureFlags = require('shared/ReactFeatureFlags');
25
- ReactFeatureFlags.enableModernEventSystem = true;
26
- return require('react-dom');
27
- }
28
-
29
- function simulateIE11() {
30
- document.documentMode = 11;
31
- window.CompositionEvent = {};
32
- }
33
-
34
- function simulateWebkit() {
35
- window.CompositionEvent = {};
36
- window.TextEvent = {};
37
- }
38
-
39
- function simulateComposition() {
40
- window.CompositionEvent = {};
41
- }
42
-
43
- function simulateNoComposition() {
44
- // no composition event in Window - will use fallback
45
- }
46
-
47
- function simulateEvent(elem, type, data) {
48
- const event = new Event(type, {bubbles: true});
49
- Object.assign(event, data);
50
- elem.dispatchEvent(event);
51
- }
52
-
53
- function simulateKeyboardEvent(elem, type, data) {
54
- const {char, value, ...rest} = data;
55
- const event = new KeyboardEvent(type, {
56
- bubbles: true,
57
- ...rest,
58
- });
59
- if (char) {
60
- event.char = char;
61
- }
62
- if (value) {
63
- elem.value = value;
64
- }
65
- elem.dispatchEvent(event);
66
- }
67
-
68
- function simulatePaste(elem) {
69
- const pasteEvent = new Event('paste', {
70
- bubbles: true,
71
- });
72
- pasteEvent.clipboardData = {
73
- dropEffect: null,
74
- effectAllowed: null,
75
- files: null,
76
- items: null,
77
- types: null,
78
- };
79
- elem.dispatchEvent(pasteEvent);
80
- }
81
-
82
- beforeEach(() => {
83
- React = require('react');
84
- container = document.createElement('div');
85
- document.body.appendChild(container);
86
- });
87
-
88
- afterEach(() => {
89
- delete document.documentMode;
90
- delete window.CompositionEvent;
91
- delete window.TextEvent;
92
- delete window.opera;
93
- document.body.removeChild(container);
94
- container = null;
95
- });
96
-
97
- function keyCode(char) {
98
- return char.charCodeAt(0);
99
- }
100
-
101
- const scenarios = [
102
- {
103
- eventSimulator: simulateEvent,
104
- eventSimulatorArgs: [
105
- 'compositionstart',
106
- {detail: {data: 'test'}, data: 'test'},
107
- ],
108
- },
109
- {
110
- eventSimulator: simulateEvent,
111
- eventSimulatorArgs: [
112
- 'compositionupdate',
113
- {detail: {data: 'test string'}, data: 'test string'},
114
- ],
115
- },
116
- {
117
- eventSimulator: simulateEvent,
118
- eventSimulatorArgs: [
119
- 'compositionend',
120
- {detail: {data: 'test string 3'}, data: 'test string 3'},
121
- ],
122
- },
123
- {
124
- eventSimulator: simulateEvent,
125
- eventSimulatorArgs: ['textInput', {data: 'abcß'}],
126
- },
127
- {
128
- eventSimulator: simulateKeyboardEvent,
129
- eventSimulatorArgs: ['keypress', {which: keyCode('a')}],
130
- },
131
- {
132
- eventSimulator: simulateKeyboardEvent,
133
- eventSimulatorArgs: ['keypress', {which: keyCode(' ')}, ' '],
134
- },
135
- {
136
- eventSimulator: simulateEvent,
137
- eventSimulatorArgs: ['textInput', {data: ' '}],
138
- },
139
- {
140
- eventSimulator: simulateKeyboardEvent,
141
- eventSimulatorArgs: ['keypress', {which: keyCode('a'), ctrlKey: true}],
142
- },
143
- {
144
- eventSimulator: simulateKeyboardEvent,
145
- eventSimulatorArgs: ['keypress', {which: keyCode('b'), altKey: true}],
146
- },
147
- {
148
- eventSimulator: simulateKeyboardEvent,
149
- eventSimulatorArgs: [
150
- 'keypress',
151
- {which: keyCode('c'), altKey: true, ctrlKey: true},
152
- ],
153
- },
154
- {
155
- eventSimulator: simulateKeyboardEvent,
156
- eventSimulatorArgs: [
157
- 'keypress',
158
- {which: keyCode('X'), char: '\uD83D\uDE0A'},
159
- ],
160
- },
161
- {
162
- eventSimulator: simulateEvent,
163
- eventSimulatorArgs: ['textInput', {data: '\uD83D\uDE0A'}],
164
- },
165
- {
166
- eventSimulator: simulateKeyboardEvent,
167
- eventSimulatorArgs: ['keydown', {keyCode: 229, value: 'foo'}],
168
- },
169
- {
170
- eventSimulator: simulateKeyboardEvent,
171
- eventSimulatorArgs: ['keydown', {keyCode: 9, value: 'foobar'}],
172
- },
173
- {
174
- eventSimulator: simulateKeyboardEvent,
175
- eventSimulatorArgs: ['keydown', {keyCode: 229, value: 'foofoo'}],
176
- },
177
- {
178
- eventSimulator: simulateKeyboardEvent,
179
- eventSimulatorArgs: ['keyup', {keyCode: 9, value: 'fooBARfoo'}],
180
- },
181
- {
182
- eventSimulator: simulateKeyboardEvent,
183
- eventSimulatorArgs: ['keydown', {keyCode: 229, value: 'foofoo'}],
184
- },
185
- {
186
- eventSimulator: simulateKeyboardEvent,
187
- eventSimulatorArgs: ['keypress', {keyCode: 60, value: 'Barfoofoo'}],
188
- },
189
- {
190
- eventSimulator: simulatePaste,
191
- eventSimulatorArgs: [],
192
- },
193
- ];
194
-
195
- const environments = [
196
- {
197
- emulator: simulateWebkit,
198
- assertions: [
199
- {
200
- run: ({
201
- beforeInputEvent,
202
- compositionStartEvent,
203
- spyOnBeforeInput,
204
- spyOnCompositionStart,
205
- }) => {
206
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
207
- expect(beforeInputEvent).toBeNull();
208
- expect(spyOnCompositionStart).toHaveBeenCalledTimes(1);
209
- expect(compositionStartEvent.type).toBe('compositionstart');
210
- expect(compositionStartEvent.data).toBe('test');
211
- },
212
- },
213
- {
214
- run: ({
215
- beforeInputEvent,
216
- compositionUpdateEvent,
217
- spyOnBeforeInput,
218
- spyOnCompositionUpdate,
219
- }) => {
220
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
221
- expect(beforeInputEvent).toBeNull();
222
- expect(spyOnCompositionUpdate).toHaveBeenCalledTimes(1);
223
- expect(compositionUpdateEvent.type).toBe('compositionupdate');
224
- expect(compositionUpdateEvent.data).toBe('test string');
225
- },
226
- },
227
- {
228
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
229
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
230
- expect(beforeInputEvent.type).toBe('compositionend');
231
- expect(beforeInputEvent.data).toBe('test string 3');
232
- },
233
- },
234
- {
235
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
236
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
237
- expect(beforeInputEvent.type).toBe('textInput');
238
- expect(beforeInputEvent.data).toBe('abcß');
239
- },
240
- },
241
- {
242
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
243
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
244
- expect(beforeInputEvent).toBeNull();
245
- },
246
- },
247
- {
248
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
249
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
250
- expect(beforeInputEvent.type).toBe('keypress');
251
- expect(beforeInputEvent.data).toBe(' ');
252
- },
253
- },
254
- {
255
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
256
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
257
- expect(beforeInputEvent).toBeNull();
258
- },
259
- },
260
- {
261
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
262
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
263
- expect(beforeInputEvent).toBeNull();
264
- },
265
- },
266
- {
267
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
268
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
269
- expect(beforeInputEvent).toBeNull();
270
- },
271
- },
272
- {
273
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
274
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
275
- expect(beforeInputEvent).toBeNull();
276
- },
277
- },
278
- {
279
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
280
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
281
- expect(beforeInputEvent).toBeNull();
282
- },
283
- },
284
- {
285
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
286
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
287
- expect(beforeInputEvent.type).toBe('textInput');
288
- expect(beforeInputEvent.data).toBe('\uD83D\uDE0A');
289
- },
290
- },
291
- {
292
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
293
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
294
- expect(beforeInputEvent).toBeNull();
295
- },
296
- },
297
- {
298
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
299
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
300
- expect(beforeInputEvent).toBeNull();
301
- },
302
- },
303
- {
304
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
305
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
306
- expect(beforeInputEvent).toBeNull();
307
- },
308
- },
309
- {
310
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
311
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
312
- expect(beforeInputEvent).toBeNull();
313
- },
314
- },
315
- {
316
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
317
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
318
- expect(beforeInputEvent).toBeNull();
319
- },
320
- },
321
- {
322
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
323
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
324
- expect(beforeInputEvent).toBeNull();
325
- },
326
- },
327
- {
328
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
329
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
330
- expect(beforeInputEvent).toBeNull();
331
- },
332
- },
333
- ],
334
- },
335
- {
336
- emulator: simulateIE11,
337
- assertions: [
338
- {
339
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
340
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
341
- expect(beforeInputEvent).toBeNull();
342
- },
343
- },
344
- {
345
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
346
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
347
- expect(beforeInputEvent).toBeNull();
348
- },
349
- },
350
- {
351
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
352
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
353
- expect(beforeInputEvent).toBeNull();
354
- },
355
- },
356
- {
357
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
358
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
359
- expect(beforeInputEvent).toBeNull();
360
- },
361
- },
362
- {
363
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
364
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
365
- expect(beforeInputEvent.type).toBe('keypress');
366
- expect(beforeInputEvent.data).toBe('a');
367
- },
368
- },
369
- {
370
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
371
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
372
- expect(beforeInputEvent.type).toBe('keypress');
373
- expect(beforeInputEvent.data).toBe(' ');
374
- },
375
- },
376
- {
377
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
378
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
379
- expect(beforeInputEvent).toBeNull();
380
- },
381
- },
382
- {
383
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
384
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
385
- expect(beforeInputEvent).toBeNull();
386
- },
387
- },
388
- {
389
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
390
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
391
- expect(beforeInputEvent).toBeNull();
392
- },
393
- },
394
- {
395
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
396
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
397
- expect(beforeInputEvent.type).toBe('keypress');
398
- expect(beforeInputEvent.data).toBe('c');
399
- },
400
- },
401
- {
402
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
403
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
404
- expect(beforeInputEvent.type).toBe('keypress');
405
- expect(beforeInputEvent.data).toBe('\uD83D\uDE0A');
406
- },
407
- },
408
- {
409
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
410
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
411
- expect(beforeInputEvent).toBeNull();
412
- },
413
- },
414
- {
415
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
416
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
417
- expect(beforeInputEvent).toBeNull();
418
- },
419
- },
420
- {
421
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
422
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
423
- expect(beforeInputEvent).toBeNull();
424
- },
425
- },
426
- {
427
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
428
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
429
- expect(beforeInputEvent).toBeNull();
430
- },
431
- },
432
- {
433
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
434
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
435
- expect(beforeInputEvent).toBeNull();
436
- },
437
- },
438
- {
439
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
440
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
441
- expect(beforeInputEvent).toBeNull();
442
- },
443
- },
444
- {
445
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
446
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
447
- expect(beforeInputEvent).toBeNull();
448
- },
449
- },
450
- {
451
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
452
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
453
- expect(beforeInputEvent).toBeNull();
454
- },
455
- },
456
- ],
457
- },
458
- {
459
- emulator: simulateNoComposition,
460
- assertions: [
461
- {
462
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
463
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
464
- expect(beforeInputEvent).toBeNull();
465
- },
466
- },
467
- {
468
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
469
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
470
- expect(beforeInputEvent).toBeNull();
471
- },
472
- },
473
- {
474
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
475
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
476
- expect(beforeInputEvent).toBeNull();
477
- },
478
- },
479
- {
480
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
481
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
482
- expect(beforeInputEvent).toBeNull();
483
- },
484
- },
485
- {
486
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
487
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
488
- expect(beforeInputEvent.type).toBe('keypress');
489
- expect(beforeInputEvent.data).toBe('a');
490
- },
491
- },
492
- {
493
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
494
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
495
- expect(beforeInputEvent.type).toBe('keypress');
496
- expect(beforeInputEvent.data).toBe(' ');
497
- },
498
- },
499
- {
500
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
501
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
502
- expect(beforeInputEvent).toBeNull();
503
- },
504
- },
505
- {
506
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
507
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
508
- expect(beforeInputEvent).toBeNull();
509
- },
510
- },
511
- {
512
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
513
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
514
- expect(beforeInputEvent).toBeNull();
515
- },
516
- },
517
- {
518
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
519
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
520
- expect(beforeInputEvent.type).toBe('keypress');
521
- expect(beforeInputEvent.data).toBe('c');
522
- },
523
- },
524
- {
525
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
526
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
527
- expect(beforeInputEvent.type).toBe('keypress');
528
- expect(beforeInputEvent.data).toBe('\uD83D\uDE0A');
529
- },
530
- },
531
- {
532
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
533
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
534
- expect(beforeInputEvent).toBeNull();
535
- },
536
- },
537
- {
538
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
539
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
540
- expect(beforeInputEvent).toBeNull();
541
- },
542
- },
543
- {
544
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
545
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
546
- expect(beforeInputEvent.type).toBe('keydown');
547
- expect(beforeInputEvent.data).toBe('bar');
548
- },
549
- },
550
- {
551
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
552
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
553
- expect(beforeInputEvent).toBeNull();
554
- },
555
- },
556
- {
557
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
558
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
559
- expect(beforeInputEvent.type).toBe('keyup');
560
- expect(beforeInputEvent.data).toBe('BAR');
561
- },
562
- },
563
- {
564
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
565
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
566
- expect(beforeInputEvent).toBeNull();
567
- },
568
- },
569
- {
570
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
571
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
572
- expect(beforeInputEvent.type).toBe('keypress');
573
- expect(beforeInputEvent.data).toBe('Bar');
574
- },
575
- },
576
- {
577
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
578
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
579
- expect(beforeInputEvent).toBeNull();
580
- },
581
- },
582
- ],
583
- },
584
- {
585
- emulator: simulateComposition,
586
- assertions: [
587
- {
588
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
589
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
590
- expect(beforeInputEvent).toBeNull();
591
- },
592
- },
593
- {
594
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
595
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
596
- expect(beforeInputEvent).toBeNull();
597
- },
598
- },
599
- {
600
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
601
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
602
- expect(beforeInputEvent.type).toBe('compositionend');
603
- expect(beforeInputEvent.data).toBe('test string 3');
604
- },
605
- },
606
- {
607
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
608
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
609
- expect(beforeInputEvent).toBeNull();
610
- },
611
- },
612
- {
613
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
614
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
615
- expect(beforeInputEvent.type).toBe('keypress');
616
- expect(beforeInputEvent.data).toBe('a');
617
- },
618
- },
619
- {
620
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
621
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
622
- expect(beforeInputEvent.type).toBe('keypress');
623
- expect(beforeInputEvent.data).toBe(' ');
624
- },
625
- },
626
- {
627
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
628
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
629
- expect(beforeInputEvent).toBeNull();
630
- },
631
- },
632
- {
633
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
634
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
635
- expect(beforeInputEvent).toBeNull();
636
- },
637
- },
638
- {
639
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
640
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
641
- expect(beforeInputEvent).toBeNull();
642
- },
643
- },
644
- {
645
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
646
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
647
- expect(beforeInputEvent.type).toBe('keypress');
648
- expect(beforeInputEvent.data).toBe('c');
649
- },
650
- },
651
- {
652
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
653
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(1);
654
- expect(beforeInputEvent.type).toBe('keypress');
655
- expect(beforeInputEvent.data).toBe('\uD83D\uDE0A');
656
- },
657
- },
658
- {
659
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
660
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
661
- expect(beforeInputEvent).toBeNull();
662
- },
663
- },
664
- {
665
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
666
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
667
- expect(beforeInputEvent).toBeNull();
668
- },
669
- },
670
- {
671
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
672
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
673
- expect(beforeInputEvent).toBeNull();
674
- },
675
- },
676
- {
677
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
678
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
679
- expect(beforeInputEvent).toBeNull();
680
- },
681
- },
682
- {
683
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
684
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
685
- expect(beforeInputEvent).toBeNull();
686
- },
687
- },
688
- {
689
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
690
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
691
- expect(beforeInputEvent).toBeNull();
692
- },
693
- },
694
- {
695
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
696
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
697
- expect(beforeInputEvent).toBeNull();
698
- },
699
- },
700
- {
701
- run: ({beforeInputEvent, spyOnBeforeInput}) => {
702
- expect(spyOnBeforeInput).toHaveBeenCalledTimes(0);
703
- expect(beforeInputEvent).toBeNull();
704
- },
705
- },
706
- ],
707
- },
708
- ];
709
-
710
- const testInputComponent = (env, scenes) => {
711
- let beforeInputEvent;
712
- let compositionStartEvent;
713
- let compositionUpdateEvent;
714
- let spyOnBeforeInput;
715
- let spyOnCompositionStart;
716
- let spyOnCompositionUpdate;
717
- ReactDOM = loadReactDOM(env.emulator);
718
- const node = ReactDOM.render(
719
- <input
720
- type="text"
721
- onBeforeInput={({type, data}) => {
722
- spyOnBeforeInput();
723
- beforeInputEvent = {type, data};
724
- }}
725
- onCompositionStart={({type, data}) => {
726
- spyOnCompositionStart();
727
- compositionStartEvent = {type, data};
728
- }}
729
- onCompositionUpdate={({type, data}) => {
730
- spyOnCompositionUpdate();
731
- compositionUpdateEvent = {type, data};
732
- }}
733
- />,
734
- container,
735
- );
736
-
737
- scenes.forEach((s, id) => {
738
- beforeInputEvent = null;
739
- compositionStartEvent = null;
740
- compositionUpdateEvent = null;
741
- spyOnBeforeInput = jest.fn();
742
- spyOnCompositionStart = jest.fn();
743
- spyOnCompositionUpdate = jest.fn();
744
- s.eventSimulator.apply(null, [node, ...s.eventSimulatorArgs]);
745
- env.assertions[id].run({
746
- beforeInputEvent,
747
- compositionStartEvent,
748
- compositionUpdateEvent,
749
- spyOnBeforeInput,
750
- spyOnCompositionStart,
751
- spyOnCompositionUpdate,
752
- });
753
- });
754
- };
755
-
756
- const testContentEditableComponent = (env, scenes) => {
757
- let beforeInputEvent;
758
- let compositionStartEvent;
759
- let compositionUpdateEvent;
760
- let spyOnBeforeInput;
761
- let spyOnCompositionStart;
762
- let spyOnCompositionUpdate;
763
- ReactDOM = loadReactDOM(env.emulator);
764
- const node = ReactDOM.render(
765
- <div
766
- contentEditable={true}
767
- onBeforeInput={({type, data}) => {
768
- spyOnBeforeInput();
769
- beforeInputEvent = {type, data};
770
- }}
771
- onCompositionStart={({type, data}) => {
772
- spyOnCompositionStart();
773
- compositionStartEvent = {type, data};
774
- }}
775
- onCompositionUpdate={({type, data}) => {
776
- spyOnCompositionUpdate();
777
- compositionUpdateEvent = {type, data};
778
- }}
779
- />,
780
- container,
781
- );
782
-
783
- scenes.forEach((s, id) => {
784
- beforeInputEvent = null;
785
- compositionStartEvent = null;
786
- compositionUpdateEvent = null;
787
- spyOnBeforeInput = jest.fn();
788
- spyOnCompositionStart = jest.fn();
789
- spyOnCompositionUpdate = jest.fn();
790
- s.eventSimulator.apply(null, [node, ...s.eventSimulatorArgs]);
791
- env.assertions[id].run({
792
- beforeInputEvent,
793
- compositionStartEvent,
794
- compositionUpdateEvent,
795
- spyOnBeforeInput,
796
- spyOnCompositionStart,
797
- spyOnCompositionUpdate,
798
- });
799
- });
800
- };
801
-
802
- it('should extract onBeforeInput when simulating in Webkit on input[type=text]', () => {
803
- testInputComponent(environments[0], scenarios);
804
- });
805
- it('should extract onBeforeInput when simulating in Webkit on contenteditable', () => {
806
- testContentEditableComponent(environments[0], scenarios);
807
- });
808
-
809
- it('should extract onBeforeInput when simulating in IE11 on input[type=text]', () => {
810
- testInputComponent(environments[1], scenarios);
811
- });
812
- it('should extract onBeforeInput when simulating in IE11 on contenteditable', () => {
813
- testContentEditableComponent(environments[1], scenarios);
814
- });
815
-
816
- it('should extract onBeforeInput when simulating in env with no CompositionEvent on input[type=text]', () => {
817
- testInputComponent(environments[2], scenarios);
818
- });
819
-
820
- // in an environment using composition fallback onBeforeInput will not work
821
- // as expected on a contenteditable as keydown and keyup events are translated
822
- // to keypress events
823
-
824
- it('should extract onBeforeInput when simulating in env with only CompositionEvent on input[type=text]', () => {
825
- testInputComponent(environments[3], scenarios);
826
- });
827
-
828
- it('should extract onBeforeInput when simulating in env with only CompositionEvent on contenteditable', () => {
829
- testContentEditableComponent(environments[3], scenarios);
830
- });
831
-});
packages/react-dom/src/events/plugins/__tests__/ModernBeforeInputEventPlugin-test.js
renamed
packages/react-dom/src/events/plugins/__tests__/ModernChangeEventPlugin-test.js
renamed
-1
@@ -54,7 +54,6 @@ describe('ChangeEventPlugin', () => {
54
postMessageCallback(postMessageEvent);
55
}
56
};
57
- ReactFeatureFlags.enableModernEventSystem = true;
57
React = require('react');
58
ReactDOM = require('react-dom');
59
TestUtils = require('react-dom/test-utils');
packages/react-dom/src/events/plugins/__tests__/ModernEnterLeaveEventPlugin-test.js
renamed
-3
@@ -11,7 +11,6 @@
11
12
let React;
13
let ReactDOM;
14
-let ReactFeatureFlags;
14
15
describe('EnterLeaveEventPlugin', () => {
16
let container;
@@ -19,8 +18,6 @@ describe('EnterLeaveEventPlugin', () => {
18
beforeEach(() => {
19
jest.resetModules();
20
22
- ReactFeatureFlags = require('shared/ReactFeatureFlags');
23
- ReactFeatureFlags.enableModernEventSystem = true;
21
React = require('react');
22
ReactDOM = require('react-dom');
23
packages/react-dom/src/events/plugins/__tests__/ModernSelectEventPlugin-test.internal.js
deleted
-167
@@ -1,167 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @emails react-core
8
- */
9
-
10
-'use strict';
11
-
12
-let React;
13
-let ReactDOM;
14
-let ReactFeatureFlags;
15
-
16
-describe('SelectEventPlugin', () => {
17
- let container;
18
-
19
- beforeEach(() => {
20
- ReactFeatureFlags = require('shared/ReactFeatureFlags');
21
- ReactFeatureFlags.enableModernEventSystem = true;
22
- React = require('react');
23
- ReactDOM = require('react-dom');
24
-
25
- container = document.createElement('div');
26
- document.body.appendChild(container);
27
- });
28
-
29
- afterEach(() => {
30
- document.body.removeChild(container);
31
- container = null;
32
- });
33
-
34
- // See https://github.com/facebook/react/pull/3639 for details.
35
- it('does not get confused when dependent events are registered independently', () => {
36
- const select = jest.fn();
37
- const onSelect = event => {
38
- expect(typeof event).toBe('object');
39
- expect(event.type).toBe('select');
40
- expect(event.target).toBe(node);
41
- select(event.currentTarget);
42
- };
43
-
44
- // Pass `onMouseDown` so React registers a top-level listener.
45
- const node = ReactDOM.render(
46
- <input type="text" onMouseDown={function() {}} />,
47
- container,
48
- );
49
-
50
- // Trigger `mousedown` and `mouseup`. Note that
51
- // React is not currently listening to `mouseup`.
52
- node.dispatchEvent(
53
- new MouseEvent('mousedown', {
54
- bubbles: true,
55
- cancelable: true,
56
- }),
57
- );
58
- node.dispatchEvent(
59
- new MouseEvent('mouseup', {
60
- bubbles: true,
61
- cancelable: true,
62
- }),
63
- );
64
-
65
- // Now subscribe to `onSelect`.
66
- ReactDOM.render(<input type="text" onSelect={onSelect} />, container);
67
- node.focus();
68
-
69
- // This triggers a `select` event in our polyfill.
70
- node.dispatchEvent(
71
- new KeyboardEvent('keydown', {bubbles: true, cancelable: true}),
72
- );
73
-
74
- // Verify that it doesn't get "stuck" waiting for
75
- // a `mouseup` event that it has "missed" because
76
- // a top-level listener didn't exist yet.
77
- expect(select).toHaveBeenCalledTimes(1);
78
- });
79
-
80
- it('should fire `onSelect` when a listener is present', () => {
81
- const select = jest.fn();
82
- const onSelect = event => {
83
- expect(typeof event).toBe('object');
84
- expect(event.type).toBe('select');
85
- expect(event.target).toBe(node);
86
- select(event.currentTarget);
87
- };
88
-
89
- const node = ReactDOM.render(
90
- <input type="text" onSelect={onSelect} />,
91
- container,
92
- );
93
- node.focus();
94
-
95
- let nativeEvent = new MouseEvent('focus', {
96
- bubbles: true,
97
- cancelable: true,
98
- });
99
- node.dispatchEvent(nativeEvent);
100
- expect(select).toHaveBeenCalledTimes(0);
101
-
102
- nativeEvent = new MouseEvent('mousedown', {
103
- bubbles: true,
104
- cancelable: true,
105
- });
106
- node.dispatchEvent(nativeEvent);
107
- expect(select).toHaveBeenCalledTimes(0);
108
-
109
- nativeEvent = new MouseEvent('mouseup', {bubbles: true, cancelable: true});
110
- node.dispatchEvent(nativeEvent);
111
- expect(select).toHaveBeenCalledTimes(1);
112
- });
113
-
114
- // Regression test for https://github.com/facebook/react/issues/11379
115
- it('should not wait for `mouseup` after receiving `dragend`', () => {
116
- const select = jest.fn();
117
- const onSelect = event => {
118
- expect(typeof event).toBe('object');
119
- expect(event.type).toBe('select');
120
- expect(event.target).toBe(node);
121
- select(event.currentTarget);
122
- };
123
-
124
- const node = ReactDOM.render(
125
- <input type="text" onSelect={onSelect} />,
126
- container,
127
- );
128
- node.focus();
129
-
130
- let nativeEvent = new MouseEvent('focus', {
131
- bubbles: true,
132
- cancelable: true,
133
- });
134
- node.dispatchEvent(nativeEvent);
135
- expect(select).toHaveBeenCalledTimes(0);
136
-
137
- nativeEvent = new MouseEvent('mousedown', {
138
- bubbles: true,
139
- cancelable: true,
140
- });
141
- node.dispatchEvent(nativeEvent);
142
- expect(select).toHaveBeenCalledTimes(0);
143
-
144
- nativeEvent = new MouseEvent('dragend', {bubbles: true, cancelable: true});
145
- node.dispatchEvent(nativeEvent);
146
- expect(select).toHaveBeenCalledTimes(1);
147
- });
148
-
149
- it('should handle selectionchange events', function() {
150
- const onSelect = jest.fn();
151
- const node = ReactDOM.render(
152
- <input type="text" onSelect={onSelect} />,
153
- container,
154
- );
155
- node.focus();
156
-
157
- // Make sure the event was not called before we emit the selection change event
158
- expect(onSelect).toHaveBeenCalledTimes(0);
159
-
160
- // This is dispatched e.g. when using CMD+a on macOS
161
- document.dispatchEvent(
162
- new Event('selectionchange', {bubbles: false, cancelable: false}),
163
- );
164
-
165
- expect(onSelect).toHaveBeenCalledTimes(1);
166
- });
167
-});
packages/react-dom/src/events/plugins/__tests__/ModernSelectEventPlugin-test.js
renamed
packages/react-dom/src/events/plugins/__tests__/ModernSimpleEventPlugin-test.internal.js
deleted
-493
@@ -1,493 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @emails react-core
8
- */
9
-
10
-'use strict';
11
-
12
-describe('SimpleEventPlugin', function() {
13
- let React;
14
- let ReactDOM;
15
- let Scheduler;
16
- let ReactFeatureFlags;
17
-
18
- let onClick;
19
- let container;
20
-
21
- function expectClickThru(element) {
22
- element.click();
23
- expect(onClick).toHaveBeenCalledTimes(1);
24
- }
25
-
26
- function expectNoClickThru(element) {
27
- element.click();
28
- expect(onClick).toHaveBeenCalledTimes(0);
29
- }
30
-
31
- function mounted(element) {
32
- container = document.createElement('div');
33
- document.body.appendChild(container);
34
- element = ReactDOM.render(element, container);
35
- return element;
36
- }
37
-
38
- beforeEach(function() {
39
- jest.resetModules();
40
- ReactFeatureFlags = require('shared/ReactFeatureFlags');
41
- ReactFeatureFlags.enableModernEventSystem = true;
42
- React = require('react');
43
- ReactDOM = require('react-dom');
44
- Scheduler = require('scheduler');
45
-
46
- onClick = jest.fn();
47
- });
48
-
49
- afterEach(() => {
50
- if (container && document.body.contains(container)) {
51
- document.body.removeChild(container);
52
- container = null;
53
- }
54
- });
55
-
56
- it('A non-interactive tags click when disabled', function() {
57
- const element = <div onClick={onClick} />;
58
- expectClickThru(mounted(element));
59
- });
60
-
61
- it('A non-interactive tags clicks bubble when disabled', function() {
62
- const element = mounted(
63
- <div onClick={onClick}>
64
- <div />
65
- </div>,
66
- );
67
- const child = element.firstChild;
68
- child.click();
69
- expect(onClick).toHaveBeenCalledTimes(1);
70
- });
71
-
72
- it('does not register a click when clicking a child of a disabled element', function() {
73
- const element = mounted(
74
- <button onClick={onClick} disabled={true}>
75
- <span />
76
- </button>,
77
- );
78
- const child = element.querySelector('span');
79
-
80
- child.click();
81
- expect(onClick).toHaveBeenCalledTimes(0);
82
- });
83
-
84
- it('triggers click events for children of disabled elements', function() {
85
- const element = mounted(
86
- <button disabled={true}>
87
- <span onClick={onClick} />
88
- </button>,
89
- );
90
- const child = element.querySelector('span');
91
-
92
- child.click();
93
- expect(onClick).toHaveBeenCalledTimes(1);
94
- });
95
-
96
- it('triggers parent captured click events when target is a child of a disabled elements', function() {
97
- const element = mounted(
98
- <div onClickCapture={onClick}>
99
- <button disabled={true}>
100
- <span />
101
- </button>
102
- </div>,
103
- );
104
- const child = element.querySelector('span');
105
-
106
- child.click();
107
- expect(onClick).toHaveBeenCalledTimes(1);
108
- });
109
-
110
- it('triggers captured click events for children of disabled elements', function() {
111
- const element = mounted(
112
- <button disabled={true}>
113
- <span onClickCapture={onClick} />
114
- </button>,
115
- );
116
- const child = element.querySelector('span');
117
-
118
- child.click();
119
- expect(onClick).toHaveBeenCalledTimes(1);
120
- });
121
-
122
- ['button', 'input', 'select', 'textarea'].forEach(function(tagName) {
123
- describe(tagName, function() {
124
- it('should forward clicks when it starts out not disabled', () => {
125
- const element = React.createElement(tagName, {
126
- onClick: onClick,
127
- });
128
-
129
- expectClickThru(mounted(element));
130
- });
131
-
132
- it('should not forward clicks when it starts out disabled', () => {
133
- const element = React.createElement(tagName, {
134
- onClick: onClick,
135
- disabled: true,
136
- });
137
-
138
- expectNoClickThru(mounted(element));
139
- });
140
-
141
- it('should forward clicks when it becomes not disabled', () => {
142
- container = document.createElement('div');
143
- document.body.appendChild(container);
144
- let element = ReactDOM.render(
145
- React.createElement(tagName, {onClick: onClick, disabled: true}),
146
- container,
147
- );
148
- element = ReactDOM.render(
149
- React.createElement(tagName, {onClick: onClick}),
150
- container,
151
- );
152
- expectClickThru(element);
153
- });
154
-
155
- it('should not forward clicks when it becomes disabled', () => {
156
- container = document.createElement('div');
157
- document.body.appendChild(container);
158
- let element = ReactDOM.render(
159
- React.createElement(tagName, {onClick: onClick}),
160
- container,
161
- );
162
- element = ReactDOM.render(
163
- React.createElement(tagName, {onClick: onClick, disabled: true}),
164
- container,
165
- );
166
- expectNoClickThru(element);
167
- });
168
-
169
- it('should work correctly if the listener is changed', () => {
170
- container = document.createElement('div');
171
- document.body.appendChild(container);
172
- let element = ReactDOM.render(
173
- React.createElement(tagName, {onClick: onClick, disabled: true}),
174
- container,
175
- );
176
- element = ReactDOM.render(
177
- React.createElement(tagName, {onClick: onClick, disabled: false}),
178
- container,
179
- );
180
- expectClickThru(element);
181
- });
182
- });
183
- });
184
-
185
- it('batches updates that occur as a result of a nested event dispatch', () => {
186
- container = document.createElement('div');
187
- document.body.appendChild(container);
188
-
189
- let button;
190
- class Button extends React.Component {
191
- state = {count: 0};
192
- increment = () =>
193
- this.setState(state => ({
194
- count: state.count + 1,
195
- }));
196
- componentDidUpdate() {
197
- Scheduler.unstable_yieldValue(`didUpdate - Count: ${this.state.count}`);
198
- }
199
- render() {
200
- return (
201
- <button
202
- ref={el => (button = el)}
203
- onFocus={this.increment}
204
- onClick={() => {
205
- // The focus call synchronously dispatches a nested event. All of
206
- // the updates in this handler should be batched together.
207
- this.increment();
208
- button.focus();
209
- this.increment();
210
- }}>
211
- Count: {this.state.count}
212
- </button>
213
- );
214
- }
215
- }
216
-
217
- function click() {
218
- button.dispatchEvent(
219
- new MouseEvent('click', {bubbles: true, cancelable: true}),
220
- );
221
- }
222
-
223
- ReactDOM.render(<Button />, container);
224
- expect(button.textContent).toEqual('Count: 0');
225
- expect(Scheduler).toHaveYielded([]);
226
-
227
- click();
228
-
229
- // There should be exactly one update.
230
- expect(Scheduler).toHaveYielded(['didUpdate - Count: 3']);
231
- expect(button.textContent).toEqual('Count: 3');
232
- });
233
-
234
- describe('interactive events, in concurrent mode', () => {
235
- beforeEach(() => {
236
- jest.resetModules();
237
- ReactFeatureFlags = require('shared/ReactFeatureFlags');
238
- ReactFeatureFlags.enableModernEventSystem = true;
239
- ReactDOM = require('react-dom');
240
- Scheduler = require('scheduler');
241
- });
242
-
243
- // @gate experimental
244
- it('flushes pending interactive work before extracting event handler', () => {
245
- container = document.createElement('div');
246
- const root = ReactDOM.createRoot(container);
247
- document.body.appendChild(container);
248
-
249
- let button;
250
- class Button extends React.Component {
251
- state = {disabled: false};
252
- onClick = () => {
253
- // Perform some side-effect
254
- Scheduler.unstable_yieldValue('Side-effect');
255
- // Disable the button
256
- this.setState({disabled: true});
257
- };
258
- render() {
259
- Scheduler.unstable_yieldValue(
260
- `render button: ${this.state.disabled ? 'disabled' : 'enabled'}`,
261
- );
262
- return (
263
- <button
264
- ref={el => (button = el)}
265
- // Handler is removed after the first click
266
- onClick={this.state.disabled ? null : this.onClick}
267
- />
268
- );
269
- }
270
- }
271
-
272
- // Initial mount
273
- root.render(<Button />);
274
- // Should not have flushed yet because it's async
275
- expect(Scheduler).toHaveYielded([]);
276
- expect(button).toBe(undefined);
277
- // Flush async work
278
- expect(Scheduler).toFlushAndYield(['render button: enabled']);
279
-
280
- function click() {
281
- button.dispatchEvent(
282
- new MouseEvent('click', {bubbles: true, cancelable: true}),
283
- );
284
- }
285
-
286
- // Click the button to trigger the side-effect
287
- click();
288
- expect(Scheduler).toHaveYielded([
289
- // The handler fired
290
- 'Side-effect',
291
- // but the component did not re-render yet, because it's async
292
- ]);
293
-
294
- // Click the button again
295
- click();
296
- expect(Scheduler).toHaveYielded([
297
- // Before handling this second click event, the previous interactive
298
- // update is flushed
299
- 'render button: disabled',
300
- // The event handler was removed from the button, so there's no second
301
- // side-effect
302
- ]);
303
-
304
- // The handler should not fire again no matter how many times we
305
- // click the handler.
306
- click();
307
- click();
308
- click();
309
- click();
310
- click();
311
- expect(Scheduler).toFlushAndYield([]);
312
- });
313
-
314
- // @gate experimental
315
- it('end result of many interactive updates is deterministic', () => {
316
- container = document.createElement('div');
317
- const root = ReactDOM.createRoot(container);
318
- document.body.appendChild(container);
319
-
320
- let button;
321
- class Button extends React.Component {
322
- state = {count: 0};
323
- render() {
324
- return (
325
- <button
326
- ref={el => (button = el)}
327
- onClick={() =>
328
- // Intentionally not using the updater form here
329
- this.setState({count: this.state.count + 1})
330
- }>
331
- Count: {this.state.count}
332
- </button>
333
- );
334
- }
335
- }
336
-
337
- // Initial mount
338
- root.render(<Button />);
339
- // Should not have flushed yet because it's async
340
- expect(button).toBe(undefined);
341
- // Flush async work
342
- Scheduler.unstable_flushAll();
343
- expect(button.textContent).toEqual('Count: 0');
344
-
345
- function click() {
346
- button.dispatchEvent(
347
- new MouseEvent('click', {bubbles: true, cancelable: true}),
348
- );
349
- }
350
-
351
- // Click the button a single time
352
- click();
353
- // The counter should not have updated yet because it's async
354
- expect(button.textContent).toEqual('Count: 0');
355
-
356
- // Click the button many more times
357
- click();
358
- click();
359
- click();
360
- click();
361
- click();
362
- click();
363
-
364
- // Flush the remaining work
365
- Scheduler.unstable_flushAll();
366
- // The counter should equal the total number of clicks
367
- expect(button.textContent).toEqual('Count: 7');
368
- });
369
-
370
- // @gate experimental
371
- it('flushes discrete updates in order', () => {
372
- container = document.createElement('div');
373
- document.body.appendChild(container);
374
-
375
- let button;
376
- class Button extends React.Component {
377
- state = {lowPriCount: 0};
378
- render() {
379
- const text = `High-pri count: ${this.props.highPriCount}, Low-pri count: ${this.state.lowPriCount}`;
380
- Scheduler.unstable_yieldValue(text);
381
- return (
382
- <button
383
- ref={el => (button = el)}
384
- onClick={() => {
385
- Scheduler.unstable_next(() => {
386
- this.setState(state => ({
387
- lowPriCount: state.lowPriCount + 1,
388
- }));
389
- });
390
- }}>
391
- {text}
392
- </button>
393
- );
394
- }
395
- }
396
-
397
- class Wrapper extends React.Component {
398
- state = {highPriCount: 0};
399
- render() {
400
- return (
401
- <div
402
- onClick={
403
- // Intentionally not using the updater form here, to test
404
- // that updates are serially processed.
405
- () => {
406
- this.setState({highPriCount: this.state.highPriCount + 1});
407
- }
408
- }>
409
- <Button highPriCount={this.state.highPriCount} />
410
- </div>
411
- );
412
- }
413
- }
414
-
415
- // Initial mount
416
- const root = ReactDOM.createRoot(container);
417
- root.render(<Wrapper />);
418
- expect(Scheduler).toFlushAndYield([
419
- 'High-pri count: 0, Low-pri count: 0',
420
- ]);
421
- expect(button.textContent).toEqual('High-pri count: 0, Low-pri count: 0');
422
-
423
- function click() {
424
- button.dispatchEvent(
425
- new MouseEvent('click', {bubbles: true, cancelable: true}),
426
- );
427
- }
428
-
429
- // Click the button a single time
430
- click();
431
- // Nothing should flush on the first click.
432
- expect(Scheduler).toHaveYielded([]);
433
- // Click again. This will force the previous discrete update to flush. But
434
- // only the high-pri count will increase.
435
- click();
436
- expect(Scheduler).toHaveYielded(['High-pri count: 1, Low-pri count: 0']);
437
- expect(button.textContent).toEqual('High-pri count: 1, Low-pri count: 0');
438
-
439
- // Click the button many more times
440
- click();
441
- click();
442
- click();
443
- click();
444
- click();
445
- click();
446
-
447
- // Flush the remaining work.
448
- expect(Scheduler).toHaveYielded([
449
- 'High-pri count: 2, Low-pri count: 0',
450
- 'High-pri count: 3, Low-pri count: 0',
451
- 'High-pri count: 4, Low-pri count: 0',
452
- 'High-pri count: 5, Low-pri count: 0',
453
- 'High-pri count: 6, Low-pri count: 0',
454
- 'High-pri count: 7, Low-pri count: 0',
455
- ]);
456
-
457
- // At the end, both counters should equal the total number of clicks
458
- expect(Scheduler).toFlushAndYield([
459
- 'High-pri count: 8, Low-pri count: 0',
460
- 'High-pri count: 8, Low-pri count: 8',
461
- ]);
462
- expect(button.textContent).toEqual('High-pri count: 8, Low-pri count: 8');
463
- });
464
- });
465
-
466
- describe('iOS bubbling click fix', function() {
467
- // See http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
468
-
469
- it('does not add a local click to interactive elements', function() {
470
- container = document.createElement('div');
471
-
472
- ReactDOM.render(<button onClick={onClick} />, container);
473
-
474
- const node = container.firstChild;
475
-
476
- node.dispatchEvent(new MouseEvent('click'));
477
-
478
- expect(onClick).toHaveBeenCalledTimes(0);
479
- });
480
-
481
- it('adds a local click listener to non-interactive elements', function() {
482
- container = document.createElement('div');
483
-
484
- ReactDOM.render(<div onClick={onClick} />, container);
485
-
486
- const node = container.firstChild;
487
-
488
- node.dispatchEvent(new MouseEvent('click'));
489
-
490
- expect(onClick).toHaveBeenCalledTimes(0);
491
- });
492
- });
493
-});
packages/react-dom/src/events/plugins/__tests__/ModernSimpleEventPlugin-test.js
renamed
+3
-4
@@ -231,7 +231,6 @@ describe('SimpleEventPlugin', function() {
231
describe('interactive events, in concurrent mode', () => {
232
beforeEach(() => {
233
jest.resetModules();
234
-
234
ReactDOM = require('react-dom');
235
Scheduler = require('scheduler');
236
});
@@ -239,7 +238,7 @@ describe('SimpleEventPlugin', function() {
238
// @gate experimental
239
it('flushes pending interactive work before extracting event handler', () => {
240
container = document.createElement('div');
242
- const root = ReactDOM.unstable_createRoot(container);
241
+ const root = ReactDOM.createRoot(container);
242
document.body.appendChild(container);
243
244
let button;
@@ -310,7 +309,7 @@ describe('SimpleEventPlugin', function() {
309
// @gate experimental
310
it('end result of many interactive updates is deterministic', () => {
311
container = document.createElement('div');
313
- const root = ReactDOM.unstable_createRoot(container);
312
+ const root = ReactDOM.createRoot(container);
313
document.body.appendChild(container);
314
315
let button;
@@ -409,7 +408,7 @@ describe('SimpleEventPlugin', function() {
408
}
409
410
// Initial mount
412
- const root = ReactDOM.unstable_createRoot(container);
411
+ const root = ReactDOM.createRoot(container);
412
root.render(<Wrapper />);
413
expect(Scheduler).toFlushAndYield([
414
'High-pri count: 0, Low-pri count: 0',
packages/react-dom/src/legacy-events/EventBatching.js
deleted
-66
@@ -1,66 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- * @flow
7
- */
8
-
9
-import invariant from 'shared/invariant';
10
-import {rethrowCaughtError} from 'shared/ReactErrorUtils';
11
-
12
-import type {ReactSyntheticEvent} from './ReactSyntheticEventType';
13
-import accumulateInto from './accumulateInto';
14
-import forEachAccumulated from './forEachAccumulated';
15
-import {executeDispatchesInOrder} from './EventPluginUtils';
16
-
17
-/**
18
- * Internal queue of events that have accumulated their dispatches and are
19
- * waiting to have their dispatches executed.
20
- */
21
-let eventQueue: ?(Array<ReactSyntheticEvent> | ReactSyntheticEvent) = null;
22
-
23
-/**
24
- * Dispatches an event and releases it back into the pool, unless persistent.
25
- *
26
- * @param {?object} event Synthetic event to be dispatched.
27
- * @private
28
- */
29
-const executeDispatchesAndRelease = function(event: ReactSyntheticEvent) {
30
- if (event) {
31
- executeDispatchesInOrder(event);
32
-
33
- if (!event.isPersistent()) {
34
- event.constructor.release(event);
35
- }
36
- }
37
-};
38
-const executeDispatchesAndReleaseTopLevel = function(e) {
39
- return executeDispatchesAndRelease(e);
40
-};
41
-
42
-export function runEventsInBatch(
43
- events: Array<ReactSyntheticEvent> | ReactSyntheticEvent | null,
44
-) {
45
- if (events !== null) {
46
- eventQueue = accumulateInto(eventQueue, events);
47
- }
48
-
49
- // Set `eventQueue` to null before processing it so that we can tell if more
50
- // events get enqueued while processing.
51
- const processingEventQueue = eventQueue;
52
- eventQueue = null;
53
-
54
- if (!processingEventQueue) {
55
- return;
56
- }
57
-
58
- forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel);
59
- invariant(
60
- !eventQueue,
61
- 'processEventQueue(): Additional events were enqueued while processing ' +
62
- 'an event queue. Support for this has not yet been implemented.',
63
- );
64
- // This would be a good time to rethrow if any of the event handlers threw.
65
- rethrowCaughtError();
66
-}
packages/react-dom/src/legacy-events/ReactGenericBatching.js
deleted
-83
@@ -1,83 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-// Used as a way to call batchedUpdates when we don't have a reference to
9
-// the renderer. Such as when we're dispatching events or if third party
10
-// libraries need to call batchedUpdates. Eventually, this API will go away when
11
-// everything is batched by default. We'll then have a similar API to opt-out of
12
-// scheduled work and instead do synchronous work.
13
-
14
-// Defaults
15
-let batchedUpdatesImpl = function(fn, bookkeeping) {
16
- return fn(bookkeeping);
17
-};
18
-let discreteUpdatesImpl = function(fn, a, b, c, d) {
19
- return fn(a, b, c, d);
20
-};
21
-let flushDiscreteUpdatesImpl = function() {};
22
-let batchedEventUpdatesImpl = batchedUpdatesImpl;
23
-
24
-let isInsideEventHandler = false;
25
-let isBatchingEventUpdates = false;
26
-
27
-export function batchedUpdates(fn, bookkeeping) {
28
- if (isInsideEventHandler) {
29
- // If we are currently inside another batch, we need to wait until it
30
- // fully completes before restoring state.
31
- return fn(bookkeeping);
32
- }
33
- isInsideEventHandler = true;
34
- try {
35
- return batchedUpdatesImpl(fn, bookkeeping);
36
- } finally {
37
- isInsideEventHandler = false;
38
- }
39
-}
40
-
41
-export function batchedEventUpdates(fn, a, b) {
42
- if (isBatchingEventUpdates) {
43
- // If we are currently inside another batch, we need to wait until it
44
- // fully completes before restoring state.
45
- return fn(a, b);
46
- }
47
- isBatchingEventUpdates = true;
48
- try {
49
- return batchedEventUpdatesImpl(fn, a, b);
50
- } finally {
51
- isBatchingEventUpdates = false;
52
- }
53
-}
54
-
55
-export function discreteUpdates(fn, a, b, c, d) {
56
- const prevIsInsideEventHandler = isInsideEventHandler;
57
- isInsideEventHandler = true;
58
- try {
59
- return discreteUpdatesImpl(fn, a, b, c, d);
60
- } finally {
61
- isInsideEventHandler = prevIsInsideEventHandler;
62
- if (!isInsideEventHandler) {
63
- }
64
- }
65
-}
66
-
67
-export function flushDiscreteUpdatesIfNeeded(timeStamp: number) {
68
- if (!isInsideEventHandler) {
69
- flushDiscreteUpdatesImpl();
70
- }
71
-}
72
-
73
-export function setBatchingImplementation(
74
- _batchedUpdatesImpl,
75
- _discreteUpdatesImpl,
76
- _flushDiscreteUpdatesImpl,
77
- _batchedEventUpdatesImpl,
78
-) {
79
- batchedUpdatesImpl = _batchedUpdatesImpl;
80
- discreteUpdatesImpl = _discreteUpdatesImpl;
81
- flushDiscreteUpdatesImpl = _flushDiscreteUpdatesImpl;
82
- batchedEventUpdatesImpl = _batchedEventUpdatesImpl;
83
-}
packages/react-dom/src/legacy-events/ResponderEventPlugin.js
deleted
-802
@@ -1,802 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-import {
9
- executeDirectDispatch,
10
- hasDispatches,
11
- executeDispatchesInOrderStopAtTrue,
12
- getInstanceFromNode,
13
- getFiberCurrentPropsFromNode,
14
-} from './EventPluginUtils';
15
-import ResponderSyntheticEvent from './ResponderSyntheticEvent';
16
-import ResponderTouchHistoryStore from './ResponderTouchHistoryStore';
17
-import accumulate from './accumulate';
18
-import {
19
- TOP_SCROLL,
20
- TOP_SELECTION_CHANGE,
21
- TOP_TOUCH_CANCEL,
22
- isStartish,
23
- isMoveish,
24
- isEndish,
25
- startDependencies,
26
- moveDependencies,
27
- endDependencies,
28
-} from './ResponderTopLevelEventTypes';
29
-import accumulateInto from './accumulateInto';
30
-import forEachAccumulated from './forEachAccumulated';
31
-import {HostComponent} from 'react-reconciler/src/ReactWorkTags';
32
-import invariant from 'shared/invariant';
33
-
34
-/**
35
- * Instance of element that should respond to touch/move types of interactions,
36
- * as indicated explicitly by relevant callbacks.
37
- */
38
-let responderInst = null;
39
-
40
-/**
41
- * Count of current touches. A textInput should become responder iff the
42
- * selection changes while there is a touch on the screen.
43
- */
44
-let trackedTouchCount = 0;
45
-
46
-const changeResponder = function(nextResponderInst, blockHostResponder) {
47
- const oldResponderInst = responderInst;
48
- responderInst = nextResponderInst;
49
- if (ResponderEventPlugin.GlobalResponderHandler !== null) {
50
- ResponderEventPlugin.GlobalResponderHandler.onChange(
51
- oldResponderInst,
52
- nextResponderInst,
53
- blockHostResponder,
54
- );
55
- }
56
-};
57
-
58
-const eventTypes = {
59
- /**
60
- * On a `touchStart`/`mouseDown`, is it desired that this element become the
61
- * responder?
62
- */
63
- startShouldSetResponder: {
64
- phasedRegistrationNames: {
65
- bubbled: 'onStartShouldSetResponder',
66
- captured: 'onStartShouldSetResponderCapture',
67
- },
68
- dependencies: startDependencies,
69
- },
70
-
71
- /**
72
- * On a `scroll`, is it desired that this element become the responder? This
73
- * is usually not needed, but should be used to retroactively infer that a
74
- * `touchStart` had occurred during momentum scroll. During a momentum scroll,
75
- * a touch start will be immediately followed by a scroll event if the view is
76
- * currently scrolling.
77
- *
78
- * TODO: This shouldn't bubble.
79
- */
80
- scrollShouldSetResponder: {
81
- phasedRegistrationNames: {
82
- bubbled: 'onScrollShouldSetResponder',
83
- captured: 'onScrollShouldSetResponderCapture',
84
- },
85
- dependencies: [TOP_SCROLL],
86
- },
87
-
88
- /**
89
- * On text selection change, should this element become the responder? This
90
- * is needed for text inputs or other views with native selection, so the
91
- * JS view can claim the responder.
92
- *
93
- * TODO: This shouldn't bubble.
94
- */
95
- selectionChangeShouldSetResponder: {
96
- phasedRegistrationNames: {
97
- bubbled: 'onSelectionChangeShouldSetResponder',
98
- captured: 'onSelectionChangeShouldSetResponderCapture',
99
- },
100
- dependencies: [TOP_SELECTION_CHANGE],
101
- },
102
-
103
- /**
104
- * On a `touchMove`/`mouseMove`, is it desired that this element become the
105
- * responder?
106
- */
107
- moveShouldSetResponder: {
108
- phasedRegistrationNames: {
109
- bubbled: 'onMoveShouldSetResponder',
110
- captured: 'onMoveShouldSetResponderCapture',
111
- },
112
- dependencies: moveDependencies,
113
- },
114
-
115
- /**
116
- * Direct responder events dispatched directly to responder. Do not bubble.
117
- */
118
- responderStart: {
119
- registrationName: 'onResponderStart',
120
- dependencies: startDependencies,
121
- },
122
- responderMove: {
123
- registrationName: 'onResponderMove',
124
- dependencies: moveDependencies,
125
- },
126
- responderEnd: {
127
- registrationName: 'onResponderEnd',
128
- dependencies: endDependencies,
129
- },
130
- responderRelease: {
131
- registrationName: 'onResponderRelease',
132
- dependencies: endDependencies,
133
- },
134
- responderTerminationRequest: {
135
- registrationName: 'onResponderTerminationRequest',
136
- dependencies: [],
137
- },
138
- responderGrant: {
139
- registrationName: 'onResponderGrant',
140
- dependencies: [],
141
- },
142
- responderReject: {
143
- registrationName: 'onResponderReject',
144
- dependencies: [],
145
- },
146
- responderTerminate: {
147
- registrationName: 'onResponderTerminate',
148
- dependencies: [],
149
- },
150
-};
151
-
152
-// Start of inline: the below functions were inlined from
153
-// EventPropagator.js, as they deviated from ReactDOM's newer
154
-// implementations.
155
-
156
-function getParent(inst) {
157
- do {
158
- inst = inst.return;
159
- // TODO: If this is a HostRoot we might want to bail out.
160
- // That is depending on if we want nested subtrees (layers) to bubble
161
- // events to their parent. We could also go through parentNode on the
162
- // host node but that wouldn't work for React Native and doesn't let us
163
- // do the portal feature.
164
- } while (inst && inst.tag !== HostComponent);
165
- if (inst) {
166
- return inst;
167
- }
168
- return null;
169
-}
170
-
171
-/**
172
- * Return the lowest common ancestor of A and B, or null if they are in
173
- * different trees.
174
- */
175
-export function getLowestCommonAncestor(instA, instB) {
176
- let depthA = 0;
177
- for (let tempA = instA; tempA; tempA = getParent(tempA)) {
178
- depthA++;
179
- }
180
- let depthB = 0;
181
- for (let tempB = instB; tempB; tempB = getParent(tempB)) {
182
- depthB++;
183
- }
184
-
185
- // If A is deeper, crawl up.
186
- while (depthA - depthB > 0) {
187
- instA = getParent(instA);
188
- depthA--;
189
- }
190
-
191
- // If B is deeper, crawl up.
192
- while (depthB - depthA > 0) {
193
- instB = getParent(instB);
194
- depthB--;
195
- }
196
-
197
- // Walk in lockstep until we find a match.
198
- let depth = depthA;
199
- while (depth--) {
200
- if (instA === instB || instA === instB.alternate) {
201
- return instA;
202
- }
203
- instA = getParent(instA);
204
- instB = getParent(instB);
205
- }
206
- return null;
207
-}
208
-
209
-/**
210
- * Return if A is an ancestor of B.
211
- */
212
-function isAncestor(instA, instB) {
213
- while (instB) {
214
- if (instA === instB || instA === instB.alternate) {
215
- return true;
216
- }
217
- instB = getParent(instB);
218
- }
219
- return false;
220
-}
221
-
222
-/**
223
- * Simulates the traversal of a two-phase, capture/bubble event dispatch.
224
- */
225
-function traverseTwoPhase(inst, fn, arg) {
226
- const path = [];
227
- while (inst) {
228
- path.push(inst);
229
- inst = getParent(inst);
230
- }
231
- let i;
232
- for (i = path.length; i-- > 0; ) {
233
- fn(path[i], 'captured', arg);
234
- }
235
- for (i = 0; i < path.length; i++) {
236
- fn(path[i], 'bubbled', arg);
237
- }
238
-}
239
-
240
-function getListener(inst, registrationName) {
241
- const stateNode = inst.stateNode;
242
- if (stateNode === null) {
243
- // Work in progress (ex: onload events in incremental mode).
244
- return null;
245
- }
246
- const props = getFiberCurrentPropsFromNode(stateNode);
247
- if (props === null) {
248
- // Work in progress.
249
- return null;
250
- }
251
- const listener = props[registrationName];
252
- invariant(
253
- !listener || typeof listener === 'function',
254
- 'Expected `%s` listener to be a function, instead got a value of `%s` type.',
255
- registrationName,
256
- typeof listener,
257
- );
258
- return listener;
259
-}
260
-
261
-function listenerAtPhase(inst, event, propagationPhase: PropagationPhases) {
262
- const registrationName =
263
- event.dispatchConfig.phasedRegistrationNames[propagationPhase];
264
- return getListener(inst, registrationName);
265
-}
266
-
267
-function accumulateDirectionalDispatches(inst, phase, event) {
268
- if (__DEV__) {
269
- if (!inst) {
270
- console.error('Dispatching inst must not be null');
271
- }
272
- }
273
- const listener = listenerAtPhase(inst, event, phase);
274
- if (listener) {
275
- event._dispatchListeners = accumulateInto(
276
- event._dispatchListeners,
277
- listener,
278
- );
279
- event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
280
- }
281
-}
282
-
283
-/**
284
- * Accumulates without regard to direction, does not look for phased
285
- * registration names. Same as `accumulateDirectDispatchesSingle` but without
286
- * requiring that the `dispatchMarker` be the same as the dispatched ID.
287
- */
288
-function accumulateDispatches(
289
- inst: Object,
290
- ignoredDirection: ?boolean,
291
- event: Object,
292
-): void {
293
- if (inst && event && event.dispatchConfig.registrationName) {
294
- const registrationName = event.dispatchConfig.registrationName;
295
- const listener = getListener(inst, registrationName);
296
- if (listener) {
297
- event._dispatchListeners = accumulateInto(
298
- event._dispatchListeners,
299
- listener,
300
- );
301
- event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
302
- }
303
- }
304
-}
305
-
306
-/**
307
- * Accumulates dispatches on an `SyntheticEvent`, but only for the
308
- * `dispatchMarker`.
309
- * @param {SyntheticEvent} event
310
- */
311
-function accumulateDirectDispatchesSingle(event: Object) {
312
- if (event && event.dispatchConfig.registrationName) {
313
- accumulateDispatches(event._targetInst, null, event);
314
- }
315
-}
316
-
317
-function accumulateDirectDispatches(events: ?(Array<Object> | Object)) {
318
- forEachAccumulated(events, accumulateDirectDispatchesSingle);
319
-}
320
-
321
-function accumulateTwoPhaseDispatchesSingleSkipTarget(event) {
322
- if (event && event.dispatchConfig.phasedRegistrationNames) {
323
- const targetInst = event._targetInst;
324
- const parentInst = targetInst ? getParent(targetInst) : null;
325
- traverseTwoPhase(parentInst, accumulateDirectionalDispatches, event);
326
- }
327
-}
328
-
329
-function accumulateTwoPhaseDispatchesSkipTarget(events) {
330
- forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget);
331
-}
332
-
333
-function accumulateTwoPhaseDispatchesSingle(event) {
334
- if (event && event.dispatchConfig.phasedRegistrationNames) {
335
- traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event);
336
- }
337
-}
338
-
339
-function accumulateTwoPhaseDispatches(events) {
340
- forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
341
-}
342
-// End of inline
343
-
344
-/**
345
- *
346
- * Responder System:
347
- * ----------------
348
- *
349
- * - A global, solitary "interaction lock" on a view.
350
- * - If a node becomes the responder, it should convey visual feedback
351
- * immediately to indicate so, either by highlighting or moving accordingly.
352
- * - To be the responder means, that touches are exclusively important to that
353
- * responder view, and no other view.
354
- * - While touches are still occurring, the responder lock can be transferred to
355
- * a new view, but only to increasingly "higher" views (meaning ancestors of
356
- * the current responder).
357
- *
358
- * Responder being granted:
359
- * ------------------------
360
- *
361
- * - Touch starts, moves, and scrolls can cause an ID to become the responder.
362
- * - We capture/bubble `startShouldSetResponder`/`moveShouldSetResponder` to
363
- * the "appropriate place".
364
- * - If nothing is currently the responder, the "appropriate place" is the
365
- * initiating event's `targetID`.
366
- * - If something *is* already the responder, the "appropriate place" is the
367
- * first common ancestor of the event target and the current `responderInst`.
368
- * - Some negotiation happens: See the timing diagram below.
369
- * - Scrolled views automatically become responder. The reasoning is that a
370
- * platform scroll view that isn't built on top of the responder system has
371
- * began scrolling, and the active responder must now be notified that the
372
- * interaction is no longer locked to it - the system has taken over.
373
- *
374
- * - Responder being released:
375
- * As soon as no more touches that *started* inside of descendants of the
376
- * *current* responderInst, an `onResponderRelease` event is dispatched to the
377
- * current responder, and the responder lock is released.
378
- *
379
- * TODO:
380
- * - on "end", a callback hook for `onResponderEndShouldRemainResponder` that
381
- * determines if the responder lock should remain.
382
- * - If a view shouldn't "remain" the responder, any active touches should by
383
- * default be considered "dead" and do not influence future negotiations or
384
- * bubble paths. It should be as if those touches do not exist.
385
- * -- For multitouch: Usually a translate-z will choose to "remain" responder
386
- * after one out of many touches ended. For translate-y, usually the view
387
- * doesn't wish to "remain" responder after one of many touches end.
388
- * - Consider building this on top of a `stopPropagation` model similar to
389
- * `W3C` events.
390
- * - Ensure that `onResponderTerminate` is called on touch cancels, whether or
391
- * not `onResponderTerminationRequest` returns `true` or `false`.
392
- *
393
- */
394
-
395
-/* Negotiation Performed
396
- +-----------------------+
397
- / \
398
-Process low level events to + Current Responder + wantsResponderID
399
-determine who to perform negot-| (if any exists at all) |
400
-iation/transition | Otherwise just pass through|
401
--------------------------------+----------------------------+------------------+
402
-Bubble to find first ID | |
403
-to return true:wantsResponderID| |
404
- | |
405
- +-------------+ | |
406
- | onTouchStart| | |
407
- +------+------+ none | |
408
- | return| |
409
-+-----------v-------------+true| +------------------------+ |
410
-|onStartShouldSetResponder|----->|onResponderStart (cur) |<-----------+
411
-+-----------+-------------+ | +------------------------+ | |
412
- | | | +--------+-------+
413
- | returned true for| false:REJECT +-------->|onResponderReject
414
- | wantsResponderID | | | +----------------+
415
- | (now attempt | +------------------+-----+ |
416
- | handoff) | | onResponder | |
417
- +------------------->| TerminationRequest| |
418
- | +------------------+-----+ |
419
- | | | +----------------+
420
- | true:GRANT +-------->|onResponderGrant|
421
- | | +--------+-------+
422
- | +------------------------+ | |
423
- | | onResponderTerminate |<-----------+
424
- | +------------------+-----+ |
425
- | | | +----------------+
426
- | +-------->|onResponderStart|
427
- | | +----------------+
428
-Bubble to find first ID | |
429
-to return true:wantsResponderID| |
430
- | |
431
- +-------------+ | |
432
- | onTouchMove | | |
433
- +------+------+ none | |
434
- | return| |
435
-+-----------v-------------+true| +------------------------+ |
436
-|onMoveShouldSetResponder |----->|onResponderMove (cur) |<-----------+
437
-+-----------+-------------+ | +------------------------+ | |
438
- | | | +--------+-------+
439
- | returned true for| false:REJECT +-------->|onResponderRejec|
440
- | wantsResponderID | | | +----------------+
441
- | (now attempt | +------------------+-----+ |
442
- | handoff) | | onResponder | |
443
- +------------------->| TerminationRequest| |
444
- | +------------------+-----+ |
445
- | | | +----------------+
446
- | true:GRANT +-------->|onResponderGrant|
447
- | | +--------+-------+
448
- | +------------------------+ | |
449
- | | onResponderTerminate |<-----------+
450
- | +------------------+-----+ |
451
- | | | +----------------+
452
- | +-------->|onResponderMove |
453
- | | +----------------+
454
- | |
455
- | |
456
- Some active touch started| |
457
- inside current responder | +------------------------+ |
458
- +------------------------->| onResponderEnd | |
459
- | | +------------------------+ |
460
- +---+---------+ | |
461
- | onTouchEnd | | |
462
- +---+---------+ | |
463
- | | +------------------------+ |
464
- +------------------------->| onResponderEnd | |
465
- No active touches started| +-----------+------------+ |
466
- inside current responder | | |
467
- | v |
468
- | +------------------------+ |
469
- | | onResponderRelease | |
470
- | +------------------------+ |
471
- | |
472
- + + */
473
-
474
-/**
475
- * A note about event ordering in the `EventPluginRegistry`.
476
- *
477
- * Suppose plugins are injected in the following order:
478
- *
479
- * `[R, S, C]`
480
- *
481
- * To help illustrate the example, assume `S` is `SimpleEventPlugin` (for
482
- * `onClick` etc) and `R` is `ResponderEventPlugin`.
483
- *
484
- * "Deferred-Dispatched Events":
485
- *
486
- * - The current event plugin system will traverse the list of injected plugins,
487
- * in order, and extract events by collecting the plugin's return value of
488
- * `extractEvents()`.
489
- * - These events that are returned from `extractEvents` are "deferred
490
- * dispatched events".
491
- * - When returned from `extractEvents`, deferred-dispatched events contain an
492
- * "accumulation" of deferred dispatches.
493
- * - These deferred dispatches are accumulated/collected before they are
494
- * returned, but processed at a later time by the `EventPluginRegistry` (hence the
495
- * name deferred).
496
- *
497
- * In the process of returning their deferred-dispatched events, event plugins
498
- * themselves can dispatch events on-demand without returning them from
499
- * `extractEvents`. Plugins might want to do this, so that they can use event
500
- * dispatching as a tool that helps them decide which events should be extracted
501
- * in the first place.
502
- *
503
- * "On-Demand-Dispatched Events":
504
- *
505
- * - On-demand-dispatched events are not returned from `extractEvents`.
506
- * - On-demand-dispatched events are dispatched during the process of returning
507
- * the deferred-dispatched events.
508
- * - They should not have side effects.
509
- * - They should be avoided, and/or eventually be replaced with another
510
- * abstraction that allows event plugins to perform multiple "rounds" of event
511
- * extraction.
512
- *
513
- * Therefore, the sequence of event dispatches becomes:
514
- *
515
- * - `R`s on-demand events (if any) (dispatched by `R` on-demand)
516
- * - `S`s on-demand events (if any) (dispatched by `S` on-demand)
517
- * - `C`s on-demand events (if any) (dispatched by `C` on-demand)
518
- * - `R`s extracted events (if any) (dispatched by `EventPluginRegistry`)
519
- * - `S`s extracted events (if any) (dispatched by `EventPluginRegistry`)
520
- * - `C`s extracted events (if any) (dispatched by `EventPluginRegistry`)
521
- *
522
- * In the case of `ResponderEventPlugin`: If the `startShouldSetResponder`
523
- * on-demand dispatch returns `true` (and some other details are satisfied) the
524
- * `onResponderGrant` deferred dispatched event is returned from
525
- * `extractEvents`. The sequence of dispatch executions in this case
526
- * will appear as follows:
527
- *
528
- * - `startShouldSetResponder` (`ResponderEventPlugin` dispatches on-demand)
529
- * - `touchStartCapture` (`EventPluginRegistry` dispatches as usual)
530
- * - `touchStart` (`EventPluginRegistry` dispatches as usual)
531
- * - `responderGrant/Reject` (`EventPluginRegistry` dispatches as usual)
532
- */
533
-
534
-function setResponderAndExtractTransfer(
535
- topLevelType,
536
- targetInst,
537
- nativeEvent,
538
- nativeEventTarget,
539
-) {
540
- const shouldSetEventType = isStartish(topLevelType)
541
- ? eventTypes.startShouldSetResponder
542
- : isMoveish(topLevelType)
543
- ? eventTypes.moveShouldSetResponder
544
- : topLevelType === TOP_SELECTION_CHANGE
545
- ? eventTypes.selectionChangeShouldSetResponder
546
- : eventTypes.scrollShouldSetResponder;
547
-
548
- // TODO: stop one short of the current responder.
549
- const bubbleShouldSetFrom = !responderInst
550
- ? targetInst
551
- : getLowestCommonAncestor(responderInst, targetInst);
552
-
553
- // When capturing/bubbling the "shouldSet" event, we want to skip the target
554
- // (deepest ID) if it happens to be the current responder. The reasoning:
555
- // It's strange to get an `onMoveShouldSetResponder` when you're *already*
556
- // the responder.
557
- const skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderInst;
558
- const shouldSetEvent = ResponderSyntheticEvent.getPooled(
559
- shouldSetEventType,
560
- bubbleShouldSetFrom,
561
- nativeEvent,
562
- nativeEventTarget,
563
- );
564
- shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
565
- if (skipOverBubbleShouldSetFrom) {
566
- accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent);
567
- } else {
568
- accumulateTwoPhaseDispatches(shouldSetEvent);
569
- }
570
- const wantsResponderInst = executeDispatchesInOrderStopAtTrue(shouldSetEvent);
571
- if (!shouldSetEvent.isPersistent()) {
572
- shouldSetEvent.constructor.release(shouldSetEvent);
573
- }
574
-
575
- if (!wantsResponderInst || wantsResponderInst === responderInst) {
576
- return null;
577
- }
578
- let extracted;
579
- const grantEvent = ResponderSyntheticEvent.getPooled(
580
- eventTypes.responderGrant,
581
- wantsResponderInst,
582
- nativeEvent,
583
- nativeEventTarget,
584
- );
585
- grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
586
-
587
- accumulateDirectDispatches(grantEvent);
588
- const blockHostResponder = executeDirectDispatch(grantEvent) === true;
589
- if (responderInst) {
590
- const terminationRequestEvent = ResponderSyntheticEvent.getPooled(
591
- eventTypes.responderTerminationRequest,
592
- responderInst,
593
- nativeEvent,
594
- nativeEventTarget,
595
- );
596
- terminationRequestEvent.touchHistory =
597
- ResponderTouchHistoryStore.touchHistory;
598
- accumulateDirectDispatches(terminationRequestEvent);
599
- const shouldSwitch =
600
- !hasDispatches(terminationRequestEvent) ||
601
- executeDirectDispatch(terminationRequestEvent);
602
- if (!terminationRequestEvent.isPersistent()) {
603
- terminationRequestEvent.constructor.release(terminationRequestEvent);
604
- }
605
-
606
- if (shouldSwitch) {
607
- const terminateEvent = ResponderSyntheticEvent.getPooled(
608
- eventTypes.responderTerminate,
609
- responderInst,
610
- nativeEvent,
611
- nativeEventTarget,
612
- );
613
- terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
614
- accumulateDirectDispatches(terminateEvent);
615
- extracted = accumulate(extracted, [grantEvent, terminateEvent]);
616
- changeResponder(wantsResponderInst, blockHostResponder);
617
- } else {
618
- const rejectEvent = ResponderSyntheticEvent.getPooled(
619
- eventTypes.responderReject,
620
- wantsResponderInst,
621
- nativeEvent,
622
- nativeEventTarget,
623
- );
624
- rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
625
- accumulateDirectDispatches(rejectEvent);
626
- extracted = accumulate(extracted, rejectEvent);
627
- }
628
- } else {
629
- extracted = accumulate(extracted, grantEvent);
630
- changeResponder(wantsResponderInst, blockHostResponder);
631
- }
632
- return extracted;
633
-}
634
-
635
-/**
636
- * A transfer is a negotiation between a currently set responder and the next
637
- * element to claim responder status. Any start event could trigger a transfer
638
- * of responderInst. Any move event could trigger a transfer.
639
- *
640
- * @param {string} topLevelType Record from `BrowserEventConstants`.
641
- * @return {boolean} True if a transfer of responder could possibly occur.
642
- */
643
-function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) {
644
- return (
645
- topLevelInst &&
646
- // responderIgnoreScroll: We are trying to migrate away from specifically
647
- // tracking native scroll events here and responderIgnoreScroll indicates we
648
- // will send topTouchCancel to handle canceling touch events instead
649
- ((topLevelType === TOP_SCROLL && !nativeEvent.responderIgnoreScroll) ||
650
- (trackedTouchCount > 0 && topLevelType === TOP_SELECTION_CHANGE) ||
651
- isStartish(topLevelType) ||
652
- isMoveish(topLevelType))
653
- );
654
-}
655
-
656
-/**
657
- * Returns whether or not this touch end event makes it such that there are no
658
- * longer any touches that started inside of the current `responderInst`.
659
- *
660
- * @param {NativeEvent} nativeEvent Native touch end event.
661
- * @return {boolean} Whether or not this touch end event ends the responder.
662
- */
663
-function noResponderTouches(nativeEvent) {
664
- const touches = nativeEvent.touches;
665
- if (!touches || touches.length === 0) {
666
- return true;
667
- }
668
- for (let i = 0; i < touches.length; i++) {
669
- const activeTouch = touches[i];
670
- const target = activeTouch.target;
671
- if (target !== null && target !== undefined && target !== 0) {
672
- // Is the original touch location inside of the current responder?
673
- const targetInst = getInstanceFromNode(target);
674
- if (isAncestor(responderInst, targetInst)) {
675
- return false;
676
- }
677
- }
678
- }
679
- return true;
680
-}
681
-
682
-const ResponderEventPlugin = {
683
- /* For unit testing only */
684
- _getResponder: function() {
685
- return responderInst;
686
- },
687
-
688
- eventTypes: eventTypes,
689
-
690
- /**
691
- * We must be resilient to `targetInst` being `null` on `touchMove` or
692
- * `touchEnd`. On certain platforms, this means that a native scroll has
693
- * assumed control and the original touch targets are destroyed.
694
- */
695
- extractEvents: function(
696
- topLevelType,
697
- targetInst,
698
- nativeEvent,
699
- nativeEventTarget,
700
- eventSystemFlags,
701
- ) {
702
- if (isStartish(topLevelType)) {
703
- trackedTouchCount += 1;
704
- } else if (isEndish(topLevelType)) {
705
- if (trackedTouchCount >= 0) {
706
- trackedTouchCount -= 1;
707
- } else {
708
- if (__DEV__) {
709
- console.warn(
710
- 'Ended a touch event which was not counted in `trackedTouchCount`.',
711
- );
712
- }
713
- return null;
714
- }
715
- }
716
-
717
- ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent);
718
-
719
- let extracted = canTriggerTransfer(topLevelType, targetInst, nativeEvent)
720
- ? setResponderAndExtractTransfer(
721
- topLevelType,
722
- targetInst,
723
- nativeEvent,
724
- nativeEventTarget,
725
- )
726
- : null;
727
- // Responder may or may not have transferred on a new touch start/move.
728
- // Regardless, whoever is the responder after any potential transfer, we
729
- // direct all touch start/move/ends to them in the form of
730
- // `onResponderMove/Start/End`. These will be called for *every* additional
731
- // finger that move/start/end, dispatched directly to whoever is the
732
- // current responder at that moment, until the responder is "released".
733
- //
734
- // These multiple individual change touch events are are always bookended
735
- // by `onResponderGrant`, and one of
736
- // (`onResponderRelease/onResponderTerminate`).
737
- const isResponderTouchStart = responderInst && isStartish(topLevelType);
738
- const isResponderTouchMove = responderInst && isMoveish(topLevelType);
739
- const isResponderTouchEnd = responderInst && isEndish(topLevelType);
740
- const incrementalTouch = isResponderTouchStart
741
- ? eventTypes.responderStart
742
- : isResponderTouchMove
743
- ? eventTypes.responderMove
744
- : isResponderTouchEnd
745
- ? eventTypes.responderEnd
746
- : null;
747
-
748
- if (incrementalTouch) {
749
- const gesture = ResponderSyntheticEvent.getPooled(
750
- incrementalTouch,
751
- responderInst,
752
- nativeEvent,
753
- nativeEventTarget,
754
- );
755
- gesture.touchHistory = ResponderTouchHistoryStore.touchHistory;
756
- accumulateDirectDispatches(gesture);
757
- extracted = accumulate(extracted, gesture);
758
- }
759
-
760
- const isResponderTerminate =
761
- responderInst && topLevelType === TOP_TOUCH_CANCEL;
762
- const isResponderRelease =
763
- responderInst &&
764
- !isResponderTerminate &&
765
- isEndish(topLevelType) &&
766
- noResponderTouches(nativeEvent);
767
- const finalTouch = isResponderTerminate
768
- ? eventTypes.responderTerminate
769
- : isResponderRelease
770
- ? eventTypes.responderRelease
771
- : null;
772
- if (finalTouch) {
773
- const finalEvent = ResponderSyntheticEvent.getPooled(
774
- finalTouch,
775
- responderInst,
776
- nativeEvent,
777
- nativeEventTarget,
778
- );
779
- finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
780
- accumulateDirectDispatches(finalEvent);
781
- extracted = accumulate(extracted, finalEvent);
782
- changeResponder(null);
783
- }
784
-
785
- return extracted;
786
- },
787
-
788
- GlobalResponderHandler: null,
789
-
790
- injection: {
791
- /**
792
- * @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler
793
- * Object that handles any change in responder. Use this to inject
794
- * integration with an existing touch handling system etc.
795
- */
796
- injectGlobalResponderHandler(GlobalResponderHandler) {
797
- ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler;
798
- },
799
- },
800
-};
801
-
802
-export default ResponderEventPlugin;
packages/react-dom/src/legacy-events/ResponderSyntheticEvent.js
deleted
-21
@@ -1,21 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-import SyntheticEvent from './SyntheticEvent';
9
-
10
-/**
11
- * `touchHistory` isn't actually on the native event, but putting it in the
12
- * interface will ensure that it is cleaned up when pooled/destroyed. The
13
- * `ResponderEventPlugin` will populate it appropriately.
14
- */
15
-const ResponderSyntheticEvent = SyntheticEvent.extend({
16
- touchHistory: function(nativeEvent) {
17
- return null; // Actually doesn't even look at the native event.
18
- },
19
-});
20
-
21
-export default ResponderSyntheticEvent;
packages/react-dom/src/legacy-events/ResponderTopLevelEventTypes.js
deleted
-31
@@ -1,31 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @flow
8
- */
9
-
10
-export const TOP_TOUCH_START = 'topTouchStart';
11
-export const TOP_TOUCH_MOVE = 'topTouchMove';
12
-export const TOP_TOUCH_END = 'topTouchEnd';
13
-export const TOP_TOUCH_CANCEL = 'topTouchCancel';
14
-export const TOP_SCROLL = 'topScroll';
15
-export const TOP_SELECTION_CHANGE = 'topSelectionChange';
16
-
17
-export function isStartish(topLevelType: mixed): boolean {
18
- return topLevelType === TOP_TOUCH_START;
19
-}
20
-
21
-export function isMoveish(topLevelType: mixed): boolean {
22
- return topLevelType === TOP_TOUCH_MOVE;
23
-}
24
-
25
-export function isEndish(topLevelType: mixed): boolean {
26
- return topLevelType === TOP_TOUCH_END || topLevelType === TOP_TOUCH_CANCEL;
27
-}
28
-
29
-export const startDependencies = [TOP_TOUCH_START];
30
-export const moveDependencies = [TOP_TOUCH_MOVE];
31
-export const endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END];
packages/react-dom/src/legacy-events/ResponderTouchHistoryStore.js
deleted
-222
@@ -1,222 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @flow
8
- */
9
-
10
-import invariant from 'shared/invariant';
11
-
12
-import {isStartish, isMoveish, isEndish} from './ResponderTopLevelEventTypes';
13
-
14
-/**
15
- * Tracks the position and time of each active touch by `touch.identifier`. We
16
- * should typically only see IDs in the range of 1-20 because IDs get recycled
17
- * when touches end and start again.
18
- */
19
-type TouchRecord = {|
20
- touchActive: boolean,
21
- startPageX: number,
22
- startPageY: number,
23
- startTimeStamp: number,
24
- currentPageX: number,
25
- currentPageY: number,
26
- currentTimeStamp: number,
27
- previousPageX: number,
28
- previousPageY: number,
29
- previousTimeStamp: number,
30
-|};
31
-
32
-const MAX_TOUCH_BANK = 20;
33
-const touchBank: Array<TouchRecord> = [];
34
-const touchHistory = {
35
- touchBank,
36
- numberActiveTouches: 0,
37
- // If there is only one active touch, we remember its location. This prevents
38
- // us having to loop through all of the touches all the time in the most
39
- // common case.
40
- indexOfSingleActiveTouch: -1,
41
- mostRecentTimeStamp: 0,
42
-};
43
-
44
-type Touch = {
45
- identifier: ?number,
46
- pageX: number,
47
- pageY: number,
48
- timestamp: number,
49
- ...
50
-};
51
-type TouchEvent = {
52
- changedTouches: Array<Touch>,
53
- touches: Array<Touch>,
54
- ...
55
-};
56
-
57
-function timestampForTouch(touch: Touch): number {
58
- // The legacy internal implementation provides "timeStamp", which has been
59
- // renamed to "timestamp". Let both work for now while we iron it out
60
- // TODO (evv): rename timeStamp to timestamp in internal code
61
- return (touch: any).timeStamp || touch.timestamp;
62
-}
63
-
64
-/**
65
- * TODO: Instead of making gestures recompute filtered velocity, we could
66
- * include a built in velocity computation that can be reused globally.
67
- */
68
-function createTouchRecord(touch: Touch): TouchRecord {
69
- return {
70
- touchActive: true,
71
- startPageX: touch.pageX,
72
- startPageY: touch.pageY,
73
- startTimeStamp: timestampForTouch(touch),
74
- currentPageX: touch.pageX,
75
- currentPageY: touch.pageY,
76
- currentTimeStamp: timestampForTouch(touch),
77
- previousPageX: touch.pageX,
78
- previousPageY: touch.pageY,
79
- previousTimeStamp: timestampForTouch(touch),
80
- };
81
-}
82
-
83
-function resetTouchRecord(touchRecord: TouchRecord, touch: Touch): void {
84
- touchRecord.touchActive = true;
85
- touchRecord.startPageX = touch.pageX;
86
- touchRecord.startPageY = touch.pageY;
87
- touchRecord.startTimeStamp = timestampForTouch(touch);
88
- touchRecord.currentPageX = touch.pageX;
89
- touchRecord.currentPageY = touch.pageY;
90
- touchRecord.currentTimeStamp = timestampForTouch(touch);
91
- touchRecord.previousPageX = touch.pageX;
92
- touchRecord.previousPageY = touch.pageY;
93
- touchRecord.previousTimeStamp = timestampForTouch(touch);
94
-}
95
-
96
-function getTouchIdentifier({identifier}: Touch): number {
97
- invariant(identifier != null, 'Touch object is missing identifier.');
98
- if (__DEV__) {
99
- if (identifier > MAX_TOUCH_BANK) {
100
- console.error(
101
- 'Touch identifier %s is greater than maximum supported %s which causes ' +
102
- 'performance issues backfilling array locations for all of the indices.',
103
- identifier,
104
- MAX_TOUCH_BANK,
105
- );
106
- }
107
- }
108
- return identifier;
109
-}
110
-
111
-function recordTouchStart(touch: Touch): void {
112
- const identifier = getTouchIdentifier(touch);
113
- const touchRecord = touchBank[identifier];
114
- if (touchRecord) {
115
- resetTouchRecord(touchRecord, touch);
116
- } else {
117
- touchBank[identifier] = createTouchRecord(touch);
118
- }
119
- touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
120
-}
121
-
122
-function recordTouchMove(touch: Touch): void {
123
- const touchRecord = touchBank[getTouchIdentifier(touch)];
124
- if (touchRecord) {
125
- touchRecord.touchActive = true;
126
- touchRecord.previousPageX = touchRecord.currentPageX;
127
- touchRecord.previousPageY = touchRecord.currentPageY;
128
- touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
129
- touchRecord.currentPageX = touch.pageX;
130
- touchRecord.currentPageY = touch.pageY;
131
- touchRecord.currentTimeStamp = timestampForTouch(touch);
132
- touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
133
- } else {
134
- if (__DEV__) {
135
- console.warn(
136
- 'Cannot record touch move without a touch start.\n' +
137
- 'Touch Move: %s\n' +
138
- 'Touch Bank: %s',
139
- printTouch(touch),
140
- printTouchBank(),
141
- );
142
- }
143
- }
144
-}
145
-
146
-function recordTouchEnd(touch: Touch): void {
147
- const touchRecord = touchBank[getTouchIdentifier(touch)];
148
- if (touchRecord) {
149
- touchRecord.touchActive = false;
150
- touchRecord.previousPageX = touchRecord.currentPageX;
151
- touchRecord.previousPageY = touchRecord.currentPageY;
152
- touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
153
- touchRecord.currentPageX = touch.pageX;
154
- touchRecord.currentPageY = touch.pageY;
155
- touchRecord.currentTimeStamp = timestampForTouch(touch);
156
- touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
157
- } else {
158
- if (__DEV__) {
159
- console.warn(
160
- 'Cannot record touch end without a touch start.\n' +
161
- 'Touch End: %s\n' +
162
- 'Touch Bank: %s',
163
- printTouch(touch),
164
- printTouchBank(),
165
- );
166
- }
167
- }
168
-}
169
-
170
-function printTouch(touch: Touch): string {
171
- return JSON.stringify({
172
- identifier: touch.identifier,
173
- pageX: touch.pageX,
174
- pageY: touch.pageY,
175
- timestamp: timestampForTouch(touch),
176
- });
177
-}
178
-
179
-function printTouchBank(): string {
180
- let printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK));
181
- if (touchBank.length > MAX_TOUCH_BANK) {
182
- printed += ' (original size: ' + touchBank.length + ')';
183
- }
184
- return printed;
185
-}
186
-
187
-const ResponderTouchHistoryStore = {
188
- recordTouchTrack(topLevelType: string, nativeEvent: TouchEvent): void {
189
- if (isMoveish(topLevelType)) {
190
- nativeEvent.changedTouches.forEach(recordTouchMove);
191
- } else if (isStartish(topLevelType)) {
192
- nativeEvent.changedTouches.forEach(recordTouchStart);
193
- touchHistory.numberActiveTouches = nativeEvent.touches.length;
194
- if (touchHistory.numberActiveTouches === 1) {
195
- touchHistory.indexOfSingleActiveTouch =
196
- nativeEvent.touches[0].identifier;
197
- }
198
- } else if (isEndish(topLevelType)) {
199
- nativeEvent.changedTouches.forEach(recordTouchEnd);
200
- touchHistory.numberActiveTouches = nativeEvent.touches.length;
201
- if (touchHistory.numberActiveTouches === 1) {
202
- for (let i = 0; i < touchBank.length; i++) {
203
- const touchTrackToCheck = touchBank[i];
204
- if (touchTrackToCheck != null && touchTrackToCheck.touchActive) {
205
- touchHistory.indexOfSingleActiveTouch = i;
206
- break;
207
- }
208
- }
209
- if (__DEV__) {
210
- const activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch];
211
- if (activeRecord == null || !activeRecord.touchActive) {
212
- console.error('Cannot find single active touch.');
213
- }
214
- }
215
- }
216
- }
217
- },
218
-
219
- touchHistory,
220
-};
221
-
222
-export default ResponderTouchHistoryStore;
packages/react-dom/src/legacy-events/SyntheticEvent.js
+4
-149
@@ -7,11 +7,6 @@
7
8
/* eslint valid-typeof: 0 */
9
10
-import invariant from 'shared/invariant';
11
-import {enableModernEventSystem} from 'shared/ReactFeatureFlags';
12
-
13
-const EVENT_POOL_SIZE = 10;
14
-
10
/**
11
* @interface Event
12
* @see http://www.w3.org/TR/DOM-Level-3-Events/
@@ -77,10 +72,6 @@ function SyntheticEvent(
72
this.dispatchConfig = dispatchConfig;
73
this._targetInst = targetInst;
74
this.nativeEvent = nativeEvent;
80
- if (!enableModernEventSystem) {
81
- this._dispatchListeners = null;
82
- this._dispatchInstances = null;
83
- }
75
76
const Interface = this.constructor.Interface;
77
for (const propName in Interface) {
@@ -158,9 +149,6 @@ Object.assign(SyntheticEvent.prototype, {
149
*/
150
persist: function() {
151
// Modern event system doesn't use pooling.
161
- if (!enableModernEventSystem) {
162
- this.isPersistent = functionThatReturnsTrue;
163
- }
152
},
153
154
/**
@@ -168,69 +156,14 @@ Object.assign(SyntheticEvent.prototype, {
156
*
157
* @return {boolean} True if this should not be released, false otherwise.
158
*/
171
- isPersistent: enableModernEventSystem
172
- ? functionThatReturnsTrue
173
- : functionThatReturnsFalse,
159
+ isPersistent: functionThatReturnsTrue,
160
161
/**
162
* `PooledClass` looks for `destructor` on each instance it releases.
163
*/
164
destructor: function() {
165
// Modern event system doesn't use pooling.
180
- if (!enableModernEventSystem) {
181
- const Interface = this.constructor.Interface;
182
- for (const propName in Interface) {
183
- if (__DEV__) {
184
- Object.defineProperty(
185
- this,
186
- propName,
187
- getPooledWarningPropertyDefinition(propName, Interface[propName]),
188
- );
189
- } else {
190
- this[propName] = null;
191
- }
192
- }
193
- this.dispatchConfig = null;
194
- this._targetInst = null;
195
- this.nativeEvent = null;
196
- this.isDefaultPrevented = functionThatReturnsFalse;
197
- this.isPropagationStopped = functionThatReturnsFalse;
198
- this._dispatchListeners = null;
199
- this._dispatchInstances = null;
200
- if (__DEV__) {
201
- Object.defineProperty(
202
- this,
203
- 'nativeEvent',
204
- getPooledWarningPropertyDefinition('nativeEvent', null),
205
- );
206
- Object.defineProperty(
207
- this,
208
- 'isDefaultPrevented',
209
- getPooledWarningPropertyDefinition(
210
- 'isDefaultPrevented',
211
- functionThatReturnsFalse,
212
- ),
213
- );
214
- Object.defineProperty(
215
- this,
216
- 'isPropagationStopped',
217
- getPooledWarningPropertyDefinition(
218
- 'isPropagationStopped',
219
- functionThatReturnsFalse,
220
- ),
221
- );
222
- Object.defineProperty(
223
- this,
224
- 'preventDefault',
225
- getPooledWarningPropertyDefinition('preventDefault', () => {}),
226
- );
227
- Object.defineProperty(
228
- this,
229
- 'stopPropagation',
230
- getPooledWarningPropertyDefinition('stopPropagation', () => {}),
231
- );
232
- }
233
- }
166
+ // TODO: remove calls to this.
167
},
168
});
169
@@ -262,53 +195,6 @@ SyntheticEvent.extend = function(Interface) {
195
196
addEventPoolingTo(SyntheticEvent);
197
265
-/**
266
- * Helper to nullify syntheticEvent instance properties when destructing
267
- *
268
- * @param {String} propName
269
- * @param {?object} getVal
270
- * @return {object} defineProperty object
271
- */
272
-function getPooledWarningPropertyDefinition(propName, getVal) {
273
- const isFunction = typeof getVal === 'function';
274
- return {
275
- configurable: true,
276
- set: set,
277
- get: get,
278
- };
279
-
280
- function set(val) {
281
- const action = isFunction ? 'setting the method' : 'setting the property';
282
- warn(action, 'This is effectively a no-op');
283
- return val;
284
- }
285
-
286
- function get() {
287
- const action = isFunction
288
- ? 'accessing the method'
289
- : 'accessing the property';
290
- const result = isFunction
291
- ? 'This is a no-op function'
292
- : 'This is set to null';
293
- warn(action, result);
294
- return getVal;
295
- }
296
-
297
- function warn(action, result) {
298
- if (__DEV__) {
299
- console.error(
300
- "This synthetic event is reused for performance reasons. If you're seeing this, " +
301
- "you're %s `%s` on a released/nullified synthetic event. %s. " +
302
- 'If you must keep the original synthetic event around, use event.persist(). ' +
303
- 'See https://fb.me/react-event-pooling for more information.',
304
- action,
305
- propName,
306
- result,
307
- );
308
- }
309
- }
310
-}
311
-
198
function createOrGetPooledEvent(
199
dispatchConfig,
200
targetInst,
@@ -317,19 +203,7 @@ function createOrGetPooledEvent(
203
) {
204
const EventConstructor = this;
205
// Modern event system doesn't use pooling.
320
- if (!enableModernEventSystem) {
321
- if (EventConstructor.eventPool.length) {
322
- const instance = EventConstructor.eventPool.pop();
323
- EventConstructor.call(
324
- instance,
325
- dispatchConfig,
326
- targetInst,
327
- nativeEvent,
328
- nativeInst,
329
- );
330
- return instance;
331
- }
332
- }
206
+ // TODO: remove this indirection.
207
return new EventConstructor(
208
dispatchConfig,
209
targetInst,
@@ -338,29 +212,10 @@ function createOrGetPooledEvent(
212
);
213
}
214
341
-function releasePooledEvent(event) {
342
- // Modern event system doesn't use pooling.
343
- if (!enableModernEventSystem) {
344
- const EventConstructor = this;
345
- invariant(
346
- event instanceof EventConstructor,
347
- 'Trying to release an event instance into a pool of a different type.',
348
- );
349
- event.destructor();
350
- if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) {
351
- EventConstructor.eventPool.push(event);
352
- }
353
- }
354
-}
355
-
215
function addEventPoolingTo(EventConstructor) {
216
EventConstructor.getPooled = createOrGetPooledEvent;
358
-
217
// Modern event system doesn't use pooling.
360
- if (!enableModernEventSystem) {
361
- EventConstructor.eventPool = [];
362
- EventConstructor.release = releasePooledEvent;
363
- }
218
+ // TODO: remove calls to this.
219
}
220
221
export default SyntheticEvent;
packages/react-dom/src/legacy-events/accumulate.js
deleted
-45
@@ -1,45 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @flow
8
- */
9
-
10
-import invariant from 'shared/invariant';
11
-
12
-/**
13
- * Accumulates items that must not be null or undefined.
14
- *
15
- * This is used to conserve memory by avoiding array allocations.
16
- *
17
- * @return {*|array<*>} An accumulation of items.
18
- */
19
-function accumulate<T>(
20
- current: ?(T | Array<T>),
21
- next: T | Array<T>,
22
-): T | Array<T> {
23
- invariant(
24
- next != null,
25
- 'accumulate(...): Accumulated items must not be null or undefined.',
26
- );
27
-
28
- if (current == null) {
29
- return next;
30
- }
31
-
32
- // Both are not empty. Warning: Never call x.concat(y) when you are not
33
- // certain that x is an Array (x could be a string with concat method).
34
- if (Array.isArray(current)) {
35
- return current.concat(next);
36
- }
37
-
38
- if (Array.isArray(next)) {
39
- return [current].concat(next);
40
- }
41
-
42
- return [current, next];
43
-}
44
-
45
-export default accumulate;
packages/react-dom/src/test-utils/ReactTestUtils.js
+3
-173
@@ -18,17 +18,14 @@ import {
18
import SyntheticEvent from '../legacy-events/SyntheticEvent';
19
import invariant from 'shared/invariant';
20
import {ELEMENT_NODE} from '../shared/HTMLNodeType';
21
-import * as DOMTopLevelEventTypes from '../events/DOMTopLevelEventTypes';
21
import act from './ReactTestUtilsAct';
22
import forEachAccumulated from '../legacy-events/forEachAccumulated';
23
import accumulateInto from '../legacy-events/accumulateInto';
25
-import {enableModernEventSystem} from 'shared/ReactFeatureFlags';
24
import {
25
rethrowCaughtError,
26
invokeGuardedCallbackAndCatchFirstError,
27
} from 'shared/ReactErrorUtils';
28
31
-const {findDOMNode} = ReactDOM;
29
// Keep in sync with ReactDOM.js, and ReactTestUtilsAct.js:
30
const [
31
getInstanceFromNode,
@@ -39,10 +36,9 @@ const [
36
/* eslint-enable no-unused-vars */
37
eventNameDispatchConfigs,
38
enqueueStateRestore,
42
- restoreStateIfNeeded,
43
- dispatchEvent,
44
- /* eslint-disable no-unused-vars */
45
- flushPassiveEffects,
39
+ restoreStateIfNeeded /* eslint-disable no-unused-vars */, // TODO: remove.
40
+ ,
41
+ /* dispatchEvent */ flushPassiveEffects,
42
IsThisRendererActing,
43
/* eslint-enable no-unused-vars */
44
] = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events;
@@ -50,7 +46,6 @@ const [
46
function Event(suffix) {}
47
48
let hasWarnedAboutDeprecatedMockComponent = false;
53
-let didWarnSimulateNativeDeprecated = false;
49
50
/**
51
* @class ReactTestUtils
@@ -667,171 +662,6 @@ function buildSimulators() {
662
663
buildSimulators();
664
670
-if (!enableModernEventSystem) {
671
- SimulateNative = {};
672
-
673
- /**
674
- * Simulates a top level event being dispatched from a raw event that occurred
675
- * on an `Element` node.
676
- * @param {number} topLevelType A number from `TopLevelEventTypes`
677
- * @param {!Element} node The dom to simulate an event occurring on.
678
- * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
679
- */
680
- const simulateNativeEventOnNode = function(
681
- topLevelType,
682
- node,
683
- fakeNativeEvent,
684
- ) {
685
- fakeNativeEvent.target = node;
686
- const PLUGIN_EVENT_SYSTEM = 1;
687
- dispatchEvent(topLevelType, PLUGIN_EVENT_SYSTEM, null, fakeNativeEvent);
688
- };
689
-
690
- /**
691
- * Simulates a top level event being dispatched from a raw event that occurred
692
- * on the `ReactDOMComponent` `comp`.
693
- * @param {Object} topLevelType A type from `BrowserEventConstants.topLevelTypes`.
694
- * @param {!ReactDOMComponent} comp
695
- * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
696
- */
697
- const simulateNativeEventOnDOMComponent = function(
698
- topLevelType,
699
- comp,
700
- fakeNativeEvent,
701
- ) {
702
- simulateNativeEventOnNode(topLevelType, findDOMNode(comp), fakeNativeEvent);
703
- };
704
-
705
- /**
706
- * Exports:
707
- *
708
- * - `SimulateNative.click(Element/ReactDOMComponent)`
709
- * - `SimulateNative.mouseMove(Element/ReactDOMComponent)`
710
- * - `SimulateNative.mouseIn/ReactDOMComponent)`
711
- * - `SimulateNative.mouseOut(Element/ReactDOMComponent)`
712
- * - ... (All keys from `BrowserEventConstants.topLevelTypes`)
713
- *
714
- * Note: Top level event types are a subset of the entire set of handler types
715
- * (which include a broader set of "synthetic" events). For example, onDragDone
716
- * is a synthetic event. Except when testing an event plugin or React's event
717
- * handling code specifically, you probably want to use Simulate
718
- * to dispatch synthetic events.
719
- */
720
-
721
- const makeNativeSimulator = function(eventType, topLevelType) {
722
- return function(domComponentOrNode, nativeEventData) {
723
- if (__DEV__) {
724
- if (!didWarnSimulateNativeDeprecated) {
725
- didWarnSimulateNativeDeprecated = true;
726
- console.warn(
727
- 'ReactTestUtils.SimulateNative is an undocumented API that does not match ' +
728
- 'how the browser dispatches events, and will be removed in a future major ' +
729
- 'version of React. If you rely on it for testing, consider attaching the root ' +
730
- 'DOM container to the document during the test, and then dispatching native browser ' +
731
- 'events by calling `node.dispatchEvent()` on the DOM nodes. Make sure to set ' +
732
- 'the `bubbles` flag to `true` when creating the native browser event.',
733
- );
734
- }
735
- }
736
-
737
- const fakeNativeEvent = new Event(eventType);
738
- Object.assign(fakeNativeEvent, nativeEventData);
739
- if (isDOMComponent(domComponentOrNode)) {
740
- simulateNativeEventOnDOMComponent(
741
- topLevelType,
742
- domComponentOrNode,
743
- fakeNativeEvent,
744
- );
745
- } else if (domComponentOrNode.tagName) {
746
- // Will allow on actual dom nodes.
747
- simulateNativeEventOnNode(
748
- topLevelType,
749
- domComponentOrNode,
750
- fakeNativeEvent,
751
- );
752
- }
753
- };
754
- };
755
-
756
- [
757
- [DOMTopLevelEventTypes.TOP_ABORT, 'abort'],
758
- [DOMTopLevelEventTypes.TOP_ANIMATION_END, 'animationEnd'],
759
- [DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION, 'animationIteration'],
760
- [DOMTopLevelEventTypes.TOP_ANIMATION_START, 'animationStart'],
761
- [DOMTopLevelEventTypes.TOP_BLUR, 'blur'],
762
- [DOMTopLevelEventTypes.TOP_CAN_PLAY_THROUGH, 'canPlayThrough'],
763
- [DOMTopLevelEventTypes.TOP_CAN_PLAY, 'canPlay'],
764
- [DOMTopLevelEventTypes.TOP_CANCEL, 'cancel'],
765
- [DOMTopLevelEventTypes.TOP_CHANGE, 'change'],
766
- [DOMTopLevelEventTypes.TOP_CLICK, 'click'],
767
- [DOMTopLevelEventTypes.TOP_CLOSE, 'close'],
768
- [DOMTopLevelEventTypes.TOP_COMPOSITION_END, 'compositionEnd'],
769
- [DOMTopLevelEventTypes.TOP_COMPOSITION_START, 'compositionStart'],
770
- [DOMTopLevelEventTypes.TOP_COMPOSITION_UPDATE, 'compositionUpdate'],
771
- [DOMTopLevelEventTypes.TOP_CONTEXT_MENU, 'contextMenu'],
772
- [DOMTopLevelEventTypes.TOP_COPY, 'copy'],
773
- [DOMTopLevelEventTypes.TOP_CUT, 'cut'],
774
- [DOMTopLevelEventTypes.TOP_DOUBLE_CLICK, 'doubleClick'],
775
- [DOMTopLevelEventTypes.TOP_DRAG_END, 'dragEnd'],
776
- [DOMTopLevelEventTypes.TOP_DRAG_ENTER, 'dragEnter'],
777
- [DOMTopLevelEventTypes.TOP_DRAG_EXIT, 'dragExit'],
778
- [DOMTopLevelEventTypes.TOP_DRAG_LEAVE, 'dragLeave'],
779
- [DOMTopLevelEventTypes.TOP_DRAG_OVER, 'dragOver'],
780
- [DOMTopLevelEventTypes.TOP_DRAG_START, 'dragStart'],
781
- [DOMTopLevelEventTypes.TOP_DRAG, 'drag'],
782
- [DOMTopLevelEventTypes.TOP_DROP, 'drop'],
783
- [DOMTopLevelEventTypes.TOP_DURATION_CHANGE, 'durationChange'],
784
- [DOMTopLevelEventTypes.TOP_EMPTIED, 'emptied'],
785
- [DOMTopLevelEventTypes.TOP_ENCRYPTED, 'encrypted'],
786
- [DOMTopLevelEventTypes.TOP_ENDED, 'ended'],
787
- [DOMTopLevelEventTypes.TOP_ERROR, 'error'],
788
- [DOMTopLevelEventTypes.TOP_FOCUS, 'focus'],
789
- [DOMTopLevelEventTypes.TOP_INPUT, 'input'],
790
- [DOMTopLevelEventTypes.TOP_KEY_DOWN, 'keyDown'],
791
- [DOMTopLevelEventTypes.TOP_KEY_PRESS, 'keyPress'],
792
- [DOMTopLevelEventTypes.TOP_KEY_UP, 'keyUp'],
793
- [DOMTopLevelEventTypes.TOP_LOAD_START, 'loadStart'],
794
- [DOMTopLevelEventTypes.TOP_LOAD_START, 'loadStart'],
795
- [DOMTopLevelEventTypes.TOP_LOAD, 'load'],
796
- [DOMTopLevelEventTypes.TOP_LOADED_DATA, 'loadedData'],
797
- [DOMTopLevelEventTypes.TOP_LOADED_METADATA, 'loadedMetadata'],
798
- [DOMTopLevelEventTypes.TOP_MOUSE_DOWN, 'mouseDown'],
799
- [DOMTopLevelEventTypes.TOP_MOUSE_MOVE, 'mouseMove'],
800
- [DOMTopLevelEventTypes.TOP_MOUSE_OUT, 'mouseOut'],
801
- [DOMTopLevelEventTypes.TOP_MOUSE_OVER, 'mouseOver'],
802
- [DOMTopLevelEventTypes.TOP_MOUSE_UP, 'mouseUp'],
803
- [DOMTopLevelEventTypes.TOP_PASTE, 'paste'],
804
- [DOMTopLevelEventTypes.TOP_PAUSE, 'pause'],
805
- [DOMTopLevelEventTypes.TOP_PLAY, 'play'],
806
- [DOMTopLevelEventTypes.TOP_PLAYING, 'playing'],
807
- [DOMTopLevelEventTypes.TOP_PROGRESS, 'progress'],
808
- [DOMTopLevelEventTypes.TOP_RATE_CHANGE, 'rateChange'],
809
- [DOMTopLevelEventTypes.TOP_SCROLL, 'scroll'],
810
- [DOMTopLevelEventTypes.TOP_SEEKED, 'seeked'],
811
- [DOMTopLevelEventTypes.TOP_SEEKING, 'seeking'],
812
- [DOMTopLevelEventTypes.TOP_SELECTION_CHANGE, 'selectionChange'],
813
- [DOMTopLevelEventTypes.TOP_STALLED, 'stalled'],
814
- [DOMTopLevelEventTypes.TOP_SUSPEND, 'suspend'],
815
- [DOMTopLevelEventTypes.TOP_TEXT_INPUT, 'textInput'],
816
- [DOMTopLevelEventTypes.TOP_TIME_UPDATE, 'timeUpdate'],
817
- [DOMTopLevelEventTypes.TOP_TOGGLE, 'toggle'],
818
- [DOMTopLevelEventTypes.TOP_TOUCH_CANCEL, 'touchCancel'],
819
- [DOMTopLevelEventTypes.TOP_TOUCH_END, 'touchEnd'],
820
- [DOMTopLevelEventTypes.TOP_TOUCH_MOVE, 'touchMove'],
821
- [DOMTopLevelEventTypes.TOP_TOUCH_START, 'touchStart'],
822
- [DOMTopLevelEventTypes.TOP_TRANSITION_END, 'transitionEnd'],
823
- [DOMTopLevelEventTypes.TOP_VOLUME_CHANGE, 'volumeChange'],
824
- [DOMTopLevelEventTypes.TOP_WAITING, 'waiting'],
825
- [DOMTopLevelEventTypes.TOP_WHEEL, 'wheel'],
826
- ].forEach(([topLevelType, eventType]) => {
827
- /**
828
- * @param {!Element|ReactDOMComponent} domComponentOrNode
829
- * @param {?Event} nativeEventData Fake native event to use in SyntheticEvent.
830
- */
831
- SimulateNative[eventType] = makeNativeSimulator(eventType, topLevelType);
832
- });
833
-}
834
-
665
export {
666
renderIntoDocument,
667
isElement,
packages/react-interactions/events/src/dom/create-event-handle/__tests__/useFocus-test.internal.js
-1
@@ -21,7 +21,6 @@ function initializeModules(hasPointerEvents) {
21
setPointerEvent(hasPointerEvents);
22
jest.resetModules();
23
ReactFeatureFlags = require('shared/ReactFeatureFlags');
24
- ReactFeatureFlags.enableModernEventSystem = true;
24
ReactFeatureFlags.enableCreateEventHandleAPI = true;
25
React = require('react');
26
ReactDOM = require('react-dom');
packages/react-interactions/events/src/dom/create-event-handle/__tests__/useFocusWithin-test.internal.js
-1
@@ -24,7 +24,6 @@ function initializeModules(hasPointerEvents) {
24
jest.resetModules();
25
ReactFeatureFlags = require('shared/ReactFeatureFlags');
26
ReactFeatureFlags.enableScopeAPI = true;
27
- ReactFeatureFlags.enableModernEventSystem = true;
27
ReactFeatureFlags.enableCreateEventHandleAPI = true;
28
React = require('react');
29
ReactDOM = require('react-dom');
packages/react-native-renderer/src/legacy-events/SyntheticEvent.js
+69
-90
@@ -8,7 +8,6 @@
8
/* eslint valid-typeof: 0 */
9
10
import invariant from 'shared/invariant';
11
-import {enableModernEventSystem} from 'shared/ReactFeatureFlags';
11
12
const EVENT_POOL_SIZE = 10;
13
@@ -77,10 +76,8 @@ function SyntheticEvent(
76
this.dispatchConfig = dispatchConfig;
77
this._targetInst = targetInst;
78
this.nativeEvent = nativeEvent;
80
- if (!enableModernEventSystem) {
81
- this._dispatchListeners = null;
82
- this._dispatchInstances = null;
83
- }
79
+ this._dispatchListeners = null;
80
+ this._dispatchInstances = null;
81
82
const Interface = this.constructor.Interface;
83
for (const propName in Interface) {
@@ -157,10 +154,7 @@ Object.assign(SyntheticEvent.prototype, {
154
* won't be added back into the pool.
155
*/
156
persist: function() {
160
- // Modern event system doesn't use pooling.
161
- if (!enableModernEventSystem) {
162
- this.isPersistent = functionThatReturnsTrue;
163
- }
157
+ this.isPersistent = functionThatReturnsTrue;
158
},
159
160
/**
@@ -168,68 +162,63 @@ Object.assign(SyntheticEvent.prototype, {
162
*
163
* @return {boolean} True if this should not be released, false otherwise.
164
*/
171
- isPersistent: enableModernEventSystem
172
- ? functionThatReturnsTrue
173
- : functionThatReturnsFalse,
165
+ isPersistent: functionThatReturnsFalse,
166
167
/**
168
* `PooledClass` looks for `destructor` on each instance it releases.
169
*/
170
destructor: function() {
179
- // Modern event system doesn't use pooling.
180
- if (!enableModernEventSystem) {
181
- const Interface = this.constructor.Interface;
182
- for (const propName in Interface) {
183
- if (__DEV__) {
184
- Object.defineProperty(
185
- this,
186
- propName,
187
- getPooledWarningPropertyDefinition(propName, Interface[propName]),
188
- );
189
- } else {
190
- this[propName] = null;
191
- }
192
- }
193
- this.dispatchConfig = null;
194
- this._targetInst = null;
195
- this.nativeEvent = null;
196
- this.isDefaultPrevented = functionThatReturnsFalse;
197
- this.isPropagationStopped = functionThatReturnsFalse;
198
- this._dispatchListeners = null;
199
- this._dispatchInstances = null;
171
+ const Interface = this.constructor.Interface;
172
+ for (const propName in Interface) {
173
if (__DEV__) {
174
Object.defineProperty(
175
this,
203
- 'nativeEvent',
204
- getPooledWarningPropertyDefinition('nativeEvent', null),
176
+ propName,
177
+ getPooledWarningPropertyDefinition(propName, Interface[propName]),
178
);
206
- Object.defineProperty(
207
- this,
179
+ } else {
180
+ this[propName] = null;
181
+ }
182
+ }
183
+ this.dispatchConfig = null;
184
+ this._targetInst = null;
185
+ this.nativeEvent = null;
186
+ this.isDefaultPrevented = functionThatReturnsFalse;
187
+ this.isPropagationStopped = functionThatReturnsFalse;
188
+ this._dispatchListeners = null;
189
+ this._dispatchInstances = null;
190
+ if (__DEV__) {
191
+ Object.defineProperty(
192
+ this,
193
+ 'nativeEvent',
194
+ getPooledWarningPropertyDefinition('nativeEvent', null),
195
+ );
196
+ Object.defineProperty(
197
+ this,
198
+ 'isDefaultPrevented',
199
+ getPooledWarningPropertyDefinition(
200
'isDefaultPrevented',
209
- getPooledWarningPropertyDefinition(
210
- 'isDefaultPrevented',
211
- functionThatReturnsFalse,
212
- ),
213
- );
214
- Object.defineProperty(
215
- this,
201
+ functionThatReturnsFalse,
202
+ ),
203
+ );
204
+ Object.defineProperty(
205
+ this,
206
+ 'isPropagationStopped',
207
+ getPooledWarningPropertyDefinition(
208
'isPropagationStopped',
217
- getPooledWarningPropertyDefinition(
218
- 'isPropagationStopped',
219
- functionThatReturnsFalse,
220
- ),
221
- );
222
- Object.defineProperty(
223
- this,
224
- 'preventDefault',
225
- getPooledWarningPropertyDefinition('preventDefault', () => {}),
226
- );
227
- Object.defineProperty(
228
- this,
229
- 'stopPropagation',
230
- getPooledWarningPropertyDefinition('stopPropagation', () => {}),
231
- );
232
- }
209
+ functionThatReturnsFalse,
210
+ ),
211
+ );
212
+ Object.defineProperty(
213
+ this,
214
+ 'preventDefault',
215
+ getPooledWarningPropertyDefinition('preventDefault', () => {}),
216
+ );
217
+ Object.defineProperty(
218
+ this,
219
+ 'stopPropagation',
220
+ getPooledWarningPropertyDefinition('stopPropagation', () => {}),
221
+ );
222
}
223
},
224
});
@@ -316,19 +305,16 @@ function createOrGetPooledEvent(
305
nativeInst,
306
) {
307
const EventConstructor = this;
319
- // Modern event system doesn't use pooling.
320
- if (!enableModernEventSystem) {
321
- if (EventConstructor.eventPool.length) {
322
- const instance = EventConstructor.eventPool.pop();
323
- EventConstructor.call(
324
- instance,
325
- dispatchConfig,
326
- targetInst,
327
- nativeEvent,
328
- nativeInst,
329
- );
330
- return instance;
331
- }
308
+ if (EventConstructor.eventPool.length) {
309
+ const instance = EventConstructor.eventPool.pop();
310
+ EventConstructor.call(
311
+ instance,
312
+ dispatchConfig,
313
+ targetInst,
314
+ nativeEvent,
315
+ nativeInst,
316
+ );
317
+ return instance;
318
}
319
return new EventConstructor(
320
dispatchConfig,
@@ -339,28 +325,21 @@ function createOrGetPooledEvent(
325
}
326
327
function releasePooledEvent(event) {
342
- // Modern event system doesn't use pooling.
343
- if (!enableModernEventSystem) {
344
- const EventConstructor = this;
345
- invariant(
346
- event instanceof EventConstructor,
347
- 'Trying to release an event instance into a pool of a different type.',
348
- );
349
- event.destructor();
350
- if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) {
351
- EventConstructor.eventPool.push(event);
352
- }
328
+ const EventConstructor = this;
329
+ invariant(
330
+ event instanceof EventConstructor,
331
+ 'Trying to release an event instance into a pool of a different type.',
332
+ );
333
+ event.destructor();
334
+ if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) {
335
+ EventConstructor.eventPool.push(event);
336
}
337
}
338
339
function addEventPoolingTo(EventConstructor) {
340
EventConstructor.getPooled = createOrGetPooledEvent;
358
-
359
- // Modern event system doesn't use pooling.
360
- if (!enableModernEventSystem) {
361
- EventConstructor.eventPool = [];
362
- EventConstructor.release = releasePooledEvent;
363
- }
341
+ EventConstructor.eventPool = [];
342
+ EventConstructor.release = releasePooledEvent;
343
}
344
345
export default SyntheticEvent;
packages/shared/ReactFeatureFlags.js
-3
@@ -111,9 +111,6 @@ export const disableModulePatternComponents = false;
111
// We should remove this flag once the above flag becomes enabled
112
export const warnUnstableRenderSubtreeIntoContainer = false;
113
114
-// Modern event system where events get registered at roots
115
-export const enableModernEventSystem = false;
116
-
114
// Support legacy Primer support on internal FB www
115
export const enableLegacyFBSupport = false;
116
packages/shared/forks/ReactFeatureFlags.native-fb.js
-1
@@ -39,7 +39,6 @@ export const enableTrustedTypesIntegration = false;
39
export const disableTextareaChildren = false;
40
export const disableModulePatternComponents = false;
41
export const warnUnstableRenderSubtreeIntoContainer = false;
42
-export const enableModernEventSystem = false;
42
export const warnAboutSpreadingKeyToJSX = false;
43
export const enableComponentStackLocations = false;
44
export const enableLegacyFBSupport = false;
packages/shared/forks/ReactFeatureFlags.native-oss.js
-1
@@ -38,7 +38,6 @@ export const enableTrustedTypesIntegration = false;
38
export const disableTextareaChildren = false;
39
export const disableModulePatternComponents = false;
40
export const warnUnstableRenderSubtreeIntoContainer = false;
41
-export const enableModernEventSystem = false;
41
export const warnAboutSpreadingKeyToJSX = false;
42
export const enableComponentStackLocations = false;
43
export const enableLegacyFBSupport = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.js
-1
@@ -38,7 +38,6 @@ export const enableTrustedTypesIntegration = false;
38
export const disableTextareaChildren = false;
39
export const disableModulePatternComponents = false;
40
export const warnUnstableRenderSubtreeIntoContainer = false;
41
-export const enableModernEventSystem = false;
41
export const warnAboutSpreadingKeyToJSX = false;
42
export const enableComponentStackLocations = true;
43
export const enableLegacyFBSupport = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
-1
@@ -38,7 +38,6 @@ export const enableTrustedTypesIntegration = false;
38
export const disableTextareaChildren = false;
39
export const disableModulePatternComponents = true;
40
export const warnUnstableRenderSubtreeIntoContainer = false;
41
-export const enableModernEventSystem = false;
41
export const warnAboutSpreadingKeyToJSX = false;
42
export const enableComponentStackLocations = true;
43
export const enableLegacyFBSupport = false;
packages/shared/forks/ReactFeatureFlags.testing.js
-1
@@ -38,7 +38,6 @@ export const enableTrustedTypesIntegration = false;
38
export const disableTextareaChildren = false;
39
export const disableModulePatternComponents = false;
40
export const warnUnstableRenderSubtreeIntoContainer = false;
41
-export const enableModernEventSystem = false;
41
export const warnAboutSpreadingKeyToJSX = false;
42
export const enableComponentStackLocations = true;
43
export const enableLegacyFBSupport = false;
packages/shared/forks/ReactFeatureFlags.testing.www.js
-1
@@ -38,7 +38,6 @@ export const enableTrustedTypesIntegration = false;
38
export const disableTextareaChildren = __EXPERIMENTAL__;
39
export const disableModulePatternComponents = true;
40
export const warnUnstableRenderSubtreeIntoContainer = false;
41
-export const enableModernEventSystem = false;
41
export const warnAboutSpreadingKeyToJSX = false;
42
export const enableComponentStackLocations = true;
43
export const enableLegacyFBSupport = !__EXPERIMENTAL__;
packages/shared/forks/ReactFeatureFlags.www.js
-2
@@ -71,8 +71,6 @@ export const disableTextareaChildren = __EXPERIMENTAL__;
71
72
export const warnUnstableRenderSubtreeIntoContainer = false;
73
74
-export const enableModernEventSystem = true;
75
-
74
// Enable forked reconciler. Piggy-backing on the "variant" global so that we
75
// don't have to add another test dimension. The build system will compile this
76
// to the correct value.