posthog-js 1.321.2 → 1.321.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/array.full.es5.js +1 -1
  2. package/dist/array.full.js +1 -1
  3. package/dist/array.full.no-external.js +1 -1
  4. package/dist/array.js +1 -1
  5. package/dist/array.no-external.js +1 -1
  6. package/dist/customizations.full.js +1 -1
  7. package/dist/lazy-recorder.js +1 -1
  8. package/dist/main.js +1 -1
  9. package/dist/main.js.map +1 -1
  10. package/dist/module.d.ts +1 -0
  11. package/dist/module.full.d.ts +1 -0
  12. package/dist/module.full.js +1 -1
  13. package/dist/module.full.js.map +1 -1
  14. package/dist/module.full.no-external.d.ts +1 -0
  15. package/dist/module.full.no-external.js +1 -1
  16. package/dist/module.full.no-external.js.map +1 -1
  17. package/dist/module.js +1 -1
  18. package/dist/module.js.map +1 -1
  19. package/dist/module.no-external.d.ts +1 -0
  20. package/dist/module.no-external.js +1 -1
  21. package/dist/module.no-external.js.map +1 -1
  22. package/dist/posthog-recorder.js +1 -1
  23. package/dist/product-tours-preview.d.ts +1 -0
  24. package/dist/product-tours-preview.js +1 -1
  25. package/dist/product-tours-preview.js.map +1 -1
  26. package/dist/product-tours.js +1 -1
  27. package/dist/product-tours.js.map +1 -1
  28. package/dist/src/extensions/product-tours/product-tours-utils.d.ts +9 -3
  29. package/dist/src/posthog-product-tours-types.d.ts +1 -0
  30. package/dist/surveys-preview.d.ts +1 -0
  31. package/lib/package.json +1 -1
  32. package/lib/src/extensions/product-tours/components/ProductTourTooltip.js +37 -14
  33. package/lib/src/extensions/product-tours/components/ProductTourTooltip.js.map +1 -1
  34. package/lib/src/extensions/product-tours/product-tours-utils.d.ts +9 -3
  35. package/lib/src/extensions/product-tours/product-tours-utils.js +13 -24
  36. package/lib/src/extensions/product-tours/product-tours-utils.js.map +1 -1
  37. package/lib/src/posthog-product-tours-types.d.ts +1 -0
  38. package/lib/src/posthog-product-tours-types.js +1 -0
  39. package/lib/src/posthog-product-tours-types.js.map +1 -1
  40. package/package.json +2 -2
@@ -15,11 +15,17 @@ export declare function getElementMetadata(element: HTMLElement): {
15
15
  };
16
16
  export type TooltipPosition = 'top' | 'bottom' | 'left' | 'right';
17
17
  export interface PositionResult {
18
- top: number;
19
- left: number;
20
18
  position: TooltipPosition;
19
+ top?: number;
20
+ bottom?: number;
21
+ left?: number;
22
+ right?: number;
21
23
  }
22
- export declare function calculateTooltipPosition(targetRect: DOMRect): PositionResult;
24
+ export interface TooltipDimensions {
25
+ width: number;
26
+ height: number;
27
+ }
28
+ export declare function calculateTooltipPosition(targetRect: DOMRect, tooltipDimensions: TooltipDimensions): PositionResult;
23
29
  export declare function getSpotlightStyle(targetRect: DOMRect, padding?: number): Record<string, string>;
24
30
  export declare function addProductTourCSSVariablesToElement(element: HTMLElement, appearance?: ProductTourAppearance): void;
25
31
  export declare function renderTipTapContent(content: any): string;
@@ -101,6 +101,7 @@ export interface ProductTourAppearance {
101
101
  whiteLabel?: boolean;
102
102
  /** defaults to true, auto-set to false for announcements/banners */
103
103
  dismissOnClickOutside?: boolean;
104
+ zIndex?: number;
104
105
  }
105
106
  export interface ProductTour {
106
107
  id: string;
@@ -1720,6 +1720,7 @@ interface ProductTourAppearance {
1720
1720
  whiteLabel?: boolean;
1721
1721
  /** defaults to true, auto-set to false for announcements/banners */
1722
1722
  dismissOnClickOutside?: boolean;
1723
+ zIndex?: number;
1723
1724
  }
1724
1725
  interface ProductTour {
1725
1726
  id: string;
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "posthog-js",
3
- "version": "1.321.2",
3
+ "version": "1.321.3",
4
4
  "description": "Posthog-js allows you to automatically capture usage and send events to PostHog.",
5
5
  "repository": "https://github.com/PostHog/posthog-js",
6
6
  "author": "hey@posthog.com",
@@ -37,7 +37,6 @@ var utils_1 = require("../../../utils");
37
37
  var globals_1 = require("../../../utils/globals");
38
38
  var ProductTourTooltipInner_1 = require("./ProductTourTooltipInner");
39
39
  var ProductTourSurveyStepInner_1 = require("./ProductTourSurveyStepInner");
40
- var core_2 = require("@posthog/core");
41
40
  var window = globals_1.window;
42
41
  function getOppositePosition(position) {
43
42
  var opposites = {
@@ -99,19 +98,32 @@ function ProductTourTooltip(_a) {
99
98
  var _c = __read((0, hooks_1.useState)('entering'), 2), transitionState = _c[0], setTransitionState = _c[1];
100
99
  var _d = __read((0, hooks_1.useState)(null), 2), position = _d[0], setPosition = _d[1];
101
100
  var _e = __read((0, hooks_1.useState)(null), 2), spotlightStyle = _e[0], setSpotlightStyle = _e[1];
102
- var _f = __read((0, hooks_1.useState)(step), 2), displayedStep = _f[0], setDisplayedStep = _f[1];
103
- var _g = __read((0, hooks_1.useState)(stepIndex), 2), displayedStepIndex = _g[0], setDisplayedStepIndex = _g[1];
101
+ var _f = __read((0, hooks_1.useState)(false), 2), isMeasured = _f[0], setIsMeasured = _f[1];
102
+ var _g = __read((0, hooks_1.useState)(step), 2), displayedStep = _g[0], setDisplayedStep = _g[1];
103
+ var _h = __read((0, hooks_1.useState)(stepIndex), 2), displayedStepIndex = _h[0], setDisplayedStepIndex = _h[1];
104
+ var tooltipRef = (0, hooks_1.useRef)(null);
104
105
  var previousStepRef = (0, hooks_1.useRef)(stepIndex);
105
106
  var isTransitioningRef = (0, hooks_1.useRef)(false);
106
107
  // Modal and survey steps use screen positioning (not anchored to an element)
107
108
  var isScreenPositioned = displayedStep.type === 'modal' || displayedStep.type === 'survey';
108
109
  var updatePosition = (0, hooks_1.useCallback)(function () {
109
- if (!targetElement)
110
+ if (!targetElement || !tooltipRef.current)
110
111
  return;
111
- var rect = targetElement.getBoundingClientRect();
112
- setPosition((0, product_tours_utils_1.calculateTooltipPosition)(rect));
113
- setSpotlightStyle((0, product_tours_utils_1.getSpotlightStyle)(rect));
112
+ var tooltipRect = tooltipRef.current.getBoundingClientRect();
113
+ var tooltipDimensions = {
114
+ width: tooltipRect.width,
115
+ height: tooltipRect.height,
116
+ };
117
+ var targetRect = targetElement.getBoundingClientRect();
118
+ setPosition((0, product_tours_utils_1.calculateTooltipPosition)(targetRect, tooltipDimensions));
119
+ setSpotlightStyle((0, product_tours_utils_1.getSpotlightStyle)(targetRect));
120
+ setIsMeasured(true);
114
121
  }, [targetElement]);
122
+ (0, hooks_1.useLayoutEffect)(function () {
123
+ if (!isScreenPositioned && !isMeasured && tooltipRef.current && targetElement) {
124
+ updatePosition();
125
+ }
126
+ }, [isScreenPositioned, isMeasured, targetElement, updatePosition]);
115
127
  (0, hooks_1.useEffect)(function () {
116
128
  var currentStepIndex = stepIndex;
117
129
  var isStepChange = previousStepRef.current !== stepIndex;
@@ -151,6 +163,7 @@ function ProductTourTooltip(_a) {
151
163
  if (step.type === 'element') {
152
164
  setPosition(null);
153
165
  setSpotlightStyle(null);
166
+ setIsMeasured(false);
154
167
  }
155
168
  setDisplayedStep(step);
156
169
  setDisplayedStepIndex(stepIndex);
@@ -200,8 +213,8 @@ function ProductTourTooltip(_a) {
200
213
  };
201
214
  var isVisible = transitionState === 'visible';
202
215
  var isSurvey = displayedStep.type === 'survey';
203
- // For element steps, don't render until position is calculated
204
- var isPositionReady = isScreenPositioned || !(0, core_2.isNull)(position);
216
+ // For element steps, position is ready once we've measured and calculated
217
+ var isPositionReady = isScreenPositioned || isMeasured;
205
218
  var basePosition = { top: 'auto', right: 'auto', bottom: 'auto', left: 'auto', transform: 'none' };
206
219
  // surveys default to bottom: 0, and PT should not, so this is a little clunky
207
220
  var getModalPosition = function () {
@@ -212,14 +225,24 @@ function ProductTourTooltip(_a) {
212
225
  }
213
226
  return pos;
214
227
  };
228
+ var getElementPositionStyle = function () {
229
+ if (!position) {
230
+ return {};
231
+ }
232
+ var isHorizontal = position.position === 'left' || position.position === 'right';
233
+ return {
234
+ top: !(0, core_1.isUndefined)(position.top) ? "".concat(position.top, "px") : 'auto',
235
+ bottom: !(0, core_1.isUndefined)(position.bottom) ? "".concat(position.bottom, "px") : 'auto',
236
+ left: !(0, core_1.isUndefined)(position.left) ? "".concat(position.left, "px") : 'auto',
237
+ right: !(0, core_1.isUndefined)(position.right) ? "".concat(position.right, "px") : 'auto',
238
+ transform: isHorizontal ? 'translateY(-50%)' : 'translateX(-50%)',
239
+ };
240
+ };
215
241
  var tooltipStyle = __assign(__assign({}, (displayedStep.maxWidth && {
216
242
  width: "".concat(displayedStep.maxWidth, "px"),
217
243
  maxWidth: "".concat(displayedStep.maxWidth, "px"),
218
244
  })), (isScreenPositioned
219
- ? __assign(__assign({}, basePosition), getModalPosition()) : {
220
- top: position ? "".concat(position.top, "px") : '0',
221
- left: position ? "".concat(position.left, "px") : '0',
222
- }));
245
+ ? __assign(__assign({}, basePosition), getModalPosition()) : getElementPositionStyle()));
223
246
  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: {
224
247
  opacity: isScreenPositioned && isVisible ? 1 : 0,
225
248
  transition: "opacity ".concat(TRANSITION_DURATION, "ms ease-out"),
@@ -232,6 +255,6 @@ function ProductTourTooltip(_a) {
232
255
  cursor: 'pointer',
233
256
  })), onClick: displayedStep.progressionTrigger === 'click' && !isScreenPositioned
234
257
  ? handleSpotlightClick
235
- : undefined }), (0, jsx_runtime_1.jsxs)("div", { 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)) })), 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 }))] })] }));
258
+ : 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)) })), 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 }))] })] }));
236
259
  }
237
260
  //# sourceMappingURL=ProductTourTooltip.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProductTourTooltip.js","sourceRoot":"","sources":["../../../../../src/extensions/product-tours/components/ProductTourTooltip.tsx"],"names":[],"mappings":"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","sourcesContent":["import { h } from 'preact'\nimport { useEffect, useState, useCallback, useRef } from 'preact/hooks'\nimport {\n ProductTour,\n ProductTourStep,\n ProductTourDismissReason,\n ProductTourStepButton,\n} from '../../../posthog-product-tours-types'\nimport { SurveyPosition } from '@posthog/core'\nimport { calculateTooltipPosition, getSpotlightStyle, TooltipPosition } from '../product-tours-utils'\nimport { getPopoverPosition } from '../../surveys/surveys-extension-utils'\nimport { addEventListener } from '../../../utils'\nimport { window as _window } from '../../../utils/globals'\nimport { ProductTourTooltipInner } from './ProductTourTooltipInner'\nimport { ProductTourSurveyStepInner } from './ProductTourSurveyStepInner'\nimport { isNull } from '@posthog/core'\n\nconst window = _window as Window & typeof globalThis\n\ntype TransitionState = 'entering' | 'visible' | 'exiting'\n\nexport interface ProductTourTooltipProps {\n tour: ProductTour\n step: ProductTourStep\n stepIndex: number\n totalSteps: number\n targetElement: HTMLElement | null\n onNext: () => void\n onPrevious: () => void\n onDismiss: (reason: ProductTourDismissReason) => void\n onSurveySubmit?: (response: string | number | null) => void\n onButtonClick?: (button: ProductTourStepButton) => void\n}\n\nfunction getOppositePosition(position: TooltipPosition): TooltipPosition {\n const opposites: Record<TooltipPosition, TooltipPosition> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n }\n return opposites[position]\n}\n\nfunction scrollToElement(element: HTMLElement, resolve: () => void): void {\n const initialRect = element.getBoundingClientRect()\n const viewportHeight = window.innerHeight\n const viewportWidth = window.innerWidth\n\n const safeMarginY = viewportHeight / 6\n const safeMarginX = viewportWidth / 6\n\n const isInSafeZone =\n initialRect.top >= safeMarginY &&\n initialRect.bottom <= viewportHeight - safeMarginY &&\n initialRect.left >= safeMarginX &&\n initialRect.right <= viewportWidth - safeMarginX\n\n if (isInSafeZone) {\n resolve()\n return\n }\n\n element.scrollIntoView({ behavior: 'smooth', block: 'center' })\n\n let lastTop = initialRect.top\n let stableCount = 0\n let resolved = false\n\n const checkStability = () => {\n if (resolved) return\n\n const currentRect = element.getBoundingClientRect()\n if (Math.abs(currentRect.top - lastTop) < 1) {\n stableCount++\n if (stableCount >= 3) {\n resolved = true\n resolve()\n return\n }\n } else {\n stableCount = 0\n }\n lastTop = currentRect.top\n setTimeout(checkStability, 50)\n }\n\n setTimeout(checkStability, 30)\n\n setTimeout(() => {\n if (!resolved) {\n resolved = true\n resolve()\n }\n }, 500)\n}\n\nconst TRANSITION_DURATION = 150\n\nexport function ProductTourTooltip({\n tour,\n step,\n stepIndex,\n totalSteps,\n targetElement,\n onNext,\n onPrevious,\n onDismiss,\n onSurveySubmit,\n onButtonClick,\n}: ProductTourTooltipProps): h.JSX.Element {\n const [transitionState, setTransitionState] = useState<TransitionState>('entering')\n const [position, setPosition] = useState<ReturnType<typeof calculateTooltipPosition> | null>(null)\n const [spotlightStyle, setSpotlightStyle] = useState<ReturnType<typeof getSpotlightStyle> | null>(null)\n\n const [displayedStep, setDisplayedStep] = useState(step)\n const [displayedStepIndex, setDisplayedStepIndex] = useState(stepIndex)\n\n const previousStepRef = useRef(stepIndex)\n const isTransitioningRef = useRef(false)\n\n // Modal and survey steps use screen positioning (not anchored to an element)\n const isScreenPositioned = displayedStep.type === 'modal' || displayedStep.type === 'survey'\n\n const updatePosition = useCallback(() => {\n if (!targetElement) return\n const rect = targetElement.getBoundingClientRect()\n setPosition(calculateTooltipPosition(rect))\n setSpotlightStyle(getSpotlightStyle(rect))\n }, [targetElement])\n\n useEffect(() => {\n const currentStepIndex = stepIndex\n const isStepChange = previousStepRef.current !== stepIndex\n\n const finishEntering = () => {\n if (previousStepRef.current !== currentStepIndex) return\n setTransitionState('visible')\n isTransitioningRef.current = false\n }\n\n const enterStep = () => {\n // Only scroll/position for element steps\n if (targetElement && step.type === 'element') {\n scrollToElement(targetElement, () => {\n if (previousStepRef.current !== currentStepIndex) return\n updatePosition()\n setTimeout(finishEntering, 50)\n })\n } else {\n setTimeout(finishEntering, 50)\n }\n }\n\n if (!isStepChange) {\n previousStepRef.current = stepIndex\n isTransitioningRef.current = true\n enterStep()\n return\n }\n\n previousStepRef.current = stepIndex\n isTransitioningRef.current = true\n setTransitionState('exiting')\n\n setTimeout(() => {\n if (previousStepRef.current !== currentStepIndex) return\n\n // Reset position for element steps to prevent flash at old position\n if (step.type === 'element') {\n setPosition(null)\n setSpotlightStyle(null)\n }\n\n setDisplayedStep(step)\n setDisplayedStepIndex(stepIndex)\n setTransitionState('entering')\n\n enterStep()\n }, TRANSITION_DURATION)\n }, [targetElement, stepIndex, step, updatePosition])\n\n useEffect(() => {\n if (transitionState !== 'visible' || isScreenPositioned) return\n\n const handleUpdate = () => {\n if (!isTransitioningRef.current) {\n updatePosition()\n }\n }\n\n addEventListener(window, 'scroll', handleUpdate as EventListener, { capture: true })\n addEventListener(window, 'resize', handleUpdate as EventListener)\n\n return () => {\n window?.removeEventListener('scroll', handleUpdate, true)\n window?.removeEventListener('resize', handleUpdate)\n }\n }, [updatePosition, transitionState, isScreenPositioned])\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onDismiss('escape_key')\n }\n }\n addEventListener(window, 'keydown', handleKeyDown as EventListener)\n return () => {\n window?.removeEventListener('keydown', handleKeyDown)\n }\n }, [onDismiss])\n\n const handleOverlayClick = (e: MouseEvent) => {\n e.stopPropagation()\n onDismiss('user_clicked_outside')\n }\n\n const handleTooltipClick = (e: MouseEvent) => {\n e.stopPropagation()\n }\n\n const handleSpotlightClick = (e: MouseEvent) => {\n e.stopPropagation()\n if (targetElement) {\n targetElement.click()\n }\n onNext()\n }\n\n const isVisible = transitionState === 'visible'\n const isSurvey = displayedStep.type === 'survey'\n\n // For element steps, don't render until position is calculated\n const isPositionReady = isScreenPositioned || !isNull(position)\n\n const basePosition = { top: 'auto', right: 'auto', bottom: 'auto', left: 'auto', transform: 'none' }\n\n // surveys default to bottom: 0, and PT should not, so this is a little clunky\n const getModalPosition = () => {\n const pos = getPopoverPosition(undefined, displayedStep.modalPosition ?? SurveyPosition.MiddleCenter)\n if (!('top' in pos) && !('bottom' in pos)) {\n return { ...pos, bottom: '30px' }\n }\n return pos\n }\n\n const tooltipStyle = {\n ...(displayedStep.maxWidth && {\n width: `${displayedStep.maxWidth}px`,\n maxWidth: `${displayedStep.maxWidth}px`,\n }),\n ...(isScreenPositioned\n ? {\n ...basePosition,\n ...getModalPosition(),\n }\n : {\n top: position ? `${position.top}px` : '0',\n left: position ? `${position.left}px` : '0',\n }),\n }\n\n return (\n <div class=\"ph-tour-container\">\n {tour.appearance?.dismissOnClickOutside !== false && (\n <div class=\"ph-tour-click-overlay\" onClick={handleOverlayClick} />\n )}\n\n {/* Modal overlay - visible for non-element steps */}\n <div\n class=\"ph-tour-modal-overlay\"\n style={{\n opacity: isScreenPositioned && isVisible ? 1 : 0,\n transition: `opacity ${TRANSITION_DURATION}ms ease-out`,\n pointerEvents: 'none',\n }}\n />\n\n {/* Spotlight - visible for element steps */}\n <div\n class=\"ph-tour-spotlight\"\n style={{\n ...(isVisible && isPositionReady && spotlightStyle\n ? spotlightStyle\n : { top: '50%', left: '50%', width: '0px', height: '0px' }),\n opacity: !isScreenPositioned && isVisible && isPositionReady ? 1 : 0,\n transition: `opacity ${TRANSITION_DURATION}ms ease-out`,\n ...(displayedStep.progressionTrigger === 'click' &&\n !isScreenPositioned && {\n pointerEvents: 'auto',\n cursor: 'pointer',\n }),\n }}\n onClick={\n displayedStep.progressionTrigger === 'click' && !isScreenPositioned\n ? handleSpotlightClick\n : undefined\n }\n />\n\n <div\n class={`ph-tour-tooltip ${isScreenPositioned ? 'ph-tour-tooltip--modal' : ''} ${isSurvey ? 'ph-tour-survey-step' : ''}`}\n style={{\n ...tooltipStyle,\n opacity: isVisible && isPositionReady ? 1 : 0,\n transition: `opacity ${TRANSITION_DURATION}ms ease-out`,\n }}\n onClick={handleTooltipClick}\n >\n {!isScreenPositioned && position && (\n <div class={`ph-tour-arrow ph-tour-arrow--${getOppositePosition(position.position)}`} />\n )}\n\n {isSurvey ? (\n <ProductTourSurveyStepInner\n step={displayedStep}\n appearance={tour.appearance}\n stepIndex={displayedStepIndex}\n totalSteps={totalSteps}\n onSubmit={onSurveySubmit}\n onPrevious={onPrevious}\n onDismiss={() => onDismiss('user_clicked_skip')}\n />\n ) : (\n <ProductTourTooltipInner\n step={displayedStep}\n appearance={tour.appearance}\n stepIndex={displayedStepIndex}\n totalSteps={totalSteps}\n onNext={onNext}\n onPrevious={onPrevious}\n onDismiss={() => onDismiss('user_clicked_skip')}\n onButtonClick={onButtonClick}\n />\n )}\n </div>\n </div>\n )\n}\n"]}
