diff --git a/Libraries/Pressability/Pressability.js b/Libraries/Pressability/Pressability.js index bae328b055185f..7511b29b5c1ced 100644 --- a/Libraries/Pressability/Pressability.js +++ b/Libraries/Pressability/Pressability.js @@ -18,6 +18,8 @@ import type { PressEvent, MouseEvent, } from '../Types/CoreEventTypes'; +import PressabilityPerformanceEventEmitter from './PressabilityPerformanceEventEmitter.js'; +import {type PressabilityTouchSignal as TouchSignal} from './PressabilityTypes.js'; import Platform from '../Utilities/Platform'; import UIManager from '../ReactNative/UIManager'; import type {HostComponent} from '../Renderer/shims/ReactNativeTypes'; @@ -174,15 +176,6 @@ type TouchState = | 'RESPONDER_ACTIVE_LONG_PRESS_OUT' | 'ERROR'; -type TouchSignal = - | 'DELAY' - | 'RESPONDER_GRANT' - | 'RESPONDER_RELEASE' - | 'RESPONDER_TERMINATED' - | 'ENTER_PRESS_RECT' - | 'LEAVE_PRESS_RECT' - | 'LONG_PRESS_DETECTED'; - const Transitions = Object.freeze({ NOT_RESPONDER: { DELAY: 'ERROR', @@ -630,6 +623,13 @@ export default class Pressability { : '<>', ); if (prevState !== nextState) { + PressabilityPerformanceEventEmitter.emitEvent(() => { + return { + signal, + touchDelayMs: Date.now() - event.nativeEvent.timestamp, + }; + }); + this._performTransitionSideEffects(prevState, nextState, signal, event); this._touchState = nextState; } diff --git a/Libraries/Pressability/PressabilityPerformanceEventEmitter.js b/Libraries/Pressability/PressabilityPerformanceEventEmitter.js new file mode 100644 index 00000000000000..832b1ee270e7e0 --- /dev/null +++ b/Libraries/Pressability/PressabilityPerformanceEventEmitter.js @@ -0,0 +1,47 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +import {type PressabilityTouchSignal as TouchSignal} from './PressabilityTypes.js'; + +export type PressabilityPerformanceEvent = $ReadOnly<{| + signal: TouchSignal, + touchDelayMs: number, +|}>; +export type PressabilityPerformanceEventListener = PressabilityPerformanceEvent => void; + +class PressabilityPerformanceEventEmitter { + _listeners: Array = []; + + constructor() {} + + addListener(listener: PressabilityPerformanceEventListener): void { + this._listeners.push(listener); + } + + removeListener(listener: PressabilityPerformanceEventListener): void { + const index = this._listeners.indexOf(listener); + if (index > -1) { + this._listeners.splice(index, 1); + } + } + + emitEvent(constructEvent: () => PressabilityPerformanceEvent): void { + if (this._listeners.length === 0) { + return; + } + + const event = constructEvent(); + this._listeners.forEach(listener => listener(event)); + } +} + +const PressabilityPerformanceEventEmitterSingleton: PressabilityPerformanceEventEmitter = new PressabilityPerformanceEventEmitter(); + +export default PressabilityPerformanceEventEmitterSingleton; diff --git a/Libraries/Pressability/PressabilityTypes.js b/Libraries/Pressability/PressabilityTypes.js new file mode 100644 index 00000000000000..5e8b1ffdb8ab47 --- /dev/null +++ b/Libraries/Pressability/PressabilityTypes.js @@ -0,0 +1,18 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +export type PressabilityTouchSignal = + | 'DELAY' + | 'RESPONDER_GRANT' + | 'RESPONDER_RELEASE' + | 'RESPONDER_TERMINATED' + | 'ENTER_PRESS_RECT' + | 'LEAVE_PRESS_RECT' + | 'LONG_PRESS_DETECTED';