UNPKG

@heap/react-native-heap

Version:

React Native event tracking with Heap.

69 lines (68 loc) 3.67 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import * as React from 'react'; import hoistNonReactStatic from 'hoist-non-react-statics'; import * as _ from 'lodash'; import { getBaseComponentProps } from './common'; import { swallowErrors } from '../util/bailer'; import { getComponentDisplayName } from '../util/hocUtil'; const DEBOUNCE_PERIOD_MS = 1000; export const autocaptureTextInputChange = track => (eventType, componentThis, event) => { // Attach a debounce function to the TextInput component instance if one's not already attached. if (!componentThis.__heap__debounceTextChange) { componentThis.__heap__debounceTextChange = _.debounce(debouncedAutocaptureTextInputChange(track), DEBOUNCE_PERIOD_MS); } componentThis.__heap__debounceTextChange(eventType, componentThis, event); }; const debouncedAutocaptureTextInputChange = track => (eventType, componentThis, event) => { const autotrackProps = getBaseComponentProps(componentThis); if (!autotrackProps) { // We're not capturing this interaction. return; } if (componentThis.props.placeholder) { autotrackProps.placeholder_text = componentThis.props.placeholder; } track(eventType, autotrackProps); }; // :HACK: In previous implementations, there would be a 'TextInput' component somewhere in the hierarchy. However, with this // implementation, this is not the case (even the TextInputComponent has a displayName of 'InternalTextInput'). This means that any event // definitions on 'TextInput' would break. // To get around this, wrap the returned HOC with a no-op component with the 'TextInput' display name. // :TODO: (jmtaber129): Consider other workarounds to this, like setting the display name of instrumented components when they're exported // from the React Native lib (via instrumentation). const NoopTextInput = props => { return props.children; }; NoopTextInput.displayName = 'TextInput'; export const withHeapTextInputAutocapture = track => TextInputComponent => { class HeapTextInputAutocapture extends React.Component { constructor() { super(...arguments); this.autocaptureTextInputChangeWithDebounce = swallowErrors(_.debounce(debouncedAutocaptureTextInputChange(track), DEBOUNCE_PERIOD_MS)); } render() { const _a = this.props, { heapForwardedRef, onChange } = _a, rest = __rest(_a, ["heapForwardedRef", "onChange"]); return (React.createElement(TextInputComponent, Object.assign({ ref: heapForwardedRef, onChange: e => { this.autocaptureTextInputChangeWithDebounce('text_edit', this, e); onChange && onChange(e); } }, rest), this.props.children)); } } HeapTextInputAutocapture.displayName = `WithHeapTextInputAutocapture(${getComponentDisplayName(TextInputComponent)})`; const forwardRefHoc = React.forwardRef((props, ref) => { return (React.createElement(NoopTextInput, Object.assign({}, props), React.createElement(HeapTextInputAutocapture, Object.assign({}, props, { heapForwardedRef: ref })))); }); hoistNonReactStatic(forwardRefHoc, TextInputComponent); return forwardRefHoc; };