1
+ {"version":3,"file":"ProductTourTooltip.js","sourceRoot":"","sources":["../../../../../src/extensions/product-tours/components/ProductTourTooltip.tsx"],"names":[],"mappings":"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","sourcesContent":["import { h } from 'preact'\nimport { useEffect, useLayoutEffect, useState, useCallback, useRef } from 'preact/hooks'\nimport {\n ProductTour,\n ProductTourStep,\n ProductTourDismissReason,\n ProductTourStepButton,\n} from '../../../posthog-product-tours-types'\nimport { isUndefined, SurveyPosition } from '@posthog/core'\nimport { calculateTooltipPosition, getSpotlightStyle, TooltipPosition, TooltipDimensions } from '../product-tours-utils'\nimport { getPopoverPosition } from '../../surveys/surveys-extension-utils'\nimport { addEventListener } from '../../../utils'\nimport { window as _window } from '../../../utils/globals'\nimport { ProductTourTooltipInner } from './ProductTourTooltipInner'\nimport { ProductTourSurveyStepInner } from './ProductTourSurveyStepInner'\n\nconst window = _window as Window & typeof globalThis\n\ntype TransitionState = 'entering' | 'visible' | 'exiting'\n\nexport interface ProductTourTooltipProps {\n tour: ProductTour\n step: ProductTourStep\n stepIndex: number\n totalSteps: number\n targetElement: HTMLElement | null\n onNext: () => void\n onPrevious: () => void\n onDismiss: (reason: ProductTourDismissReason) => void\n onSurveySubmit?: (response: string | number | null) => void\n onButtonClick?: (button: ProductTourStepButton) => void\n}\n\nfunction getOppositePosition(position: TooltipPosition): TooltipPosition {\n const opposites: Record<TooltipPosition, TooltipPosition> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n }\n return opposites[position]\n}\n\nfunction scrollToElement(element: HTMLElement, resolve: () => void): void {\n const initialRect = element.getBoundingClientRect()\n const viewportHeight = window.innerHeight\n const viewportWidth = window.innerWidth\n\n const safeMarginY = viewportHeight / 6\n const safeMarginX = viewportWidth / 6\n\n const isInSafeZone =\n initialRect.top >= safeMarginY &&\n initialRect.bottom <= viewportHeight - safeMarginY &&\n initialRect.left >= safeMarginX &&\n initialRect.right <= viewportWidth - safeMarginX\n\n if (isInSafeZone) {\n resolve()\n return\n }\n\n element.scrollIntoView({ behavior: 'smooth', block: 'center' })\n\n let lastTop = initialRect.top\n let stableCount = 0\n let resolved = false\n\n const checkStability = () => {\n if (resolved) return\n\n const currentRect = element.getBoundingClientRect()\n if (Math.abs(currentRect.top - lastTop) < 1) {\n stableCount++\n if (stableCount >= 3) {\n resolved = true\n resolve()\n return\n }\n } else {\n stableCount = 0\n }\n lastTop = currentRect.top\n setTimeout(checkStability, 50)\n }\n\n setTimeout(checkStability, 30)\n\n setTimeout(() => {\n if (!resolved) {\n resolved = true\n resolve()\n }\n }, 500)\n}\n\nconst TRANSITION_DURATION = 150\n\nexport function ProductTourTooltip({\n tour,\n step,\n stepIndex,\n totalSteps,\n targetElement,\n onNext,\n onPrevious,\n onDismiss,\n onSurveySubmit,\n onButtonClick,\n}: ProductTourTooltipProps): h.JSX.Element {\n const [transitionState, setTransitionState] = useState<TransitionState>('entering')\n const [position, setPosition] = useState<ReturnType<typeof calculateTooltipPosition> | null>(null)\n const [spotlightStyle, setSpotlightStyle] = useState<ReturnType<typeof getSpotlightStyle> | null>(null)\n const [isMeasured, setIsMeasured] = useState(false)\n\n const [displayedStep, setDisplayedStep] = useState(step)\n const [displayedStepIndex, setDisplayedStepIndex] = useState(stepIndex)\n\n const tooltipRef = useRef<HTMLDivElement>(null)\n const previousStepRef = useRef(stepIndex)\n const isTransitioningRef = useRef(false)\n\n // Modal and survey steps use screen positioning (not anchored to an element)\n const isScreenPositioned = displayedStep.type === 'modal' || displayedStep.type === 'survey'\n\n const updatePosition = useCallback(() => {\n if (!targetElement || !tooltipRef.current) return\n\n const tooltipRect = tooltipRef.current.getBoundingClientRect()\n const tooltipDimensions: TooltipDimensions = {\n width: tooltipRect.width,\n height: tooltipRect.height,\n }\n\n const targetRect = targetElement.getBoundingClientRect()\n setPosition(calculateTooltipPosition(targetRect, tooltipDimensions))\n setSpotlightStyle(getSpotlightStyle(targetRect))\n setIsMeasured(true)\n }, [targetElement])\n\n useLayoutEffect(() => {\n if (!isScreenPositioned && !isMeasured && tooltipRef.current && targetElement) {\n updatePosition()\n }\n }, [isScreenPositioned, isMeasured, targetElement, updatePosition])\n\n useEffect(() => {\n const currentStepIndex = stepIndex\n const isStepChange = previousStepRef.current !== stepIndex\n\n const finishEntering = () => {\n if (previousStepRef.current !== currentStepIndex) return\n setTransitionState('visible')\n isTransitioningRef.current = false\n }\n\n const enterStep = () => {\n // Only scroll/position for element steps\n if (targetElement && step.type === 'element') {\n scrollToElement(targetElement, () => {\n if (previousStepRef.current !== currentStepIndex) return\n updatePosition()\n setTimeout(finishEntering, 50)\n })\n } else {\n setTimeout(finishEntering, 50)\n }\n }\n\n if (!isStepChange) {\n previousStepRef.current = stepIndex\n isTransitioningRef.current = true\n enterStep()\n return\n }\n\n previousStepRef.current = stepIndex\n isTransitioningRef.current = true\n setTransitionState('exiting')\n\n setTimeout(() => {\n if (previousStepRef.current !== currentStepIndex) return\n\n // Reset position for element steps to prevent flash at old position\n if (step.type === 'element') {\n setPosition(null)\n setSpotlightStyle(null)\n setIsMeasured(false)\n }\n\n setDisplayedStep(step)\n setDisplayedStepIndex(stepIndex)\n setTransitionState('entering')\n\n enterStep()\n }, TRANSITION_DURATION)\n }, [targetElement, stepIndex, step, updatePosition])\n\n useEffect(() => {\n if (transitionState !== 'visible' || isScreenPositioned) return\n\n const handleUpdate = () => {\n if (!isTransitioningRef.current) {\n updatePosition()\n }\n }\n\n addEventListener(window, 'scroll', handleUpdate as EventListener, { capture: true })\n addEventListener(window, 'resize', handleUpdate as EventListener)\n\n return () => {\n window?.removeEventListener('scroll', handleUpdate, true)\n window?.removeEventListener('resize', handleUpdate)\n }\n }, [updatePosition, transitionState, isScreenPositioned])\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onDismiss('escape_key')\n }\n }\n addEventListener(window, 'keydown', handleKeyDown as EventListener)\n return () => {\n window?.removeEventListener('keydown', handleKeyDown)\n }\n }, [onDismiss])\n\n const handleOverlayClick = (e: MouseEvent) => {\n e.stopPropagation()\n onDismiss('user_clicked_outside')\n }\n\n const handleTooltipClick = (e: MouseEvent) => {\n e.stopPropagation()\n }\n\n const handleSpotlightClick = (e: MouseEvent) => {\n e.stopPropagation()\n if (targetElement) {\n targetElement.click()\n }\n onNext()\n }\n\n const isVisible = transitionState === 'visible'\n const isSurvey = displayedStep.type === 'survey'\n\n // For element steps, position is ready once we've measured and calculated\n const isPositionReady = isScreenPositioned || isMeasured\n\n const basePosition = { top: 'auto', right: 'auto', bottom: 'auto', left: 'auto', transform: 'none' }\n\n // surveys default to bottom: 0, and PT should not, so this is a little clunky\n const getModalPosition = () => {\n const pos = getPopoverPosition(undefined, displayedStep.modalPosition ?? SurveyPosition.MiddleCenter)\n if (!('top' in pos) && !('bottom' in pos)) {\n return { ...pos, bottom: '30px' }\n }\n return pos\n }\n\n const getElementPositionStyle = (): Record<string, string> => {\n if (!position) {\n return {}\n }\n\n const isHorizontal = position.position === 'left' || position.position === 'right'\n\n return {\n top: !isUndefined(position.top) ? `${position.top}px` : 'auto',\n bottom: !isUndefined(position.bottom) ? `${position.bottom}px` : 'auto',\n left: !isUndefined(position.left) ? `${position.left}px` : 'auto',\n right: !isUndefined(position.right) ? `${position.right}px` : 'auto',\n transform: isHorizontal ? 'translateY(-50%)' : 'translateX(-50%)',\n }\n }\n\n const tooltipStyle = {\n ...(displayedStep.maxWidth && {\n width: `${displayedStep.maxWidth}px`,\n maxWidth: `${displayedStep.maxWidth}px`,\n }),\n ...(isScreenPositioned\n ? {\n ...basePosition,\n ...getModalPosition(),\n }\n : getElementPositionStyle()),\n }\n\n return (\n <div class=\"ph-tour-container\">\n {tour.appearance?.dismissOnClickOutside !== false && (\n <div class=\"ph-tour-click-overlay\" onClick={handleOverlayClick} />\n )}\n\n {/* Modal overlay - visible for non-element steps */}\n <div\n class=\"ph-tour-modal-overlay\"\n style={{\n opacity: isScreenPositioned && isVisible ? 1 : 0,\n transition: `opacity ${TRANSITION_DURATION}ms ease-out`,\n pointerEvents: 'none',\n }}\n />\n\n {/* Spotlight - visible for element steps */}\n <div\n class=\"ph-tour-spotlight\"\n style={{\n ...(isVisible && isPositionReady && spotlightStyle\n ? spotlightStyle\n : { top: '50%', left: '50%', width: '0px', height: '0px' }),\n opacity: !isScreenPositioned && isVisible && isPositionReady ? 1 : 0,\n transition: `opacity ${TRANSITION_DURATION}ms ease-out`,\n ...(displayedStep.progressionTrigger === 'click' &&\n !isScreenPositioned && {\n pointerEvents: 'auto',\n cursor: 'pointer',\n }),\n }}\n onClick={\n displayedStep.progressionTrigger === 'click' && !isScreenPositioned\n ? handleSpotlightClick\n : undefined\n }\n />\n\n <div\n ref={tooltipRef}\n class={`ph-tour-tooltip ${isScreenPositioned ? 'ph-tour-tooltip--modal' : ''} ${isSurvey ? 'ph-tour-survey-step' : ''}`}\n style={{\n ...tooltipStyle,\n opacity: isVisible && isPositionReady ? 1 : 0,\n transition: `opacity ${TRANSITION_DURATION}ms ease-out`,\n }}\n onClick={handleTooltipClick}\n >\n {!isScreenPositioned && position && (\n <div class={`ph-tour-arrow ph-tour-arrow--${getOppositePosition(position.position)}`} />\n )}\n\n {isSurvey ? (\n <ProductTourSurveyStepInner\n step={displayedStep}\n appearance={tour.appearance}\n stepIndex={displayedStepIndex}\n totalSteps={totalSteps}\n onSubmit={onSurveySubmit}\n onPrevious={onPrevious}\n onDismiss={() => onDismiss('user_clicked_skip')}\n />\n ) : (\n <ProductTourTooltipInner\n step={displayedStep}\n appearance={tour.appearance}\n stepIndex={displayedStepIndex}\n totalSteps={totalSteps}\n onNext={onNext}\n onPrevious={onPrevious}\n onDismiss={() => onDismiss('user_clicked_skip')}\n onButtonClick={onButtonClick}\n />\n )}\n </div>\n </div>\n )\n}\n"]}
@@ -15,11 +15,17 @@ export declare function getElementMetadata(element: HTMLElement): {
15
15
  };
