Fork legacy-events folder into react-dom and react-native (#19228)
Dan Abramov committed
Jul 1, 2020 at 16:37 UTC
e3f4eb7272d4ca0ee49f27577156b57eeb07cf73
76 files changed
+2422
-107
packages/legacy-events/package.json
deleted
-5
@@ -1,5 +0,0 @@
1
-{
2
- "private": true,
3
- "name": "legacy-events",
4
- "version": "0.0.0"
5
-}
packages/react-dom/src/client/ReactDOM.js
+1
-1
@@ -42,7 +42,7 @@ import {canUseDOM} from 'shared/ExecutionEnvironment';
42
import {
43
eventNameDispatchConfigs,
44
injectEventPluginsByName,
45
-} from 'legacy-events/EventPluginRegistry';
45
+} from '../legacy-events/EventPluginRegistry';
46
import ReactVersion from 'shared/ReactVersion';
47
import invariant from 'shared/invariant';
48
import {
packages/react-dom/src/client/ReactDOMClientInjection.js
+2
-2
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import {setComponentTree} from 'legacy-events/EventPluginUtils';
8
+import {setComponentTree} from '../legacy-events/EventPluginUtils';
9
10
import {
11
getFiberCurrentPropsFromNode,
@@ -29,7 +29,7 @@ import {
29
injectEventPluginOrder,
30
injectEventPluginsByName,
31
injectEventPlugins,
32
-} from 'legacy-events/EventPluginRegistry';
32
+} from '../legacy-events/EventPluginRegistry';
33
import {enableModernEventSystem} from 'shared/ReactFeatureFlags';
34
35
if (enableModernEventSystem) {
packages/react-dom/src/client/ReactDOMComponent.js
+1
-1
@@ -7,7 +7,7 @@
7
* @flow
8
*/
9
10
-import {registrationNameModules} from 'legacy-events/EventPluginRegistry';
10
+import {registrationNameModules} from '../legacy-events/EventPluginRegistry';
11
import {canUseDOM} from 'shared/ExecutionEnvironment';
12
import invariant from 'shared/invariant';
13
import {
packages/react-dom/src/client/ReactDOMComponentTree.js
+1
-1
@@ -17,7 +17,7 @@ import type {
17
SuspenseInstance,
18
Props,
19
} from './ReactDOMHostConfig';
20
-import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
20
+import type {DOMTopLevelEventType} from '../legacy-events/TopLevelEventTypes';
21
22
import {
23
HostComponent,
packages/react-dom/src/client/ReactDOMEventHandle.js
+1
-1
@@ -7,7 +7,7 @@
7
* @flow
8
*/
9
10
-import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
10
+import type {DOMTopLevelEventType} from '../legacy-events/TopLevelEventTypes';
11
import type {EventPriority, ReactScopeInstance} from 'shared/ReactTypes';
12
import type {
13
ReactDOMEventHandle,
packages/react-dom/src/client/ReactDOMHostConfig.js
+1
-1
@@ -7,7 +7,7 @@
7
* @flow
8
*/
9
10
-import type {TopLevelType} from 'legacy-events/TopLevelEventTypes';
10
+import type {TopLevelType} from '../legacy-events/TopLevelEventTypes';
11
import type {Fiber, FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
12
import type {
13
BoundingRect,
packages/react-dom/src/events/DOMEventProperties.js
+2
-2
@@ -11,11 +11,11 @@ import type {EventPriority} from 'shared/ReactTypes';
11
import type {
12
TopLevelType,
13
DOMTopLevelEventType,
14
-} from 'legacy-events/TopLevelEventTypes';
14
+} from '../legacy-events/TopLevelEventTypes';
15
import type {
16
DispatchConfig,
17
CustomDispatchConfig,
18
-} from 'legacy-events/ReactSyntheticEventType';
18
+} from '../legacy-events/ReactSyntheticEventType';
19
20
import * as DOMTopLevelEventTypes from './DOMTopLevelEventTypes';
21
import {
packages/react-dom/src/events/DOMLegacyEventPluginSystem.js
+10
-10
@@ -7,15 +7,15 @@
7
* @flow
8
*/
9
10
-import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
11
-import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
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';
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,
@@ -23,10 +23,10 @@ import {
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';
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 {
packages/react-dom/src/events/DOMModernPluginEventSystem.js
+6
-6
@@ -7,8 +7,8 @@
7
* @flow
8
*/
9
10
-import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
11
-import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
10
+import type {AnyNativeEvent} from '../legacy-events/PluginModuleType';
11
+import type {DOMTopLevelEventType} from '../legacy-events/TopLevelEventTypes';
12
import type {
13
ElementListenerMap,
14
ElementListenerMapEntry,
@@ -22,14 +22,14 @@ import type {
22
DispatchQueueItem,
23
DispatchQueueItemPhase,
24
DispatchQueueItemPhaseEntry,
25
-} from 'legacy-events/PluginModuleType';
25
+} from '../legacy-events/PluginModuleType';
26
import type {
27
ReactSyntheticEvent,
28
CustomDispatchConfig,
29
-} from 'legacy-events/ReactSyntheticEventType';
29
+} from '../legacy-events/ReactSyntheticEventType';
30
31
-import {registrationNameDependencies} from 'legacy-events/EventPluginRegistry';
32
-import {plugins} from 'legacy-events/EventPluginRegistry';
31
+import {registrationNameDependencies} from '../legacy-events/EventPluginRegistry';
32
+import {plugins} from '../legacy-events/EventPluginRegistry';
33
import {
34
PLUGIN_EVENT_SYSTEM,
35
LEGACY_FB_SUPPORT,
packages/react-dom/src/events/DOMTopLevelEventTypes.js
+2
-2
@@ -7,12 +7,12 @@
7
* @flow
8
*/
9
10
-import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
10
+import type {DOMTopLevelEventType} from '../legacy-events/TopLevelEventTypes';
11
12
import {
13
unsafeCastStringToDOMTopLevelType,
14
unsafeCastDOMTopLevelTypeToString,
15
-} from 'legacy-events/TopLevelEventTypes';
15
+} from '../legacy-events/TopLevelEventTypes';
16
import getVendorPrefixedEventName from './getVendorPrefixedEventName';
17
18
/**
packages/react-dom/src/events/DeprecatedDOMEventResponderSystem.js
+2
-2
@@ -12,7 +12,7 @@ import {
12
PASSIVE_NOT_SUPPORTED,
13
RESPONDER_EVENT_SYSTEM,
14
} from './EventSystemFlags';
15
-import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
15
+import type {AnyNativeEvent} from '../legacy-events/PluginModuleType';
16
import {
17
HostComponent,
18
ScopeComponent,
@@ -25,7 +25,7 @@ import type {
25
ReactDOMResponderContext,
26
ReactDOMResponderEvent,
27
} from '../shared/ReactDOMTypes';
28
-import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
28
+import type {DOMTopLevelEventType} from '../legacy-events/TopLevelEventTypes';
29
import {
30
batchedEventUpdates,
31
discreteUpdates,
packages/react-dom/src/events/ReactDOMEventListener.js
+2
-2
@@ -7,11 +7,11 @@
7
* @flow
8
*/
9
10
-import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
10
+import type {AnyNativeEvent} from '../legacy-events/PluginModuleType';
11
import type {EventPriority} from 'shared/ReactTypes';
12
import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
13
import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
14
-import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
14
+import type {DOMTopLevelEventType} from '../legacy-events/TopLevelEventTypes';
15
16
// Intentionally not named imports because Rollup would use dynamic dispatch for
17
// CommonJS interop named imports.
packages/react-dom/src/events/ReactDOMEventReplaying.js
+3
-3
@@ -7,9 +7,9 @@
7
* @flow
8
*/
9
10
-import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
10
+import type {AnyNativeEvent} from '../legacy-events/PluginModuleType';
11
import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
12
-import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
12
+import type {DOMTopLevelEventType} from '../legacy-events/TopLevelEventTypes';
13
import type {ElementListenerMap} from '../client/ReactDOMComponentTree';
14
import type {EventSystemFlags} from './EventSystemFlags';
15
import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
@@ -36,7 +36,7 @@ import {
36
getClosestInstanceFromNode,
37
getEventListenerMap,
38
} from '../client/ReactDOMComponentTree';
39
-import {unsafeCastDOMTopLevelTypeToString} from 'legacy-events/TopLevelEventTypes';
39
+import {unsafeCastDOMTopLevelTypeToString} from '../legacy-events/TopLevelEventTypes';
40
import {HostRoot, SuspenseComponent} from 'react-reconciler/src/ReactWorkTags';
41
42
let attemptSynchronousHydration: (fiber: Object) => void;
packages/react-dom/src/events/SyntheticAnimationEvent.js
+1
-1
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import SyntheticEvent from 'legacy-events/SyntheticEvent';
8
+import SyntheticEvent from '../legacy-events/SyntheticEvent';
9
10
/**
11
* @interface Event
packages/react-dom/src/events/SyntheticClipboardEvent.js
+1
-1
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import SyntheticEvent from 'legacy-events/SyntheticEvent';
8
+import SyntheticEvent from '../legacy-events/SyntheticEvent';
9
10
/**
11
* @interface Event
packages/react-dom/src/events/SyntheticCompositionEvent.js
+1
-1
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import SyntheticEvent from 'legacy-events/SyntheticEvent';
8
+import SyntheticEvent from '../legacy-events/SyntheticEvent';
9
10
/**
11
* @interface Event
packages/react-dom/src/events/SyntheticInputEvent.js
+1
-1
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import SyntheticEvent from 'legacy-events/SyntheticEvent';
8
+import SyntheticEvent from '../legacy-events/SyntheticEvent';
9
10
/**
11
* @interface Event
packages/react-dom/src/events/SyntheticTransitionEvent.js
+1
-1
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import SyntheticEvent from 'legacy-events/SyntheticEvent';
8
+import SyntheticEvent from '../legacy-events/SyntheticEvent';
9
10
/**
11
* @interface Event
packages/react-dom/src/events/SyntheticUIEvent.js
+1
-1
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import SyntheticEvent from 'legacy-events/SyntheticEvent';
8
+import SyntheticEvent from '../legacy-events/SyntheticEvent';
9
10
const SyntheticUIEvent = SyntheticEvent.extend({
11
view: null,
packages/react-dom/src/events/getEventModifierState.js
+1
-1
@@ -12,7 +12,7 @@
12
* @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers
13
*/
14
15
-import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
15
+import type {AnyNativeEvent} from '../legacy-events/PluginModuleType';
16
17
const modifierKeyToProp = {
18
Alt: 'altKey',
packages/react-dom/src/events/plugins/LegacyBeforeInputEventPlugin.js
+1
-1
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import type {TopLevelType} from 'legacy-events/TopLevelEventTypes';
8
+import type {TopLevelType} from '../../legacy-events/TopLevelEventTypes';
9
10
import {canUseDOM} from 'shared/ExecutionEnvironment';
11
packages/react-dom/src/events/plugins/LegacyChangeEventPlugin.js
+2
-2
@@ -5,8 +5,8 @@
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';
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
packages/react-dom/src/events/plugins/LegacySelectEventPlugin.js
+2
-2
@@ -6,7 +6,7 @@
6
*/
7
8
import {canUseDOM} from 'shared/ExecutionEnvironment';
9
-import SyntheticEvent from 'legacy-events/SyntheticEvent';
9
+import SyntheticEvent from '../../legacy-events/SyntheticEvent';
10
import isTextInputElement from '../isTextInputElement';
11
import shallowEqual from 'shared/shallowEqual';
12
@@ -30,7 +30,7 @@ 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';
33
+import {registrationNameDependencies} from '../../legacy-events/EventPluginRegistry';
34
35
const skipSelectionChangeEvent =
36
canUseDOM && 'documentMode' in document && document.documentMode <= 11;
packages/react-dom/src/events/plugins/LegacySimpleEventPlugin.js
+4
-4
@@ -10,12 +10,12 @@
10
import type {
11
TopLevelType,
12
DOMTopLevelEventType,
13
-} from 'legacy-events/TopLevelEventTypes';
14
-import type {ReactSyntheticEvent} from 'legacy-events/ReactSyntheticEventType';
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';
16
+import type {LegacyPluginModule} from '../../legacy-events/PluginModuleType';
17
18
-import SyntheticEvent from 'legacy-events/SyntheticEvent';
18
+import SyntheticEvent from '../../legacy-events/SyntheticEvent';
19
20
import * as DOMTopLevelEventTypes from '../DOMTopLevelEventTypes';
21
import {
packages/react-dom/src/events/plugins/ModernBeforeInputEventPlugin.js
+1
-1
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import type {TopLevelType} from 'legacy-events/TopLevelEventTypes';
8
+import type {TopLevelType} from '../../legacy-events/TopLevelEventTypes';
9
10
import {canUseDOM} from 'shared/ExecutionEnvironment';
11
packages/react-dom/src/events/plugins/ModernChangeEventPlugin.js
+1
-1
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import SyntheticEvent from 'legacy-events/SyntheticEvent';
8
+import SyntheticEvent from '../../legacy-events/SyntheticEvent';
9
import isTextInputElement from '../isTextInputElement';
10
import {canUseDOM} from 'shared/ExecutionEnvironment';
11
packages/react-dom/src/events/plugins/ModernSelectEventPlugin.js
+1
-1
@@ -6,7 +6,7 @@
6
*/
7
8
import {canUseDOM} from 'shared/ExecutionEnvironment';
9
-import SyntheticEvent from 'legacy-events/SyntheticEvent';
9
+import SyntheticEvent from '../../legacy-events/SyntheticEvent';
10
import isTextInputElement from '../isTextInputElement';
11
import shallowEqual from 'shared/shallowEqual';
12
packages/react-dom/src/events/plugins/ModernSimpleEventPlugin.js
+3
-3
@@ -10,15 +10,15 @@
10
import type {
11
TopLevelType,
12
DOMTopLevelEventType,
13
-} from 'legacy-events/TopLevelEventTypes';
13
+} from '../../legacy-events/TopLevelEventTypes';
14
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
15
import type {
16
ModernPluginModule,
17
DispatchQueue,
18
-} from 'legacy-events/PluginModuleType';
18
+} from '../../legacy-events/PluginModuleType';
19
import type {EventSystemFlags} from '../EventSystemFlags';
20
21
-import SyntheticEvent from 'legacy-events/SyntheticEvent';
21
+import SyntheticEvent from '../../legacy-events/SyntheticEvent';
22
23
import * as DOMTopLevelEventTypes from '../DOMTopLevelEventTypes';
24
import {
packages/react-dom/src/legacy-events/EventBatching.js
renamed
packages/react-dom/src/legacy-events/EventPluginRegistry.js
renamed
packages/react-dom/src/legacy-events/EventPluginUtils.js
renamed
packages/react-dom/src/legacy-events/PluginModuleType.js
renamed
packages/react-dom/src/legacy-events/ReactGenericBatching.js
renamed
packages/react-dom/src/legacy-events/ReactSyntheticEventType.js
renamed
packages/react-dom/src/legacy-events/ResponderEventPlugin.js
renamed
packages/react-dom/src/legacy-events/ResponderSyntheticEvent.js
renamed
packages/react-dom/src/legacy-events/ResponderTopLevelEventTypes.js
renamed
packages/react-dom/src/legacy-events/ResponderTouchHistoryStore.js
renamed
packages/react-dom/src/legacy-events/SyntheticEvent.js
renamed
packages/react-dom/src/legacy-events/TopLevelEventTypes.js
renamed
packages/react-dom/src/legacy-events/accumulate.js
renamed
packages/react-dom/src/legacy-events/accumulateInto.js
renamed
packages/react-dom/src/legacy-events/forEachAccumulated.js
renamed
packages/react-dom/src/shared/ReactDOMTypes.js
+1
-1
@@ -14,7 +14,7 @@ import type {
14
EventPriority,
15
ReactScopeInstance,
16
} from 'shared/ReactTypes';
17
-import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
17
+import type {DOMTopLevelEventType} from '../legacy-events/TopLevelEventTypes';
18
19
type AnyNativeEvent = Event | KeyboardEvent | MouseEvent | Touch;
20
packages/react-dom/src/shared/ReactDOMUnknownPropertyHook.js
+1
-1
@@ -8,7 +8,7 @@
8
import {
9
registrationNameModules,
10
possibleRegistrationNames,
11
-} from 'legacy-events/EventPluginRegistry';
11
+} from '../legacy-events/EventPluginRegistry';
12
13
import {
14
ATTRIBUTE_NAME_CHAR,
packages/react-dom/src/test-utils/ReactTestUtils.js
+3
-3
@@ -15,13 +15,13 @@ import {
15
HostComponent,
16
HostText,
17
} from 'react-reconciler/src/ReactWorkTags';
18
-import SyntheticEvent from 'legacy-events/SyntheticEvent';
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';
22
import act from './ReactTestUtilsAct';
23
-import forEachAccumulated from 'legacy-events/forEachAccumulated';
24
-import accumulateInto from 'legacy-events/accumulateInto';
23
+import forEachAccumulated from '../legacy-events/forEachAccumulated';
24
+import accumulateInto from '../legacy-events/accumulateInto';
25
import {enableModernEventSystem} from 'shared/ReactFeatureFlags';
26
import {
27
rethrowCaughtError,
packages/react-native-renderer/src/ReactFabric.js
+1
-1
@@ -27,7 +27,7 @@ import {
27
} from 'react-reconciler/src/ReactFiberReconciler';
28
29
import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal';
30
-import {setBatchingImplementation} from 'legacy-events/ReactGenericBatching';
30
+import {setBatchingImplementation} from './legacy-events/ReactGenericBatching';
31
import ReactVersion from 'shared/ReactVersion';
32
33
// Module provided by RN:
packages/react-native-renderer/src/ReactFabricEventEmitter.js
+9
-9
@@ -7,19 +7,19 @@
7
* @flow
8
*/
9
10
-import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
10
+import type {AnyNativeEvent} from './legacy-events/PluginModuleType';
11
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
12
-import type {LegacyPluginModule} from 'legacy-events/PluginModuleType';
13
-import type {ReactSyntheticEvent} from 'legacy-events/ReactSyntheticEventType';
14
-import type {TopLevelType} from 'legacy-events/TopLevelEventTypes';
12
+import type {LegacyPluginModule} from './legacy-events/PluginModuleType';
13
+import type {ReactSyntheticEvent} from './legacy-events/ReactSyntheticEventType';
14
+import type {TopLevelType} from './legacy-events/TopLevelEventTypes';
15
16
-import {registrationNameModules} from 'legacy-events/EventPluginRegistry';
17
-import {batchedUpdates} from 'legacy-events/ReactGenericBatching';
18
-import accumulateInto from 'legacy-events/accumulateInto';
16
+import {registrationNameModules} from './legacy-events/EventPluginRegistry';
17
+import {batchedUpdates} from './legacy-events/ReactGenericBatching';
18
+import accumulateInto from './legacy-events/accumulateInto';
19
20
-import {plugins} from 'legacy-events/EventPluginRegistry';
20
+import {plugins} from './legacy-events/EventPluginRegistry';
21
import getListener from './ReactNativeGetListener';
22
-import {runEventsInBatch} from 'legacy-events/EventBatching';
22
+import {runEventsInBatch} from './legacy-events/EventBatching';
23
24
export {getListener, registrationNameModules as registrationNames};
25
packages/react-native-renderer/src/ReactFabricInjection.js
+2
-2
@@ -14,9 +14,9 @@ import {
14
getInstanceFromNode,
15
getNodeFromInstance,
16
} from './ReactFabricComponentTree';
17
-import {setComponentTree} from 'legacy-events/EventPluginUtils';
17
+import {setComponentTree} from './legacy-events/EventPluginUtils';
18
import ReactFabricGlobalResponderHandler from './ReactFabricGlobalResponderHandler';
19
-import ResponderEventPlugin from 'legacy-events/ResponderEventPlugin';
19
+import ResponderEventPlugin from './legacy-events/ResponderEventPlugin';
20
21
setComponentTree(
22
getFiberCurrentPropsFromNode,
packages/react-native-renderer/src/ReactNativeBridgeEventPlugin.js
+5
-5
@@ -7,16 +7,16 @@
7
* @flow
8
*/
9
10
-import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
11
-import type {TopLevelType} from 'legacy-events/TopLevelEventTypes';
12
-import SyntheticEvent from 'legacy-events/SyntheticEvent';
10
+import type {AnyNativeEvent} from './legacy-events/PluginModuleType';
11
+import type {TopLevelType} from './legacy-events/TopLevelEventTypes';
12
+import SyntheticEvent from './legacy-events/SyntheticEvent';
13
import invariant from 'shared/invariant';
14
15
// Module provided by RN:
16
import {ReactNativeViewConfigRegistry} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
17
-import accumulateInto from 'legacy-events/accumulateInto';
17
+import accumulateInto from './legacy-events/accumulateInto';
18
import getListener from './ReactNativeGetListener';
19
-import forEachAccumulated from 'legacy-events/forEachAccumulated';
19
+import forEachAccumulated from './legacy-events/forEachAccumulated';
20
import {HostComponent} from 'react-reconciler/src/ReactWorkTags';
21
22
const {
packages/react-native-renderer/src/ReactNativeEventEmitter.js
+10
-10
@@ -7,18 +7,18 @@
7
* @flow
8
*/
9
10
-import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
10
+import type {AnyNativeEvent} from './legacy-events/PluginModuleType';
11
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
12
-import type {LegacyPluginModule} from 'legacy-events/PluginModuleType';
13
-import type {ReactSyntheticEvent} from 'legacy-events/ReactSyntheticEventType';
14
-import type {TopLevelType} from 'legacy-events/TopLevelEventTypes';
15
-
16
-import {registrationNameModules} from 'legacy-events/EventPluginRegistry';
17
-import {batchedUpdates} from 'legacy-events/ReactGenericBatching';
18
-import {runEventsInBatch} from 'legacy-events/EventBatching';
19
-import {plugins} from 'legacy-events/EventPluginRegistry';
12
+import type {LegacyPluginModule} from './legacy-events/PluginModuleType';
13
+import type {ReactSyntheticEvent} from './legacy-events/ReactSyntheticEventType';
14
+import type {TopLevelType} from './legacy-events/TopLevelEventTypes';
15
+
16
+import {registrationNameModules} from './legacy-events/EventPluginRegistry';
17
+import {batchedUpdates} from './legacy-events/ReactGenericBatching';
18
+import {runEventsInBatch} from './legacy-events/EventBatching';
19
+import {plugins} from './legacy-events/EventPluginRegistry';
20
import getListener from './ReactNativeGetListener';
21
-import accumulateInto from 'legacy-events/accumulateInto';
21
+import accumulateInto from './legacy-events/accumulateInto';
22
23
import {getInstanceFromNode} from './ReactNativeComponentTree';
24
packages/react-native-renderer/src/ReactNativeGetListener.js
+1
-1
@@ -9,7 +9,7 @@
9
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
10
11
import invariant from 'shared/invariant';
12
-import {getFiberCurrentPropsFromNode} from 'legacy-events/EventPluginUtils';
12
+import {getFiberCurrentPropsFromNode} from './legacy-events/EventPluginUtils';
13
14
export default function getListener(
15
inst: Fiber,
packages/react-native-renderer/src/ReactNativeInjection.js
+2
-2
@@ -14,10 +14,10 @@ import {
14
getInstanceFromNode,
15
getNodeFromInstance,
16
} from './ReactNativeComponentTree';
17
-import {setComponentTree} from 'legacy-events/EventPluginUtils';
17
+import {setComponentTree} from './legacy-events/EventPluginUtils';
18
import {receiveEvent, receiveTouches} from './ReactNativeEventEmitter';
19
import ReactNativeGlobalResponderHandler from './ReactNativeGlobalResponderHandler';
20
-import ResponderEventPlugin from 'legacy-events/ResponderEventPlugin';
20
+import ResponderEventPlugin from './legacy-events/ResponderEventPlugin';
21
22
// Module provided by RN:
23
import {RCTEventEmitter} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
packages/react-native-renderer/src/ReactNativeInjectionShared.js
+2
-2
@@ -16,11 +16,11 @@
16
// Module provided by RN:
17
import 'react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore';
18
19
-import ResponderEventPlugin from 'legacy-events/ResponderEventPlugin';
19
+import ResponderEventPlugin from './legacy-events/ResponderEventPlugin';
20
import {
21
injectEventPluginOrder,
22
injectEventPluginsByName,
23
-} from 'legacy-events/EventPluginRegistry';
23
+} from './legacy-events/EventPluginRegistry';
24
25
import ReactNativeBridgeEventPlugin from './ReactNativeBridgeEventPlugin';
26
import ReactNativeEventPluginOrder from './ReactNativeEventPluginOrder';
packages/react-native-renderer/src/ReactNativeRenderer.js
+1
-1
@@ -30,7 +30,7 @@ import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal
30
import {
31
setBatchingImplementation,
32
batchedUpdates,
33
-} from 'legacy-events/ReactGenericBatching';
33
+} from './legacy-events/ReactGenericBatching';
34
import ReactVersion from 'shared/ReactVersion';
35
// Module provided by RN:
36
import {UIManager} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
packages/react-native-renderer/src/__tests__/EventPluginRegistry-test.internal.js
+1
-1
@@ -19,7 +19,7 @@ describe('EventPluginRegistry', () => {
19
// The public API surface of this is covered by other tests so
20
// if `EventPluginRegistry` is ever deleted, these tests should be
21
// safe to remove too.
22
- EventPluginRegistry = require('legacy-events/EventPluginRegistry');
22
+ EventPluginRegistry = require('react-native-renderer/src/legacy-events/EventPluginRegistry');
23
24
createPlugin = function(properties) {
25
return Object.assign({extractEvents: function() {}}, properties);
packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js
+2
-1
@@ -68,7 +68,8 @@ beforeEach(() => {
68
.RCTEventEmitter;
69
React = require('react');
70
ReactNative = require('react-native-renderer');
71
- ResponderEventPlugin = require('legacy-events/ResponderEventPlugin').default;
71
+ ResponderEventPlugin = require('react-native-renderer/src/legacy-events/ResponderEventPlugin')
72
+ .default;
73
UIManager = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface')
74
.UIManager;
75
createReactNativeComponentClass = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface')
packages/react-native-renderer/src/__tests__/ResponderEventPlugin-test.internal.js
+5
-4
@@ -407,9 +407,9 @@ describe('ResponderEventPlugin', () => {
407
beforeEach(() => {
408
jest.resetModules();
409
410
- EventBatching = require('legacy-events/EventBatching');
411
- EventPluginUtils = require('legacy-events/EventPluginUtils');
412
- ResponderEventPlugin = require('legacy-events/ResponderEventPlugin')
410
+ EventBatching = require('react-native-renderer/src/legacy-events/EventBatching');
411
+ EventPluginUtils = require('react-native-renderer/src/legacy-events/EventPluginUtils');
412
+ ResponderEventPlugin = require('react-native-renderer/src/legacy-events/ResponderEventPlugin')
413
.default;
414
415
deleteAllListeners(GRANDPARENT_INST);
@@ -1380,8 +1380,9 @@ describe('ResponderEventPlugin', () => {
1380
// ResponderEventPlugin uses `getLowestCommonAncestor`
1381
const React = require('react');
1382
const ReactTestUtils = require('react-dom/test-utils');
1383
- const getLowestCommonAncestor = require('legacy-events/ResponderEventPlugin')
1383
+ const getLowestCommonAncestor = require('react-native-renderer/src/legacy-events/ResponderEventPlugin')
1384
.getLowestCommonAncestor;
1385
+ // This works by accident and will likely break in the future.
1386
const ReactDOMComponentTree = require('react-dom/src/client/ReactDOMComponentTree');
1387
1388
class ChildComponent extends React.Component {
packages/react-native-renderer/src/legacy-events/EventBatching.js
new
+66
@@ -0,0 +1,66 @@
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-native-renderer/src/legacy-events/EventPluginRegistry.js
new
+270
@@ -0,0 +1,270 @@
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 {DispatchConfig} from './ReactSyntheticEventType';
11
+import type {
12
+ AnyNativeEvent,
13
+ PluginName,
14
+ LegacyPluginModule,
15
+ ModernPluginModule,
16
+} from './PluginModuleType';
17
+
18
+import invariant from 'shared/invariant';
19
+
20
+type NamesToPlugins = {
21
+ [key: PluginName]:
22
+ | LegacyPluginModule<AnyNativeEvent>
23
+ | ModernPluginModule<AnyNativeEvent>,
24
+ ...,
25
+};
26
+type EventPluginOrder = null | Array<PluginName>;
27
+
28
+/**
29
+ * Injectable ordering of event plugins.
30
+ */
31
+let eventPluginOrder: EventPluginOrder = null;
32
+
33
+/**
34
+ * Injectable mapping from names to event plugin modules.
35
+ */
36
+const namesToPlugins: NamesToPlugins = {};
37
+
38
+/**
39
+ * Recomputes the plugin list using the injected plugins and plugin ordering.
40
+ *
41
+ * @private
42
+ */
43
+function recomputePluginOrdering(): void {
44
+ if (!eventPluginOrder) {
45
+ // Wait until an `eventPluginOrder` is injected.
46
+ return;
47
+ }
48
+ for (const pluginName in namesToPlugins) {
49
+ const pluginModule = namesToPlugins[pluginName];
50
+ const pluginIndex = eventPluginOrder.indexOf(pluginName);
51
+ invariant(
52
+ pluginIndex > -1,
53
+ 'EventPluginRegistry: Cannot inject event plugins that do not exist in ' +
54
+ 'the plugin ordering, `%s`.',
55
+ pluginName,
56
+ );
57
+ if (plugins[pluginIndex]) {
58
+ continue;
59
+ }
60
+ invariant(
61
+ pluginModule.extractEvents,
62
+ 'EventPluginRegistry: Event plugins must implement an `extractEvents` ' +
63
+ 'method, but `%s` does not.',
64
+ pluginName,
65
+ );
66
+ plugins[pluginIndex] = pluginModule;
67
+ const publishedEvents = pluginModule.eventTypes;
68
+ for (const eventName in publishedEvents) {
69
+ invariant(
70
+ publishEventForPlugin(
71
+ publishedEvents[eventName],
72
+ pluginModule,
73
+ eventName,
74
+ ),
75
+ 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.',
76
+ eventName,
77
+ pluginName,
78
+ );
79
+ }
80
+ }
81
+}
82
+
83
+/**
84
+ * Publishes an event so that it can be dispatched by the supplied plugin.
85
+ *
86
+ * @param {object} dispatchConfig Dispatch configuration for the event.
87
+ * @param {object} PluginModule Plugin publishing the event.
88
+ * @return {boolean} True if the event was successfully published.
89
+ * @private
90
+ */
91
+function publishEventForPlugin(
92
+ dispatchConfig: DispatchConfig,
93
+ pluginModule:
94
+ | LegacyPluginModule<AnyNativeEvent>
95
+ | ModernPluginModule<AnyNativeEvent>,
96
+ eventName: string,
97
+): boolean {
98
+ invariant(
99
+ !eventNameDispatchConfigs.hasOwnProperty(eventName),
100
+ 'EventPluginRegistry: More than one plugin attempted to publish the same ' +
101
+ 'event name, `%s`.',
102
+ eventName,
103
+ );
104
+ eventNameDispatchConfigs[eventName] = dispatchConfig;
105
+
106
+ const phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
107
+ if (phasedRegistrationNames) {
108
+ for (const phaseName in phasedRegistrationNames) {
109
+ if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
110
+ const phasedRegistrationName = phasedRegistrationNames[phaseName];
111
+ publishRegistrationName(
112
+ phasedRegistrationName,
113
+ pluginModule,
114
+ eventName,
115
+ );
116
+ }
117
+ }
118
+ return true;
119
+ } else if (dispatchConfig.registrationName) {
120
+ publishRegistrationName(
121
+ dispatchConfig.registrationName,
122
+ pluginModule,
123
+ eventName,
124
+ );
125
+ return true;
126
+ }
127
+ return false;
128
+}
129
+
130
+/**
131
+ * Publishes a registration name that is used to identify dispatched events.
132
+ *
133
+ * @param {string} registrationName Registration name to add.
134
+ * @param {object} PluginModule Plugin publishing the event.
135
+ * @private
136
+ */
137
+function publishRegistrationName(
138
+ registrationName: string,
139
+ pluginModule:
140
+ | LegacyPluginModule<AnyNativeEvent>
141
+ | ModernPluginModule<AnyNativeEvent>,
142
+ eventName: string,
143
+): void {
144
+ invariant(
145
+ !registrationNameModules[registrationName],
146
+ 'EventPluginRegistry: More than one plugin attempted to publish the same ' +
147
+ 'registration name, `%s`.',
148
+ registrationName,
149
+ );
150
+ registrationNameModules[registrationName] = pluginModule;
151
+ registrationNameDependencies[registrationName] =
152
+ pluginModule.eventTypes[eventName].dependencies;
153
+
154
+ if (__DEV__) {
155
+ const lowerCasedName = registrationName.toLowerCase();
156
+ possibleRegistrationNames[lowerCasedName] = registrationName;
157
+
158
+ if (registrationName === 'onDoubleClick') {
159
+ possibleRegistrationNames.ondblclick = registrationName;
160
+ }
161
+ }
162
+}
163
+
164
+/**
165
+ * Registers plugins so that they can extract and dispatch events.
166
+ */
167
+
168
+/**
169
+ * Ordered list of injected plugins.
170
+ */
171
+export const plugins = [];
172
+
173
+/**
174
+ * Mapping from event name to dispatch config
175
+ */
176
+export const eventNameDispatchConfigs = {};
177
+
178
+/**
179
+ * Mapping from registration name to plugin module
180
+ */
181
+export const registrationNameModules = {};
182
+
183
+/**
184
+ * Mapping from registration name to event name
185
+ */
186
+export const registrationNameDependencies = {};
187
+
188
+/**
189
+ * Mapping from lowercase registration names to the properly cased version,
190
+ * used to warn in the case of missing event handlers. Available
191
+ * only in __DEV__.
192
+ * @type {Object}
193
+ */
194
+export const possibleRegistrationNames = __DEV__ ? {} : (null: any);
195
+// Trust the developer to only use possibleRegistrationNames in __DEV__
196
+
197
+/**
198
+ * Injects an ordering of plugins (by plugin name). This allows the ordering
199
+ * to be decoupled from injection of the actual plugins so that ordering is
200
+ * always deterministic regardless of packaging, on-the-fly injection, etc.
201
+ *
202
+ * @param {array} InjectedEventPluginOrder
203
+ * @internal
204
+ */
205
+export function injectEventPluginOrder(
206
+ injectedEventPluginOrder: EventPluginOrder,
207
+): void {
208
+ invariant(
209
+ !eventPluginOrder,
210
+ 'EventPluginRegistry: Cannot inject event plugin ordering more than ' +
211
+ 'once. You are likely trying to load more than one copy of React.',
212
+ );
213
+ // Clone the ordering so it cannot be dynamically mutated.
214
+ eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder);
215
+ recomputePluginOrdering();
216
+}
217
+
218
+/**
219
+ * Injects plugins to be used by plugin event system. The plugin names must be
220
+ * in the ordering injected by `injectEventPluginOrder`.
221
+ *
222
+ * Plugins can be injected as part of page initialization or on-the-fly.
223
+ *
224
+ * @param {object} injectedNamesToPlugins Map from names to plugin modules.
225
+ * @internal
226
+ */
227
+export function injectEventPluginsByName(
228
+ injectedNamesToPlugins: NamesToPlugins,
229
+): void {
230
+ let isOrderingDirty = false;
231
+ for (const pluginName in injectedNamesToPlugins) {
232
+ if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) {
233
+ continue;
234
+ }
235
+ const pluginModule = injectedNamesToPlugins[pluginName];
236
+ if (
237
+ !namesToPlugins.hasOwnProperty(pluginName) ||
238
+ namesToPlugins[pluginName] !== pluginModule
239
+ ) {
240
+ invariant(
241
+ !namesToPlugins[pluginName],
242
+ 'EventPluginRegistry: Cannot inject two different event plugins ' +
243
+ 'using the same name, `%s`.',
244
+ pluginName,
245
+ );
246
+ namesToPlugins[pluginName] = pluginModule;
247
+ isOrderingDirty = true;
248
+ }
249
+ }
250
+ if (isOrderingDirty) {
251
+ recomputePluginOrdering();
252
+ }
253
+}
254
+
255
+export function injectEventPlugins(
256
+ eventPlugins: [ModernPluginModule<AnyNativeEvent>],
257
+): void {
258
+ for (let i = 0; i < eventPlugins.length; i++) {
259
+ const pluginModule = eventPlugins[i];
260
+ plugins.push(pluginModule);
261
+ const publishedEvents = pluginModule.eventTypes;
262
+ for (const eventName in publishedEvents) {
263
+ publishEventForPlugin(
264
+ publishedEvents[eventName],
265
+ pluginModule,
266
+ eventName,
267
+ );
268
+ }
269
+ }
270
+}
packages/react-native-renderer/src/legacy-events/EventPluginUtils.js
new
+172
@@ -0,0 +1,172 @@
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 {invokeGuardedCallbackAndCatchFirstError} from 'shared/ReactErrorUtils';
9
+import invariant from 'shared/invariant';
10
+
11
+export let getFiberCurrentPropsFromNode = null;
12
+export let getInstanceFromNode = null;
13
+export let getNodeFromInstance = null;
14
+
15
+export function setComponentTree(
16
+ getFiberCurrentPropsFromNodeImpl,
17
+ getInstanceFromNodeImpl,
18
+ getNodeFromInstanceImpl,
19
+) {
20
+ getFiberCurrentPropsFromNode = getFiberCurrentPropsFromNodeImpl;
21
+ getInstanceFromNode = getInstanceFromNodeImpl;
22
+ getNodeFromInstance = getNodeFromInstanceImpl;
23
+ if (__DEV__) {
24
+ if (!getNodeFromInstance || !getInstanceFromNode) {
25
+ console.error(
26
+ 'EventPluginUtils.setComponentTree(...): Injected ' +
27
+ 'module is missing getNodeFromInstance or getInstanceFromNode.',
28
+ );
29
+ }
30
+ }
31
+}
32
+
33
+let validateEventDispatches;
34
+if (__DEV__) {
35
+ validateEventDispatches = function(event) {
36
+ const dispatchListeners = event._dispatchListeners;
37
+ const dispatchInstances = event._dispatchInstances;
38
+
39
+ const listenersIsArr = Array.isArray(dispatchListeners);
40
+ const listenersLen = listenersIsArr
41
+ ? dispatchListeners.length
42
+ : dispatchListeners
43
+ ? 1
44
+ : 0;
45
+
46
+ const instancesIsArr = Array.isArray(dispatchInstances);
47
+ const instancesLen = instancesIsArr
48
+ ? dispatchInstances.length
49
+ : dispatchInstances
50
+ ? 1
51
+ : 0;
52
+
53
+ if (instancesIsArr !== listenersIsArr || instancesLen !== listenersLen) {
54
+ console.error('EventPluginUtils: Invalid `event`.');
55
+ }
56
+ };
57
+}
58
+
59
+/**
60
+ * Dispatch the event to the listener.
61
+ * @param {SyntheticEvent} event SyntheticEvent to handle
62
+ * @param {function} listener Application-level callback
63
+ * @param {*} inst Internal component instance
64
+ */
65
+export function executeDispatch(event, listener, inst) {
66
+ const type = event.type || 'unknown-event';
67
+ event.currentTarget = getNodeFromInstance(inst);
68
+ invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event);
69
+ event.currentTarget = null;
70
+}
71
+
72
+/**
73
+ * Standard/simple iteration through an event's collected dispatches.
74
+ */
75
+export function executeDispatchesInOrder(event) {
76
+ const dispatchListeners = event._dispatchListeners;
77
+ const dispatchInstances = event._dispatchInstances;
78
+ if (__DEV__) {
79
+ validateEventDispatches(event);
80
+ }
81
+ if (Array.isArray(dispatchListeners)) {
82
+ for (let i = 0; i < dispatchListeners.length; i++) {
83
+ if (event.isPropagationStopped()) {
84
+ break;
85
+ }
86
+ // Listeners and Instances are two parallel arrays that are always in sync.
87
+ executeDispatch(event, dispatchListeners[i], dispatchInstances[i]);
88
+ }
89
+ } else if (dispatchListeners) {
90
+ executeDispatch(event, dispatchListeners, dispatchInstances);
91
+ }
92
+ event._dispatchListeners = null;
93
+ event._dispatchInstances = null;
94
+}
95
+
96
+/**
97
+ * Standard/simple iteration through an event's collected dispatches, but stops
98
+ * at the first dispatch execution returning true, and returns that id.
99
+ *
100
+ * @return {?string} id of the first dispatch execution who's listener returns
101
+ * true, or null if no listener returned true.
102
+ */
103
+function executeDispatchesInOrderStopAtTrueImpl(event) {
104
+ const dispatchListeners = event._dispatchListeners;
105
+ const dispatchInstances = event._dispatchInstances;
106
+ if (__DEV__) {
107
+ validateEventDispatches(event);
108
+ }
109
+ if (Array.isArray(dispatchListeners)) {
110
+ for (let i = 0; i < dispatchListeners.length; i++) {
111
+ if (event.isPropagationStopped()) {
112
+ break;
113
+ }
114
+ // Listeners and Instances are two parallel arrays that are always in sync.
115
+ if (dispatchListeners[i](event, dispatchInstances[i])) {
116
+ return dispatchInstances[i];
117
+ }
118
+ }
119
+ } else if (dispatchListeners) {
120
+ if (dispatchListeners(event, dispatchInstances)) {
121
+ return dispatchInstances;
122
+ }
123
+ }
124
+ return null;
125
+}
126
+
127
+/**
128
+ * @see executeDispatchesInOrderStopAtTrueImpl
129
+ */
130
+export function executeDispatchesInOrderStopAtTrue(event) {
131
+ const ret = executeDispatchesInOrderStopAtTrueImpl(event);
132
+ event._dispatchInstances = null;
133
+ event._dispatchListeners = null;
134
+ return ret;
135
+}
136
+
137
+/**
138
+ * Execution of a "direct" dispatch - there must be at most one dispatch
139
+ * accumulated on the event or it is considered an error. It doesn't really make
140
+ * sense for an event with multiple dispatches (bubbled) to keep track of the
141
+ * return values at each dispatch execution, but it does tend to make sense when
142
+ * dealing with "direct" dispatches.
143
+ *
144
+ * @return {*} The return value of executing the single dispatch.
145
+ */
146
+export function executeDirectDispatch(event) {
147
+ if (__DEV__) {
148
+ validateEventDispatches(event);
149
+ }
150
+ const dispatchListener = event._dispatchListeners;
151
+ const dispatchInstance = event._dispatchInstances;
152
+ invariant(
153
+ !Array.isArray(dispatchListener),
154
+ 'executeDirectDispatch(...): Invalid `event`.',
155
+ );
156
+ event.currentTarget = dispatchListener
157
+ ? getNodeFromInstance(dispatchInstance)
158
+ : null;
159
+ const res = dispatchListener ? dispatchListener(event) : null;
160
+ event.currentTarget = null;
161
+ event._dispatchListeners = null;
162
+ event._dispatchInstances = null;
163
+ return res;
164
+}
165
+
166
+/**
167
+ * @param {SyntheticEvent} event
168
+ * @return {boolean} True iff number of dispatches accumulated is greater than 0.
169
+ */
170
+export function hasDispatches(event) {
171
+ return !!event._dispatchListeners;
172
+}
packages/react-native-renderer/src/legacy-events/PluginModuleType.js
new
+65
@@ -0,0 +1,65 @@
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 {Fiber} from 'react-reconciler/src/ReactInternalTypes';
11
+import type {
12
+ DispatchConfig,
13
+ ReactSyntheticEvent,
14
+} from './ReactSyntheticEventType';
15
+import type {TopLevelType} from './TopLevelEventTypes';
16
+
17
+export type EventTypes = {[key: string]: DispatchConfig, ...};
18
+
19
+export type AnyNativeEvent = Event | KeyboardEvent | MouseEvent | TouchEvent;
20
+
21
+export type PluginName = string;
22
+
23
+export type EventSystemFlags = number;
24
+
25
+export type LegacyPluginModule<NativeEvent> = {
26
+ eventTypes: EventTypes,
27
+ extractEvents: (
28
+ topLevelType: TopLevelType,
29
+ targetInst: null | Fiber,
30
+ nativeTarget: NativeEvent,
31
+ nativeEventTarget: null | EventTarget,
32
+ eventSystemFlags?: number,
33
+ container?: null | EventTarget,
34
+ ) => ?ReactSyntheticEvent,
35
+ tapMoveThreshold?: number,
36
+};
37
+
38
+export type DispatchQueueItemPhaseEntry = {|
39
+ instance: null | Fiber,
40
+ listener: Function,
41
+ currentTarget: EventTarget,
42
+|};
43
+
44
+export type DispatchQueueItemPhase = Array<DispatchQueueItemPhaseEntry>;
45
+
46
+export type DispatchQueueItem = {|
47
+ event: ReactSyntheticEvent,
48
+ capture: DispatchQueueItemPhase,
49
+ bubble: DispatchQueueItemPhase,
50
+|};
51
+
52
+export type DispatchQueue = Array<DispatchQueueItem>;
53
+
54
+export type ModernPluginModule<NativeEvent> = {
55
+ eventTypes: EventTypes,
56
+ extractEvents: (
57
+ dispatchQueue: DispatchQueue,
58
+ topLevelType: TopLevelType,
59
+ targetInst: null | Fiber,
60
+ nativeTarget: NativeEvent,
61
+ nativeEventTarget: null | EventTarget,
62
+ eventSystemFlags: number,
63
+ container: null | EventTarget,
64
+ ) => void,
65
+};
packages/react-native-renderer/src/legacy-events/ReactGenericBatching.js
new
+83
@@ -0,0 +1,83 @@
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-native-renderer/src/legacy-events/ReactSyntheticEventType.js
new
+49
@@ -0,0 +1,49 @@
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 type for SyntheticEvent class that includes private properties
8
+ * @flow
9
+ */
10
+
11
+import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
12
+import type {EventPriority} from 'shared/ReactTypes';
13
+import type {TopLevelType} from './TopLevelEventTypes';
14
+
15
+export type DispatchConfig = {|
16
+ dependencies?: Array<TopLevelType>,
17
+ phasedRegistrationNames: {|
18
+ bubbled: null | string,
19
+ captured: null | string,
20
+ |},
21
+ registrationName?: string,
22
+ eventPriority: EventPriority,
23
+|};
24
+
25
+export type CustomDispatchConfig = {|
26
+ phasedRegistrationNames: {|
27
+ bubbled: null,
28
+ captured: null,
29
+ |},
30
+ registrationName?: string,
31
+ customEvent: true,
32
+|};
33
+
34
+export type ReactSyntheticEvent = {|
35
+ dispatchConfig: DispatchConfig | CustomDispatchConfig,
36
+ getPooled: (
37
+ dispatchConfig: DispatchConfig | CustomDispatchConfig,
38
+ targetInst: Fiber,
39
+ nativeTarget: Event,
40
+ nativeEventTarget: EventTarget,
41
+ ) => ReactSyntheticEvent,
42
+ isPersistent: () => boolean,
43
+ isPropagationStopped: () => boolean,
44
+ _dispatchInstances?: null | Array<Fiber | null> | Fiber,
45
+ _dispatchListeners?: null | Array<Function> | Function,
46
+ _targetInst: Fiber,
47
+ type: string,
48
+ currentTarget: null | EventTarget,
49
+|};
packages/react-native-renderer/src/legacy-events/ResponderEventPlugin.js
new
+802
@@ -0,0 +1,802 @@
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-native-renderer/src/legacy-events/ResponderSyntheticEvent.js
new
+21
@@ -0,0 +1,21 @@
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-native-renderer/src/legacy-events/ResponderTopLevelEventTypes.js
new
+31
@@ -0,0 +1,31 @@
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-native-renderer/src/legacy-events/ResponderTouchHistoryStore.js
new
+222
@@ -0,0 +1,222 @@
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-native-renderer/src/legacy-events/SyntheticEvent.js
new
+366
@@ -0,0 +1,366 @@
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
+/* 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
+
15
+/**
16
+ * @interface Event
17
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
18
+ */
19
+const EventInterface = {
20
+ type: null,
21
+ target: null,
22
+ // currentTarget is set when dispatching; no use in copying it here
23
+ currentTarget: function() {
24
+ return null;
25
+ },
26
+ eventPhase: null,
27
+ bubbles: null,
28
+ cancelable: null,
29
+ timeStamp: function(event) {
30
+ return event.timeStamp || Date.now();
31
+ },
32
+ defaultPrevented: null,
33
+ isTrusted: null,
34
+};
35
+
36
+function functionThatReturnsTrue() {
37
+ return true;
38
+}
39
+
40
+function functionThatReturnsFalse() {
41
+ return false;
42
+}
43
+
44
+/**
45
+ * Synthetic events are dispatched by event plugins, typically in response to a
46
+ * top-level event delegation handler.
47
+ *
48
+ * These systems should generally use pooling to reduce the frequency of garbage
49
+ * collection. The system should check `isPersistent` to determine whether the
50
+ * event should be released into the pool after being dispatched. Users that
51
+ * need a persisted event should invoke `persist`.
52
+ *
53
+ * Synthetic events (and subclasses) implement the DOM Level 3 Events API by
54
+ * normalizing browser quirks. Subclasses do not necessarily have to implement a
55
+ * DOM interface; custom application-specific events can also subclass this.
56
+ *
57
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
58
+ * @param {*} targetInst Marker identifying the event target.
59
+ * @param {object} nativeEvent Native browser event.
60
+ * @param {DOMEventTarget} nativeEventTarget Target node.
61
+ */
62
+function SyntheticEvent(
63
+ dispatchConfig,
64
+ targetInst,
65
+ nativeEvent,
66
+ nativeEventTarget,
67
+) {
68
+ if (__DEV__) {
69
+ // these have a getter/setter for warnings
70
+ delete this.nativeEvent;
71
+ delete this.preventDefault;
72
+ delete this.stopPropagation;
73
+ delete this.isDefaultPrevented;
74
+ delete this.isPropagationStopped;
75
+ }
76
+
77
+ this.dispatchConfig = dispatchConfig;
78
+ this._targetInst = targetInst;
79
+ this.nativeEvent = nativeEvent;
80
+ if (!enableModernEventSystem) {
81
+ this._dispatchListeners = null;
82
+ this._dispatchInstances = null;
83
+ }
84
+
85
+ const Interface = this.constructor.Interface;
86
+ for (const propName in Interface) {
87
+ if (!Interface.hasOwnProperty(propName)) {
88
+ continue;
89
+ }
90
+ if (__DEV__) {
91
+ delete this[propName]; // this has a getter/setter for warnings
92
+ }
93
+ const normalize = Interface[propName];
94
+ if (normalize) {
95
+ this[propName] = normalize(nativeEvent);
96
+ } else {
97
+ if (propName === 'target') {
98
+ this.target = nativeEventTarget;
99
+ } else {
100
+ this[propName] = nativeEvent[propName];
101
+ }
102
+ }
103
+ }
104
+
105
+ const defaultPrevented =
106
+ nativeEvent.defaultPrevented != null
107
+ ? nativeEvent.defaultPrevented
108
+ : nativeEvent.returnValue === false;
109
+ if (defaultPrevented) {
110
+ this.isDefaultPrevented = functionThatReturnsTrue;
111
+ } else {
112
+ this.isDefaultPrevented = functionThatReturnsFalse;
113
+ }
114
+ this.isPropagationStopped = functionThatReturnsFalse;
115
+ return this;
116
+}
117
+
118
+Object.assign(SyntheticEvent.prototype, {
119
+ preventDefault: function() {
120
+ this.defaultPrevented = true;
121
+ const event = this.nativeEvent;
122
+ if (!event) {
123
+ return;
124
+ }
125
+
126
+ if (event.preventDefault) {
127
+ event.preventDefault();
128
+ } else if (typeof event.returnValue !== 'unknown') {
129
+ event.returnValue = false;
130
+ }
131
+ this.isDefaultPrevented = functionThatReturnsTrue;
132
+ },
133
+
134
+ stopPropagation: function() {
135
+ const event = this.nativeEvent;
136
+ if (!event) {
137
+ return;
138
+ }
139
+
140
+ if (event.stopPropagation) {
141
+ event.stopPropagation();
142
+ } else if (typeof event.cancelBubble !== 'unknown') {
143
+ // The ChangeEventPlugin registers a "propertychange" event for
144
+ // IE. This event does not support bubbling or cancelling, and
145
+ // any references to cancelBubble throw "Member not found". A
146
+ // typeof check of "unknown" circumvents this issue (and is also
147
+ // IE specific).
148
+ event.cancelBubble = true;
149
+ }
150
+
151
+ this.isPropagationStopped = functionThatReturnsTrue;
152
+ },
153
+
154
+ /**
155
+ * We release all dispatched `SyntheticEvent`s after each event loop, adding
156
+ * them back into the pool. This allows a way to hold onto a reference that
157
+ * won't be added back into the pool.
158
+ */
159
+ persist: function() {
160
+ // Modern event system doesn't use pooling.
161
+ if (!enableModernEventSystem) {
162
+ this.isPersistent = functionThatReturnsTrue;
163
+ }
164
+ },
165
+
166
+ /**
167
+ * Checks if this event should be released back into the pool.
168
+ *
169
+ * @return {boolean} True if this should not be released, false otherwise.
170
+ */
171
+ isPersistent: enableModernEventSystem
172
+ ? functionThatReturnsTrue
173
+ : functionThatReturnsFalse,
174
+
175
+ /**
176
+ * `PooledClass` looks for `destructor` on each instance it releases.
177
+ */
178
+ 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;
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
+ }
234
+ },
235
+});
236
+
237
+SyntheticEvent.Interface = EventInterface;
238
+
239
+/**
240
+ * Helper to reduce boilerplate when creating subclasses.
241
+ */
242
+SyntheticEvent.extend = function(Interface) {
243
+ const Super = this;
244
+
245
+ const E = function() {};
246
+ E.prototype = Super.prototype;
247
+ const prototype = new E();
248
+
249
+ function Class() {
250
+ return Super.apply(this, arguments);
251
+ }
252
+ Object.assign(prototype, Class.prototype);
253
+ Class.prototype = prototype;
254
+ Class.prototype.constructor = Class;
255
+
256
+ Class.Interface = Object.assign({}, Super.Interface, Interface);
257
+ Class.extend = Super.extend;
258
+ addEventPoolingTo(Class);
259
+
260
+ return Class;
261
+};
262
+
263
+addEventPoolingTo(SyntheticEvent);
264
+
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
+
312
+function createOrGetPooledEvent(
313
+ dispatchConfig,
314
+ targetInst,
315
+ nativeEvent,
316
+ nativeInst,
317
+) {
318
+ 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
+ }
332
+ }
333
+ return new EventConstructor(
334
+ dispatchConfig,
335
+ targetInst,
336
+ nativeEvent,
337
+ nativeInst,
338
+ );
339
+}
340
+
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
+
356
+function addEventPoolingTo(EventConstructor) {
357
+ EventConstructor.getPooled = createOrGetPooledEvent;
358
+
359
+ // Modern event system doesn't use pooling.
360
+ if (!enableModernEventSystem) {
361
+ EventConstructor.eventPool = [];
362
+ EventConstructor.release = releasePooledEvent;
363
+ }
364
+}
365
+
366
+export default SyntheticEvent;
packages/react-native-renderer/src/legacy-events/TopLevelEventTypes.js
new
+39
@@ -0,0 +1,39 @@
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 type RNTopLevelEventType =
11
+ | 'topMouseDown'
12
+ | 'topMouseMove'
13
+ | 'topMouseUp'
14
+ | 'topScroll'
15
+ | 'topSelectionChange'
16
+ | 'topTouchCancel'
17
+ | 'topTouchEnd'
18
+ | 'topTouchMove'
19
+ | 'topTouchStart';
20
+
21
+export opaque type DOMTopLevelEventType = string;
22
+
23
+// Do not use the below two methods directly!
24
+// Instead use constants exported from DOMTopLevelEventTypes in ReactDOM.
25
+// (It is the only module that is allowed to access these methods.)
26
+
27
+export function unsafeCastStringToDOMTopLevelType(
28
+ topLevelType: string,
29
+): DOMTopLevelEventType {
30
+ return topLevelType;
31
+}
32
+
33
+export function unsafeCastDOMTopLevelTypeToString(
34
+ topLevelType: DOMTopLevelEventType,
35
+): string {
36
+ return topLevelType;
37
+}
38
+
39
+export type TopLevelType = DOMTopLevelEventType | RNTopLevelEventType;
packages/react-native-renderer/src/legacy-events/accumulate.js
new
+45
@@ -0,0 +1,45 @@
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-native-renderer/src/legacy-events/accumulateInto.js
new
+57
@@ -0,0 +1,57 @@
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 into the first one. This
14
+ * is used to conserve memory by avoiding array allocations, and thus sacrifices
15
+ * API cleanness. Since `current` can be null before being passed in and not
16
+ * null after this function, make sure to assign it back to `current`:
17
+ *
18
+ * `a = accumulateInto(a, b);`
19
+ *
20
+ * This API should be sparingly used. Try `accumulate` for something cleaner.
21
+ *
22
+ * @return {*|array<*>} An accumulation of items.
23
+ */
24
+
25
+function accumulateInto<T>(
26
+ current: ?(Array<T> | T),
27
+ next: T | Array<T>,
28
+): T | Array<T> {
29
+ invariant(
30
+ next != null,
31
+ 'accumulateInto(...): Accumulated items must not be null or undefined.',
32
+ );
33
+
34
+ if (current == null) {
35
+ return next;
36
+ }
37
+
38
+ // Both are not empty. Warning: Never call x.concat(y) when you are not
39
+ // certain that x is an Array (x could be a string with concat method).
40
+ if (Array.isArray(current)) {
41
+ if (Array.isArray(next)) {
42
+ current.push.apply(current, next);
43
+ return current;
44
+ }
45
+ current.push(next);
46
+ return current;
47
+ }
48
+
49
+ if (Array.isArray(next)) {
50
+ // A bit too dangerous to mutate `next`.
51
+ return [current].concat(next);
52
+ }
53
+
54
+ return [current, next];
55
+}
56
+
57
+export default accumulateInto;
packages/react-native-renderer/src/legacy-events/forEachAccumulated.js
new
+31
@@ -0,0 +1,31 @@
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
+/**
11
+ * @param {array} arr an "accumulation" of items which is either an Array or
12
+ * a single item. Useful when paired with the `accumulate` module. This is a
13
+ * simple utility that allows us to reason about a collection of items, but
14
+ * handling the case when there is exactly one item (and we do not need to
15
+ * allocate an array).
16
+ * @param {function} cb Callback invoked with each element or a collection.
17
+ * @param {?} [scope] Scope used as `this` in a callback.
18
+ */
19
+function forEachAccumulated<T>(
20
+ arr: ?(Array<T> | T),
21
+ cb: (elem: T) => void,
22
+ scope: ?any,
23
+) {
24
+ if (Array.isArray(arr)) {
25
+ arr.forEach(cb, scope);
26
+ } else if (arr) {
27
+ cb.call(scope, arr);
28
+ }
29
+}
30
+
31
+export default forEachAccumulated;
scripts/flow/react-native-host-hooks.js
+1
-1
@@ -16,7 +16,7 @@ import type {
16
ReactNativeBaseComponentViewConfig,
17
ViewConfigGetter,
18
} from 'react-native-renderer/src/ReactNativeTypes';
19
-import type {RNTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
19
+import type {RNTopLevelEventType} from 'react-native-renderer/src/legacy-events/TopLevelEventTypes';
20
import type {CapturedError} from 'react-reconciler/src/ReactCapturedValue';
21
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
22
scripts/shared/pathsByLanguageVersion.js
-1
@@ -15,7 +15,6 @@ const esNextPaths = [
15
'packages/dom-event-testing-library/**/*.js',
16
'packages/react-interactions/**/*.js',
17
'packages/react-interactions/**/*.js',
18
- 'packages/legacy-events/**/*.js',
18
'packages/shared/**/*.js',
19
// Shims and Flow environment
20
'scripts/flow/*.js',