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

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

Merged
merged 6 commits into from
Apr 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 1 addition & 2 deletions packages/events/EventSystemFlags.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
12 changes: 1 addition & 11 deletions packages/react-dom/src/client/ReactDOMComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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);
Expand Down
30 changes: 2 additions & 28 deletions packages/react-dom/src/events/DOMEventResponderSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import {
type EventSystemFlags,
IS_PASSIVE,
IS_CAPTURE,
PASSIVE_NOT_SUPPORTED,
} from 'events/EventSystemFlags';
import type {AnyNativeEvent} from 'events/PluginModuleType';
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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,
);
Expand Down Expand Up @@ -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}`;
}
9 changes: 6 additions & 3 deletions packages/react-dom/src/events/EventListener.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
}
21 changes: 11 additions & 10 deletions packages/react-dom/src/events/ReactDOMEventListener.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -168,7 +167,6 @@ export function trapCapturedEvent(
export function trapEventForResponderEventSystem(
element: Document | Element | Node,
topLevelType: DOMTopLevelEventType,
capture: boolean,
passive: boolean,
): void {
if (enableEventAPI) {
Expand All @@ -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);
}
}
}

Expand Down
11 changes: 4 additions & 7 deletions packages/react-dom/src/events/forks/EventListener-www.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/react-events/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions packages/react-events/src/Focus.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,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},
];

function createFocusEvent(
Expand Down
2 changes: 1 addition & 1 deletion packages/react-events/src/FocusScope.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions packages/react-events/src/__tests__/Press-test.internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
]);
});

Expand Down
2 changes: 1 addition & 1 deletion packages/shared/ReactTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
6 changes: 6 additions & 0 deletions scripts/flow/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
}