@samitouri / QOS-React / commits / 9307932fe5

Refactor event object creation for the experimental event API (#15295)

* Refactor event object creation for the experimental event API

Dominic Gannaway committed Apr 2, 2019 at 20:03 UTC 9307932fe5b59c2d5ce8d04823b94ec0e48b206e
9 files changed +348 -147
packages/events/EventTypes.js
+14 -14
@@ -7,29 +7,29 @@
7 * @flow
8 */
9
10 -import SyntheticEvent from 'events/SyntheticEvent';
10 import type {AnyNativeEvent} from 'events/PluginModuleType';
11 import type {ReactEventResponderEventType} from 'shared/ReactTypes';
12
13 export type EventResponderContext = {
14 event: AnyNativeEvent,
16 - eventTarget: EventTarget,
15 + eventTarget: Element | Document,
16 eventType: string,
17 isPassive: () => boolean,
18 isPassiveSupported: () => boolean,
20 - dispatchEvent: (
21 - name: string,
22 - listener: (e: SyntheticEvent) => void | null,
23 - pressTarget: EventTarget | null,
24 - discrete: boolean,
25 - extraProperties?: Object,
19 + dispatchEvent: <E>(
20 + eventObject: E,
21 + {
22 + capture?: boolean,
23 + discrete?: boolean,
24 + stopPropagation?: boolean,
25 + },
26 ) => void,
27 isTargetWithinElement: (
28 - childTarget: EventTarget,
29 - parentTarget: EventTarget,
28 + childTarget: Element | Document,
29 + parentTarget: Element | Document,
30 ) => boolean,
31 - isTargetOwned: EventTarget => boolean,
32 - isTargetWithinEventComponent: EventTarget => boolean,
31 + isTargetOwned: (Element | Document) => boolean,
32 + isTargetWithinEventComponent: (Element | Document) => boolean,
33 isPositionWithinTouchHitTarget: (x: number, y: number) => boolean,
34 addRootEventTypes: (
35 rootEventTypes: Array<ReactEventResponderEventType>,
@@ -37,6 +37,6 @@ export type EventResponderContext = {
37 removeRootEventTypes: (
38 rootEventTypes: Array<ReactEventResponderEventType>,
39 ) => void,
40 - requestOwnership: (target: EventTarget | null) => boolean,
41 - releaseOwnership: (target: EventTarget | null) => boolean,
40 + requestOwnership: (target: Element | Document | null) => boolean,
41 + releaseOwnership: (target: Element | Document | null) => boolean,
42 };
packages/react-dom/src/events/DOMEventResponderSystem.js
+132 -58
@@ -18,15 +18,13 @@ import type {
18 ReactEventResponderEventType,
19 } from 'shared/ReactTypes';
20 import type {DOMTopLevelEventType} from 'events/TopLevelEventTypes';
21 -import SyntheticEvent from 'events/SyntheticEvent';
22 -import {runEventsInBatch} from 'events/EventBatching';
23 -import {interactiveUpdates} from 'events/ReactGenericBatching';
24 -import {executeDispatch} from 'events/EventPluginUtils';
21 +import {batchedUpdates, interactiveUpdates} from 'events/ReactGenericBatching';
22 import type {Fiber} from 'react-reconciler/src/ReactFiber';
26 -
23 import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
24
25 import {enableEventAPI} from 'shared/ReactFeatureFlags';
26 +import {invokeGuardedCallbackAndCatchFirstError} from 'shared/ReactErrorUtils';
27 +import warning from 'shared/warning';
28
29 let listenToResponderEventTypesImpl;
30
@@ -36,6 +34,8 @@ export function setListenToResponderEventTypes(
34 listenToResponderEventTypesImpl = _listenToResponderEventTypesImpl;
35 }
36
37 +const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set;
38 +
39 const rootEventTypesToEventComponents: Map<
40 DOMTopLevelEventType | string,
41 Set<Fiber>,
@@ -45,12 +45,76 @@ const targetEventTypeCached: Map<
45 Set<DOMTopLevelEventType>,
46 > = new Map();
47 const targetOwnership: Map<EventTarget, Fiber> = new Map();
48 +const eventsWithStopPropagation:
49 + | WeakSet
50 + | Set<$Shape<PartialEventObject>> = new PossiblyWeakSet();
51 +
52 +type PartialEventObject = {
53 + listener: ($Shape<PartialEventObject>) => void,
54 + target: Element | Document,
55 + type: string,
56 +};
57 +type EventQueue = {
58 + bubble: null | Array<$Shape<PartialEventObject>>,
59 + capture: null | Array<$Shape<PartialEventObject>>,
60 + discrete: boolean,
61 + phase: EventQueuePhase,
62 +};
63 +type EventQueuePhase = 0 | 1;
64 +
65 +const DURING_EVENT_PHASE = 0;
66 +const AFTER_EVENT_PHASE = 1;
67
49 -type EventListener = (event: SyntheticEvent) => void;
68 +function createEventQueue(phase: EventQueuePhase): EventQueue {
69 + return {
70 + bubble: null,
71 + capture: null,
72 + discrete: false,
73 + phase,
74 + };
75 +}
76 +
77 +function processEvent(event: $Shape<PartialEventObject>): void {
78 + const type = event.type;
79 + const listener = event.listener;
80 + invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event);
81 +}
82
51 -function copyEventProperties(eventData, syntheticEvent) {
52 - for (let propName in eventData) {
53 - syntheticEvent[propName] = eventData[propName];
83 +function processEvents(
84 + bubble: null | Array<$Shape<PartialEventObject>>,
85 + capture: null | Array<$Shape<PartialEventObject>>,
86 +): void {
87 + let i, length;
88 +
89 + if (capture !== null) {
90 + for (i = capture.length; i-- > 0; ) {
91 + const event = capture[i];
92 + processEvent(capture[i]);
93 + if (eventsWithStopPropagation.has(event)) {
94 + return;
95 + }
96 + }
97 + }
98 + if (bubble !== null) {
99 + for (i = 0, length = bubble.length; i < length; ++i) {
100 + const event = bubble[i];
101 + processEvent(event);
102 + if (eventsWithStopPropagation.has(event)) {
103 + return;
104 + }
105 + }
106 + }
107 +}
108 +
109 +function processEventQueue(eventQueue: EventQueue): void {
110 + const {bubble, capture, discrete} = eventQueue;
111 +
112 + if (discrete) {
113 + interactiveUpdates(() => {
114 + processEvents(bubble, capture);
115 + });
116 + } else {
117 + processEvents(bubble, capture);
118 }
119 }
120
@@ -70,6 +134,7 @@ function DOMEventResponderContext(
134 this._discreteEvents = null;
135 this._nonDiscreteEvents = null;
136 this._isBatching = true;
137 + this._eventQueue = createEventQueue(DURING_EVENT_PHASE);
138 }
139
140 DOMEventResponderContext.prototype.isPassive = function(): boolean {
@@ -81,49 +146,66 @@ DOMEventResponderContext.prototype.isPassiveSupported = function(): boolean {
146 };
147
148 DOMEventResponderContext.prototype.dispatchEvent = function(
84 - eventName: string,
85 - eventListener: EventListener,
86 - eventTarget: AnyNativeEvent,
87 - discrete: boolean,
88 - extraProperties?: Object,
149 + possibleEventObject: Object,
150 + {
151 + capture,
152 + discrete,
153 + stopPropagation,
154 + }: {
155 + capture?: boolean,
156 + discrete?: boolean,
157 + stopPropagation?: boolean,
158 + },
159 ): void {
90 - const eventTargetFiber = getClosestInstanceFromNode(eventTarget);
91 - const syntheticEvent = SyntheticEvent.getPooled(
92 - null,
93 - eventTargetFiber,
94 - this.event,
95 - eventTarget,
96 - );
97 - if (extraProperties !== undefined) {
98 - copyEventProperties(extraProperties, syntheticEvent);
160 + const eventQueue = this._eventQueue;
161 + const {listener, target, type} = possibleEventObject;
162 +
163 + if (listener == null || target == null || type == null) {
164 + throw new Error(
165 + 'context.dispatchEvent: "listener", "target" and "type" fields on event object are required.',
166 + );
167 }
100 - syntheticEvent.type = eventName;
101 - syntheticEvent._dispatchInstances = [eventTargetFiber];
102 - syntheticEvent._dispatchListeners = [eventListener];
103 -
104 - if (this._isBatching) {
105 - let events;
106 - if (discrete) {
107 - events = this._discreteEvents;
108 - if (events === null) {
109 - events = this._discreteEvents = [];
110 - }
111 - } else {
112 - events = this._nonDiscreteEvents;
113 - if (events === null) {
114 - events = this._nonDiscreteEvents = [];
115 - }
168 + if (__DEV__) {
169 + possibleEventObject.preventDefault = () => {
170 + // Update this warning when we have a story around dealing with preventDefault
171 + warning(
172 + false,
173 + 'preventDefault() is no longer available on event objects created from event responder modules.',
174 + );
175 + };
176 + possibleEventObject.stopPropagation = () => {
177 + // Update this warning when we have a story around dealing with stopPropgation
178 + warning(
179 + false,
180 + 'stopPropagation() is no longer available on event objects created from event responder modules.',
181 + );
182 + };
183 + }
184 + const eventObject = ((possibleEventObject: any): $Shape<PartialEventObject>);
185 + let events;
186 +
187 + if (capture) {
188 + events = eventQueue.capture;
189 + if (events === null) {
190 + events = eventQueue.capture = [];
191 }
117 - events.push(syntheticEvent);
192 } else {
119 - if (discrete) {
120 - interactiveUpdates(() => {
121 - executeDispatch(syntheticEvent, eventListener, eventTargetFiber);
122 - });
123 - } else {
124 - executeDispatch(syntheticEvent, eventListener, eventTargetFiber);
193 + events = eventQueue.bubble;
194 + if (events === null) {
195 + events = eventQueue.bubble = [];
196 }
197 }
198 + if (discrete) {
199 + eventQueue.discrete = true;
200 + }
201 + events.push(eventObject);
202 +
203 + if (stopPropagation) {
204 + eventsWithStopPropagation.add(eventObject);
205 + }
206 + if (eventQueue.phase === AFTER_EVENT_PHASE) {
207 + batchedUpdates(processEventQueue, eventQueue);
208 + }
209 };
210
211 DOMEventResponderContext.prototype.isTargetWithinEventComponent = function(
@@ -318,17 +400,9 @@ export function runResponderEventsInBatch(
400 );
401 }
402 }
321 - // Run batched events
322 - const discreteEvents = context._discreteEvents;
323 - if (discreteEvents !== null) {
324 - interactiveUpdates(() => {
325 - runEventsInBatch(discreteEvents);
326 - });
327 - }
328 - const nonDiscreteEvents = context._nonDiscreteEvents;
329 - if (nonDiscreteEvents !== null) {
330 - runEventsInBatch(nonDiscreteEvents);
331 - }
332 - context._isBatching = false;
403 + processEventQueue(context._eventQueue);
404 + // In order to capture and process async events from responder modules
405 + // we create a new event queue.
406 + context._eventQueue = createEventQueue(AFTER_EVENT_PHASE);
407 }
408 }
packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js
+6 -6
@@ -228,12 +228,12 @@ describe('DOMEventResponderSystem', () => {
228 ['click'],
229 (context, props) => {
230 if (props.onMagicClick) {
231 - context.dispatchEvent(
232 - 'magicclick',
233 - props.onMagicClick,
234 - context.eventTarget,
235 - false,
236 - );
231 + const event = {
232 + listener: props.onMagicClick,
233 + target: context.eventTarget,
234 + type: 'magicclick',
235 + };
236 + context.dispatchEvent(event, {discrete: true});
237 }
238 },
239 );
packages/react-events/src/Drag.js
+41 -12
@@ -14,7 +14,7 @@ const targetEventTypes = ['pointerdown', 'pointercancel'];
14 const rootEventTypes = ['pointerup', {name: 'pointermove', passive: false}];
15
16 type DragState = {
17 - dragTarget: null | EventTarget,
17 + dragTarget: null | Element | Document,
18 isPointerDown: boolean,
19 isDragging: boolean,
20 startX: number,
@@ -33,18 +33,45 @@ if (typeof window !== 'undefined' && window.PointerEvent === undefined) {
33 });
34 }
35
36 +type EventData = {
37 + diffX: number,
38 + diffY: number,
39 +};
40 +type DragEventType = 'dragend' | 'dragchange' | 'dragmove';
41 +
42 +type DragEvent = {|
43 + listener: DragEvent => void,
44 + target: Element | Document,
45 + type: DragEventType,
46 + diffX?: number,
47 + diffY?: number,
48 +|};
49 +
50 +function createDragEvent(
51 + type: DragEventType,
52 + target: Element | Document,
53 + listener: DragEvent => void,
54 + eventData?: EventData,
55 +): DragEvent {
56 + return {
57 + listener,
58 + target,
59 + type,
60 + ...eventData,
61 + };
62 +}
63 +
64 function dispatchDragEvent(
65 context: EventResponderContext,
38 - name: string,
39 - listener: (e: Object) => void,
66 + name: DragEventType,
67 + listener: DragEvent => void,
68 state: DragState,
69 discrete: boolean,
42 - eventData?: {
43 - diffX: number,
44 - diffY: number,
45 - },
70 + eventData?: EventData,
71 ): void {
47 - context.dispatchEvent(name, listener, state.dragTarget, discrete, eventData);
72 + const target = ((state.dragTarget: any): Element | Document);
73 + const syntheticEvent = createDragEvent(name, target, listener, eventData);
74 + context.dispatchEvent(syntheticEvent, {discrete});
75 }
76
77 const DragResponder = {
@@ -112,10 +139,11 @@ const DragResponder = {
139 const dragChangeEventListener = () => {
140 props.onDragChange(true);
141 };
115 - context.dispatchEvent(
142 + dispatchDragEvent(
143 + context,
144 'dragchange',
145 dragChangeEventListener,
118 - state.dragTarget,
146 + state,
147 true,
148 );
149 }
@@ -160,10 +188,11 @@ const DragResponder = {
188 const dragChangeEventListener = () => {
189 props.onDragChange(false);
190 };
163 - context.dispatchEvent(
191 + dispatchDragEvent(
192 + context,
193 'dragchange',
194 dragChangeEventListener,
166 - state.dragTarget,
195 + state,
196 true,
197 );
198 }
packages/react-events/src/Focus.js
+34 -8
@@ -19,24 +19,49 @@ type FocusState = {
19 isFocused: boolean,
20 };
21
22 +type FocusEventType = 'focus' | 'blur' | 'focuschange';
23 +
24 +type FocusEvent = {|
25 + listener: FocusEvent => void,
26 + target: Element | Document,
27 + type: FocusEventType,
28 +|};
29 +
30 +function createFocusEvent(
31 + type: FocusEventType,
32 + target: Element | Document,
33 + listener: FocusEvent => void,
34 +): FocusEvent {
35 + return {
36 + listener,
37 + target,
38 + type,
39 + };
40 +}
41 +
42 function dispatchFocusInEvents(context: EventResponderContext, props: Object) {
43 const {event, eventTarget} = context;
44 if (context.isTargetWithinEventComponent((event: any).relatedTarget)) {
45 return;
46 }
47 if (props.onFocus) {
28 - context.dispatchEvent('focus', props.onFocus, eventTarget, true);
48 + const syntheticEvent = createFocusEvent(
49 + 'focus',
50 + eventTarget,
51 + props.onFocus,
52 + );
53 + context.dispatchEvent(syntheticEvent, {discrete: true});
54 }
55 if (props.onFocusChange) {
56 const focusChangeEventListener = () => {
57 props.onFocusChange(true);
58 };
34 - context.dispatchEvent(
59 + const syntheticEvent = createFocusEvent(
60 'focuschange',
36 - focusChangeEventListener,
61 eventTarget,
38 - true,
62 + focusChangeEventListener,
63 );
64 + context.dispatchEvent(syntheticEvent, {discrete: true});
65 }
66 }
67
@@ -46,18 +71,19 @@ function dispatchFocusOutEvents(context: EventResponderContext, props: Object) {
71 return;
72 }
73 if (props.onBlur) {
49 - context.dispatchEvent('blur', props.onBlur, eventTarget, true);
74 + const syntheticEvent = createFocusEvent('blur', eventTarget, props.onBlur);
75 + context.dispatchEvent(syntheticEvent, {discrete: true});
76 }
77 if (props.onFocusChange) {
78 const focusChangeEventListener = () => {
79 props.onFocusChange(false);
80 };
55 - context.dispatchEvent(
81 + const syntheticEvent = createFocusEvent(
82 'focuschange',
57 - focusChangeEventListener,
83 eventTarget,
59 - true,
84 + focusChangeEventListener,
85 );
86 + context.dispatchEvent(syntheticEvent, {discrete: true});
87 }
88 }
89
packages/react-events/src/Hover.js
+38 -8
@@ -23,6 +23,26 @@ type HoverState = {
23 isTouched: boolean,
24 };
25
26 +type HoverEventType = 'hoverstart' | 'hoverend' | 'hoverchange';
27 +
28 +type HoverEvent = {|
29 + listener: HoverEvent => void,
30 + target: Element | Document,
31 + type: HoverEventType,
32 +|};
33 +
34 +function createHoverEvent(
35 + type: HoverEventType,
36 + target: Element | Document,
37 + listener: HoverEvent => void,
38 +): HoverEvent {
39 + return {
40 + listener,
41 + target,
42 + type,
43 + };
44 +}
45 +
46 // In the case we don't have PointerEvents (Safari), we listen to touch events
47 // too
48 if (typeof window !== 'undefined' && window.PointerEvent === undefined) {
@@ -39,18 +59,23 @@ function dispatchHoverStartEvents(
59 return;
60 }
61 if (props.onHoverStart) {
42 - context.dispatchEvent('hoverstart', props.onHoverStart, eventTarget, true);
62 + const syntheticEvent = createHoverEvent(
63 + 'hoverstart',
64 + eventTarget,
65 + props.onHoverStart,
66 + );
67 + context.dispatchEvent(syntheticEvent, {discrete: true});
68 }
69 if (props.onHoverChange) {
70 const hoverChangeEventListener = () => {
71 props.onHoverChange(true);
72 };
48 - context.dispatchEvent(
73 + const syntheticEvent = createHoverEvent(
74 'hoverchange',
50 - hoverChangeEventListener,
75 eventTarget,
52 - true,
76 + hoverChangeEventListener,
77 );
78 + context.dispatchEvent(syntheticEvent, {discrete: true});
79 }
80 }
81
@@ -60,18 +85,23 @@ function dispatchHoverEndEvents(context: EventResponderContext, props: Object) {
85 return;
86 }
87 if (props.onHoverEnd) {
63 - context.dispatchEvent('hoverend', props.onHoverEnd, eventTarget, true);
88 + const syntheticEvent = createHoverEvent(
89 + 'hoverend',
90 + eventTarget,
91 + props.onHoverEnd,
92 + );
93 + context.dispatchEvent(syntheticEvent, {discrete: true});
94 }
95 if (props.onHoverChange) {
96 const hoverChangeEventListener = () => {
97 props.onHoverChange(false);
98 };
69 - context.dispatchEvent(
99 + const syntheticEvent = createHoverEvent(
100 'hoverchange',
71 - hoverChangeEventListener,
101 eventTarget,
73 - true,
102 + hoverChangeEventListener,
103 );
104 + context.dispatchEvent(syntheticEvent, {discrete: true});
105 }
106 }
107
packages/react-events/src/Press.js
+44 -31
@@ -36,13 +36,13 @@ type PressProps = {
36 delayLongPress: number,
37 delayPressEnd: number,
38 delayPressStart: number,
39 - onLongPress: (e: Object) => void,
39 + onLongPress: (e: PressEvent) => void,
40 onLongPressChange: boolean => void,
41 onLongPressShouldCancelPress: () => boolean,
42 - onPress: (e: Object) => void,
42 + onPress: (e: PressEvent) => void,
43 onPressChange: boolean => void,
44 - onPressEnd: (e: Object) => void,
45 - onPressStart: (e: Object) => void,
44 + onPressEnd: (e: PressEvent) => void,
45 + onPressStart: (e: PressEvent) => void,
46 pressRententionOffset: Object,
47 };
48
@@ -52,17 +52,45 @@ type PressState = {
52 isLongPressed: boolean,
53 isPressed: boolean,
54 longPressTimeout: null | TimeoutID,
55 - pressTarget: null | EventTarget,
55 + pressTarget: null | Element | Document,
56 shouldSkipMouseAfterTouch: boolean,
57 };
58
59 +type PressEventType =
60 + | 'press'
61 + | 'pressstart'
62 + | 'pressend'
63 + | 'presschange'
64 + | 'longpress'
65 + | 'longpresschange';
66 +
67 +type PressEvent = {|
68 + listener: PressEvent => void,
69 + target: Element | Document,
70 + type: PressEventType,
71 +|};
72 +
73 +function createPressEvent(
74 + type: PressEventType,
75 + target: Element | Document,
76 + listener: PressEvent => void,
77 +): PressEvent {
78 + return {
79 + listener,
80 + target,
81 + type,
82 + };
83 +}
84 +
85 function dispatchPressEvent(
86 context: EventResponderContext,
87 state: PressState,
62 - name: string,
88 + name: PressEventType,
89 listener: (e: Object) => void,
90 ): void {
65 - context.dispatchEvent(name, listener, state.pressTarget, true);
91 + const target = ((state.pressTarget: any): Element | Document);
92 + const syntheticEvent = createPressEvent(name, target, listener);
93 + context.dispatchEvent(syntheticEvent, {discrete: true});
94 }
95
96 function dispatchPressStartEvents(
@@ -97,9 +125,10 @@ function dispatchPressStartEvents(
125 if (props.onLongPress) {
126 const longPressEventListener = e => {
127 props.onLongPress(e);
100 - if (e.nativeEvent.defaultPrevented) {
101 - state.defaultPrevented = true;
102 - }
128 + // TODO address this again at some point
129 + // if (e.nativeEvent.defaultPrevented) {
130 + // state.defaultPrevented = true;
131 + // }
132 };
133 dispatchPressEvent(context, state, 'longpress', longPressEventListener);
134 }
@@ -193,24 +222,7 @@ const PressResponder = {
222 ) {
223 return;
224 }
196 - let keyPressEventListener = props.onPress;
197 -
198 - // Wrap listener with prevent default behaviour, unless
199 - // we are dealing with an anchor. Anchor tags are special beacuse
200 - // we need to use the "click" event, to properly allow browser
201 - // heuristics for cancelling link clicks. Furthermore, iOS and
202 - // Android can show previous of anchor tags that requires working
203 - // with click rather than touch events (and mouse down/up).
204 - if (!isAnchorTagElement(eventTarget)) {
205 - keyPressEventListener = e => {
206 - if (!e.isDefaultPrevented() && !e.nativeEvent.defaultPrevented) {
207 - e.preventDefault();
208 - state.defaultPrevented = true;
209 - props.onPress(e);
210 - }
211 - };
212 - }
213 - dispatchPressEvent(context, state, 'press', keyPressEventListener);
225 + dispatchPressEvent(context, state, 'press', props.onPress);
226 break;
227 }
228
@@ -332,9 +344,10 @@ const PressResponder = {
344 ) {
345 const pressEventListener = e => {
346 props.onPress(e);
335 - if (e.nativeEvent.defaultPrevented) {
336 - state.defaultPrevented = true;
337 - }
347 + // TODO address this again at some point
348 + // if (e.nativeEvent.defaultPrevented) {
349 + // state.defaultPrevented = true;
350 + // }
351 };
352 dispatchPressEvent(context, state, 'press', pressEventListener);
353 }
packages/react-events/src/Swipe.js
+35 -8
@@ -23,18 +23,45 @@ if (typeof window !== 'undefined' && window.PointerEvent === undefined) {
23 });
24 }
25
26 +type EventData = {
27 + diffX: number,
28 + diffY: number,
29 +};
30 +type SwipeEventType = 'swipeleft' | 'swiperight' | 'swipeend' | 'swipemove';
31 +
32 +type SwipeEvent = {|
33 + listener: SwipeEvent => void,
34 + target: Element | Document,
35 + type: SwipeEventType,
36 + diffX?: number,
37 + diffY?: number,
38 +|};
39 +
40 +function createSwipeEvent(
41 + type: SwipeEventType,
42 + target: Element | Document,
43 + listener: SwipeEvent => void,
44 + eventData?: EventData,
45 +): SwipeEvent {
46 + return {
47 + listener,
48 + target,
49 + type,
50 + ...eventData,
51 + };
52 +}
53 +
54 function dispatchSwipeEvent(
55 context: EventResponderContext,
28 - name: string,
29 - listener: (e: Object) => void,
56 + name: SwipeEventType,
57 + listener: SwipeEvent => void,
58 state: SwipeState,
59 discrete: boolean,
32 - eventData?: {
33 - diffX: number,
34 - diffY: number,
35 - },
60 + eventData?: EventData,
61 ) {
37 - context.dispatchEvent(name, listener, state.swipeTarget, discrete, eventData);
62 + const target = ((state.swipeTarget: any): Element | Document);
63 + const syntheticEvent = createSwipeEvent(name, target, listener, eventData);
64 + context.dispatchEvent(syntheticEvent, {discrete});
65 }
66
67 type SwipeState = {
@@ -44,7 +71,7 @@ type SwipeState = {
71 startX: number,
72 startY: number,
73 touchId: null | number,
47 - swipeTarget: null | EventTarget,
74 + swipeTarget: null | Element | Document,
75 x: number,
76 y: number,
77 };
packages/react-events/src/__tests__/Press-test.internal.js
+4 -2
@@ -388,8 +388,10 @@ describe('Event responder: Press', () => {
388
389 events = [];
390 ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
391 - // Outer press should not occur as inner press will preventDefault
392 - expect(events).toEqual(['keydown', 'inner: onPress']);
391 + // TODO update this test once we have a form of stopPropagation in
392 + // the responder system again. This test had to be updated because
393 + // we have removed stopPropagation() from synthetic events.
394 + expect(events).toEqual(['keydown', 'inner: onPress', 'outer: onPress']);
395 });
396 });
397 });