@samitouri / QOS-React-2 / commits / 9fba65efa5

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.