@heap/react-native-heap
Version:
React Native event tracking with Heap.
69 lines (68 loc) • 3.67 kB
JavaScript
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;
};