UNPKG

@datadog/mobile-react-native

Version:

A client-side React Native module to interact with Datadog

80 lines (79 loc) 3.53 kB
/* * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. * This product includes software developed at Datadog (https://www.datadoghq.com/). * Copyright 2016-Present Datadog, Inc. */ import { InternalLog } from '../../../InternalLog'; import { SdkVerbosity } from '../../../SdkVerbosity'; import { DdRum } from '../../DdRum'; import { RumActionType } from '../../types'; export const UNKNOWN_TARGET_NAME = 'unknown_target'; const DEBOUNCE_EVENT_THRESHOLD_IN_MS = 10; const HANDLE_EVENT_APP_EXECUTION_TIME_IN_MS = 1; const DD_ACTION_NAME_PROP = 'dd-action-name'; export class DdEventsInterceptor { static ACTION_EVENT_DROPPED_DEBUG_MESSAGE = 'An action event was dropped because either the `onPress` method arguments' + ' were undefined or they were missing the target information.' + ' This log can happen if you use an abstraction component with an `onPress` prop' + ' that does not receive the native event is first argument.' + ' In this case, you can ignore this log.'; debouncingStartedTimestamp = Number.MIN_VALUE; constructor(options = {}) { this.actionNameAttribute = options.actionNameAttribute; this.useAccessibilityLabel = options.useAccessibilityLabel ?? true; } interceptOnPress(...args) { if (args.length > 0 && args[0] && args[0]._targetInst) { const currentTime = Date.now(); const timestampDifference = Math.abs(Date.now() - this.debouncingStartedTimestamp); if (timestampDifference > DEBOUNCE_EVENT_THRESHOLD_IN_MS) { const targetNode = args[0]._targetInst; this.handleTargetEvent(targetNode, args[0]); // we add an approximated 1 millisecond for the execution time of the `handleTargetEvent` function this.debouncingStartedTimestamp = currentTime + HANDLE_EVENT_APP_EXECUTION_TIME_IN_MS; } } else { InternalLog.log(DdEventsInterceptor.ACTION_EVENT_DROPPED_DEBUG_MESSAGE, SdkVerbosity.DEBUG); } } handleTargetEvent(targetNode, event) { if (targetNode) { const resolvedTargetName = this.resolveTargetName(targetNode); DdRum.addAction(RumActionType.TAP, resolvedTargetName, {}, undefined, event); } } resolveTargetName(targetNode) { const closestActionLabel = this.findClosestActionLabel(targetNode); if (closestActionLabel != null) { return closestActionLabel; } if (this.useAccessibilityLabel) { const accessibilityLabel = targetNode.memoizedProps?.accessibilityLabel; if (accessibilityLabel != null) { return accessibilityLabel; } } const elementTypeName = this.resolveElementTypeName(targetNode.elementType); return elementTypeName || UNKNOWN_TARGET_NAME; } resolveElementTypeName(elementType) { let elementTypeName = null; if (typeof elementType === 'string') { elementTypeName = elementType; } else if (elementType && typeof elementType.name === 'string') { elementTypeName = elementType.name; } return elementTypeName; } findClosestActionLabel(targetNode) { let currentNode = targetNode; while (currentNode) { const props = currentNode.memoizedProps; if (props && props[DD_ACTION_NAME_PROP]) { return props[DD_ACTION_NAME_PROP]; } if (this.actionNameAttribute && props && props[this.actionNameAttribute]) { return props[this.actionNameAttribute]; } currentNode = currentNode.return; } return null; } } //# sourceMappingURL=DdEventsInterceptor.js.map