Event API: use capture for all event listeners using experimental responder system (#15526)

This commit is contained in:
Dominic Gannaway
2019-04-30 11:40:45 +01:00
committed by GitHub
parent 72ca3c60e7
commit bd88982fbf
12 changed files with 38 additions and 68 deletions

View File

@@ -13,5 +13,4 @@ export const PLUGIN_EVENT_SYSTEM = 1;
export const RESPONDER_EVENT_SYSTEM = 1 << 1;
export const IS_PASSIVE = 1 << 2;
export const IS_ACTIVE = 1 << 3;
export const IS_CAPTURE = 1 << 4;
export const PASSIVE_NOT_SUPPORTED = 1 << 5;
export const PASSIVE_NOT_SUPPORTED = 1 << 4;

View File

@@ -1294,7 +1294,6 @@ export function listenToEventResponderEventTypes(
for (let i = 0, length = eventTypes.length; i < length; ++i) {
const targetEventType = eventTypes[i];
let topLevelType;
let capture = false;
let passive = true;
// If no event config object is provided (i.e. - only a string),
@@ -1313,26 +1312,17 @@ export function listenToEventResponderEventTypes(
const targetEventConfigObject = ((targetEventType: any): {
name: string,
passive?: boolean,
capture?: boolean,
});
topLevelType = targetEventConfigObject.name;
if (targetEventConfigObject.passive !== undefined) {
passive = targetEventConfigObject.passive;
}
if (targetEventConfigObject.capture !== undefined) {
capture = targetEventConfigObject.capture;
}
}
const listeningName = generateListeningKey(
topLevelType,
passive,
capture,
);
const listeningName = generateListeningKey(topLevelType, passive);
if (!listeningSet.has(listeningName)) {
trapEventForResponderEventSystem(
element,
((topLevelType: any): DOMTopLevelEventType),
capture,
passive,
);
listeningSet.add(listeningName);

View File

@@ -9,7 +9,6 @@
import {
type EventSystemFlags,
IS_PASSIVE,
IS_CAPTURE,
PASSIVE_NOT_SUPPORTED,
} from 'events/EventSystemFlags';
import type {AnyNativeEvent} from 'events/PluginModuleType';
@@ -247,28 +246,22 @@ const eventResponderContext: ReactResponderContext = {
for (let i = 0; i < rootEventTypes.length; i++) {
const rootEventType = rootEventTypes[i];
let name = rootEventType;
let capture = false;
let passive = true;
if (typeof rootEventType !== 'string') {
const targetEventConfigObject = ((rootEventType: any): {
name: string,
passive?: boolean,
capture?: boolean,
});
name = targetEventConfigObject.name;
if (targetEventConfigObject.passive !== undefined) {
passive = targetEventConfigObject.passive;
}
if (targetEventConfigObject.capture !== undefined) {
capture = targetEventConfigObject.capture;
}
}
const listeningName = generateListeningKey(
((name: any): string),
passive,
capture,
);
let rootEventComponents = rootEventTypesToEventComponentInstances.get(
listeningName,
@@ -537,27 +530,21 @@ function getTargetEventTypesSet(
for (let i = 0; i < eventTypes.length; i++) {
const eventType = eventTypes[i];
let name = eventType;
let capture = false;
let passive = true;
if (typeof eventType !== 'string') {
const targetEventConfigObject = ((eventType: any): {
name: string,
passive?: boolean,
capture?: boolean,
});
name = targetEventConfigObject.name;
if (targetEventConfigObject.passive !== undefined) {
passive = targetEventConfigObject.passive;
}
if (targetEventConfigObject.capture !== undefined) {
capture = targetEventConfigObject.capture;
}
}
const listeningName = generateListeningKey(
((name: any): string),
passive,
capture,
);
cachedSet.add(listeningName);
}
@@ -640,12 +627,10 @@ function traverseAndHandleEventResponderInstances(
eventSystemFlags: EventSystemFlags,
): void {
const isPassiveEvent = (eventSystemFlags & IS_PASSIVE) !== 0;
const isCaptureEvent = (eventSystemFlags & IS_CAPTURE) !== 0;
const isPassiveSupported = (eventSystemFlags & PASSIVE_NOT_SUPPORTED) === 0;
const listeningName = generateListeningKey(
((topLevelType: any): string),
isPassiveEvent || !isPassiveSupported,
isCaptureEvent,
);
// Trigger event responders in this order:
@@ -875,29 +860,20 @@ function registerRootEventType(
eventComponentInstance: ReactEventComponentInstance,
): void {
let name = rootEventType;
let capture = false;
let passive = true;
if (typeof rootEventType !== 'string') {
const targetEventConfigObject = ((rootEventType: any): {
name: string,
passive?: boolean,
capture?: boolean,
});
name = targetEventConfigObject.name;
if (targetEventConfigObject.passive !== undefined) {
passive = targetEventConfigObject.passive;
}
if (targetEventConfigObject.capture !== undefined) {
capture = targetEventConfigObject.capture;
}
}
const listeningName = generateListeningKey(
((name: any): string),
passive,
capture,
);
const listeningName = generateListeningKey(((name: any): string), passive);
let rootEventComponentInstances = rootEventTypesToEventComponentInstances.get(
listeningName,
);
@@ -928,12 +904,10 @@ function registerRootEventType(
export function generateListeningKey(
topLevelType: string,
passive: boolean,
capture: boolean,
): string {
// Create a unique name for this event, plus its properties. We'll
// use this to ensure we don't listen to the same event with the same
// properties again.
const passiveKey = passive ? '_passive' : '_active';
const captureKey = capture ? '_capture' : '';
return `${topLevelType}${passiveKey}${captureKey}`;
return `${topLevelType}${passiveKey}`;
}

View File

@@ -23,11 +23,14 @@ export function addEventCaptureListener(
element.addEventListener(eventType, listener, true);
}
export function addEventListener(
export function addEventCaptureListenerWithPassiveFlag(
element: Document | Element | Node,
eventType: string,
listener: Function,
options: {passive: boolean},
passive: boolean,
): void {
element.addEventListener(eventType, listener, (options: any));
element.addEventListener(eventType, listener, {
capture: true,
passive,
});
}

View File

@@ -22,14 +22,13 @@ import {
RESPONDER_EVENT_SYSTEM,
IS_PASSIVE,
IS_ACTIVE,
IS_CAPTURE,
PASSIVE_NOT_SUPPORTED,
} from 'events/EventSystemFlags';
import {
addEventBubbleListener,
addEventCaptureListener,
addEventListener,
addEventCaptureListenerWithPassiveFlag,
} from './EventListener';
import getEventTarget from './getEventTarget';
import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
@@ -168,7 +167,6 @@ export function trapCapturedEvent(
export function trapEventForResponderEventSystem(
element: Document | Element | Node,
topLevelType: DOMTopLevelEventType,
capture: boolean,
passive: boolean,
): void {
if (enableEventAPI) {
@@ -190,15 +188,18 @@ export function trapEventForResponderEventSystem(
} else {
eventFlags |= IS_ACTIVE;
}
if (capture) {
eventFlags |= IS_CAPTURE;
}
// Check if interactive and wrap in interactiveUpdates
const listener = dispatchEvent.bind(null, topLevelType, eventFlags);
addEventListener(element, rawEventName, listener, {
capture,
passive,
});
if (passiveBrowserEventsSupported) {
addEventCaptureListenerWithPassiveFlag(
element,
rawEventName,
listener,
passive,
);
} else {
addEventCaptureListener(element, rawEventName, listener);
}
}
}

View File

@@ -12,8 +12,6 @@ const EventListenerWWW = require('EventListener');
import typeof * as EventListenerType from '../EventListener';
import typeof * as EventListenerShimType from './EventListener-www';
const NORMAL_PRIORITY = 0;
export function addEventBubbleListener(
element: Element,
eventType: string,
@@ -30,18 +28,17 @@ export function addEventCaptureListener(
EventListenerWWW.capture(element, eventType, listener);
}
export function addEventListener(
export function addEventCaptureListenerWithPassiveFlag(
element: Element,
eventType: string,
listener: Function,
options: {passive: boolean},
passive: boolean,
): void {
EventListenerWWW.listen(
EventListenerWWW.captureWithPassiveFlag(
element,
eventType,
listener,
NORMAL_PRIORITY,
options,
passive,
);
}

View File

@@ -34,7 +34,7 @@ events, and implement a state machine.
// types
type ResponderEventType =
| string
| {name: string, passive?: boolean, capture?: boolean};
| {name: string, passive?: boolean};
type ResponderEvent = {|
nativeEvent: any,

View File

@@ -36,8 +36,8 @@ type FocusEvent = {|
|};
const targetEventTypes = [
{name: 'focus', passive: true, capture: true},
{name: 'blur', passive: true, capture: true},
{name: 'focus', passive: true},
{name: 'blur', passive: true},
];
const rootEventTypes = [

View File

@@ -25,7 +25,7 @@ type FocusScopeState = {
};
const targetEventTypes = [{name: 'keydown', passive: false}];
const rootEventTypes = [{name: 'focus', passive: true, capture: true}];
const rootEventTypes = [{name: 'focus', passive: true}];
function focusElement(element: ?HTMLElement) {
if (element != null) {

View File

@@ -1269,13 +1269,13 @@ describe('Event responder: Press', () => {
createPointerEvent('pointerup', {pageX: 10, pageY: 10}),
);
expect(events).toEqual([
'pointerdown',
'inner: onPressStart',
'inner: onPressChange',
'pointerup',
'pointerdown',
'inner: onPressEnd',
'inner: onPressChange',
'inner: onPress',
'pointerup',
]);
});

View File

@@ -83,7 +83,7 @@ export type RefObject = {|
export type ReactEventResponderEventType =
| string
| {name: string, passive?: boolean, capture?: boolean};
| {name: string, passive?: boolean};
export type ReactEventResponder = {
targetEventTypes?: Array<ReactEventResponderEventType>,

View File

@@ -39,5 +39,11 @@ declare module 'EventListener' {
options?: {passive: boolean},
) => mixed,
capture: (target: Element, type: string, callback: Function) => mixed,
captureWithPassiveFlag: (
target: Element,
type: string,
callback: Function,
passive: boolean,
) => mixed,
};
}