UNPKG

posthog-js

Version:

Posthog-js allows you to automatically capture usage and send events to PostHog.

409 lines • 19.5 kB
var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) { if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name }); }; 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; }; var _a; import React, { Children, createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react"; var GLOBAL_KEY = "__POSTHOG_REACT_SHARED_STATE__"; var globalObject = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : {}; var statesByReact; try { statesByReact = globalObject[GLOBAL_KEY] = globalObject[GLOBAL_KEY] || new WeakMap(); } catch (_b) { statesByReact = new WeakMap(); } if (!statesByReact.has(createContext)) statesByReact.set(createContext, {}); var sharedState = statesByReact.get(createContext); if (!sharedState.context) sharedState.context = createContext({ get client() { return sharedState.defaultPostHogInstance; }, bootstrap: void 0 }); var PostHogContext = sharedState.context; function PostHogProvider(_b) { var client = _b.client, children = _b.children; var value = useMemo(function () { var _b; return ({ client: client, bootstrap: (_b = client.config) === null || _b === void 0 ? void 0 : _b.bootstrap }); }, [client]); return React.createElement(PostHogContext.Provider, { value: value }, children); } var isFunction = function (f) { return typeof f === "function"; }; var isUndefined = function (x) { return x === void 0; }; var isNull = function (x) { return x === null; }; function useFeatureFlagEnabled(flag, defaultValue) { var _b, _c; var _d = useContext(PostHogContext), client = _d.client, bootstrap = _d.bootstrap; var _e = useState(function () { return client.isFeatureEnabled(flag); }), featureEnabled = _e[0], setFeatureEnabled = _e[1]; useEffect(function () { return client.onFeatureFlags(function () { setFeatureEnabled(client.isFeatureEnabled(flag)); }); }, [client, flag]); var bootstrapped = (_b = bootstrap === null || bootstrap === void 0 ? void 0 : bootstrap.featureFlags) === null || _b === void 0 ? void 0 : _b[flag]; if (!((_c = client === null || client === void 0 ? void 0 : client.featureFlags) === null || _c === void 0 ? void 0 : _c.hasLoadedFlags) && (bootstrap === null || bootstrap === void 0 ? void 0 : bootstrap.featureFlags)) return isUndefined(bootstrapped) ? defaultValue : !!bootstrapped; return isUndefined(featureEnabled) ? defaultValue : featureEnabled; } function useFeatureFlagPayload(flag) { var _b; var _c = useContext(PostHogContext), client = _c.client, bootstrap = _c.bootstrap; var _d = useState(function () { var _b; return (_b = client.getFeatureFlagResult(flag, { send_event: false })) === null || _b === void 0 ? void 0 : _b.payload; }), featureFlagPayload = _d[0], setFeatureFlagPayload = _d[1]; useEffect(function () { return client.onFeatureFlags(function () { var _b; setFeatureFlagPayload((_b = client.getFeatureFlagResult(flag, { send_event: false })) === null || _b === void 0 ? void 0 : _b.payload); }); }, [client, flag]); if (!((_b = client === null || client === void 0 ? void 0 : client.featureFlags) === null || _b === void 0 ? void 0 : _b.hasLoadedFlags) && (bootstrap === null || bootstrap === void 0 ? void 0 : bootstrap.featureFlagPayloads)) return bootstrap.featureFlagPayloads[flag]; return featureFlagPayload; } function useFeatureFlagResult(flag) { var _b, _c; var _d = useContext(PostHogContext), client = _d.client, bootstrap = _d.bootstrap; var _e = useState(function () { return client.getFeatureFlagResult(flag); }), result = _e[0], setResult = _e[1]; useEffect(function () { return client.onFeatureFlags(function () { setResult(client.getFeatureFlagResult(flag)); }); }, [client, flag]); if (!((_b = client === null || client === void 0 ? void 0 : client.featureFlags) === null || _b === void 0 ? void 0 : _b.hasLoadedFlags) && (bootstrap === null || bootstrap === void 0 ? void 0 : bootstrap.featureFlags)) { var bootstrappedValue = bootstrap.featureFlags[flag]; if (isUndefined(bootstrappedValue)) return; return { key: flag, enabled: typeof bootstrappedValue === "string" ? true : !!bootstrappedValue, variant: typeof bootstrappedValue === "string" ? bootstrappedValue : void 0, payload: (_c = bootstrap.featureFlagPayloads) === null || _c === void 0 ? void 0 : _c[flag] }; } return result; } function useActiveFeatureFlags() { var _b; var _c = useContext(PostHogContext), client = _c.client, bootstrap = _c.bootstrap; var _d = useState(function () { return client.featureFlags.getFlags(); }), featureFlags = _d[0], setFeatureFlags = _d[1]; useEffect(function () { return client.onFeatureFlags(function (flags) { setFeatureFlags(flags); }); }, [client]); if (!((_b = client === null || client === void 0 ? void 0 : client.featureFlags) === null || _b === void 0 ? void 0 : _b.hasLoadedFlags) && (bootstrap === null || bootstrap === void 0 ? void 0 : bootstrap.featureFlags)) return Object.entries(bootstrap.featureFlags).filter(function (_b) { var value = _b[1]; return value; }).map(function (_b) { var key = _b[0]; return key; }); return featureFlags; } function useFeatureFlagVariantKey(flag) { var _b; var _c = useContext(PostHogContext), client = _c.client, bootstrap = _c.bootstrap; var _d = useState(function () { return client.getFeatureFlag(flag); }), featureFlagVariantKey = _d[0], setFeatureFlagVariantKey = _d[1]; useEffect(function () { return client.onFeatureFlags(function () { setFeatureFlagVariantKey(client.getFeatureFlag(flag)); }); }, [client, flag]); if (!((_b = client === null || client === void 0 ? void 0 : client.featureFlags) === null || _b === void 0 ? void 0 : _b.hasLoadedFlags) && (bootstrap === null || bootstrap === void 0 ? void 0 : bootstrap.featureFlags)) return bootstrap.featureFlags[flag]; return featureFlagVariantKey; } var usePostHog = function () { var client = useContext(PostHogContext).client; return client; }; function VisibilityAndClickTracker(_b) { var children = _b.children, onIntersect = _b.onIntersect, onClick = _b.onClick, trackView = _b.trackView, options = _b.options, props = __rest(_b, ["children", "onIntersect", "onClick", "trackView", "options"]); var ref = useRef(null); var observerOptions = useMemo(function () { return (__assign({ threshold: .1 }, options)); }, [ options === null || options === void 0 ? void 0 : options.threshold, options === null || options === void 0 ? void 0 : options.root, options === null || options === void 0 ? void 0 : options.rootMargin ]); useEffect(function () { if (isNull(ref.current) || !trackView) return; var observer = new IntersectionObserver(function (_b) { var entry = _b[0]; return onIntersect(entry); }, observerOptions); observer.observe(ref.current); return function () { return observer.disconnect(); }; }, [ observerOptions, trackView, onIntersect ]); return React.createElement("div", __assign(__assign({ ref: ref }, props), { onClick: onClick }), children); } function VisibilityAndClickTrackers(_b) { var children = _b.children, trackInteraction = _b.trackInteraction, trackView = _b.trackView, options = _b.options, onInteract = _b.onInteract, onView = _b.onView, props = __rest(_b, ["children", "trackInteraction", "trackView", "options", "onInteract", "onView"]); var clickTrackedRef = useRef(false); var visibilityTrackedRef = useRef(false); var cachedOnClick = useCallback(function () { if (!clickTrackedRef.current && trackInteraction && onInteract) { onInteract(); clickTrackedRef.current = true; } }, [trackInteraction, onInteract]); var onIntersect = function (entry) { if (!visibilityTrackedRef.current && entry.isIntersecting && onView) { onView(); visibilityTrackedRef.current = true; } }; var trackedChildren = Children.map(children, function (child) { return React.createElement(VisibilityAndClickTracker, __assign({ onClick: cachedOnClick, onIntersect: onIntersect, trackView: trackView, options: options }, props), child); }); return React.createElement(React.Fragment, null, trackedChildren); } function PostHogFeature(_b) { var flag = _b.flag, match = _b.match, children = _b.children, fallback = _b.fallback, visibilityObserverOptions = _b.visibilityObserverOptions, trackInteraction = _b.trackInteraction, trackView = _b.trackView, props = __rest(_b, ["flag", "match", "children", "fallback", "visibilityObserverOptions", "trackInteraction", "trackView"]); var payload = useFeatureFlagPayload(flag); var variant = useFeatureFlagVariantKey(flag); var posthog = usePostHog(); var shouldTrackInteraction = trackInteraction !== null && trackInteraction !== void 0 ? trackInteraction : true; var shouldTrackView = trackView !== null && trackView !== void 0 ? trackView : true; if (!isUndefined(variant)) { if (isUndefined(match) ? variant !== false : variant === match) { var childNode = isFunction(children) ? children(payload) : children; return React.createElement(VisibilityAndClickTrackers, __assign({ flag: flag, options: visibilityObserverOptions, trackInteraction: shouldTrackInteraction, trackView: shouldTrackView, onInteract: function () { return captureFeatureInteraction({ flag: flag, posthog: posthog, flagVariant: variant }); }, onView: function () { return captureFeatureView({ flag: flag, posthog: posthog, flagVariant: variant }); } }, props), childNode); } } return React.createElement(React.Fragment, null, fallback); } function captureFeatureEvent(event, _b) { var _c; var flag = _b.flag, posthog = _b.posthog, flagVariant = _b.flagVariant; var properties = { feature_flag: flag, $set: (_c = {}, _c["".concat(event, "/").concat(flag)] = flagVariant !== null && flagVariant !== void 0 ? flagVariant : true, _c) }; if (typeof flagVariant === "string") properties.feature_flag_variant = flagVariant; posthog.capture(event, properties); } function captureFeatureInteraction(options) { captureFeatureEvent("$feature_interaction", options); } function captureFeatureView(options) { captureFeatureEvent("$feature_view", options); } function TrackedChild(_b) { var child = _b.child, index = _b.index, name = _b.name, properties = _b.properties, observerOptions = _b.observerOptions; var trackedRef = useRef(false); var posthog = usePostHog(); var onIntersect = useCallback(function (entry) { if (entry.isIntersecting && !trackedRef.current) { posthog.capture("$element_viewed", __assign({ element_name: name, child_index: index }, properties)); trackedRef.current = true; } }, [ posthog, name, index, properties ]); return React.createElement(VisibilityAndClickTracker, { onIntersect: onIntersect, trackView: true, options: observerOptions }, child); } function PostHogCaptureOnViewed(_b) { var name = _b.name, properties = _b.properties, observerOptions = _b.observerOptions, trackAllChildren = _b.trackAllChildren, children = _b.children, props = __rest(_b, ["name", "properties", "observerOptions", "trackAllChildren", "children"]); var trackedRef = useRef(false); var posthog = usePostHog(); var onIntersect = useCallback(function (entry) { if (entry.isIntersecting && !trackedRef.current) { posthog.capture("$element_viewed", __assign({ element_name: name }, properties)); trackedRef.current = true; } }, [ posthog, name, properties ]); if (trackAllChildren) { var trackedChildren = Children.map(children, function (child, index) { return React.createElement(TrackedChild, { key: index, child: child, index: index, name: name, properties: properties, observerOptions: observerOptions }); }); return React.createElement("div", props, trackedChildren); } return React.createElement(VisibilityAndClickTracker, __assign({ onIntersect: onIntersect, trackView: true, options: observerOptions }, props), children); } var isError = function (value) { var tag = Object.prototype.toString.call(value); return value instanceof Error || tag === "[object Error]" || tag === "[object Exception]" || tag === "[object DOMException]" || tag === "[object DOMError]"; }; var defineErrorName = function (error, name) { try { Object.defineProperty(error, "name", { value: name, writable: true, enumerable: true, configurable: true }); } catch (_b) { } }; var setCause = function (error, cause) { var seenErrors = new WeakSet(); var currentError = error; while (!seenErrors.has(currentError)) { seenErrors.add(currentError); if (!isError(currentError.cause)) { if (!isUndefined(currentError.cause)) cause.cause = currentError.cause; currentError.cause = cause; return; } currentError = currentError.cause; } }; var addReactComponentStack = function (error, componentStack) { if (!componentStack) return error; var componentStackError = new Error(isError(error) ? error.message : "Primitive value captured as exception: ".concat(String(error))); defineErrorName(componentStackError, "React ErrorBoundary ".concat(isError(error) ? error.name : "Error")); componentStackError.stack = componentStack; if (isError(error)) { setCause(error, componentStackError); return error; } return componentStackError; }; var INITIAL_STATE = { componentStack: null, exceptionEvent: null, error: null }; var __POSTHOG_ERROR_MESSAGES = { INVALID_FALLBACK: "[PostHog.js][PostHogErrorBoundary] Invalid fallback prop, provide a valid React element or a function that returns a valid React element." }; var PostHogErrorBoundary = (_a = (function (_super) { __extends(class_1, _super); function class_1(props) { var _this = _super.call(this, props) || this; _this._resetError = function () { _this.setState(INITIAL_STATE); }; _this.state = INITIAL_STATE; return _this; } class_1.prototype.componentDidCatch = function (error, errorInfo) { var additionalProperties = this.props.additionalProperties; var currentProperties; if (isFunction(additionalProperties)) currentProperties = additionalProperties(error, errorInfo); else if (typeof additionalProperties === "object") currentProperties = additionalProperties; var client = this.context.client; var componentStack = errorInfo.componentStack; var exceptionEvent = client.captureException(addReactComponentStack(error, componentStack), currentProperties); this.setState({ error: error, componentStack: componentStack !== null && componentStack !== void 0 ? componentStack : null, exceptionEvent: exceptionEvent }); }; class_1.prototype.render = function () { var _b = this.props, children = _b.children, fallback = _b.fallback; var state = this.state; if (state.componentStack == null) return isFunction(children) ? children() : children; var element = isFunction(fallback) ? React.createElement(fallback, { error: state.error, componentStack: state.componentStack, exceptionEvent: state.exceptionEvent, resetError: this._resetError }) : fallback; if (React.isValidElement(element)) return element; console.warn(__POSTHOG_ERROR_MESSAGES.INVALID_FALLBACK); return React.createElement(React.Fragment, null); }; return class_1; }(React.Component)), __setFunctionName(_a, "PostHogErrorBoundary"), (function () { _a.contextType = PostHogContext; })(), _a); var setupReactErrorHandler = function (client, callback) { return function (error, errorInfo) { var event = client.captureException(addReactComponentStack(error, errorInfo.componentStack)); if (callback) callback(event, error, errorInfo); }; }; export { PostHogCaptureOnViewed, PostHogContext, PostHogErrorBoundary, PostHogFeature, PostHogProvider, captureFeatureInteraction, captureFeatureView, setupReactErrorHandler, useActiveFeatureFlags, useFeatureFlagEnabled, useFeatureFlagPayload, useFeatureFlagResult, useFeatureFlagVariantKey, usePostHog }; //# sourceMappingURL=index.js.map