16
16
  export type TooltipPosition = 'top' | 'bottom' | 'left' | 'right';
17
17
  export interface PositionResult {
18
- top: number;
19
- left: number;
20
18
  position: TooltipPosition;
19
+ top?: number;
20
+ bottom?: number;
21
+ left?: number;
22
+ right?: number;
21
23
  }
22
- export declare function calculateTooltipPosition(targetRect: DOMRect): PositionResult;
24
+ export interface TooltipDimensions {
25
+ width: number;
26
+ height: number;
27
+ }
28
+ export declare function calculateTooltipPosition(targetRect: DOMRect, tooltipDimensions: TooltipDimensions): PositionResult;
23
29
  export declare function getSpotlightStyle(targetRect: DOMRect, padding?: number): Record<string, string>;
24
30
  export declare function addProductTourCSSVariablesToElement(element: HTMLElement, appearance?: ProductTourAppearance): void;
25
31
  export declare function renderTipTapContent(content: any): string;
@@ -88,38 +88,26 @@ function getElementMetadata(element) {
88
88
  };
89
89
  }
90
90
  var TOOLTIP_MARGIN = 12;
91
- var TOOLTIP_WIDTH = 320;
92
- var TOOLTIP_HEIGHT_ESTIMATE = 180;
93
- function calculateTooltipPosition(targetRect) {
91
+ function calculateTooltipPosition(targetRect, tooltipDimensions) {
94
92
  var viewportWidth = window.innerWidth;
95
93
  var viewportHeight = window.innerHeight;
94
+ var width = tooltipDimensions.width, height = tooltipDimensions.height;
95
+ var spaceAbove = targetRect.top;
96
96
  var spaceBelow = viewportHeight - targetRect.bottom;
97
97
  var spaceLeft = targetRect.left;
98
98
  var spaceRight = viewportWidth - targetRect.right;
99
- var position;
100
- var top;
101
- var left;
102
- if (spaceRight >= TOOLTIP_WIDTH + TOOLTIP_MARGIN) {
103
- position = 'right';
104
- top = targetRect.top + targetRect.height / 2 - TOOLTIP_HEIGHT_ESTIMATE / 2;
105
- left = targetRect.right + TOOLTIP_MARGIN;
99
+ var targetCenterY = targetRect.top + targetRect.height / 2;
100
+ var targetCenterX = targetRect.left + targetRect.width / 2;
101
+ if (spaceRight >= width + TOOLTIP_MARGIN) {
102
+ return { position: 'right', top: targetCenterY, left: targetRect.right + TOOLTIP_MARGIN };
106
103
  }
107
- else if (spaceLeft >= TOOLTIP_WIDTH + TOOLTIP_MARGIN) {
108
- position = 'left';
109
- top = targetRect.top + targetRect.height / 2 - TOOLTIP_HEIGHT_ESTIMATE / 2;
110
- left = targetRect.left - TOOLTIP_WIDTH - TOOLTIP_MARGIN;
104
+ if (spaceLeft >= width + TOOLTIP_MARGIN) {
105
+ return { position: 'left', top: targetCenterY, right: viewportWidth - targetRect.left + TOOLTIP_MARGIN };
111
106
  }
112
- else if (spaceBelow >= TOOLTIP_HEIGHT_ESTIMATE + TOOLTIP_MARGIN) {
113
- position = 'bottom';
114
- top = targetRect.bottom + TOOLTIP_MARGIN;
115
- left = targetRect.left + targetRect.width / 2 - TOOLTIP_WIDTH / 2;
107
+ if (spaceAbove >= height + TOOLTIP_MARGIN && spaceBelow < height + TOOLTIP_MARGIN) {
108
+ return { position: 'top', bottom: viewportHeight - targetRect.top + TOOLTIP_MARGIN, left: targetCenterX };
116
109
  }
117
- else {
118
- position = 'top';
119
- top = targetRect.top - TOOLTIP_HEIGHT_ESTIMATE - TOOLTIP_MARGIN;
120
- left = targetRect.left + targetRect.width / 2 - TOOLTIP_WIDTH / 2;
121
- }
122
- return { top: top, left: left, position: position };
110
+ return { position: 'bottom', top: targetRect.bottom + TOOLTIP_MARGIN, left: targetCenterX };
123
111
  }
124
112
  function getSpotlightStyle(targetRect, padding) {
125
113
  if (padding === void 0) { padding = 8; }
@@ -147,6 +135,7 @@ function addProductTourCSSVariablesToElement(element, appearance) {
147
135
  style.setProperty('--ph-tour-button-text-color', (0, surveys_extension_utils_1.getContrastingTextColor)(merged.buttonColor));
148
136
  style.setProperty('--ph-tour-box-shadow', merged.boxShadow);
149
137
  style.setProperty('--ph-tour-overlay-color', merged.showOverlay ? 'rgba(0, 0, 0, 0.5)' : 'transparent');
138
+ style.setProperty('--ph-tour-z-index', String(merged.zIndex));
150
139
  // Internal styling variables (not customizable)
151
140
  style.setProperty('--ph-tour-button-secondary-color', 'transparent');
152
141
  style.setProperty('--ph-tour-button-secondary-text-color', merged.textColor);
@@ -1 +1 @@
1
- {"version":3,"file":"product-tours-utils.js","sourceRoot":"","sources":["../../../../src/extensions/product-tours/product-tours-utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBA,4DAIC;AAQD,sDAsBC;AAED,4CAaC;AAED,gDAYC;AAcD,4DA+BC;AAED,8CAOC;AAED,kFAyBC;AAED,kDAwDC;AAED,oCAEC;AAQD,kCAUC;AAjPD,wDAAiC;AAEjC,iFAK0C;AAC1C,gEAA8D;AAC9D,+CAA8E;AAC9E,8EAAsG;AAEtG,wEAAkD;AAElD,IAAM,QAAQ,GAAG,kBAAqB,CAAA;AACtC,IAAM,MAAM,GAAG,gBAAqC,CAAA;AAEpD,SAAgB,wBAAwB;IACpC,IAAM,UAAU,GAAG,IAAA,qCAAiB,EAAC,QAAQ,EAAE,OAAO,0BAAiB,KAAK,QAAQ,CAAC,CAAC,CAAC,0BAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAC9G,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,YAAY,CAAC,4BAA4B,EAAE,MAAM,CAAC,CAAA;IAC9D,OAAO,UAAU,CAAA;AACrB,CAAC;AAQD,SAAgB,qBAAqB,CAAC,QAAgB;IAClD,IAAI,CAAC;QACD,IAAM,QAAQ,GAAG,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QAEpD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,EAAE,CAAA;QAC/D,CAAC;QAED,IAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAgB,CAAA;QAE1C,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAA;QAC/E,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,EAAE,OAAO,SAAA,EAAE,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAA;QAC9E,CAAC;QAED,OAAO,EAAE,OAAO,SAAA,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,CAAA;IAClD,CAAC;IAAC,WAAM,CAAC;QACL,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,EAAE,CAAA;IAC/D,CAAC;AACL,CAAC;AAED,SAAgB,gBAAgB,CAAC,OAAoB;IACjD,IAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAA;IAE9C,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,IAAI,KAAK,CAAC,UAAU,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,KAAK,GAAG,EAAE,CAAC;QACrF,OAAO,KAAK,CAAA;IAChB,CAAC;IAED,IAAM,IAAI,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAA;IAC5C,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,OAAO,KAAK,CAAA;IAChB,CAAC;IAED,OAAO,IAAI,CAAA;AACf,CAAC;AAED,SAAgB,kBAAkB,CAAC,OAAoB;;IAMnD,OAAO;QACH,GAAG,EAAE,OAAO,CAAC,OAAO;QACpB,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,SAAS;QAC3B,OAAO,EAAE,OAAO,CAAC,SAAS,IAAI,SAAS;QACvC,IAAI,EAAE,CAAA,MAAA,OAAO,CAAC,SAAS,0CAAE,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,KAAI,SAAS;KACtD,CAAA;AACL,CAAC;AAUD,IAAM,cAAc,GAAG,EAAE,CAAA;AACzB,IAAM,aAAa,GAAG,GAAG,CAAA;AACzB,IAAM,uBAAuB,GAAG,GAAG,CAAA;AAEnC,SAAgB,wBAAwB,CAAC,UAAmB;IACxD,IAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAA;IACvC,IAAM,cAAc,GAAG,MAAM,CAAC,WAAW,CAAA;IAEzC,IAAM,UAAU,GAAG,cAAc,GAAG,UAAU,CAAC,MAAM,CAAA;IACrD,IAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAA;IACjC,IAAM,UAAU,GAAG,aAAa,GAAG,UAAU,CAAC,KAAK,CAAA;IAEnD,IAAI,QAAyB,CAAA;IAC7B,IAAI,GAAW,CAAA;IACf,IAAI,IAAY,CAAA;IAEhB,IAAI,UAAU,IAAI,aAAa,GAAG,cAAc,EAAE,CAAC;QAC/C,QAAQ,GAAG,OAAO,CAAA;QAClB,GAAG,GAAG,UAAU,CAAC,GAAG,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,GAAG,uBAAuB,GAAG,CAAC,CAAA;QAC1E,IAAI,GAAG,UAAU,CAAC,KAAK,GAAG,cAAc,CAAA;IAC5C,CAAC;SAAM,IAAI,SAAS,IAAI,aAAa,GAAG,cAAc,EAAE,CAAC;QACrD,QAAQ,GAAG,MAAM,CAAA;QACjB,GAAG,GAAG,UAAU,CAAC,GAAG,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,GAAG,uBAAuB,GAAG,CAAC,CAAA;QAC1E,IAAI,GAAG,UAAU,CAAC,IAAI,GAAG,aAAa,GAAG,cAAc,CAAA;IAC3D,CAAC;SAAM,IAAI,UAAU,IAAI,uBAAuB,GAAG,cAAc,EAAE,CAAC;QAChE,QAAQ,GAAG,QAAQ,CAAA;QACnB,GAAG,GAAG,UAAU,CAAC,MAAM,GAAG,cAAc,CAAA;QACxC,IAAI,GAAG,UAAU,CAAC,IAAI,GAAG,UAAU,CAAC,KAAK,GAAG,CAAC,GAAG,aAAa,GAAG,CAAC,CAAA;IACrE,CAAC;SAAM,CAAC;QACJ,QAAQ,GAAG,KAAK,CAAA;QAChB,GAAG,GAAG,UAAU,CAAC,GAAG,GAAG,uBAAuB,GAAG,cAAc,CAAA;QAC/D,IAAI,GAAG,UAAU,CAAC,IAAI,GAAG,UAAU,CAAC,KAAK,GAAG,CAAC,GAAG,aAAa,GAAG,CAAC,CAAA;IACrE,CAAC;IAED,OAAO,EAAE,GAAG,KAAA,EAAE,IAAI,MAAA,EAAE,QAAQ,UAAA,EAAE,CAAA;AAClC,CAAC;AAED,SAAgB,iBAAiB,CAAC,UAAmB,EAAE,OAAmB;IAAnB,wBAAA,EAAA,WAAmB;IACtE,OAAO;QACH,GAAG,EAAE,UAAG,UAAU,CAAC,GAAG,GAAG,OAAO,OAAI;QACpC,IAAI,EAAE,UAAG,UAAU,CAAC,IAAI,GAAG,OAAO,OAAI;QACtC,KAAK,EAAE,UAAG,UAAU,CAAC,KAAK,GAAG,OAAO,GAAG,CAAC,OAAI;QAC5C,MAAM,EAAE,UAAG,UAAU,CAAC,MAAM,GAAG,OAAO,GAAG,CAAC,OAAI;KACjD,CAAA;AACL,CAAC;AAED,SAAgB,mCAAmC,CAAC,OAAoB,EAAE,UAAkC;IACxG,IAAM,MAAM,yBAAQ,6DAA+B,GAAK,UAAU,CAAE,CAAA;IACpE,IAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAA;IAE3B,8BAA8B;IAC9B,KAAK,CAAC,WAAW,CAAC,4BAA4B,EAAE,MAAM,CAAC,eAAe,CAAC,CAAA;IACvE,KAAK,CAAC,WAAW,CAAC,sBAAsB,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;IAC3D,KAAK,CAAC,WAAW,CAAC,wBAAwB,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;IAC/D,KAAK,CAAC,WAAW,CAAC,yBAAyB,EAAE,UAAG,MAAM,CAAC,YAAY,OAAI,CAAC,CAAA;IACxE,KAAK,CAAC,WAAW,CAAC,gCAAgC,EAAE,UAAG,MAAM,CAAC,kBAAkB,OAAI,CAAC,CAAA;IACrF,KAAK,CAAC,WAAW,CAAC,wBAAwB,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;IAC/D,KAAK,CAAC,WAAW,CAAC,uBAAuB,EAAE,IAAA,uCAAa,EAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAA;IAE5E,iBAAiB;IACjB,KAAK,CAAC,WAAW,CAAC,gCAAgC,EAAE,IAAA,mCAAS,EAAC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAA;IACrF,KAAK,CAAC,WAAW,CAAC,+BAA+B,EAAE,IAAA,iDAAuB,EAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAA;IACnG,KAAK,CAAC,WAAW,CAAC,6BAA6B,EAAE,IAAA,iDAAuB,EAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAA;IAC7F,KAAK,CAAC,WAAW,CAAC,sBAAsB,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;IAC3D,KAAK,CAAC,WAAW,CAAC,yBAAyB,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAA;IAEvG,gDAAgD;IAChD,KAAK,CAAC,WAAW,CAAC,kCAAkC,EAAE,aAAa,CAAC,CAAA;IACpE,KAAK,CAAC,WAAW,CAAC,uCAAuC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;IAC5E,KAAK,CAAC,WAAW,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAA;IACjD,KAAK,CAAC,WAAW,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAA;AAClD,CAAC;AAED,SAAgB,mBAAmB,CAAC,OAAY;;;IAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,OAAO,EAAE,CAAA;IACb,CAAC;IAED,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,UAAU,CAAC,OAAO,CAAC,CAAA;IAC9B,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC1B,IAAI,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;QAEzC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;;gBAChB,KAAmB,IAAA,KAAA,SAAA,OAAO,CAAC,KAAK,CAAA,gBAAA,4BAAE,CAAC;oBAA9B,IAAM,IAAI,WAAA;oBACX,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;wBAChB,KAAK,MAAM;4BACP,IAAI,GAAG,kBAAW,IAAI,cAAW,CAAA;4BACjC,MAAK;wBACT,KAAK,QAAQ;4BACT,IAAI,GAAG,cAAO,IAAI,UAAO,CAAA;4BACzB,MAAK;wBACT,KAAK,WAAW;4BACZ,IAAI,GAAG,aAAM,IAAI,SAAM,CAAA;4BACvB,MAAK;wBACT,KAAK,QAAQ;4BACT,IAAI,GAAG,aAAM,IAAI,SAAM,CAAA;4BACvB,MAAK;oBACb,CAAC;gBACL,CAAC;;;;;;;;;QACL,CAAC;QAED,OAAO,IAAI,CAAA;IACf,CAAC;IAED,IAAM,QAAQ,GAAG,CAAA,MAAA,OAAO,CAAC,OAAO,0CAAE,GAAG,CAAC,mBAAmB,EAAE,IAAI,CAAC,EAAE,CAAC,KAAI,EAAE,CAAA;IAEzE,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,KAAK;YACN,OAAO,QAAQ,CAAA;QACnB,KAAK,WAAW;YACZ,OAAO,aAAM,QAAQ,SAAM,CAAA;QAC/B,KAAK,SAAS,CAAC,CAAC,CAAC;YACb,IAAM,KAAK,GAAG,CAAA,MAAA,OAAO,CAAC,KAAK,0CAAE,KAAK,KAAI,CAAC,CAAA;YACvC,OAAO,YAAK,KAAK,cAAI,QAAQ,gBAAM,KAAK,MAAG,CAAA;QAC/C,CAAC;QACD,KAAK,YAAY;YACb,OAAO,cAAO,QAAQ,UAAO,CAAA;QACjC,KAAK,aAAa;YACd,OAAO,cAAO,QAAQ,UAAO,CAAA;QACjC,KAAK,UAAU;YACX,OAAO,cAAO,QAAQ,UAAO,CAAA;QACjC,KAAK,WAAW;YACZ,OAAO,MAAM,CAAA;QACjB;YACI,OAAO,QAAQ,CAAA;IACvB,CAAC;AACL,CAAC;AAED,SAAgB,YAAY,CAAC,GAAW;IACpC,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;AACrD,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC5B,IAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IACzC,GAAG,CAAC,WAAW,GAAG,IAAI,CAAA;IACtB,OAAO,GAAG,CAAC,SAAS,CAAA;AACxB,CAAC;AAED,SAAgB,WAAW,CAAC,IAAqB;IAC7C,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,OAAO,mBAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE;YACxC,QAAQ,EAAE,CAAC,QAAQ,CAAC;YACpB,QAAQ,EAAE,CAAC,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,CAAC;SACjE,CAAC,CAAA;IACN,CAAC;IAED,uCAAuC;IACvC,OAAO,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;AAC5C,CAAC","sourcesContent":["import DOMPurify from 'dompurify'\n\nimport {\n ProductTourAppearance,\n ProductTourSelectorError,\n ProductTourStep,\n DEFAULT_PRODUCT_TOUR_APPEARANCE,\n} from '../../posthog-product-tours-types'\nimport { prepareStylesheet } from '../utils/stylesheet-loader'\nimport { document as _document, window as _window } from '../../utils/globals'\nimport { getFontFamily, getContrastingTextColor, hexToRgba } from '../surveys/surveys-extension-utils'\n\nimport productTourStyles from './product-tour.css'\n\nconst document = _document as Document\nconst window = _window as Window & typeof globalThis\n\nexport function getProductTourStylesheet(): HTMLStyleElement | null {\n const stylesheet = prepareStylesheet(document, typeof productTourStyles === 'string' ? productTourStyles : '')\n stylesheet?.setAttribute('data-ph-product-tour-style', 'true')\n return stylesheet\n}\n\nexport interface ElementFindResult {\n element: HTMLElement | null\n error: ProductTourSelectorError | null\n matchCount: number\n}\n\nexport function findElementBySelector(selector: string): ElementFindResult {\n try {\n const elements = document.querySelectorAll(selector)\n\n if (elements.length === 0) {\n return { element: null, error: 'not_found', matchCount: 0 }\n }\n\n const element = elements[0] as HTMLElement\n\n if (!isElementVisible(element)) {\n return { element: null, error: 'not_visible', matchCount: elements.length }\n }\n\n if (elements.length > 1) {\n return { element, error: 'multiple_matches', matchCount: elements.length }\n }\n\n return { element, error: null, matchCount: 1 }\n } catch {\n return { element: null, error: 'not_found', matchCount: 0 }\n }\n}\n\nexport function isElementVisible(element: HTMLElement): boolean {\n const style = window.getComputedStyle(element)\n\n if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {\n return false\n }\n\n const rect = element.getBoundingClientRect()\n if (rect.width === 0 || rect.height === 0) {\n return false\n }\n\n return true\n}\n\nexport function getElementMetadata(element: HTMLElement): {\n tag: string\n id: string | undefined\n classes: string | undefined\n text: string | undefined\n} {\n return {\n tag: element.tagName,\n id: element.id || undefined,\n classes: element.className || undefined,\n text: element.innerText?.slice(0, 100) || undefined,\n }\n}\n\nexport type TooltipPosition = 'top' | 'bottom' | 'left' | 'right'\n\nexport interface PositionResult {\n top: number\n left: number\n position: TooltipPosition\n}\n\nconst TOOLTIP_MARGIN = 12\nconst TOOLTIP_WIDTH = 320\nconst TOOLTIP_HEIGHT_ESTIMATE = 180\n\nexport function calculateTooltipPosition(targetRect: DOMRect): PositionResult {\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n\n const spaceBelow = viewportHeight - targetRect.bottom\n const spaceLeft = targetRect.left\n const spaceRight = viewportWidth - targetRect.right\n\n let position: TooltipPosition\n let top: number\n let left: number\n\n if (spaceRight >= TOOLTIP_WIDTH + TOOLTIP_MARGIN) {\n position = 'right'\n top = targetRect.top + targetRect.height / 2 - TOOLTIP_HEIGHT_ESTIMATE / 2\n left = targetRect.right + TOOLTIP_MARGIN\n } else if (spaceLeft >= TOOLTIP_WIDTH + TOOLTIP_MARGIN) {\n position = 'left'\n top = targetRect.top + targetRect.height / 2 - TOOLTIP_HEIGHT_ESTIMATE / 2\n left = targetRect.left - TOOLTIP_WIDTH - TOOLTIP_MARGIN\n } else if (spaceBelow >= TOOLTIP_HEIGHT_ESTIMATE + TOOLTIP_MARGIN) {\n position = 'bottom'\n top = targetRect.bottom + TOOLTIP_MARGIN\n left = targetRect.left + targetRect.width / 2 - TOOLTIP_WIDTH / 2\n } else {\n position = 'top'\n top = targetRect.top - TOOLTIP_HEIGHT_ESTIMATE - TOOLTIP_MARGIN\n left = targetRect.left + targetRect.width / 2 - TOOLTIP_WIDTH / 2\n }\n\n return { top, left, position }\n}\n\nexport function getSpotlightStyle(targetRect: DOMRect, padding: number = 8): Record<string, string> {\n return {\n top: `${targetRect.top - padding}px`,\n left: `${targetRect.left - padding}px`,\n width: `${targetRect.width + padding * 2}px`,\n height: `${targetRect.height + padding * 2}px`,\n }\n}\n\nexport function addProductTourCSSVariablesToElement(element: HTMLElement, appearance?: ProductTourAppearance): void {\n const merged = { ...DEFAULT_PRODUCT_TOUR_APPEARANCE, ...appearance }\n const style = element.style\n\n // User-customizable variables\n style.setProperty('--ph-tour-background-color', merged.backgroundColor)\n style.setProperty('--ph-tour-text-color', merged.textColor)\n style.setProperty('--ph-tour-button-color', merged.buttonColor)\n style.setProperty('--ph-tour-border-radius', `${merged.borderRadius}px`)\n style.setProperty('--ph-tour-button-border-radius', `${merged.buttonBorderRadius}px`)\n style.setProperty('--ph-tour-border-color', merged.borderColor)\n style.setProperty('--ph-tour-font-family', getFontFamily(merged.fontFamily))\n\n // Derived colors\n style.setProperty('--ph-tour-text-secondary-color', hexToRgba(merged.textColor, 0.6))\n style.setProperty('--ph-tour-branding-text-color', getContrastingTextColor(merged.backgroundColor))\n style.setProperty('--ph-tour-button-text-color', getContrastingTextColor(merged.buttonColor))\n style.setProperty('--ph-tour-box-shadow', merged.boxShadow)\n style.setProperty('--ph-tour-overlay-color', merged.showOverlay ? 'rgba(0, 0, 0, 0.5)' : 'transparent')\n\n // Internal styling variables (not customizable)\n style.setProperty('--ph-tour-button-secondary-color', 'transparent')\n style.setProperty('--ph-tour-button-secondary-text-color', merged.textColor)\n style.setProperty('--ph-tour-max-width', '320px')\n style.setProperty('--ph-tour-padding', '16px')\n}\n\nexport function renderTipTapContent(content: any): string {\n if (!content) {\n return ''\n }\n\n if (typeof content === 'string') {\n return escapeHtml(content)\n }\n\n if (content.type === 'text') {\n let text = escapeHtml(content.text || '')\n\n if (content.marks) {\n for (const mark of content.marks) {\n switch (mark.type) {\n case 'bold':\n text = `<strong>${text}</strong>`\n break\n case 'italic':\n text = `<em>${text}</em>`\n break\n case 'underline':\n text = `<u>${text}</u>`\n break\n case 'strike':\n text = `<s>${text}</s>`\n break\n }\n }\n }\n\n return text\n }\n\n const children = content.content?.map(renderTipTapContent).join('') || ''\n\n switch (content.type) {\n case 'doc':\n return children\n case 'paragraph':\n return `<p>${children}</p>`\n case 'heading': {\n const level = content.attrs?.level || 1\n return `<h${level}>${children}</h${level}>`\n }\n case 'bulletList':\n return `<ul>${children}</ul>`\n case 'orderedList':\n return `<ol>${children}</ol>`\n case 'listItem':\n return `<li>${children}</li>`\n case 'hardBreak':\n return '<br>'\n default:\n return children\n }\n}\n\nexport function normalizeUrl(url: string): string {\n return url.endsWith('/') ? url.slice(0, -1) : url\n}\n\nfunction escapeHtml(text: string): string {\n const div = document.createElement('div')\n div.textContent = text\n return div.innerHTML\n}\n\nexport function getStepHtml(step: ProductTourStep): string {\n if (step.contentHtml) {\n return DOMPurify.sanitize(step.contentHtml, {\n ADD_TAGS: ['iframe'],\n ADD_ATTR: ['allowfullscreen', 'frameborder', 'referrerpolicy'],\n })\n }\n\n // backwards compat, will be deprecated\n return renderTipTapContent(step.content)\n}\n"]}
1
+ {"version":3,"file":"product-tours-utils.js","sourceRoot":"","sources":["../../../../src/extensions/product-tours/product-tours-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import DOMPurify from 'dompurify'\n\nimport {\n ProductTourAppearance,\n ProductTourSelectorError,\n ProductTourStep,\n DEFAULT_PRODUCT_TOUR_APPEARANCE,\n} from '../../posthog-product-tours-types'\nimport { prepareStylesheet } from '../utils/stylesheet-loader'\nimport { document as _document, window as _window } from '../../utils/globals'\nimport { getFontFamily, getContrastingTextColor, hexToRgba } from '../surveys/surveys-extension-utils'\n\nimport productTourStyles from './product-tour.css'\n\nconst document = _document as Document\nconst window = _window as Window & typeof globalThis\n\nexport function getProductTourStylesheet(): HTMLStyleElement | null {\n const stylesheet = prepareStylesheet(document, typeof productTourStyles === 'string' ? productTourStyles : '')\n stylesheet?.setAttribute('data-ph-product-tour-style', 'true')\n return stylesheet\n}\n\nexport interface ElementFindResult {\n element: HTMLElement | null\n error: ProductTourSelectorError | null\n matchCount: number\n}\n\nexport function findElementBySelector(selector: string): ElementFindResult {\n try {\n const elements = document.querySelectorAll(selector)\n\n if (elements.length === 0) {\n return { element: null, error: 'not_found', matchCount: 0 }\n }\n\n const element = elements[0] as HTMLElement\n\n if (!isElementVisible(element)) {\n return { element: null, error: 'not_visible', matchCount: elements.length }\n }\n\n if (elements.length > 1) {\n return { element, error: 'multiple_matches', matchCount: elements.length }\n }\n\n return { element, error: null, matchCount: 1 }\n } catch {\n return { element: null, error: 'not_found', matchCount: 0 }\n }\n}\n\nexport function isElementVisible(element: HTMLElement): boolean {\n const style = window.getComputedStyle(element)\n\n if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {\n return false\n }\n\n const rect = element.getBoundingClientRect()\n if (rect.width === 0 || rect.height === 0) {\n return false\n }\n\n return true\n}\n\nexport function getElementMetadata(element: HTMLElement): {\n tag: string\n id: string | undefined\n classes: string | undefined\n text: string | undefined\n} {\n return {\n tag: element.tagName,\n id: element.id || undefined,\n classes: element.className || undefined,\n text: element.innerText?.slice(0, 100) || undefined,\n }\n}\n\nexport type TooltipPosition = 'top' | 'bottom' | 'left' | 'right'\n\nexport interface PositionResult {\n position: TooltipPosition\n top?: number\n bottom?: number\n left?: number\n right?: number\n}\n\nconst TOOLTIP_MARGIN = 12\n\nexport interface TooltipDimensions {\n width: number\n height: number\n}\n\nexport function calculateTooltipPosition(targetRect: DOMRect, tooltipDimensions: TooltipDimensions): PositionResult {\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n\n const { width, height } = tooltipDimensions\n const spaceAbove = targetRect.top\n const spaceBelow = viewportHeight - targetRect.bottom\n const spaceLeft = targetRect.left\n const spaceRight = viewportWidth - targetRect.right\n\n const targetCenterY = targetRect.top + targetRect.height / 2\n const targetCenterX = targetRect.left + targetRect.width / 2\n\n if (spaceRight >= width + TOOLTIP_MARGIN) {\n return { position: 'right', top: targetCenterY, left: targetRect.right + TOOLTIP_MARGIN }\n }\n if (spaceLeft >= width + TOOLTIP_MARGIN) {\n return { position: 'left', top: targetCenterY, right: viewportWidth - targetRect.left + TOOLTIP_MARGIN }\n }\n if (spaceAbove >= height + TOOLTIP_MARGIN && spaceBelow < height + TOOLTIP_MARGIN) {\n return { position: 'top', bottom: viewportHeight - targetRect.top + TOOLTIP_MARGIN, left: targetCenterX }\n }\n return { position: 'bottom', top: targetRect.bottom + TOOLTIP_MARGIN, left: targetCenterX }\n}\n\nexport function getSpotlightStyle(targetRect: DOMRect, padding: number = 8): Record<string, string> {\n return {\n top: `${targetRect.top - padding}px`,\n left: `${targetRect.left - padding}px`,\n width: `${targetRect.width + padding * 2}px`,\n height: `${targetRect.height + padding * 2}px`,\n }\n}\n\nexport function addProductTourCSSVariablesToElement(element: HTMLElement, appearance?: ProductTourAppearance): void {\n const merged = { ...DEFAULT_PRODUCT_TOUR_APPEARANCE, ...appearance }\n const style = element.style\n\n // User-customizable variables\n style.setProperty('--ph-tour-background-color', merged.backgroundColor)\n style.setProperty('--ph-tour-text-color', merged.textColor)\n style.setProperty('--ph-tour-button-color', merged.buttonColor)\n style.setProperty('--ph-tour-border-radius', `${merged.borderRadius}px`)\n style.setProperty('--ph-tour-button-border-radius', `${merged.buttonBorderRadius}px`)\n style.setProperty('--ph-tour-border-color', merged.borderColor)\n style.setProperty('--ph-tour-font-family', getFontFamily(merged.fontFamily))\n\n // Derived colors\n style.setProperty('--ph-tour-text-secondary-color', hexToRgba(merged.textColor, 0.6))\n style.setProperty('--ph-tour-branding-text-color', getContrastingTextColor(merged.backgroundColor))\n style.setProperty('--ph-tour-button-text-color', getContrastingTextColor(merged.buttonColor))\n style.setProperty('--ph-tour-box-shadow', merged.boxShadow)\n style.setProperty('--ph-tour-overlay-color', merged.showOverlay ? 'rgba(0, 0, 0, 0.5)' : 'transparent')\n style.setProperty('--ph-tour-z-index', String(merged.zIndex))\n\n // Internal styling variables (not customizable)\n style.setProperty('--ph-tour-button-secondary-color', 'transparent')\n style.setProperty('--ph-tour-button-secondary-text-color', merged.textColor)\n style.setProperty('--ph-tour-max-width', '320px')\n style.setProperty('--ph-tour-padding', '16px')\n}\n\nexport function renderTipTapContent(content: any): string {\n if (!content) {\n return ''\n }\n\n if (typeof content === 'string') {\n return escapeHtml(content)\n }\n\n if (content.type === 'text') {\n let text = escapeHtml(content.text || '')\n\n if (content.marks) {\n for (const mark of content.marks) {\n switch (mark.type) {\n case 'bold':\n text = `<strong>${text}</strong>`\n break\n case 'italic':\n text = `<em>${text}</em>`\n break\n case 'underline':\n text = `<u>${text}</u>`\n break\n case 'strike':\n text = `<s>${text}</s>`\n break\n }\n }\n }\n\n return text\n }\n\n const children = content.content?.map(renderTipTapContent).join('') || ''\n\n switch (content.type) {\n case 'doc':\n return children\n case 'paragraph':\n return `<p>${children}</p>`\n case 'heading': {\n const level = content.attrs?.level || 1\n return `<h${level}>${children}</h${level}>`\n }\n case 'bulletList':\n return `<ul>${children}</ul>`\n case 'orderedList':\n return `<ol>${children}</ol>`\n case 'listItem':\n return `<li>${children}</li>`\n case 'hardBreak':\n return '<br>'\n default:\n return children\n }\n}\n\nexport function normalizeUrl(url: string): string {\n return url.endsWith('/') ? url.slice(0, -1) : url\n}\n\nfunction escapeHtml(text: string): string {\n const div = document.createElement('div')\n div.textContent = text\n return div.innerHTML\n}\n\nexport function getStepHtml(step: ProductTourStep): string {\n if (step.contentHtml) {\n return DOMPurify.sanitize(step.contentHtml, {\n ADD_TAGS: ['iframe'],\n ADD_ATTR: ['allowfullscreen', 'frameborder', 'referrerpolicy'],\n })\n }\n\n // backwards compat, will be deprecated\n return renderTipTapContent(step.content)\n}\n"]}
@@ -101,6 +101,7 @@ export interface ProductTourAppearance {
101
101
  whiteLabel?: boolean;
102
102
  /** defaults to true, auto-set to false for announcements/banners */
103
103
  dismissOnClickOutside?: boolean;
104
+ zIndex?: number;
104
105
  }
105
106
  export interface ProductTour {
106
107
  id: string;
@@ -13,5 +13,6 @@ exports.DEFAULT_PRODUCT_TOUR_APPEARANCE = {
13
13
  showOverlay: true,
14
14
  whiteLabel: false,
15
15
  dismissOnClickOutside: true,
16
+ zIndex: 2147483646,
16
17
  };
17
18
  //# sourceMappingURL=posthog-product-tours-types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"posthog-product-tours-types.js","sourceRoot":"","sources":["../../src/posthog-product-tours-types.ts"],"names":[],"mappings":";;;AA6Ia,QAAA,+BAA+B,GAAoC;IAC5E,eAAe,EAAE,SAAS;IAC1B,SAAS,EAAE,SAAS;IACpB,WAAW,EAAE,SAAS;IACtB,YAAY,EAAE,CAAC;IACf,kBAAkB,EAAE,CAAC;IACrB,WAAW,EAAE,SAAS;IACtB,UAAU,EAAE,WAAW;IACvB,SAAS,EAAE,gCAAgC;IAC3C,WAAW,EAAE,IAAI;IACjB,UAAU,EAAE,KAAK;IACjB,qBAAqB,EAAE,IAAI;CAC9B,CAAA","sourcesContent":["import { PropertyMatchType } from './types'\nimport { SurveyActionType, SurveyEventWithFilters } from './posthog-surveys-types'\nimport type { InferredSelector } from './extensions/product-tours/element-inference'\nimport { SurveyPosition } from '@posthog/core'\n\nexport interface JSONContent {\n type?: string\n attrs?: Record<string, any>\n content?: JSONContent[]\n marks?: { type: string; attrs?: Record<string, any> }[]\n text?: string\n}\n\nexport type ProductTourStepType = 'element' | 'modal' | 'survey' | 'banner'\n\nexport interface ProductTourBannerConfig {\n behavior: 'sticky' | 'static'\n action?: {\n type: 'none' | 'link' | 'trigger_tour'\n link?: string\n tourId?: string\n }\n}\n\n/** Button actions available on modal steps */\nexport type ProductTourButtonAction = 'dismiss' | 'link' | 'next_step' | 'previous_step' | 'trigger_tour'\n\nexport interface ProductTourStepButton {\n text: string\n action: ProductTourButtonAction\n /** URL to open when action is 'link' */\n link?: string\n /** Tour ID to trigger when action is 'trigger_tour' */\n tourId?: string\n}\n\nexport interface ProductTourStepButtons {\n primary?: ProductTourStepButton\n secondary?: ProductTourStepButton\n}\n\nexport type ProductTourSurveyQuestionType = 'open' | 'rating'\n\nexport interface ProductTourSurveyQuestion {\n type: ProductTourSurveyQuestionType\n questionText: string\n /** Rating display type - emoji or number */\n display?: 'emoji' | 'number'\n /** Rating scale - 3 or 5 for emoji, 5 or 10 for number */\n scale?: 3 | 5 | 10\n /** Label for low end of rating scale (e.g., \"Not likely\") */\n lowerBoundLabel?: string\n /** Label for high end of rating scale (e.g., \"Very likely\") */\n upperBoundLabel?: string\n}\n\nexport interface ProductTourStep {\n id: string\n type: ProductTourStepType\n selector?: string\n progressionTrigger: 'button' | 'click'\n content: JSONContent | null\n /** Pre-rendered HTML content from the editor. If present, SDK should use this instead of rendering from JSONContent. */\n contentHtml?: string\n /** Inline survey question config - if present, this is a survey step */\n survey?: ProductTourSurveyQuestion\n /** ID of the auto-created survey for this step (set by backend) */\n linkedSurveyId?: string\n /** ID of the survey question (set by backend, used for event tracking) */\n linkedSurveyQuestionId?: string\n /** Enhanced element data for more reliable lookup at runtime */\n inferenceData?: InferredSelector\n /** Maximum tooltip width in pixels (defaults to 320px) */\n maxWidth?: number\n /** Position for modal/survey steps (defaults to middle_center) */\n modalPosition?: SurveyPosition\n /** Button configuration for modal steps */\n buttons?: ProductTourStepButtons\n /** Banner configuration (only for banner steps) */\n bannerConfig?: ProductTourBannerConfig\n}\n\nexport interface ProductTourConditions {\n url?: string\n urlMatchType?: PropertyMatchType\n selector?: string\n autoShowDelaySeconds?: number\n events?: {\n values: SurveyEventWithFilters[]\n } | null\n cancelEvents?: {\n values: SurveyEventWithFilters[]\n } | null\n actions?: {\n values: SurveyActionType[]\n } | null\n}\n\nexport interface ProductTourAppearance {\n backgroundColor?: string\n textColor?: string\n buttonColor?: string\n borderRadius?: number\n buttonBorderRadius?: number\n borderColor?: string\n fontFamily?: string\n boxShadow?: string\n showOverlay?: boolean\n whiteLabel?: boolean\n /** defaults to true, auto-set to false for announcements/banners */\n dismissOnClickOutside?: boolean\n}\n\nexport interface ProductTour {\n id: string\n name: string\n description?: string\n type: 'product_tour'\n auto_launch?: boolean\n start_date: string | null\n end_date: string | null\n current_iteration?: number\n conditions?: ProductTourConditions\n appearance?: ProductTourAppearance\n steps: ProductTourStep[]\n internal_targeting_flag_key?: string\n linked_flag_key?: string\n}\n\nexport type ProductTourCallback = (tours: ProductTour[], context?: { isLoaded: boolean; error?: string }) => void\n\nexport type ProductTourSelectorError = 'not_found' | 'multiple_matches' | 'not_visible'\n\nexport type ProductTourDismissReason =\n | 'user_clicked_skip'\n | 'user_clicked_outside'\n | 'escape_key'\n | 'element_unavailable'\n\nexport type ProductTourRenderReason = 'auto' | 'api' | 'trigger' | 'event'\n\nexport const DEFAULT_PRODUCT_TOUR_APPEARANCE: Required<ProductTourAppearance> = {\n backgroundColor: '#ffffff',\n textColor: '#1d1f27',\n buttonColor: '#1d1f27',\n borderRadius: 8,\n buttonBorderRadius: 6,\n borderColor: '#e5e7eb',\n fontFamily: 'system-ui',\n boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',\n showOverlay: true,\n whiteLabel: false,\n dismissOnClickOutside: true,\n}\n\nexport interface ShowTourOptions {\n reason?: ProductTourRenderReason\n enableStrictValidation?: boolean\n}\n"]}
1
+ {"version":3,"file":"posthog-product-tours-types.js","sourceRoot":"","sources":["../../src/posthog-product-tours-types.ts"],"names":[],"mappings":";;;AA8Ia,QAAA,+BAA+B,GAAoC;IAC5E,eAAe,EAAE,SAAS;IAC1B,SAAS,EAAE,SAAS;IACpB,WAAW,EAAE,SAAS;IACtB,YAAY,EAAE,CAAC;IACf,kBAAkB,EAAE,CAAC;IACrB,WAAW,EAAE,SAAS;IACtB,UAAU,EAAE,WAAW;IACvB,SAAS,EAAE,gCAAgC;IAC3C,WAAW,EAAE,IAAI;IACjB,UAAU,EAAE,KAAK;IACjB,qBAAqB,EAAE,IAAI;IAC3B,MAAM,EAAE,UAAU;CACrB,CAAA","sourcesContent":["import { PropertyMatchType } from './types'\nimport { SurveyActionType, SurveyEventWithFilters } from './posthog-surveys-types'\nimport type { InferredSelector } from './extensions/product-tours/element-inference'\nimport { SurveyPosition } from '@posthog/core'\n\nexport interface JSONContent {\n type?: string\n attrs?: Record<string, any>\n content?: JSONContent[]\n marks?: { type: string; attrs?: Record<string, any> }[]\n text?: string\n}\n\nexport type ProductTourStepType = 'element' | 'modal' | 'survey' | 'banner'\n\nexport interface ProductTourBannerConfig {\n behavior: 'sticky' | 'static'\n action?: {\n type: 'none' | 'link' | 'trigger_tour'\n link?: string\n tourId?: string\n }\n}\n\n/** Button actions available on modal steps */\nexport type ProductTourButtonAction = 'dismiss' | 'link' | 'next_step' | 'previous_step' | 'trigger_tour'\n\nexport interface ProductTourStepButton {\n text: string\n action: ProductTourButtonAction\n /** URL to open when action is 'link' */\n link?: string\n /** Tour ID to trigger when action is 'trigger_tour' */\n tourId?: string\n}\n\nexport interface ProductTourStepButtons {\n primary?: ProductTourStepButton\n secondary?: ProductTourStepButton\n}\n\nexport type ProductTourSurveyQuestionType = 'open' | 'rating'\n\nexport interface ProductTourSurveyQuestion {\n type: ProductTourSurveyQuestionType\n questionText: string\n /** Rating display type - emoji or number */\n display?: 'emoji' | 'number'\n /** Rating scale - 3 or 5 for emoji, 5 or 10 for number */\n scale?: 3 | 5 | 10\n /** Label for low end of rating scale (e.g., \"Not likely\") */\n lowerBoundLabel?: string\n /** Label for high end of rating scale (e.g., \"Very likely\") */\n upperBoundLabel?: string\n}\n\nexport interface ProductTourStep {\n id: string\n type: ProductTourStepType\n selector?: string\n progressionTrigger: 'button' | 'click'\n content: JSONContent | null\n /** Pre-rendered HTML content from the editor. If present, SDK should use this instead of rendering from JSONContent. */\n contentHtml?: string\n /** Inline survey question config - if present, this is a survey step */\n survey?: ProductTourSurveyQuestion\n /** ID of the auto-created survey for this step (set by backend) */\n linkedSurveyId?: string\n /** ID of the survey question (set by backend, used for event tracking) */\n linkedSurveyQuestionId?: string\n /** Enhanced element data for more reliable lookup at runtime */\n inferenceData?: InferredSelector\n /** Maximum tooltip width in pixels (defaults to 320px) */\n maxWidth?: number\n /** Position for modal/survey steps (defaults to middle_center) */\n modalPosition?: SurveyPosition\n /** Button configuration for modal steps */\n buttons?: ProductTourStepButtons\n /** Banner configuration (only for banner steps) */\n bannerConfig?: ProductTourBannerConfig\n}\n\nexport interface ProductTourConditions {\n url?: string\n urlMatchType?: PropertyMatchType\n selector?: string\n autoShowDelaySeconds?: number\n events?: {\n values: SurveyEventWithFilters[]\n } | null\n cancelEvents?: {\n values: SurveyEventWithFilters[]\n } | null\n actions?: {\n values: SurveyActionType[]\n } | null\n}\n\nexport interface ProductTourAppearance {\n backgroundColor?: string\n textColor?: string\n buttonColor?: string\n borderRadius?: number\n buttonBorderRadius?: number\n borderColor?: string\n fontFamily?: string\n boxShadow?: string\n showOverlay?: boolean\n whiteLabel?: boolean\n /** defaults to true, auto-set to false for announcements/banners */\n dismissOnClickOutside?: boolean\n zIndex?: number\n}\n\nexport interface ProductTour {\n id: string\n name: string\n description?: string\n type: 'product_tour'\n auto_launch?: boolean\n start_date: string | null\n end_date: string | null\n current_iteration?: number\n conditions?: ProductTourConditions\n appearance?: ProductTourAppearance\n steps: ProductTourStep[]\n internal_targeting_flag_key?: string\n linked_flag_key?: string\n}\n\nexport type ProductTourCallback = (tours: ProductTour[], context?: { isLoaded: boolean; error?: string }) => void\n\nexport type ProductTourSelectorError = 'not_found' | 'multiple_matches' | 'not_visible'\n\nexport type ProductTourDismissReason =\n | 'user_clicked_skip'\n | 'user_clicked_outside'\n | 'escape_key'\n | 'element_unavailable'\n\nexport type ProductTourRenderReason = 'auto' | 'api' | 'trigger' | 'event'\n\nexport const DEFAULT_PRODUCT_TOUR_APPEARANCE: Required<ProductTourAppearance> = {\n backgroundColor: '#ffffff',\n textColor: '#1d1f27',\n buttonColor: '#1d1f27',\n borderRadius: 8,\n buttonBorderRadius: 6,\n borderColor: '#e5e7eb',\n fontFamily: 'system-ui',\n boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',\n showOverlay: true,\n whiteLabel: false,\n dismissOnClickOutside: true,\n zIndex: 2147483646,\n}\n\nexport interface ShowTourOptions {\n reason?: ProductTourRenderReason\n enableStrictValidation?: boolean\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "posthog-js",
3
- "version": "1.321.2",
3
+ "version": "1.321.3",
4
4
  "description": "Posthog-js allows you to automatically capture usage and send events to PostHog.",
5
5
  "repository": "https://github.com/PostHog/posthog-js",
6
6
  "author": "hey@posthog.com",
@@ -28,7 +28,7 @@
28
28
  "@opentelemetry/resources": "^2.2.0",
29
29
  "@opentelemetry/sdk-logs": "^0.208.0",
30
30
  "@posthog/core": "1.9.1",
31
- "@posthog/types": "1.321.2"
31
+ "@posthog/types": "1.321.3"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@babel/core": "^7.27.1",