mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
Event API: normalize event timeStamp property to be in event system (#15598)
This commit is contained in:
+21
-6
@@ -64,6 +64,7 @@ type ResponderTimer = {|
|
||||
instance: ReactEventComponentInstance,
|
||||
func: () => void,
|
||||
id: Symbol,
|
||||
timeStamp: number,
|
||||
|};
|
||||
|
||||
const activeTimeouts: Map<Symbol, ResponderTimeout> = new Map();
|
||||
@@ -90,6 +91,7 @@ const responderOwners: Map<
|
||||
> = new Map();
|
||||
let globalOwner = null;
|
||||
|
||||
let currentTimeStamp = 0;
|
||||
let currentTimers = new Map();
|
||||
let currentInstance: null | ReactEventComponentInstance = null;
|
||||
let currentEventQueue: null | EventQueue = null;
|
||||
@@ -101,11 +103,11 @@ const eventResponderContext: ReactResponderContext = {
|
||||
{discrete}: ReactResponderDispatchEventOptions,
|
||||
): void {
|
||||
validateResponderContext();
|
||||
const {target, type} = possibleEventObject;
|
||||
const {target, type, timeStamp} = possibleEventObject;
|
||||
|
||||
if (target == null || type == null) {
|
||||
if (target == null || type == null || timeStamp == null) {
|
||||
throw new Error(
|
||||
'context.dispatchEvent: "target" and "type" fields on event object are required.',
|
||||
'context.dispatchEvent: "target", "timeStamp", and "type" fields on event object are required.',
|
||||
);
|
||||
}
|
||||
if (__DEV__) {
|
||||
@@ -313,7 +315,7 @@ const eventResponderContext: ReactResponderContext = {
|
||||
if (timeout === undefined) {
|
||||
const timers = new Map();
|
||||
const id = setTimeout(() => {
|
||||
processTimers(timers);
|
||||
processTimers(timers, delay);
|
||||
}, delay);
|
||||
timeout = {
|
||||
id,
|
||||
@@ -325,6 +327,7 @@ const eventResponderContext: ReactResponderContext = {
|
||||
instance: ((currentInstance: any): ReactEventComponentInstance),
|
||||
func,
|
||||
id: timerId,
|
||||
timeStamp: currentTimeStamp,
|
||||
});
|
||||
activeTimeouts.set(timerId, timeout);
|
||||
return timerId;
|
||||
@@ -408,6 +411,9 @@ const eventResponderContext: ReactResponderContext = {
|
||||
}
|
||||
return currentTarget;
|
||||
},
|
||||
getTimeStamp(): number {
|
||||
return currentTimeStamp;
|
||||
},
|
||||
};
|
||||
|
||||
function isTargetWithinEventComponent(target: Element | Document): boolean {
|
||||
@@ -478,13 +484,17 @@ function isFiberHostComponentFocusable(fiber: Fiber): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function processTimers(timers: Map<Symbol, ResponderTimer>): void {
|
||||
function processTimers(
|
||||
timers: Map<Symbol, ResponderTimer>,
|
||||
delay: number,
|
||||
): void {
|
||||
const timersArr = Array.from(timers.values());
|
||||
currentEventQueue = createEventQueue();
|
||||
try {
|
||||
for (let i = 0; i < timersArr.length; i++) {
|
||||
const {instance, func, id} = timersArr[i];
|
||||
const {instance, func, id, timeStamp} = timersArr[i];
|
||||
currentInstance = instance;
|
||||
currentTimeStamp = timeStamp + delay;
|
||||
try {
|
||||
func();
|
||||
} finally {
|
||||
@@ -496,6 +506,7 @@ function processTimers(timers: Map<Symbol, ResponderTimer>): void {
|
||||
currentTimers = null;
|
||||
currentInstance = null;
|
||||
currentEventQueue = null;
|
||||
currentTimeStamp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -861,8 +872,11 @@ export function dispatchEventForResponderEventSystem(
|
||||
const previousEventQueue = currentEventQueue;
|
||||
const previousInstance = currentInstance;
|
||||
const previousTimers = currentTimers;
|
||||
const previousTimeStamp = currentTimeStamp;
|
||||
currentTimers = null;
|
||||
currentEventQueue = createEventQueue();
|
||||
// We might want to control timeStamp another way here
|
||||
currentTimeStamp = (nativeEvent: any).timeStamp;
|
||||
try {
|
||||
traverseAndHandleEventResponderInstances(
|
||||
topLevelType,
|
||||
@@ -876,6 +890,7 @@ export function dispatchEventForResponderEventSystem(
|
||||
currentTimers = previousTimers;
|
||||
currentInstance = previousInstance;
|
||||
currentEventQueue = previousEventQueue;
|
||||
currentTimeStamp = previousTimeStamp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,6 +422,7 @@ describe('DOMEventResponderSystem', () => {
|
||||
target: event.target,
|
||||
type: 'magicclick',
|
||||
phase: 'bubble',
|
||||
timeStamp: context.getTimeStamp(),
|
||||
};
|
||||
context.dispatchEvent(syntheticEvent, props.onMagicClick, {
|
||||
discrete: true,
|
||||
@@ -434,6 +435,7 @@ describe('DOMEventResponderSystem', () => {
|
||||
target: event.target,
|
||||
type: 'magicclick',
|
||||
phase: 'capture',
|
||||
timeStamp: context.getTimeStamp(),
|
||||
};
|
||||
context.dispatchEvent(syntheticEvent, props.onMagicClick, {
|
||||
discrete: true,
|
||||
@@ -477,6 +479,7 @@ describe('DOMEventResponderSystem', () => {
|
||||
target: event.target,
|
||||
type: 'press',
|
||||
phase,
|
||||
timeStamp: context.getTimeStamp(),
|
||||
};
|
||||
context.dispatchEvent(pressEvent, props.onPress, {discrete: true});
|
||||
|
||||
@@ -486,6 +489,7 @@ describe('DOMEventResponderSystem', () => {
|
||||
target: event.target,
|
||||
type: 'longpress',
|
||||
phase,
|
||||
timeStamp: context.getTimeStamp(),
|
||||
};
|
||||
context.dispatchEvent(longPressEvent, props.onLongPress, {
|
||||
discrete: true,
|
||||
@@ -497,6 +501,7 @@ describe('DOMEventResponderSystem', () => {
|
||||
target: event.target,
|
||||
type: 'longpresschange',
|
||||
phase,
|
||||
timeStamp: context.getTimeStamp(),
|
||||
};
|
||||
context.dispatchEvent(longPressChangeEvent, props.onLongPressChange, {
|
||||
discrete: true,
|
||||
@@ -901,6 +906,7 @@ describe('DOMEventResponderSystem', () => {
|
||||
const syntheticEvent = {
|
||||
target: event.target,
|
||||
type: 'click',
|
||||
timeStamp: context.getTimeStamp(),
|
||||
};
|
||||
context.dispatchEvent(syntheticEvent, props.onClick, {
|
||||
discrete: true,
|
||||
|
||||
Vendored
+4
-1
@@ -50,11 +50,13 @@ type DragEventType = 'dragstart' | 'dragend' | 'dragchange' | 'dragmove';
|
||||
type DragEvent = {|
|
||||
target: Element | Document,
|
||||
type: DragEventType,
|
||||
timeStamp: number,
|
||||
diffX?: number,
|
||||
diffY?: number,
|
||||
|};
|
||||
|
||||
function createDragEvent(
|
||||
context: ReactResponderContext,
|
||||
type: DragEventType,
|
||||
target: Element | Document,
|
||||
eventData?: EventData,
|
||||
@@ -62,6 +64,7 @@ function createDragEvent(
|
||||
return {
|
||||
target,
|
||||
type,
|
||||
timeStamp: context.getTimeStamp(),
|
||||
...eventData,
|
||||
};
|
||||
}
|
||||
@@ -75,7 +78,7 @@ function dispatchDragEvent(
|
||||
eventData?: EventData,
|
||||
): void {
|
||||
const target = ((state.dragTarget: any): Element | Document);
|
||||
const syntheticEvent = createDragEvent(name, target, eventData);
|
||||
const syntheticEvent = createDragEvent(context, name, target, eventData);
|
||||
context.dispatchEvent(syntheticEvent, listener, {discrete});
|
||||
}
|
||||
|
||||
|
||||
Vendored
+17
-6
@@ -33,6 +33,7 @@ type FocusEventType = 'focus' | 'blur' | 'focuschange' | 'focusvisiblechange';
|
||||
type FocusEvent = {|
|
||||
target: Element | Document,
|
||||
type: FocusEventType,
|
||||
timeStamp: number,
|
||||
|};
|
||||
|
||||
const targetEventTypes = [
|
||||
@@ -56,12 +57,14 @@ const rootEventTypes = [
|
||||
];
|
||||
|
||||
function createFocusEvent(
|
||||
context: ReactResponderContext,
|
||||
type: FocusEventType,
|
||||
target: Element | Document,
|
||||
): FocusEvent {
|
||||
return {
|
||||
target,
|
||||
type,
|
||||
timeStamp: context.getTimeStamp(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -72,21 +75,25 @@ function dispatchFocusInEvents(
|
||||
) {
|
||||
const target = ((state.focusTarget: any): Element | Document);
|
||||
if (props.onFocus) {
|
||||
const syntheticEvent = createFocusEvent('focus', target);
|
||||
const syntheticEvent = createFocusEvent(context, 'focus', target);
|
||||
context.dispatchEvent(syntheticEvent, props.onFocus, {discrete: true});
|
||||
}
|
||||
if (props.onFocusChange) {
|
||||
const listener = () => {
|
||||
props.onFocusChange(true);
|
||||
};
|
||||
const syntheticEvent = createFocusEvent('focuschange', target);
|
||||
const syntheticEvent = createFocusEvent(context, 'focuschange', target);
|
||||
context.dispatchEvent(syntheticEvent, listener, {discrete: true});
|
||||
}
|
||||
if (props.onFocusVisibleChange && state.isLocalFocusVisible) {
|
||||
const listener = () => {
|
||||
props.onFocusVisibleChange(true);
|
||||
};
|
||||
const syntheticEvent = createFocusEvent('focusvisiblechange', target);
|
||||
const syntheticEvent = createFocusEvent(
|
||||
context,
|
||||
'focusvisiblechange',
|
||||
target,
|
||||
);
|
||||
context.dispatchEvent(syntheticEvent, listener, {discrete: true});
|
||||
}
|
||||
}
|
||||
@@ -98,14 +105,14 @@ function dispatchFocusOutEvents(
|
||||
) {
|
||||
const target = ((state.focusTarget: any): Element | Document);
|
||||
if (props.onBlur) {
|
||||
const syntheticEvent = createFocusEvent('blur', target);
|
||||
const syntheticEvent = createFocusEvent(context, 'blur', target);
|
||||
context.dispatchEvent(syntheticEvent, props.onBlur, {discrete: true});
|
||||
}
|
||||
if (props.onFocusChange) {
|
||||
const listener = () => {
|
||||
props.onFocusChange(false);
|
||||
};
|
||||
const syntheticEvent = createFocusEvent('focuschange', target);
|
||||
const syntheticEvent = createFocusEvent(context, 'focuschange', target);
|
||||
context.dispatchEvent(syntheticEvent, listener, {discrete: true});
|
||||
}
|
||||
dispatchFocusVisibleOutEvent(context, props, state);
|
||||
@@ -121,7 +128,11 @@ function dispatchFocusVisibleOutEvent(
|
||||
const listener = () => {
|
||||
props.onFocusVisibleChange(false);
|
||||
};
|
||||
const syntheticEvent = createFocusEvent('focusvisiblechange', target);
|
||||
const syntheticEvent = createFocusEvent(
|
||||
context,
|
||||
'focusvisiblechange',
|
||||
target,
|
||||
);
|
||||
context.dispatchEvent(syntheticEvent, listener, {discrete: true});
|
||||
state.isLocalFocusVisible = false;
|
||||
}
|
||||
|
||||
Vendored
+7
@@ -42,6 +42,7 @@ type HoverEventType = 'hoverstart' | 'hoverend' | 'hoverchange' | 'hovermove';
|
||||
type HoverEvent = {|
|
||||
target: Element | Document,
|
||||
type: HoverEventType,
|
||||
timeStamp: number,
|
||||
|};
|
||||
|
||||
const DEFAULT_HOVER_END_DELAY_MS = 0;
|
||||
@@ -60,12 +61,14 @@ if (typeof window !== 'undefined' && window.PointerEvent === undefined) {
|
||||
}
|
||||
|
||||
function createHoverEvent(
|
||||
context: ReactResponderContext,
|
||||
type: HoverEventType,
|
||||
target: Element | Document,
|
||||
): HoverEvent {
|
||||
return {
|
||||
target,
|
||||
type,
|
||||
timeStamp: context.getTimeStamp(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -79,6 +82,7 @@ function dispatchHoverChangeEvent(
|
||||
props.onHoverChange(bool);
|
||||
};
|
||||
const syntheticEvent = createHoverEvent(
|
||||
context,
|
||||
'hoverchange',
|
||||
((state.hoverTarget: any): Element | Document),
|
||||
);
|
||||
@@ -115,6 +119,7 @@ function dispatchHoverStartEvents(
|
||||
|
||||
if (props.onHoverStart) {
|
||||
const syntheticEvent = createHoverEvent(
|
||||
context,
|
||||
'hoverstart',
|
||||
((target: any): Element | Document),
|
||||
);
|
||||
@@ -174,6 +179,7 @@ function dispatchHoverEndEvents(
|
||||
|
||||
if (props.onHoverEnd) {
|
||||
const syntheticEvent = createHoverEvent(
|
||||
context,
|
||||
'hoverend',
|
||||
((target: any): Element | Document),
|
||||
);
|
||||
@@ -311,6 +317,7 @@ const HoverResponder = {
|
||||
} else {
|
||||
if (props.onHoverMove && state.hoverTarget !== null) {
|
||||
const syntheticEvent = createHoverEvent(
|
||||
context,
|
||||
'hovermove',
|
||||
state.hoverTarget,
|
||||
);
|
||||
|
||||
Vendored
+20
-62
@@ -84,7 +84,7 @@ type PressEvent = {|
|
||||
target: Element | Document,
|
||||
type: PressEventType,
|
||||
pointerType: PointerType,
|
||||
timeStamp: null | number,
|
||||
timeStamp: number,
|
||||
clientX: null | number,
|
||||
clientY: null | number,
|
||||
pageX: null | number,
|
||||
@@ -135,23 +135,22 @@ if (typeof window !== 'undefined' && window.PointerEvent === undefined) {
|
||||
}
|
||||
|
||||
function createPressEvent(
|
||||
context: ReactResponderContext,
|
||||
type: PressEventType,
|
||||
target: Element | Document,
|
||||
pointerType: PointerType,
|
||||
event: ?ReactResponderEvent,
|
||||
delay: number,
|
||||
): PressEvent {
|
||||
const timeStamp = context.getTimeStamp();
|
||||
let clientX = null;
|
||||
let clientY = null;
|
||||
let pageX = null;
|
||||
let pageY = null;
|
||||
let screenX = null;
|
||||
let screenY = null;
|
||||
let timeStamp = null;
|
||||
|
||||
if (event) {
|
||||
const nativeEvent = (event.nativeEvent: any);
|
||||
timeStamp = nativeEvent.timeStamp + delay;
|
||||
// Only check for one property, checking for all of them is costly. We can assume
|
||||
// if clientX exists, so do the rest.
|
||||
let eventObject;
|
||||
@@ -185,16 +184,15 @@ function dispatchEvent(
|
||||
name: PressEventType,
|
||||
listener: (e: Object) => void,
|
||||
discrete: boolean,
|
||||
delay: number,
|
||||
): void {
|
||||
const target = ((state.pressTarget: any): Element | Document);
|
||||
const pointerType = state.pointerType;
|
||||
const syntheticEvent = createPressEvent(
|
||||
context,
|
||||
name,
|
||||
target,
|
||||
pointerType,
|
||||
event,
|
||||
delay,
|
||||
);
|
||||
context.dispatchEvent(syntheticEvent, listener, {
|
||||
discrete,
|
||||
@@ -206,13 +204,12 @@ function dispatchPressChangeEvent(
|
||||
context: ReactResponderContext,
|
||||
props: PressProps,
|
||||
state: PressState,
|
||||
delay: number,
|
||||
): void {
|
||||
const bool = state.isActivePressed;
|
||||
const listener = () => {
|
||||
props.onPressChange(bool);
|
||||
};
|
||||
dispatchEvent(event, context, state, 'presschange', listener, true, delay);
|
||||
dispatchEvent(event, context, state, 'presschange', listener, true);
|
||||
}
|
||||
|
||||
function dispatchLongPressChangeEvent(
|
||||
@@ -220,30 +217,15 @@ function dispatchLongPressChangeEvent(
|
||||
context: ReactResponderContext,
|
||||
props: PressProps,
|
||||
state: PressState,
|
||||
delay: number,
|
||||
): void {
|
||||
const bool = state.isLongPressed;
|
||||
const listener = () => {
|
||||
props.onLongPressChange(bool);
|
||||
};
|
||||
dispatchEvent(
|
||||
event,
|
||||
context,
|
||||
state,
|
||||
'longpresschange',
|
||||
listener,
|
||||
true,
|
||||
delay,
|
||||
);
|
||||
dispatchEvent(event, context, state, 'longpresschange', listener, true);
|
||||
}
|
||||
|
||||
function activate(
|
||||
event: ReactResponderEvent,
|
||||
context,
|
||||
props,
|
||||
state,
|
||||
delay: number,
|
||||
) {
|
||||
function activate(event: ReactResponderEvent, context, props, state) {
|
||||
const nativeEvent: any = event.nativeEvent;
|
||||
const {x, y} = getEventPageCoords(nativeEvent);
|
||||
const wasActivePressed = state.isActivePressed;
|
||||
@@ -263,41 +245,26 @@ function activate(
|
||||
'pressstart',
|
||||
props.onPressStart,
|
||||
true,
|
||||
delay,
|
||||
);
|
||||
}
|
||||
if (!wasActivePressed && props.onPressChange) {
|
||||
dispatchPressChangeEvent(event, context, props, state, delay);
|
||||
dispatchPressChangeEvent(event, context, props, state);
|
||||
}
|
||||
}
|
||||
|
||||
function deactivate(
|
||||
event: ?ReactResponderEvent,
|
||||
context,
|
||||
props,
|
||||
state,
|
||||
delay: number,
|
||||
) {
|
||||
function deactivate(event: ?ReactResponderEvent, context, props, state) {
|
||||
const wasLongPressed = state.isLongPressed;
|
||||
state.isActivePressed = false;
|
||||
state.isLongPressed = false;
|
||||
|
||||
if (props.onPressEnd) {
|
||||
dispatchEvent(
|
||||
event,
|
||||
context,
|
||||
state,
|
||||
'pressend',
|
||||
props.onPressEnd,
|
||||
true,
|
||||
delay,
|
||||
);
|
||||
dispatchEvent(event, context, state, 'pressend', props.onPressEnd, true);
|
||||
}
|
||||
if (props.onPressChange) {
|
||||
dispatchPressChangeEvent(event, context, props, state, delay);
|
||||
dispatchPressChangeEvent(event, context, props, state);
|
||||
}
|
||||
if (wasLongPressed && props.onLongPressChange) {
|
||||
dispatchLongPressChangeEvent(event, context, props, state, delay);
|
||||
dispatchLongPressChangeEvent(event, context, props, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,9 +281,9 @@ function dispatchPressStartEvents(
|
||||
state.pressEndTimeout = null;
|
||||
}
|
||||
|
||||
const dispatch = (delay: number) => {
|
||||
const dispatch = () => {
|
||||
state.isActivePressStart = true;
|
||||
activate(event, context, props, state, delay);
|
||||
activate(event, context, props, state);
|
||||
|
||||
if (
|
||||
(props.onLongPress || props.onLongPressChange) &&
|
||||
@@ -338,17 +305,10 @@ function dispatchPressStartEvents(
|
||||
'longpress',
|
||||
props.onLongPress,
|
||||
true,
|
||||
delayLongPress + delay,
|
||||
);
|
||||
}
|
||||
if (props.onLongPressChange) {
|
||||
dispatchLongPressChangeEvent(
|
||||
event,
|
||||
context,
|
||||
props,
|
||||
state,
|
||||
delayLongPress + delay,
|
||||
);
|
||||
dispatchLongPressChangeEvent(event, context, props, state);
|
||||
}
|
||||
}, delayLongPress);
|
||||
}
|
||||
@@ -363,10 +323,10 @@ function dispatchPressStartEvents(
|
||||
if (delayPressStart > 0) {
|
||||
state.pressStartTimeout = context.setTimeout(() => {
|
||||
state.pressStartTimeout = null;
|
||||
dispatch(delayPressStart);
|
||||
dispatch();
|
||||
}, delayPressStart);
|
||||
} else {
|
||||
dispatch(0);
|
||||
dispatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -394,7 +354,7 @@ function dispatchPressEndEvents(
|
||||
// don't activate if a press has moved beyond the responder region
|
||||
if (state.isPressWithinResponderRegion && event != null) {
|
||||
// if we haven't yet activated (due to delays), activate now
|
||||
activate(event, context, props, state, 0);
|
||||
activate(event, context, props, state);
|
||||
activationWasForced = true;
|
||||
}
|
||||
}
|
||||
@@ -411,10 +371,10 @@ function dispatchPressEndEvents(
|
||||
if (delayPressEnd > 0) {
|
||||
state.pressEndTimeout = context.setTimeout(() => {
|
||||
state.pressEndTimeout = null;
|
||||
deactivate(event, context, props, state, delayPressEnd);
|
||||
deactivate(event, context, props, state);
|
||||
}, delayPressEnd);
|
||||
} else {
|
||||
deactivate(event, context, props, state, 0);
|
||||
deactivate(event, context, props, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -758,7 +718,6 @@ const PressResponder = {
|
||||
'pressmove',
|
||||
props.onPressMove,
|
||||
false,
|
||||
0,
|
||||
);
|
||||
}
|
||||
if (
|
||||
@@ -843,7 +802,6 @@ const PressResponder = {
|
||||
'press',
|
||||
props.onPress,
|
||||
true,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+4
-1
@@ -40,11 +40,13 @@ type SwipeEventType = 'swipeleft' | 'swiperight' | 'swipeend' | 'swipemove';
|
||||
type SwipeEvent = {|
|
||||
target: Element | Document,
|
||||
type: SwipeEventType,
|
||||
timeStamp: number,
|
||||
diffX?: number,
|
||||
diffY?: number,
|
||||
|};
|
||||
|
||||
function createSwipeEvent(
|
||||
context: ReactResponderContext,
|
||||
type: SwipeEventType,
|
||||
target: Element | Document,
|
||||
eventData?: EventData,
|
||||
@@ -52,6 +54,7 @@ function createSwipeEvent(
|
||||
return {
|
||||
target,
|
||||
type,
|
||||
timeStamp: context.getTimeStamp(),
|
||||
...eventData,
|
||||
};
|
||||
}
|
||||
@@ -65,7 +68,7 @@ function dispatchSwipeEvent(
|
||||
eventData?: EventData,
|
||||
) {
|
||||
const target = ((state.swipeTarget: any): Element | Document);
|
||||
const syntheticEvent = createSwipeEvent(name, target, eventData);
|
||||
const syntheticEvent = createSwipeEvent(context, name, target, eventData);
|
||||
context.dispatchEvent(syntheticEvent, listener, {discrete});
|
||||
}
|
||||
|
||||
|
||||
@@ -193,4 +193,5 @@ export type ReactResponderContext = {
|
||||
event: ReactResponderEvent,
|
||||
): '' | 'mouse' | 'keyboard' | 'pen' | 'touch',
|
||||
getEventCurrentTarget(event: ReactResponderEvent): Element,
|
||||
getTimeStamp: () => number,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user