From bbffe86fd65f5b0342098f019305a61c72cbe0b2 Mon Sep 17 00:00:00 2001 From: Ondrej Zaruba Date: Mon, 3 Jan 2022 12:03:51 +0100 Subject: [PATCH] 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 --- .../useResponderEvents/ResponderSystem.js | 12 ++- .../ResponderTouchHistoryStore.js | 84 +++++++++++-------- .../createResponderEvent.js | 30 +++---- 3 files changed, 68 insertions(+), 58 deletions(-) diff --git a/packages/react-native-web/src/modules/useResponderEvents/ResponderSystem.js b/packages/react-native-web/src/modules/useResponderEvents/ResponderSystem.js index 915a1ac6..6b6c4da0 100644 --- a/packages/react-native-web/src/modules/useResponderEvents/ResponderSystem.js +++ b/packages/react-native-web/src/modules/useResponderEvents/ResponderSystem.js @@ -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); } diff --git a/packages/react-native-web/src/modules/useResponderEvents/ResponderTouchHistoryStore.js b/packages/react-native-web/src/modules/useResponderEvents/ResponderTouchHistoryStore.js index ea68039a..12f3a024 100644 --- a/packages/react-native-web/src/modules/useResponderEvents/ResponderTouchHistoryStore.js +++ b/packages/react-native-web/src/modules/useResponderEvents/ResponderTouchHistoryStore.js @@ -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 +|}>; + /** * 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 = []; -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 + 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; + } +} diff --git a/packages/react-native-web/src/modules/useResponderEvents/createResponderEvent.js b/packages/react-native-web/src/modules/useResponderEvents/createResponderEvent.js index 30f1442c..ca063955 100644 --- a/packages/react-native-web/src/modules/useResponderEvents/createResponderEvent.js +++ b/packages/react-native-web/src/modules/useResponderEvents/createResponderEvent.js @@ -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: