posthog-js
Version:
Posthog-js allows you to automatically capture usage and send events to PostHog.
271 lines • 14.1 kB
JavaScript
;
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 __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProductTourTooltip = ProductTourTooltip;
var jsx_runtime_1 = require("preact/jsx-runtime");
var hooks_1 = require("preact/hooks");
var core_1 = require("@posthog/core");
var product_tours_utils_1 = require("../product-tours-utils");
var surveys_extension_utils_1 = require("@posthog/browser-common/surveys/surveys-extension-utils");
var general_utils_1 = require("@posthog/browser-common/utils/general-utils");
var globals_1 = require("@posthog/browser-common/utils/globals");
var ProductTourTooltipInner_1 = require("./ProductTourTooltipInner");
var ProductTourSurveyStepInner_1 = require("./ProductTourSurveyStepInner");
var window = globals_1.window;
function getOppositePosition(position) {
var opposites = {
top: 'bottom',
bottom: 'top',
left: 'right',
right: 'left',
};
return opposites[position];
}
function scrollToElement(element, resolve) {
var initialRect = element.getBoundingClientRect();
var viewportHeight = window.innerHeight;
var viewportWidth = window.innerWidth;
var safeMarginY = viewportHeight / 6;
var safeMarginX = viewportWidth / 6;
var isInSafeZone = initialRect.top >= safeMarginY &&
initialRect.bottom <= viewportHeight - safeMarginY &&
initialRect.left >= safeMarginX &&
initialRect.right <= viewportWidth - safeMarginX;
if (isInSafeZone) {
resolve();
return;
}
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
var lastTop = initialRect.top;
var stableCount = 0;
var resolved = false;
var checkStability = function () {
if (resolved)
return;
var currentRect = element.getBoundingClientRect();
if (Math.abs(currentRect.top - lastTop) < 1) {
stableCount++;
if (stableCount >= 3) {
resolved = true;
resolve();
return;
}
}
else {
stableCount = 0;
}
lastTop = currentRect.top;
setTimeout(checkStability, 50);
};
setTimeout(checkStability, 30);
setTimeout(function () {
if (!resolved) {
resolved = true;
resolve();
}
}, 500);
}
var TRANSITION_DURATION = 150;
function ProductTourTooltip(_a) {
var _b;
var tour = _a.tour, step = _a.step, stepIndex = _a.stepIndex, totalSteps = _a.totalSteps, targetElement = _a.targetElement, onNext = _a.onNext, onPrevious = _a.onPrevious, onDismiss = _a.onDismiss, onSurveySubmit = _a.onSurveySubmit, onButtonClick = _a.onButtonClick;
var _c = __read((0, hooks_1.useState)('entering'), 2), transitionState = _c[0], setTransitionState = _c[1];
var _d = __read((0, hooks_1.useState)(null), 2), position = _d[0], setPosition = _d[1];
var _e = __read((0, hooks_1.useState)(null), 2), spotlightStyle = _e[0], setSpotlightStyle = _e[1];
var _f = __read((0, hooks_1.useState)(false), 2), isMeasured = _f[0], setIsMeasured = _f[1];
var _g = __read((0, hooks_1.useState)(step), 2), displayedStep = _g[0], setDisplayedStep = _g[1];
var _h = __read((0, hooks_1.useState)(stepIndex), 2), displayedStepIndex = _h[0], setDisplayedStepIndex = _h[1];
var tooltipRef = (0, hooks_1.useRef)(null);
var previousStepRef = (0, hooks_1.useRef)(stepIndex);
var isTransitioningRef = (0, hooks_1.useRef)(false);
var resolvedElementRef = (0, hooks_1.useRef)(targetElement);
// Steps without element targeting use screen positioning
var isScreenPositioned = !(0, product_tours_utils_1.hasElementTarget)(displayedStep) || displayedStep.type === 'survey';
(0, hooks_1.useLayoutEffect)(function () {
resolvedElementRef.current = targetElement;
}, [targetElement]);
var updatePosition = (0, hooks_1.useCallback)(function () {
var element = resolvedElementRef.current;
if (!element || !tooltipRef.current)
return;
var tooltipRect = tooltipRef.current.getBoundingClientRect();
var tooltipDimensions = {
width: tooltipRect.width,
height: tooltipRect.height,
};
var targetRect = element.getBoundingClientRect();
setPosition((0, product_tours_utils_1.calculateTooltipPosition)(targetRect, tooltipDimensions));
setSpotlightStyle((0, product_tours_utils_1.getSpotlightStyle)(targetRect));
setIsMeasured(true);
}, []);
(0, hooks_1.useLayoutEffect)(function () {
if (!isScreenPositioned && !isMeasured && tooltipRef.current && targetElement) {
updatePosition();
}
}, [isScreenPositioned, isMeasured, targetElement, updatePosition]);
(0, hooks_1.useEffect)(function () {
var currentStepIndex = stepIndex;
var isStepChange = previousStepRef.current !== stepIndex;
var finishEntering = function () {
if (previousStepRef.current !== currentStepIndex)
return;
setTransitionState('visible');
isTransitioningRef.current = false;
};
var enterStep = function () {
// Only scroll/position for steps with element targeting
if (resolvedElementRef.current && (0, product_tours_utils_1.hasElementTarget)(step)) {
if (!resolvedElementRef.current.isConnected) {
resolvedElementRef.current = (0, product_tours_utils_1.findStepElement)(step).element;
}
if (resolvedElementRef.current) {
scrollToElement(resolvedElementRef.current, function () {
if (previousStepRef.current !== currentStepIndex)
return;
updatePosition();
setTimeout(finishEntering, 50);
});
return;
}
}
setTimeout(finishEntering, 50);
};
if (!isStepChange) {
previousStepRef.current = stepIndex;
isTransitioningRef.current = true;
enterStep();
return;
}
previousStepRef.current = stepIndex;
isTransitioningRef.current = true;
setTransitionState('exiting');
setTimeout(function () {
if (previousStepRef.current !== currentStepIndex)
return;
// Reset position for element-targeted steps to prevent flash at old position
if ((0, product_tours_utils_1.hasElementTarget)(step)) {
setPosition(null);
setSpotlightStyle(null);
setIsMeasured(false);
}
setDisplayedStep(step);
setDisplayedStepIndex(stepIndex);
setTransitionState('entering');
enterStep();
}, TRANSITION_DURATION);
}, [targetElement, stepIndex, step, updatePosition]);
(0, hooks_1.useEffect)(function () {
if (transitionState !== 'visible' || isScreenPositioned)
return;
var handleUpdate = function () {
if (!isTransitioningRef.current) {
updatePosition();
}
};
(0, general_utils_1.addEventListener)(window, 'scroll', handleUpdate, { capture: true });
(0, general_utils_1.addEventListener)(window, 'resize', handleUpdate);
return function () {
window === null || window === void 0 ? void 0 : window.removeEventListener('scroll', handleUpdate, true);
window === null || window === void 0 ? void 0 : window.removeEventListener('resize', handleUpdate);
};
}, [updatePosition, transitionState, isScreenPositioned]);
(0, hooks_1.useEffect)(function () {
var handleKeyDown = function (e) {
if (e.key === 'Escape') {
onDismiss('escape_key');
}
};
(0, general_utils_1.addEventListener)(window, 'keydown', handleKeyDown);
return function () {
window === null || window === void 0 ? void 0 : window.removeEventListener('keydown', handleKeyDown);
};
}, [onDismiss]);
var handleOverlayClick = function (e) {
e.stopPropagation();
onDismiss('user_clicked_outside');
};
var handleTooltipClick = function (e) {
e.stopPropagation();
};
var handleSpotlightClick = function (e) {
e.stopPropagation();
if (resolvedElementRef.current) {
resolvedElementRef.current.click();
}
onNext();
};
var isVisible = transitionState === 'visible';
var isSurvey = displayedStep.type === 'survey';
// For element steps, position is ready once we've measured and calculated
var isPositionReady = isScreenPositioned || isMeasured;
var basePosition = { top: 'auto', right: 'auto', bottom: 'auto', left: 'auto', transform: 'none' };
// surveys default to bottom: 0, and PT should not, so this is a little clunky
var getModalPosition = function () {
var _a;
var pos = (0, surveys_extension_utils_1.getPopoverPosition)(undefined, (_a = displayedStep.modalPosition) !== null && _a !== void 0 ? _a : core_1.SurveyPosition.MiddleCenter);
if (!('top' in pos) && !('bottom' in pos)) {
return __assign(__assign({}, pos), { bottom: '30px' });
}
return pos;
};
var getElementPositionStyle = function () {
if (!position) {
return {};
}
var isHorizontal = position.position === 'left' || position.position === 'right';
return {
top: !(0, core_1.isUndefined)(position.top) ? "".concat(position.top, "px") : 'auto',
bottom: !(0, core_1.isUndefined)(position.bottom) ? "".concat(position.bottom, "px") : 'auto',
left: !(0, core_1.isUndefined)(position.left) ? "".concat(position.left, "px") : 'auto',
right: !(0, core_1.isUndefined)(position.right) ? "".concat(position.right, "px") : 'auto',
transform: isHorizontal ? 'translateY(-50%)' : 'translateX(-50%)',
};
};
var tooltipStyle = __assign(__assign({}, (displayedStep.maxWidth && {
width: "min(".concat(displayedStep.maxWidth, "px, calc(100vw - 16px))"),
maxWidth: "min(".concat(displayedStep.maxWidth, "px, calc(100vw - 16px))"),
})), (isScreenPositioned
? __assign(__assign({}, basePosition), getModalPosition()) : getElementPositionStyle()));
return ((0, jsx_runtime_1.jsxs)("div", { class: "ph-tour-container", children: [((_b = tour.appearance) === null || _b === void 0 ? void 0 : _b.dismissOnClickOutside) !== false && ((0, jsx_runtime_1.jsx)("div", { class: "ph-tour-click-overlay", onClick: handleOverlayClick })), (0, jsx_runtime_1.jsx)("div", { class: "ph-tour-modal-overlay", style: {
opacity: isScreenPositioned && isVisible ? 1 : 0,
transition: "opacity ".concat(TRANSITION_DURATION, "ms ease-out"),
pointerEvents: 'none',
} }), (0, jsx_runtime_1.jsx)("div", { class: "ph-tour-spotlight", style: __assign(__assign(__assign({}, (isVisible && isPositionReady && spotlightStyle
? spotlightStyle
: { top: '50%', left: '50%', width: '0px', height: '0px' })), { opacity: !isScreenPositioned && isVisible && isPositionReady ? 1 : 0, transition: "opacity ".concat(TRANSITION_DURATION, "ms ease-out") }), (displayedStep.progressionTrigger === 'click' &&
!isScreenPositioned && {
pointerEvents: 'auto',
cursor: 'pointer',
})), onClick: displayedStep.progressionTrigger === 'click' && !isScreenPositioned
? handleSpotlightClick
: undefined }), (0, jsx_runtime_1.jsxs)("div", { ref: tooltipRef, class: "ph-tour-tooltip ".concat(isScreenPositioned ? 'ph-tour-tooltip--modal' : '', " ").concat(isSurvey ? 'ph-tour-survey-step' : ''), style: __assign(__assign({}, tooltipStyle), { opacity: isVisible && isPositionReady ? 1 : 0, transition: "opacity ".concat(TRANSITION_DURATION, "ms ease-out") }), onClick: handleTooltipClick, children: [!isScreenPositioned && position && ((0, jsx_runtime_1.jsx)("div", { class: "ph-tour-arrow ph-tour-arrow--".concat(getOppositePosition(position.position)), style: position.arrowOffset !== 0
? { '--ph-tour-arrow-offset': "".concat(position.arrowOffset, "px") }
: undefined })), isSurvey ? ((0, jsx_runtime_1.jsx)(ProductTourSurveyStepInner_1.ProductTourSurveyStepInner, { step: displayedStep, appearance: tour.appearance, stepIndex: displayedStepIndex, totalSteps: totalSteps, onSubmit: onSurveySubmit, onPrevious: onPrevious, onDismiss: function () { return onDismiss('user_clicked_skip'); } })) : ((0, jsx_runtime_1.jsx)(ProductTourTooltipInner_1.ProductTourTooltipInner, { step: displayedStep, appearance: tour.appearance, stepIndex: displayedStepIndex, totalSteps: totalSteps, onNext: onNext, onPrevious: onPrevious, onDismiss: function () { return onDismiss('user_clicked_skip'); }, onButtonClick: onButtonClick }))] })] }));
}
//# sourceMappingURL=ProductTourTooltip.js.map