Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use browser event names for top-level event types in React DOM #12629

Merged
merged 46 commits into from
May 15, 2018
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
d02d86a
Add TopLevelEventTypes
philipp-spiess Apr 16, 2018
45713ce
Fix `ReactBrowserEventEmitter`
philipp-spiess Apr 16, 2018
5f11da0
Fix EventPluginUtils
philipp-spiess Apr 16, 2018
58a24ba
Fix TapEventPlugin
philipp-spiess Apr 16, 2018
390fb51
Fix ResponderEventPlugin
philipp-spiess Apr 16, 2018
3dcbf4d
Update ReactDOMFiberComponent
philipp-spiess Apr 16, 2018
1fb5cd8
Fix BeforeInputEventPlugin
philipp-spiess Apr 16, 2018
96ce3cd
Fix ChangeEventPlugin
philipp-spiess Apr 16, 2018
737626a
Fix EnterLeaveEventPlugin
philipp-spiess Apr 16, 2018
a03d896
Add missing non top event type used in ChangeEventPlugin
philipp-spiess Apr 16, 2018
d58cd30
Fix SelectEventPlugin
philipp-spiess Apr 16, 2018
e1b9166
Fix SimpleEventPlugin
philipp-spiess Apr 16, 2018
f07a64f
Fix outstanding Flow issues and move TopLevelEventTypes
philipp-spiess Apr 16, 2018
da64f27
Inline a list of all events in `ReactTestUtils`
philipp-spiess Apr 16, 2018
16c39e5
Fix tests
philipp-spiess Apr 17, 2018
4a7114e
Make it pretty
philipp-spiess Apr 17, 2018
2a87568
Fix completly unrelated typo
philipp-spiess Apr 17, 2018
0d864ca
Don’t use map constructor because of IE11
philipp-spiess Apr 17, 2018
586708e
Update typings, revert changes to native code
philipp-spiess Apr 21, 2018
12c9ac3
Make topLevelTypes in ResponderEventPlugin injectable and create DOM …
philipp-spiess Apr 21, 2018
9d684fc
Set proper dependencies for DOMResponderEventPlugin
philipp-spiess Apr 21, 2018
c27ab85
Prettify
philipp-spiess Apr 21, 2018
4043f87
Make some react dom tests no longer depend on internal API
philipp-spiess Apr 21, 2018
f029940
Use factories to create top level speific generic event modules
philipp-spiess Apr 21, 2018
0ace5a1
Remove unused dependency
philipp-spiess Apr 21, 2018
653492c
Revert exposed module renaming, hide store creation, and inline depen…
philipp-spiess Apr 23, 2018
7e8b34f
Add Flow types to createResponderEventPlugin and its consumers
philipp-spiess Apr 23, 2018
2d21c09
Remove unused dependency
philipp-spiess Apr 23, 2018
d1c390b
Use opaque flow type for TopLevelType
philipp-spiess Apr 24, 2018
ec0b881
Add missing semis
philipp-spiess Apr 24, 2018
352dfbf
Use raw event names as top level identifer
philipp-spiess Apr 24, 2018
ac6e3e2
Upgrade baylon
philipp-spiess Apr 24, 2018
4a7bf07
Clean up flow types
philipp-spiess Apr 24, 2018
3ebd359
Revert Map changes of ReactBrowserEventEmitter
philipp-spiess Apr 24, 2018
6095b0f
Upgrade babel-* packages
philipp-spiess Apr 24, 2018
bb057bc
Revert Map changes of SimpleEventPlugin
philipp-spiess Apr 24, 2018
6800d01
Clean up ReactTestUtils
philipp-spiess Apr 24, 2018
4d76b15
Add missing semi
philipp-spiess Apr 24, 2018
af02875
Fix Flow issue
philipp-spiess Apr 25, 2018
c1f6b38
Make TopLevelType clearer
philipp-spiess Apr 25, 2018
0cb8fad
Favor for loops
philipp-spiess Apr 25, 2018
df7f91d
Explain the new DOMTopLevelEventTypes concept
philipp-spiess Apr 25, 2018
15c2723
Use static injection for Responder plugin types
gaearon May 4, 2018
4b2ca6b
Remove null check and rely on flow checks
philipp-spiess May 7, 2018
e19f37b
Add missing ResponderEventPlugin dependencies
philipp-spiess May 11, 2018
0c6982d
Merge branch 'master' into no-top-level-events
gaearon May 15, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -38,7 +38,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",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've upgraded babylon and all babel-* packages. This was required to get proper support for opaque types across the toolchain. All upgrades where minor version only.

"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) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those methods have been used by the responder plugin and a dependency of the responder and were thus added in the events/ shared package. Since don't have the top level types for DOM here anymore, those were removed.

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: [],
},
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) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was unused so I removed it.

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';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By importing the type from the react-dom module, we can use an opaque type and avoid leaking the underlying type in any other module.

Defining the opaque type in DOMTopLevelEventTypes makes the types a lot easier but introduces this not-so-nice type dependency on react-dom.


type RNTopLevelEventType =
| 'topMouseDown'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment clarifying these are RN types? Or even declare them separately as RNTopLevelEventType and use that in the union?

| '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];