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
@@ -150,7 +150,7 @@ import {
isPrimaryPointerDown, isPrimaryPointerDown,
setResponderId setResponderId
} from './utils'; } from './utils';
import ResponderTouchHistoryStore from './ResponderTouchHistoryStore'; import { ResponderTouchHistoryStore } from './ResponderTouchHistoryStore';
import canUseDOM from '../canUseDom'; import canUseDOM from '../canUseDom';
/* ------------ TYPES ------------ */ /* ------------ TYPES ------------ */
@@ -232,6 +232,7 @@ let currentResponder: ResponderInstance = {
node: null, node: null,
idPath: null idPath: null
}; };
const responderTouchHistoryStore = new ResponderTouchHistoryStore();
function changeCurrentResponder(responder: ResponderInstance) { function changeCurrentResponder(responder: ResponderInstance) {
currentResponder = responder; currentResponder = responder;
@@ -294,7 +295,10 @@ function eventListener(domEvent: any) {
const isEndEvent = isEndish(eventType); const isEndEvent = isEndish(eventType);
const isScrollEvent = isScroll(eventType); const isScrollEvent = isScroll(eventType);
const isSelectionChangeEvent = isSelectionChange(eventType); const isSelectionChangeEvent = isSelectionChange(eventType);
const responderEvent = createResponderEvent(domEvent); const responderEvent = createResponderEvent(
domEvent,
responderTouchHistoryStore
);
/** /**
* Record the state of active pointers * Record the state of active pointers
@@ -310,7 +314,7 @@ function eventListener(domEvent: any) {
trackedTouchCount = 0; trackedTouchCount = 0;
} }
} }
ResponderTouchHistoryStore.recordTouchTrack( responderTouchHistoryStore.recordTouchTrack(
eventType, eventType,
responderEvent.nativeEvent responderEvent.nativeEvent
); );
@@ -665,7 +669,7 @@ export function terminateResponder() {
if (id != null && node != null) { if (id != null && node != null) {
const { onResponderTerminate } = getResponderConfig(id); const { onResponderTerminate } = getResponderConfig(id);
if (onResponderTerminate != null) { if (onResponderTerminate != null) {
const event = createResponderEvent({}); const event = createResponderEvent({}, responderTouchHistoryStore);
event.currentTarget = node; event.currentTarget = node;
onResponderTerminate(event); onResponderTerminate(event);
} }
@@ -11,18 +11,25 @@ import type { Touch, TouchEvent } from './ResponderEventTypes';
import { isStartish, isMoveish, isEndish } from './ResponderEventTypes'; import { isStartish, isMoveish, isEndish } from './ResponderEventTypes';
type TouchRecord = {| type TouchRecord = {|
touchActive: boolean,
startPageX: number,
startPageY: number,
startTimeStamp: number,
currentPageX: number, currentPageX: number,
currentPageY: number, currentPageY: number,
currentTimeStamp: number, currentTimeStamp: number,
previousPageX: number, previousPageX: number,
previousPageY: 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 * 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 * 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 __DEV__ = process.env.NODE_ENV !== 'production';
const MAX_TOUCH_BANK = 20; 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 { function timestampForTouch(touch: Touch): number {
// The legacy internal implementation provides "timeStamp", which has been // The legacy internal implementation provides "timeStamp", which has been
@@ -97,19 +94,19 @@ function getTouchIdentifier({ identifier }: Touch): number {
return identifier; return identifier;
} }
function recordTouchStart(touch: Touch): void { function recordTouchStart(touch: Touch, touchHistory): void {
const identifier = getTouchIdentifier(touch); const identifier = getTouchIdentifier(touch);
const touchRecord = touchBank[identifier]; const touchRecord = touchHistory.touchBank[identifier];
if (touchRecord) { if (touchRecord) {
resetTouchRecord(touchRecord, touch); resetTouchRecord(touchRecord, touch);
} else { } else {
touchBank[identifier] = createTouchRecord(touch); touchHistory.touchBank[identifier] = createTouchRecord(touch);
} }
touchHistory.mostRecentTimeStamp = timestampForTouch(touch); touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
} }
function recordTouchMove(touch: Touch): void { function recordTouchMove(touch: Touch, touchHistory): void {
const touchRecord = touchBank[getTouchIdentifier(touch)]; const touchRecord = touchHistory.touchBank[getTouchIdentifier(touch)];
if (touchRecord) { if (touchRecord) {
touchRecord.touchActive = true; touchRecord.touchActive = true;
touchRecord.previousPageX = touchRecord.currentPageX; touchRecord.previousPageX = touchRecord.currentPageX;
@@ -123,13 +120,13 @@ function recordTouchMove(touch: Touch): void {
console.warn( console.warn(
'Cannot record touch move without a touch start.\n', 'Cannot record touch move without a touch start.\n',
`Touch Move: ${printTouch(touch)}\n`, `Touch Move: ${printTouch(touch)}\n`,
`Touch Bank: ${printTouchBank()}` `Touch Bank: ${printTouchBank(touchHistory)}`
); );
} }
} }
function recordTouchEnd(touch: Touch): void { function recordTouchEnd(touch: Touch, touchHistory): void {
const touchRecord = touchBank[getTouchIdentifier(touch)]; const touchRecord = touchHistory.touchBank[getTouchIdentifier(touch)];
if (touchRecord) { if (touchRecord) {
touchRecord.touchActive = false; touchRecord.touchActive = false;
touchRecord.previousPageX = touchRecord.currentPageX; touchRecord.previousPageX = touchRecord.currentPageX;
@@ -143,7 +140,7 @@ function recordTouchEnd(touch: Touch): void {
console.warn( console.warn(
'Cannot record touch end without a touch start.\n', 'Cannot record touch end without a touch start.\n',
`Touch End: ${printTouch(touch)}\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)); let printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK));
if (touchBank.length > MAX_TOUCH_BANK) { if (touchBank.length > MAX_TOUCH_BANK) {
printed += ' (original size: ' + touchBank.length + ')'; printed += ' (original size: ' + touchBank.length + ')';
@@ -165,21 +163,39 @@ function printTouchBank(): string {
return printed; 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 { recordTouchTrack(topLevelType: string, nativeEvent: TouchEvent): void {
const touchHistory = this._touchHistory;
if (isMoveish(topLevelType)) { if (isMoveish(topLevelType)) {
nativeEvent.changedTouches.forEach(recordTouchMove); nativeEvent.changedTouches.forEach((touch) =>
recordTouchMove(touch, touchHistory)
);
} else if (isStartish(topLevelType)) { } else if (isStartish(topLevelType)) {
nativeEvent.changedTouches.forEach(recordTouchStart); nativeEvent.changedTouches.forEach((touch) =>
recordTouchStart(touch, touchHistory)
);
touchHistory.numberActiveTouches = nativeEvent.touches.length; touchHistory.numberActiveTouches = nativeEvent.touches.length;
if (touchHistory.numberActiveTouches === 1) { if (touchHistory.numberActiveTouches === 1) {
touchHistory.indexOfSingleActiveTouch = touchHistory.indexOfSingleActiveTouch =
nativeEvent.touches[0].identifier; nativeEvent.touches[0].identifier;
} }
} else if (isEndish(topLevelType)) { } else if (isEndish(topLevelType)) {
nativeEvent.changedTouches.forEach(recordTouchEnd); nativeEvent.changedTouches.forEach((touch) =>
recordTouchEnd(touch, touchHistory)
);
touchHistory.numberActiveTouches = nativeEvent.touches.length; touchHistory.numberActiveTouches = nativeEvent.touches.length;
if (touchHistory.numberActiveTouches === 1) { if (touchHistory.numberActiveTouches === 1) {
const { touchBank } = touchHistory;
for (let i = 0; i < touchBank.length; i++) { for (let i = 0; i < touchBank.length; i++) {
const touchTrackToCheck = touchBank[i]; const touchTrackToCheck = touchBank[i];
if (touchTrackToCheck != null && touchTrackToCheck.touchActive) { if (touchTrackToCheck != null && touchTrackToCheck.touchActive) {
@@ -195,9 +211,9 @@ const ResponderTouchHistoryStore = {
} }
} }
} }
}, }
touchHistory get touchHistory(): TouchHistory {
}; return this._touchHistory;
}
export default ResponderTouchHistoryStore; }
@@ -7,10 +7,13 @@
* @flow * @flow
*/ */
import type {
ResponderTouchHistoryStore,
TouchHistory
} from './ResponderTouchHistoryStore';
import type { TouchEvent } from './ResponderEventTypes'; import type { TouchEvent } from './ResponderEventTypes';
import getBoundingClientRect from '../../modules/getBoundingClientRect'; import getBoundingClientRect from '../../modules/getBoundingClientRect';
import ResponderTouchHistoryStore from './ResponderTouchHistoryStore';
export type ResponderEvent = {| export type ResponderEvent = {|
bubbles: boolean, bubbles: boolean,
@@ -34,23 +37,7 @@ export type ResponderEvent = {|
persist: () => void, persist: () => void,
target: ?any, target: ?any,
timeStamp: number, timeStamp: number,
touchHistory: $ReadOnly<{| touchHistory: TouchHistory
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
|}>
|}>
|}; |};
const emptyFunction = () => {}; const emptyFunction = () => {};
@@ -70,7 +57,10 @@ function normalizeIdentifier(identifier) {
* Converts a native DOM event to a ResponderEvent. * Converts a native DOM event to a ResponderEvent.
* Mouse events are transformed into fake touch events. * 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 rect;
let propagationWasStopped = false; let propagationWasStopped = false;
let changedTouches; let changedTouches;
@@ -193,7 +183,7 @@ export default function createResponderEvent(domEvent: any): ResponderEvent {
}, },
target: domEvent.target, target: domEvent.target,
timeStamp: timestamp, timeStamp: timestamp,
touchHistory: ResponderTouchHistoryStore.touchHistory touchHistory: responderTouchHistoryStore.touchHistory
}; };
// Using getters and functions serves two purposes: // Using getters and functions serves two purposes: