Skip to content

Commit

Permalink
Use browser event names for top-level event types in React DOM (faceb…
Browse files Browse the repository at this point in the history
…ook#12629)

* Add TopLevelEventTypes

* Fix `ReactBrowserEventEmitter`

* Fix EventPluginUtils

* Fix TapEventPlugin

* Fix ResponderEventPlugin

* Update ReactDOMFiberComponent

* Fix BeforeInputEventPlugin

* Fix ChangeEventPlugin

* Fix EnterLeaveEventPlugin

* Add missing non top event type used in ChangeEventPlugin

* Fix SelectEventPlugin

* Fix SimpleEventPlugin

* Fix outstanding Flow issues and move TopLevelEventTypes

* Inline a list of all events in `ReactTestUtils`

* Fix tests

* Make it pretty

* Fix completly unrelated typo

* Don’t use map constructor because of IE11

* Update typings, revert changes to native code

* Make topLevelTypes in ResponderEventPlugin injectable and create DOM and ReactNative variant

* Set proper dependencies for DOMResponderEventPlugin

* Prettify

* Make some react dom tests no longer depend on internal API

* Use factories to create top level speific generic event modules

* Remove unused dependency

* Revert exposed module renaming, hide store creation, and inline dependency decleration

* Add Flow types to createResponderEventPlugin and its consumers

* Remove unused dependency

* Use opaque flow type for TopLevelType

* Add missing semis

* Use raw event names as top level identifer

* Upgrade baylon

This is required for parsing opaque flow types in our CI tests.

* Clean up flow types

* Revert Map changes of ReactBrowserEventEmitter

* Upgrade babel-* packages

Apparently local unit tests also have issues with parsing JavaScript
modules that contain opaque types (not sure why I didn't notice
earlier!?).

* Revert Map changes of SimpleEventPlugin

* Clean up ReactTestUtils

* Add missing semi

* Fix Flow issue

* Make TopLevelType clearer

* Favor for loops

* Explain the new DOMTopLevelEventTypes concept

* Use static injection for Responder plugin types

* Remove null check and rely on flow checks

* Add missing ResponderEventPlugin dependencies
  • Loading branch information
philipp-spiess authored and gaearon committed May 15, 2018
1 parent 1047980 commit e96dc14
Show file tree
Hide file tree
Showing 32 changed files with 1,965 additions and 996 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function NumberInputs() {
`}
affectedBrowsers="IE Edge, IE 11">
<TestCase.Steps>
<li>Type any string (not an actual password</li>
<li>Type any string (not an actual password)</li>
</TestCase.Steps>

<TestCase.ExpectedResult>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"babel-plugin-transform-regenerator": "^6.26.0",
"babel-preset-react": "^6.5.0",
"babel-traverse": "^6.9.0",
"babylon": "6.15.0",
"babylon": "6.18.0",
"bundle-collapser": "^1.1.1",
"chalk": "^1.1.3",
"cli-table": "^0.3.1",
Expand Down
5 changes: 3 additions & 2 deletions packages/events/EventPluginHub.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import type {PluginModule} from './PluginModuleType';
import type {ReactSyntheticEvent} from './ReactSyntheticEventType';
import type {Fiber} from 'react-reconciler/src/ReactFiber';
import type {AnyNativeEvent} from './PluginModuleType';
import type {TopLevelType} from './TopLevelEventTypes';

/**
* Internal queue of events that have accumulated their dispatches and are
Expand Down Expand Up @@ -165,7 +166,7 @@ export function getListener(inst: Fiber, registrationName: string) {
* @internal
*/
function extractEvents(
topLevelType: string,
topLevelType: TopLevelType,
targetInst: Fiber,
nativeEvent: AnyNativeEvent,
nativeEventTarget: EventTarget,
Expand Down Expand Up @@ -227,7 +228,7 @@ export function runEventsInBatch(
}

export function runExtractedEventsInBatch(
topLevelType: string,
topLevelType: TopLevelType,
targetInst: Fiber,
nativeEvent: AnyNativeEvent,
nativeEventTarget: EventTarget,
Expand Down
15 changes: 0 additions & 15 deletions packages/events/EventPluginUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,6 @@ export const injection = {
},
};

export function isEndish(topLevelType) {
return (
topLevelType === 'topMouseUp' ||
topLevelType === 'topTouchEnd' ||
topLevelType === 'topTouchCancel'
);
}

export function isMoveish(topLevelType) {
return topLevelType === 'topMouseMove' || topLevelType === 'topTouchMove';
}
export function isStartish(topLevelType) {
return topLevelType === 'topMouseDown' || topLevelType === 'topTouchStart';
}

let validateEventDispatches;
if (__DEV__) {
validateEventDispatches = function(event) {
Expand Down
3 changes: 2 additions & 1 deletion packages/events/PluginModuleType.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {
DispatchConfig,
ReactSyntheticEvent,
} from './ReactSyntheticEventType';
import type {TopLevelType} from './TopLevelEventTypes';

export type EventTypes = {[key: string]: DispatchConfig};

Expand All @@ -22,7 +23,7 @@ export type PluginName = string;
export type PluginModule<NativeEvent> = {
eventTypes: EventTypes,
extractEvents: (
topLevelType: string,
topLevelType: TopLevelType,
targetInst: Fiber,
nativeTarget: NativeEvent,
nativeEventTarget: EventTarget,
Expand Down
3 changes: 2 additions & 1 deletion packages/events/ReactSyntheticEventType.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
*/

import type {Fiber} from 'react-reconciler/src/ReactFiber';
import type {TopLevelType} from './TopLevelEventTypes';

export type DispatchConfig = {
dependencies: Array<string>,
dependencies: Array<TopLevelType>,
phasedRegistrationNames?: {
bubbled: string,
captured: string,
Expand Down
90 changes: 49 additions & 41 deletions packages/events/ResponderEventPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
import {getLowestCommonAncestor, isAncestor} from 'shared/ReactTreeTraversal';

import {
isStartish,
isMoveish,
isEndish,
executeDirectDispatch,
hasDispatches,
executeDispatchesInOrderStopAtTrue,
Expand All @@ -24,6 +21,17 @@ import {
import ResponderSyntheticEvent from './ResponderSyntheticEvent';
import ResponderTouchHistoryStore from './ResponderTouchHistoryStore';
import accumulate from './accumulate';
import {
TOP_SCROLL,
TOP_SELECTION_CHANGE,
TOP_TOUCH_CANCEL,
isStartish,
isMoveish,
isEndish,
startDependencies,
moveDependencies,
endDependencies,
} from './ResponderTopLevelEventTypes';

/**
* Instance of element that should respond to touch/move types of interactions,
Expand All @@ -37,11 +45,6 @@ let responderInst = null;
*/
let trackedTouchCount = 0;

/**
* Last reported number of active touches.
*/
let previousActiveTouches = 0;

const changeResponder = function(nextResponderInst, blockHostResponder) {
const oldResponderInst = responderInst;
responderInst = nextResponderInst;
Expand All @@ -64,6 +67,7 @@ const eventTypes = {
bubbled: 'onStartShouldSetResponder',
captured: 'onStartShouldSetResponderCapture',
},
dependencies: startDependencies,
},

/**
Expand All @@ -80,6 +84,7 @@ const eventTypes = {
bubbled: 'onScrollShouldSetResponder',
captured: 'onScrollShouldSetResponderCapture',
},
dependencies: [TOP_SCROLL],
},

/**
Expand All @@ -94,6 +99,7 @@ const eventTypes = {
bubbled: 'onSelectionChangeShouldSetResponder',
captured: 'onSelectionChangeShouldSetResponderCapture',
},
dependencies: [TOP_SELECTION_CHANGE],
},

/**
Expand All @@ -105,21 +111,44 @@ const eventTypes = {
bubbled: 'onMoveShouldSetResponder',
captured: 'onMoveShouldSetResponderCapture',
},
dependencies: moveDependencies,
},

/**
* Direct responder events dispatched directly to responder. Do not bubble.
*/
responderStart: {registrationName: 'onResponderStart'},
responderMove: {registrationName: 'onResponderMove'},
responderEnd: {registrationName: 'onResponderEnd'},
responderRelease: {registrationName: 'onResponderRelease'},
responderStart: {
registrationName: 'onResponderStart',
dependencies: startDependencies,
},
responderMove: {
registrationName: 'onResponderMove',
dependencies: moveDependencies,
},
responderEnd: {
registrationName: 'onResponderEnd',
dependencies: endDependencies,
},
responderRelease: {
registrationName: 'onResponderRelease',
dependencies: endDependencies,
},
responderTerminationRequest: {
registrationName: 'onResponderTerminationRequest',
dependencies: [],
},
responderGrant: {
registrationName: 'onResponderGrant',
dependencies: [],
},
responderReject: {
registrationName: 'onResponderReject',
dependencies: [],
},
responderTerminate: {
registrationName: 'onResponderTerminate',
dependencies: [],
},
responderGrant: {registrationName: 'onResponderGrant'},
responderReject: {registrationName: 'onResponderReject'},
responderTerminate: {registrationName: 'onResponderTerminate'},
};

/**
Expand Down Expand Up @@ -322,7 +351,7 @@ function setResponderAndExtractTransfer(
? eventTypes.startShouldSetResponder
: isMoveish(topLevelType)
? eventTypes.moveShouldSetResponder
: topLevelType === 'topSelectionChange'
: topLevelType === TOP_SELECTION_CHANGE
? eventTypes.selectionChangeShouldSetResponder
: eventTypes.scrollShouldSetResponder;

Expand Down Expand Up @@ -427,8 +456,8 @@ function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) {
// responderIgnoreScroll: We are trying to migrate away from specifically
// tracking native scroll events here and responderIgnoreScroll indicates we
// will send topTouchCancel to handle canceling touch events instead
((topLevelType === 'topScroll' && !nativeEvent.responderIgnoreScroll) ||
(trackedTouchCount > 0 && topLevelType === 'topSelectionChange') ||
((topLevelType === TOP_SCROLL && !nativeEvent.responderIgnoreScroll) ||
(trackedTouchCount > 0 && topLevelType === TOP_SELECTION_CHANGE) ||
isStartish(topLevelType) ||
isMoveish(topLevelType))
);
Expand Down Expand Up @@ -534,7 +563,7 @@ const ResponderEventPlugin = {
}

const isResponderTerminate =
responderInst && topLevelType === 'topTouchCancel';
responderInst && topLevelType === TOP_TOUCH_CANCEL;
const isResponderRelease =
responderInst &&
!isResponderTerminate &&
Expand All @@ -556,41 +585,20 @@ const ResponderEventPlugin = {
changeResponder(null);
}

const numberActiveTouches =
ResponderTouchHistoryStore.touchHistory.numberActiveTouches;
if (
ResponderEventPlugin.GlobalInteractionHandler &&
numberActiveTouches !== previousActiveTouches
) {
ResponderEventPlugin.GlobalInteractionHandler.onChange(
numberActiveTouches,
);
}
previousActiveTouches = numberActiveTouches;

return extracted;
},

GlobalResponderHandler: null,
GlobalInteractionHandler: null,

injection: {
/**
* @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler
* Object that handles any change in responder. Use this to inject
* integration with an existing touch handling system etc.
*/
injectGlobalResponderHandler: function(GlobalResponderHandler) {
injectGlobalResponderHandler(GlobalResponderHandler) {
ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler;
},

/**
* @param {{onChange: (numberActiveTouches) => void} GlobalInteractionHandler
* Object that handles any change in the number of active touches.
*/
injectGlobalInteractionHandler: function(GlobalInteractionHandler) {
ResponderEventPlugin.GlobalInteractionHandler = GlobalInteractionHandler;
},
},
};

Expand Down
31 changes: 31 additions & 0 deletions packages/events/ResponderTopLevelEventTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

export const TOP_TOUCH_START = 'topTouchStart';
export const TOP_TOUCH_MOVE = 'topTouchMove';
export const TOP_TOUCH_END = 'topTouchEnd';
export const TOP_TOUCH_CANCEL = 'topTouchCancel';
export const TOP_SCROLL = 'topScroll';
export const TOP_SELECTION_CHANGE = 'topSelectionChange';

export function isStartish(topLevelType: mixed): boolean {
return topLevelType === TOP_TOUCH_START;
}

export function isMoveish(topLevelType: mixed): boolean {
return topLevelType === TOP_TOUCH_MOVE;
}

export function isEndish(topLevelType: mixed): boolean {
return topLevelType === TOP_TOUCH_END || topLevelType === TOP_TOUCH_CANCEL;
}

export const startDependencies = [TOP_TOUCH_START];
export const moveDependencies = [TOP_TOUCH_MOVE];
export const endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END];
2 changes: 1 addition & 1 deletion packages/events/ResponderTouchHistoryStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import invariant from 'fbjs/lib/invariant';
import warning from 'fbjs/lib/warning';

import {isEndish, isMoveish, isStartish} from './EventPluginUtils';
import {isStartish, isMoveish, isEndish} from './ResponderTopLevelEventTypes';

/**
* Tracks the position and time of each active touch by `touch.identifier`. We
Expand Down
23 changes: 23 additions & 0 deletions packages/events/TopLevelEventTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import type {DOMTopLevelEventType} from 'react-dom/src/events/DOMTopLevelEventTypes';

type RNTopLevelEventType =
| 'topMouseDown'
| 'topMouseMove'
| 'topMouseUp'
| 'topScroll'
| 'topSelectionChange'
| 'topTouchCancel'
| 'topTouchEnd'
| 'topTouchMove'
| 'topTouchStart';

export type TopLevelType = DOMTopLevelEventType | RNTopLevelEventType;
41 changes: 41 additions & 0 deletions packages/events/forks/ResponderTopLevelEventTypes.dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

// Note: ideally these would be imported from DOMTopLevelEventTypes,
// but our build system currently doesn't let us do that from a fork.

export const TOP_TOUCH_START = 'touchstart';
export const TOP_TOUCH_MOVE = 'touchmove';
export const TOP_TOUCH_END = 'touchend';
export const TOP_TOUCH_CANCEL = 'touchcancel';
export const TOP_SCROLL = 'scroll';
export const TOP_SELECTION_CHANGE = 'selectionchange';
export const TOP_MOUSE_DOWN = 'mousedown';
export const TOP_MOUSE_MOVE = 'mousemove';
export const TOP_MOUSE_UP = 'mouseup';

export function isStartish(topLevelType: mixed): boolean {
return topLevelType === TOP_TOUCH_START || topLevelType === TOP_MOUSE_DOWN;
}

export function isMoveish(topLevelType: mixed): boolean {
return topLevelType === TOP_TOUCH_MOVE || topLevelType === TOP_MOUSE_MOVE;
}

export function isEndish(topLevelType: mixed): boolean {
return (
topLevelType === TOP_TOUCH_END ||
topLevelType === TOP_TOUCH_CANCEL ||
topLevelType === TOP_MOUSE_UP
);
}

export const startDependencies = [TOP_TOUCH_START, TOP_MOUSE_DOWN];
export const moveDependencies = [TOP_TOUCH_MOVE, TOP_MOUSE_MOVE];
export const endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END, TOP_MOUSE_UP];
Loading

0 comments on commit e96dc14

Please sign in to comment.