ResponderTouchHistoryStore into instanciated class

Refactor ResponderTouchHistoryStore from singleton to class instantiated
in ResponderSystem. This is a part of greater effort to enable support
for multiple browser windows

Close #2190
This commit is contained in:
Ondrej Zaruba
2022-01-03 12:03:51 +01:00
committed by Nicolas Gallagher
parent 32a4bf8e51
commit bbffe86fd6
3 changed files with 68 additions and 58 deletions

View File

@@ -150,7 +150,7 @@ import {
isPrimaryPointerDown,
setResponderId
} from './utils';
import ResponderTouchHistoryStore from './ResponderTouchHistoryStore';
import { ResponderTouchHistoryStore } from './ResponderTouchHistoryStore';
import canUseDOM from '../canUseDom';
/* ------------ TYPES ------------ */
@@ -232,6 +232,7 @@ let currentResponder: ResponderInstance = {
node: null,
idPath: null
};
const responderTouchHistoryStore = new ResponderTouchHistoryStore();
function changeCurrentResponder(responder: ResponderInstance) {
currentResponder = responder;
@@ -294,7 +295,10 @@ function eventListener(domEvent: any) {
const isEndEvent = isEndish(eventType);
const isScrollEvent = isScroll(eventType);
const isSelectionChangeEvent = isSelectionChange(eventType);
const responderEvent = createResponderEvent(domEvent);
const responderEvent = createResponderEvent(
domEvent,
responderTouchHistoryStore
);
/**
* Record the state of active pointers
@@ -310,7 +314,7 @@ function eventListener(domEvent: any) {
trackedTouchCount = 0;
}
}
ResponderTouchHistoryStore.recordTouchTrack(
responderTouchHistoryStore.recordTouchTrack(
eventType,
responderEvent.nativeEvent
);
@@ -665,7 +669,7 @@ export function terminateResponder() {
if (id != null && node != null) {
const { onResponderTerminate } = getResponderConfig(id);
if (onResponderTerminate != null) {
const event = createResponderEvent({});
const event = createResponderEvent({}, responderTouchHistoryStore);
event.currentTarget = node;
onResponderTerminate(event);
}

View File

@@ -11,18 +11,25 @@ import type { Touch, TouchEvent } from './ResponderEventTypes';
import { isStartish, isMoveish, isEndish } from './ResponderEventTypes';
type TouchRecord = {|
touchActive: boolean,
startPageX: number,
startPageY: number,
startTimeStamp: number,
currentPageX: number,
currentPageY: number,
currentTimeStamp: number,
previousPageX: number,
previousPageY: number,
previousTimeStamp: number
previousTimeStamp: number,
startPageX: number,
startPageY: number,
startTimeStamp: number,
touchActive: boolean
|};
export type TouchHistory = $ReadOnly<{|
indexOfSingleActiveTouch: number,
mostRecentTimeStamp: number,
numberActiveTouches: number,
touchBank: Array<TouchRecord>
|}>;
/**
* Tracks the position and time of each active touch by `touch.identifier`. We
* should typically only see IDs in the range of 1-20 because IDs get recycled
@@ -31,16 +38,6 @@ type TouchRecord = {|
const __DEV__ = process.env.NODE_ENV !== 'production';
const MAX_TOUCH_BANK = 20;
const touchBank: Array<TouchRecord> = [];
const touchHistory = {
touchBank,
numberActiveTouches: 0,
// If there is only one active touch, we remember its location. This prevents
// us having to loop through all of the touches all the time in the most
// common case.
indexOfSingleActiveTouch: -1,
mostRecentTimeStamp: 0
};
function timestampForTouch(touch: Touch): number {
// The legacy internal implementation provides "timeStamp", which has been
@@ -97,19 +94,19 @@ function getTouchIdentifier({ identifier }: Touch): number {
return identifier;
}
function recordTouchStart(touch: Touch): void {
function recordTouchStart(touch: Touch, touchHistory): void {
const identifier = getTouchIdentifier(touch);
const touchRecord = touchBank[identifier];
const touchRecord = touchHistory.touchBank[identifier];
if (touchRecord) {
resetTouchRecord(touchRecord, touch);
} else {
touchBank[identifier] = createTouchRecord(touch);
touchHistory.touchBank[identifier] = createTouchRecord(touch);
}
touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
}
function recordTouchMove(touch: Touch): void {
const touchRecord = touchBank[getTouchIdentifier(touch)];
function recordTouchMove(touch: Touch, touchHistory): void {
const touchRecord = touchHistory.touchBank[getTouchIdentifier(touch)];
if (touchRecord) {
touchRecord.touchActive = true;
touchRecord.previousPageX = touchRecord.currentPageX;
@@ -123,13 +120,13 @@ function recordTouchMove(touch: Touch): void {
console.warn(
'Cannot record touch move without a touch start.\n',
`Touch Move: ${printTouch(touch)}\n`,
`Touch Bank: ${printTouchBank()}`
`Touch Bank: ${printTouchBank(touchHistory)}`
);
}
}
function recordTouchEnd(touch: Touch): void {
const touchRecord = touchBank[getTouchIdentifier(touch)];
function recordTouchEnd(touch: Touch, touchHistory): void {
const touchRecord = touchHistory.touchBank[getTouchIdentifier(touch)];
if (touchRecord) {
touchRecord.touchActive = false;
touchRecord.previousPageX = touchRecord.currentPageX;
@@ -143,7 +140,7 @@ function recordTouchEnd(touch: Touch): void {
console.warn(
'Cannot record touch end without a touch start.\n',
`Touch End: ${printTouch(touch)}\n`,
`Touch Bank: ${printTouchBank()}`
`Touch Bank: ${printTouchBank(touchHistory)}`
);
}
}
@@ -157,7 +154,8 @@ function printTouch(touch: Touch): string {
});
}
function printTouchBank(): string {
function printTouchBank(touchHistory): string {
const { touchBank } = touchHistory;
let printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK));
if (touchBank.length > MAX_TOUCH_BANK) {
printed += ' (original size: ' + touchBank.length + ')';
@@ -165,21 +163,39 @@ function printTouchBank(): string {
return printed;
}
const ResponderTouchHistoryStore = {
export class ResponderTouchHistoryStore {
_touchHistory = {
touchBank: [], //Array<TouchRecord>
numberActiveTouches: 0,
// If there is only one active touch, we remember its location. This prevents
// us having to loop through all of the touches all the time in the most
// common case.
indexOfSingleActiveTouch: -1,
mostRecentTimeStamp: 0
};
recordTouchTrack(topLevelType: string, nativeEvent: TouchEvent): void {
const touchHistory = this._touchHistory;
if (isMoveish(topLevelType)) {
nativeEvent.changedTouches.forEach(recordTouchMove);
nativeEvent.changedTouches.forEach((touch) =>
recordTouchMove(touch, touchHistory)
);
} else if (isStartish(topLevelType)) {
nativeEvent.changedTouches.forEach(recordTouchStart);
nativeEvent.changedTouches.forEach((touch) =>
recordTouchStart(touch, touchHistory)
);
touchHistory.numberActiveTouches = nativeEvent.touches.length;
if (touchHistory.numberActiveTouches === 1) {
touchHistory.indexOfSingleActiveTouch =
nativeEvent.touches[0].identifier;
}
} else if (isEndish(topLevelType)) {
nativeEvent.changedTouches.forEach(recordTouchEnd);
nativeEvent.changedTouches.forEach((touch) =>
recordTouchEnd(touch, touchHistory)
);
touchHistory.numberActiveTouches = nativeEvent.touches.length;
if (touchHistory.numberActiveTouches === 1) {
const { touchBank } = touchHistory;
for (let i = 0; i < touchBank.length; i++) {
const touchTrackToCheck = touchBank[i];
if (touchTrackToCheck != null && touchTrackToCheck.touchActive) {
@@ -195,9 +211,9 @@ const ResponderTouchHistoryStore = {
}
}
}
},
}
touchHistory
};
export default ResponderTouchHistoryStore;
get touchHistory(): TouchHistory {
return this._touchHistory;
}
}

View File

@@ -7,10 +7,13 @@
* @flow
*/
import type {
ResponderTouchHistoryStore,
TouchHistory
} from './ResponderTouchHistoryStore';
import type { TouchEvent } from './ResponderEventTypes';
import getBoundingClientRect from '../../modules/getBoundingClientRect';
import ResponderTouchHistoryStore from './ResponderTouchHistoryStore';
export type ResponderEvent = {|
bubbles: boolean,
@@ -34,23 +37,7 @@ export type ResponderEvent = {|
persist: () => void,
target: ?any,
timeStamp: number,
touchHistory: $ReadOnly<{|
indexOfSingleActiveTouch: number,
mostRecentTimeStamp: number,
numberActiveTouches: number,
touchBank: Array<{|
currentPageX: number,
currentPageY: number,
currentTimeStamp: number,
previousPageX: number,
previousPageY: number,
previousTimeStamp: number,
startPageX: number,
startPageY: number,
startTimeStamp: number,
touchActive: boolean
|}>
|}>
touchHistory: TouchHistory
|};
const emptyFunction = () => {};
@@ -70,7 +57,10 @@ function normalizeIdentifier(identifier) {
* Converts a native DOM event to a ResponderEvent.
* Mouse events are transformed into fake touch events.
*/
export default function createResponderEvent(domEvent: any): ResponderEvent {
export default function createResponderEvent(
domEvent: any,
responderTouchHistoryStore: ResponderTouchHistoryStore
): ResponderEvent {
let rect;
let propagationWasStopped = false;
let changedTouches;
@@ -193,7 +183,7 @@ export default function createResponderEvent(domEvent: any): ResponderEvent {
},
target: domEvent.target,
timeStamp: timestamp,
touchHistory: ResponderTouchHistoryStore.touchHistory
touchHistory: responderTouchHistoryStore.touchHistory
};
// Using getters and functions serves two purposes: