posthog-js 1.303.1 → 1.305.0
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.
- package/dist/array.full.es5.js +1 -1
- package/dist/array.full.es5.js.map +1 -1
- package/dist/array.full.js +1 -1
- package/dist/array.full.js.map +1 -1
- package/dist/array.full.no-external.js +1 -1
- package/dist/array.full.no-external.js.map +1 -1
- package/dist/array.js +1 -1
- package/dist/array.js.map +1 -1
- package/dist/array.no-external.js +1 -1
- package/dist/array.no-external.js.map +1 -1
- package/dist/customizations.full.js +1 -1
- package/dist/lazy-recorder.js +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/module.d.ts +20 -2
- package/dist/module.full.d.ts +20 -2
- package/dist/module.full.js +1 -1
- package/dist/module.full.js.map +1 -1
- package/dist/module.full.no-external.d.ts +20 -2
- package/dist/module.full.no-external.js +1 -1
- package/dist/module.full.no-external.js.map +1 -1
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/dist/module.no-external.d.ts +20 -2
- package/dist/module.no-external.js +1 -1
- package/dist/module.no-external.js.map +1 -1
- package/dist/posthog-recorder.js +1 -1
- package/dist/product-tours.js +1 -1
- package/dist/product-tours.js.map +1 -1
- package/dist/src/extensions/product-tours/components/ProductTourTooltip.d.ts +1 -1
- package/dist/src/extensions/product-tours/product-tours.d.ts +7 -1
- package/dist/src/posthog-product-tours-types.d.ts +19 -1
- package/dist/surveys-preview.d.ts +19 -1
- package/lib/package.json +1 -1
- package/lib/src/extensions/product-tours/components/ProductTourTooltip.d.ts +1 -1
- package/lib/src/extensions/product-tours/components/ProductTourTooltip.js +31 -6
- package/lib/src/extensions/product-tours/components/ProductTourTooltip.js.map +1 -1
- package/lib/src/extensions/product-tours/product-tours.d.ts +7 -1
- package/lib/src/extensions/product-tours/product-tours.js +183 -8
- package/lib/src/extensions/product-tours/product-tours.js.map +1 -1
- package/lib/src/posthog-product-tours-types.d.ts +19 -1
- package/lib/src/posthog-product-tours-types.js.map +1 -1
- package/lib/src/posthog-product-tours.js +10 -42
- package/lib/src/posthog-product-tours.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/src/utils/product-tour-utils.d.ts +0 -5
- package/lib/src/utils/product-tour-utils.d.ts +0 -5
- package/lib/src/utils/product-tour-utils.js +0 -67
- package/lib/src/utils/product-tour-utils.js.map +0 -1
|
@@ -5,7 +5,7 @@ export interface ProductTourTooltipProps {
|
|
|
5
5
|
step: ProductTourStep;
|
|
6
6
|
stepIndex: number;
|
|
7
7
|
totalSteps: number;
|
|
8
|
-
targetElement: HTMLElement;
|
|
8
|
+
targetElement: HTMLElement | null;
|
|
9
9
|
onNext: () => void;
|
|
10
10
|
onPrevious: () => void;
|
|
11
11
|
onDismiss: (reason: ProductTourDismissReason) => void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PostHog } from '../../posthog-core';
|
|
2
|
-
import { ProductTour, ProductTourDismissReason, ProductTourRenderReason } from '../../posthog-product-tours-types';
|
|
2
|
+
import { ProductTour, ProductTourCallback, ProductTourDismissReason, ProductTourRenderReason } from '../../posthog-product-tours-types';
|
|
3
3
|
export declare class ProductTourManager {
|
|
4
4
|
private _instance;
|
|
5
5
|
private _activeTour;
|
|
@@ -7,6 +7,7 @@ export declare class ProductTourManager {
|
|
|
7
7
|
private _renderReason;
|
|
8
8
|
private _checkInterval;
|
|
9
9
|
private _triggerSelectorListeners;
|
|
10
|
+
private _surveyEventUnsubscribe;
|
|
10
11
|
constructor(instance: PostHog);
|
|
11
12
|
start(): void;
|
|
12
13
|
stop(): void;
|
|
@@ -21,9 +22,14 @@ export declare class ProductTourManager {
|
|
|
21
22
|
private _completeTour;
|
|
22
23
|
private _renderCurrentStep;
|
|
23
24
|
private _renderTooltipWithPreact;
|
|
25
|
+
private _renderSurveyStep;
|
|
26
|
+
private _cleanupSurveyListener;
|
|
24
27
|
private _cleanup;
|
|
25
28
|
private _manageTriggerSelectorListener;
|
|
26
29
|
private _removeTriggerSelectorListener;
|
|
27
30
|
private _removeAllTriggerListeners;
|
|
28
31
|
private _captureEvent;
|
|
32
|
+
getActiveProductTours(callback: ProductTourCallback): void;
|
|
33
|
+
resetTour(tourId: string): void;
|
|
34
|
+
resetAllTours(): void;
|
|
29
35
|
}
|
|
@@ -8,10 +8,27 @@ export interface JSONContent {
|
|
|
8
8
|
}[];
|
|
9
9
|
text?: string;
|
|
10
10
|
}
|
|
11
|
+
export type ProductTourSurveyQuestionType = 'open' | 'rating';
|
|
12
|
+
export interface ProductTourSurveyQuestion {
|
|
13
|
+
type: ProductTourSurveyQuestionType;
|
|
14
|
+
questionText: string;
|
|
15
|
+
/** Rating display type - emoji or number */
|
|
16
|
+
display?: 'emoji' | 'number';
|
|
17
|
+
/** Rating scale - 3 or 5 for emoji, 5 or 10 for number */
|
|
18
|
+
scale?: 3 | 5 | 10;
|
|
19
|
+
/** Label for low end of rating scale (e.g., "Not likely") */
|
|
20
|
+
lowerBoundLabel?: string;
|
|
21
|
+
/** Label for high end of rating scale (e.g., "Very likely") */
|
|
22
|
+
upperBoundLabel?: string;
|
|
23
|
+
}
|
|
11
24
|
export interface ProductTourStep {
|
|
12
25
|
id: string;
|
|
13
|
-
selector
|
|
26
|
+
selector?: string;
|
|
14
27
|
content: JSONContent | null;
|
|
28
|
+
/** Inline survey question config - if present, this is a survey step */
|
|
29
|
+
survey?: ProductTourSurveyQuestion;
|
|
30
|
+
/** ID of the auto-created survey for this step (set by backend) */
|
|
31
|
+
linkedSurveyId?: string;
|
|
15
32
|
}
|
|
16
33
|
export interface ProductTourConditions {
|
|
17
34
|
url?: string;
|
|
@@ -32,6 +49,7 @@ export interface ProductTour {
|
|
|
32
49
|
name: string;
|
|
33
50
|
description?: string;
|
|
34
51
|
type: 'product_tour';
|
|
52
|
+
auto_launch?: boolean;
|
|
35
53
|
start_date: string | null;
|
|
36
54
|
end_date: string | null;
|
|
37
55
|
current_iteration?: number;
|
|
@@ -2944,10 +2944,27 @@ interface JSONContent {
|
|
|
2944
2944
|
}[];
|
|
2945
2945
|
text?: string;
|
|
2946
2946
|
}
|
|
2947
|
+
type ProductTourSurveyQuestionType = 'open' | 'rating';
|
|
2948
|
+
interface ProductTourSurveyQuestion {
|
|
2949
|
+
type: ProductTourSurveyQuestionType;
|
|
2950
|
+
questionText: string;
|
|
2951
|
+
/** Rating display type - emoji or number */
|
|
2952
|
+
display?: 'emoji' | 'number';
|
|
2953
|
+
/** Rating scale - 3 or 5 for emoji, 5 or 10 for number */
|
|
2954
|
+
scale?: 3 | 5 | 10;
|
|
2955
|
+
/** Label for low end of rating scale (e.g., "Not likely") */
|
|
2956
|
+
lowerBoundLabel?: string;
|
|
2957
|
+
/** Label for high end of rating scale (e.g., "Very likely") */
|
|
2958
|
+
upperBoundLabel?: string;
|
|
2959
|
+
}
|
|
2947
2960
|
interface ProductTourStep {
|
|
2948
2961
|
id: string;
|
|
2949
|
-
selector
|
|
2962
|
+
selector?: string;
|
|
2950
2963
|
content: JSONContent | null;
|
|
2964
|
+
/** Inline survey question config - if present, this is a survey step */
|
|
2965
|
+
survey?: ProductTourSurveyQuestion;
|
|
2966
|
+
/** ID of the auto-created survey for this step (set by backend) */
|
|
2967
|
+
linkedSurveyId?: string;
|
|
2951
2968
|
}
|
|
2952
2969
|
interface ProductTourConditions {
|
|
2953
2970
|
url?: string;
|
|
@@ -2968,6 +2985,7 @@ interface ProductTour {
|
|
|
2968
2985
|
name: string;
|
|
2969
2986
|
description?: string;
|
|
2970
2987
|
type: 'product_tour';
|
|
2988
|
+
auto_launch?: boolean;
|
|
2971
2989
|
start_date: string | null;
|
|
2972
2990
|
end_date: string | null;
|
|
2973
2991
|
current_iteration?: number;
|
package/lib/package.json
CHANGED
|
@@ -5,7 +5,7 @@ export interface ProductTourTooltipProps {
|
|
|
5
5
|
step: ProductTourStep;
|
|
6
6
|
stepIndex: number;
|
|
7
7
|
totalSteps: number;
|
|
8
|
-
targetElement: HTMLElement;
|
|
8
|
+
targetElement: HTMLElement | null;
|
|
9
9
|
onNext: () => void;
|
|
10
10
|
onPrevious: () => void;
|
|
11
11
|
onDismiss: (reason: ProductTourDismissReason) => void;
|
|
@@ -88,11 +88,15 @@ function ProductTourTooltip(_a) {
|
|
|
88
88
|
var previousStepRef = (0, hooks_1.useRef)(stepIndex);
|
|
89
89
|
var isTransitioningRef = (0, hooks_1.useRef)(false);
|
|
90
90
|
var isFirstRender = (0, hooks_1.useRef)(true);
|
|
91
|
+
var isModalStep = !targetElement;
|
|
91
92
|
var updatePosition = (0, hooks_1.useCallback)(function () {
|
|
93
|
+
if (isModalStep) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
92
96
|
var rect = targetElement.getBoundingClientRect();
|
|
93
97
|
setPosition((0, product_tours_utils_1.calculateTooltipPosition)(rect));
|
|
94
98
|
setSpotlightStyle((0, product_tours_utils_1.getSpotlightStyle)(rect));
|
|
95
|
-
}, [targetElement]);
|
|
99
|
+
}, [targetElement, isModalStep]);
|
|
96
100
|
(0, hooks_1.useEffect)(function () {
|
|
97
101
|
var isStepChange = previousStepRef.current !== stepIndex;
|
|
98
102
|
var currentStepIndex = stepIndex;
|
|
@@ -100,6 +104,12 @@ function ProductTourTooltip(_a) {
|
|
|
100
104
|
isFirstRender.current = false;
|
|
101
105
|
previousStepRef.current = stepIndex;
|
|
102
106
|
isTransitioningRef.current = true;
|
|
107
|
+
if (isModalStep) {
|
|
108
|
+
// Modal steps are just centered on screen - no positioning needed
|
|
109
|
+
setTransitionState('visible');
|
|
110
|
+
isTransitioningRef.current = false;
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
103
113
|
scrollToElement(targetElement, function () {
|
|
104
114
|
if (previousStepRef.current !== currentStepIndex) {
|
|
105
115
|
return;
|
|
@@ -123,6 +133,17 @@ function ProductTourTooltip(_a) {
|
|
|
123
133
|
setDisplayedStep(step);
|
|
124
134
|
setDisplayedStepIndex(stepIndex);
|
|
125
135
|
setTransitionState('entering');
|
|
136
|
+
if (isModalStep) {
|
|
137
|
+
// Modal steps don't need scrolling or position calculation
|
|
138
|
+
setTimeout(function () {
|
|
139
|
+
if (previousStepRef.current !== currentStepIndex) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
setTransitionState('visible');
|
|
143
|
+
isTransitioningRef.current = false;
|
|
144
|
+
}, 50);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
126
147
|
scrollToElement(targetElement, function () {
|
|
127
148
|
if (previousStepRef.current !== currentStepIndex) {
|
|
128
149
|
return;
|
|
@@ -138,9 +159,9 @@ function ProductTourTooltip(_a) {
|
|
|
138
159
|
});
|
|
139
160
|
}, 150);
|
|
140
161
|
}
|
|
141
|
-
}, [targetElement, stepIndex, step, updatePosition]);
|
|
162
|
+
}, [targetElement, stepIndex, step, updatePosition, isModalStep]);
|
|
142
163
|
(0, hooks_1.useEffect)(function () {
|
|
143
|
-
if (transitionState !== 'visible') {
|
|
164
|
+
if (transitionState !== 'visible' || isModalStep) {
|
|
144
165
|
return;
|
|
145
166
|
}
|
|
146
167
|
var handleUpdate = function () {
|
|
@@ -154,7 +175,7 @@ function ProductTourTooltip(_a) {
|
|
|
154
175
|
window === null || window === void 0 ? void 0 : window.removeEventListener('scroll', handleUpdate, true);
|
|
155
176
|
window === null || window === void 0 ? void 0 : window.removeEventListener('resize', handleUpdate);
|
|
156
177
|
};
|
|
157
|
-
}, [updatePosition, transitionState]);
|
|
178
|
+
}, [updatePosition, transitionState, isModalStep]);
|
|
158
179
|
(0, hooks_1.useEffect)(function () {
|
|
159
180
|
var handleKeyDown = function (e) {
|
|
160
181
|
if (e.key === 'Escape') {
|
|
@@ -183,12 +204,16 @@ function ProductTourTooltip(_a) {
|
|
|
183
204
|
'--ph-tour-border-radius': "".concat(appearance.borderRadius, "px"),
|
|
184
205
|
'--ph-tour-border-color': appearance.borderColor,
|
|
185
206
|
};
|
|
186
|
-
var isReady = transitionState !== 'initializing' && position && spotlightStyle;
|
|
207
|
+
var isReady = isModalStep || (transitionState !== 'initializing' && position && spotlightStyle);
|
|
187
208
|
var isVisible = transitionState === 'visible';
|
|
188
209
|
if (!isReady) {
|
|
189
210
|
return ((0, jsx_runtime_1.jsxs)("div", { class: "ph-tour-container", style: containerStyle, children: [(0, jsx_runtime_1.jsx)("div", { class: "ph-tour-click-overlay", onClick: handleOverlayClick }), (0, jsx_runtime_1.jsx)("div", { class: "ph-tour-spotlight", style: { top: '50%', left: '50%', width: '0px', height: '0px' } })] }));
|
|
190
211
|
}
|
|
191
|
-
|
|
212
|
+
// Modal step: centered on screen with overlay dimming, no spotlight/arrow
|
|
213
|
+
if (isModalStep) {
|
|
214
|
+
return ((0, jsx_runtime_1.jsxs)("div", { class: "ph-tour-container", style: containerStyle, children: [(0, jsx_runtime_1.jsx)("div", { class: "ph-tour-click-overlay", onClick: handleOverlayClick }), (0, jsx_runtime_1.jsx)("div", { class: "ph-tour-modal-overlay" }), (0, jsx_runtime_1.jsxs)("div", { class: "ph-tour-tooltip ph-tour-tooltip--modal", onClick: handleTooltipClick, children: [(0, jsx_runtime_1.jsx)("button", { class: "ph-tour-dismiss", onClick: function () { return onDismiss('user_clicked_skip'); }, "aria-label": "Close tour", children: icons_1.cancelSVG }), (0, jsx_runtime_1.jsx)("div", { class: "ph-tour-content", dangerouslySetInnerHTML: { __html: (0, product_tours_utils_1.renderTipTapContent)(displayedStep.content) } }), (0, jsx_runtime_1.jsxs)("div", { class: "ph-tour-footer", children: [(0, jsx_runtime_1.jsxs)("span", { class: "ph-tour-progress", children: [displayedStepIndex + 1, " of ", totalSteps] }), (0, jsx_runtime_1.jsxs)("div", { class: "ph-tour-buttons", children: [!isFirstStep && ((0, jsx_runtime_1.jsx)("button", { class: "ph-tour-button ph-tour-button--secondary", onClick: onPrevious, children: "Back" })), (0, jsx_runtime_1.jsx)("button", { class: "ph-tour-button ph-tour-button--primary", onClick: onNext, children: isLastStep ? 'Done' : 'Next' })] })] }), !appearance.whiteLabel && ((0, jsx_runtime_1.jsxs)("a", { href: "https://posthog.com/product-tours", target: "_blank", rel: "noopener noreferrer", class: "ph-tour-branding", children: ["Tour by ", icons_1.IconPosthogLogo] }))] })] }));
|
|
215
|
+
}
|
|
216
|
+
return ((0, jsx_runtime_1.jsxs)("div", { class: "ph-tour-container", style: containerStyle, children: [(0, jsx_runtime_1.jsx)("div", { class: "ph-tour-click-overlay", onClick: handleOverlayClick }), (0, jsx_runtime_1.jsx)("div", { class: "ph-tour-spotlight", style: isVisible && spotlightStyle
|
|
192
217
|
? spotlightStyle
|
|
193
218
|
: {
|
|
194
219
|
top: '50%',
|
|
@@ -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 { ProductTour, ProductTourStep, ProductTourDismissReason } from '../../../posthog-product-tours-types'\nimport {\n calculateTooltipPosition,\n getSpotlightStyle,\n mergeAppearance,\n renderTipTapContent,\n TooltipPosition,\n} from '../product-tours-utils'\nimport { addEventListener } from '../../../utils'\nimport { window as _window } from '../../../utils/globals'\nimport { IconPosthogLogo, cancelSVG } from '../../surveys/icons'\n\nconst window = _window as Window & typeof globalThis\n\ntype TransitionState = 'initializing' | 'entering' | 'visible' | 'exiting'\n\nexport interface ProductTourTooltipProps {\n tour: ProductTour\n step: ProductTourStep\n stepIndex: number\n totalSteps: number\n targetElement: HTMLElement\n onNext: () => void\n onPrevious: () => void\n onDismiss: (reason: ProductTourDismissReason) => 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\nexport function ProductTourTooltip({\n tour,\n step,\n stepIndex,\n totalSteps,\n targetElement,\n onNext,\n onPrevious,\n onDismiss,\n}: ProductTourTooltipProps): h.JSX.Element {\n const appearance = mergeAppearance(tour.appearance)\n const [transitionState, setTransitionState] = useState<TransitionState>('initializing')\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 const isFirstRender = useRef(true)\n\n const updatePosition = useCallback(() => {\n const rect = targetElement.getBoundingClientRect()\n setPosition(calculateTooltipPosition(rect))\n setSpotlightStyle(getSpotlightStyle(rect))\n }, [targetElement])\n\n useEffect(() => {\n const isStepChange = previousStepRef.current !== stepIndex\n\n const currentStepIndex = stepIndex\n\n if (isFirstRender.current) {\n isFirstRender.current = false\n previousStepRef.current = stepIndex\n isTransitioningRef.current = true\n\n scrollToElement(targetElement, () => {\n if (previousStepRef.current !== currentStepIndex) {\n return\n }\n\n const rect = targetElement.getBoundingClientRect()\n setPosition(calculateTooltipPosition(rect))\n setSpotlightStyle(getSpotlightStyle(rect))\n setTransitionState('visible')\n isTransitioningRef.current = false\n })\n return\n }\n\n if (isStepChange) {\n previousStepRef.current = stepIndex\n isTransitioningRef.current = true\n\n setTransitionState('exiting')\n\n setTimeout(() => {\n if (previousStepRef.current !== currentStepIndex) {\n return\n }\n\n setDisplayedStep(step)\n setDisplayedStepIndex(stepIndex)\n setTransitionState('entering')\n\n scrollToElement(targetElement, () => {\n if (previousStepRef.current !== currentStepIndex) {\n return\n }\n\n updatePosition()\n setTimeout(() => {\n if (previousStepRef.current !== currentStepIndex) {\n return\n }\n setTransitionState('visible')\n isTransitioningRef.current = false\n }, 50)\n })\n }, 150)\n }\n }, [targetElement, stepIndex, step, updatePosition])\n\n useEffect(() => {\n if (transitionState !== 'visible') {\n return\n }\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])\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 isLastStep = displayedStepIndex >= totalSteps - 1\n const isFirstStep = displayedStepIndex === 0\n\n const containerStyle = {\n '--ph-tour-background-color': appearance.backgroundColor,\n '--ph-tour-text-color': appearance.textColor,\n '--ph-tour-button-color': appearance.buttonColor,\n '--ph-tour-button-text-color': appearance.buttonTextColor,\n '--ph-tour-border-radius': `${appearance.borderRadius}px`,\n '--ph-tour-border-color': appearance.borderColor,\n } as h.JSX.CSSProperties\n\n const isReady = transitionState !== 'initializing' && position && spotlightStyle\n const isVisible = transitionState === 'visible'\n\n if (!isReady) {\n return (\n <div class=\"ph-tour-container\" style={containerStyle}>\n <div class=\"ph-tour-click-overlay\" onClick={handleOverlayClick} />\n <div class=\"ph-tour-spotlight\" style={{ top: '50%', left: '50%', width: '0px', height: '0px' }} />\n </div>\n )\n }\n\n return (\n <div class=\"ph-tour-container\" style={containerStyle}>\n <div class=\"ph-tour-click-overlay\" onClick={handleOverlayClick} />\n\n <div\n class=\"ph-tour-spotlight\"\n style={\n isVisible\n ? spotlightStyle\n : {\n top: '50%',\n left: '50%',\n width: '0px',\n height: '0px',\n }\n }\n />\n\n <div\n class={`ph-tour-tooltip ${isVisible ? 'ph-tour-tooltip--visible' : 'ph-tour-tooltip--hidden'}`}\n style={{\n top: `${position.top}px`,\n left: `${position.left}px`,\n opacity: isVisible ? 1 : 0,\n transform: isVisible ? 'translateY(0)' : 'translateY(10px)',\n transition: 'opacity 0.15s ease-out, transform 0.15s ease-out',\n }}\n onClick={handleTooltipClick}\n >\n <div class={`ph-tour-arrow ph-tour-arrow--${getOppositePosition(position.position)}`} />\n\n <button class=\"ph-tour-dismiss\" onClick={() => onDismiss('user_clicked_skip')} aria-label=\"Close tour\">\n {cancelSVG}\n </button>\n\n <div\n class=\"ph-tour-content\"\n dangerouslySetInnerHTML={{ __html: renderTipTapContent(displayedStep.content) }}\n />\n\n <div class=\"ph-tour-footer\">\n <span class=\"ph-tour-progress\">\n {displayedStepIndex + 1} of {totalSteps}\n </span>\n\n <div class=\"ph-tour-buttons\">\n {!isFirstStep && (\n <button class=\"ph-tour-button ph-tour-button--secondary\" onClick={onPrevious}>\n Back\n </button>\n )}\n <button class=\"ph-tour-button ph-tour-button--primary\" onClick={onNext}>\n {isLastStep ? 'Done' : 'Next'}\n </button>\n </div>\n </div>\n\n {!appearance.whiteLabel && (\n <a\n href=\"https://posthog.com/product-tours\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"ph-tour-branding\"\n >\n Tour by {IconPosthogLogo}\n </a>\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, useState, useCallback, useRef } from 'preact/hooks'\nimport { ProductTour, ProductTourStep, ProductTourDismissReason } from '../../../posthog-product-tours-types'\nimport {\n calculateTooltipPosition,\n getSpotlightStyle,\n mergeAppearance,\n renderTipTapContent,\n TooltipPosition,\n} from '../product-tours-utils'\nimport { addEventListener } from '../../../utils'\nimport { window as _window } from '../../../utils/globals'\nimport { IconPosthogLogo, cancelSVG } from '../../surveys/icons'\n\nconst window = _window as Window & typeof globalThis\n\ntype TransitionState = 'initializing' | '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}\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\nexport function ProductTourTooltip({\n tour,\n step,\n stepIndex,\n totalSteps,\n targetElement,\n onNext,\n onPrevious,\n onDismiss,\n}: ProductTourTooltipProps): h.JSX.Element {\n const appearance = mergeAppearance(tour.appearance)\n const [transitionState, setTransitionState] = useState<TransitionState>('initializing')\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 const isFirstRender = useRef(true)\n\n const isModalStep = !targetElement\n\n const updatePosition = useCallback(() => {\n if (isModalStep) {\n return\n }\n const rect = targetElement.getBoundingClientRect()\n setPosition(calculateTooltipPosition(rect))\n setSpotlightStyle(getSpotlightStyle(rect))\n }, [targetElement, isModalStep])\n\n useEffect(() => {\n const isStepChange = previousStepRef.current !== stepIndex\n\n const currentStepIndex = stepIndex\n\n if (isFirstRender.current) {\n isFirstRender.current = false\n previousStepRef.current = stepIndex\n isTransitioningRef.current = true\n\n if (isModalStep) {\n // Modal steps are just centered on screen - no positioning needed\n setTransitionState('visible')\n isTransitioningRef.current = false\n return\n }\n\n scrollToElement(targetElement, () => {\n if (previousStepRef.current !== currentStepIndex) {\n return\n }\n\n const rect = targetElement.getBoundingClientRect()\n setPosition(calculateTooltipPosition(rect))\n setSpotlightStyle(getSpotlightStyle(rect))\n setTransitionState('visible')\n isTransitioningRef.current = false\n })\n return\n }\n\n if (isStepChange) {\n previousStepRef.current = stepIndex\n isTransitioningRef.current = true\n\n setTransitionState('exiting')\n\n setTimeout(() => {\n if (previousStepRef.current !== currentStepIndex) {\n return\n }\n\n setDisplayedStep(step)\n setDisplayedStepIndex(stepIndex)\n setTransitionState('entering')\n\n if (isModalStep) {\n // Modal steps don't need scrolling or position calculation\n setTimeout(() => {\n if (previousStepRef.current !== currentStepIndex) {\n return\n }\n setTransitionState('visible')\n isTransitioningRef.current = false\n }, 50)\n return\n }\n\n scrollToElement(targetElement, () => {\n if (previousStepRef.current !== currentStepIndex) {\n return\n }\n\n updatePosition()\n setTimeout(() => {\n if (previousStepRef.current !== currentStepIndex) {\n return\n }\n setTransitionState('visible')\n isTransitioningRef.current = false\n }, 50)\n })\n }, 150)\n }\n }, [targetElement, stepIndex, step, updatePosition, isModalStep])\n\n useEffect(() => {\n if (transitionState !== 'visible' || isModalStep) {\n return\n }\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, isModalStep])\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 isLastStep = displayedStepIndex >= totalSteps - 1\n const isFirstStep = displayedStepIndex === 0\n\n const containerStyle = {\n '--ph-tour-background-color': appearance.backgroundColor,\n '--ph-tour-text-color': appearance.textColor,\n '--ph-tour-button-color': appearance.buttonColor,\n '--ph-tour-button-text-color': appearance.buttonTextColor,\n '--ph-tour-border-radius': `${appearance.borderRadius}px`,\n '--ph-tour-border-color': appearance.borderColor,\n } as h.JSX.CSSProperties\n\n const isReady = isModalStep || (transitionState !== 'initializing' && position && spotlightStyle)\n const isVisible = transitionState === 'visible'\n\n if (!isReady) {\n return (\n <div class=\"ph-tour-container\" style={containerStyle}>\n <div class=\"ph-tour-click-overlay\" onClick={handleOverlayClick} />\n <div class=\"ph-tour-spotlight\" style={{ top: '50%', left: '50%', width: '0px', height: '0px' }} />\n </div>\n )\n }\n\n // Modal step: centered on screen with overlay dimming, no spotlight/arrow\n if (isModalStep) {\n return (\n <div class=\"ph-tour-container\" style={containerStyle}>\n <div class=\"ph-tour-click-overlay\" onClick={handleOverlayClick} />\n <div class=\"ph-tour-modal-overlay\" />\n <div class=\"ph-tour-tooltip ph-tour-tooltip--modal\" onClick={handleTooltipClick}>\n <button\n class=\"ph-tour-dismiss\"\n onClick={() => onDismiss('user_clicked_skip')}\n aria-label=\"Close tour\"\n >\n {cancelSVG}\n </button>\n\n <div\n class=\"ph-tour-content\"\n dangerouslySetInnerHTML={{ __html: renderTipTapContent(displayedStep.content) }}\n />\n\n <div class=\"ph-tour-footer\">\n <span class=\"ph-tour-progress\">\n {displayedStepIndex + 1} of {totalSteps}\n </span>\n\n <div class=\"ph-tour-buttons\">\n {!isFirstStep && (\n <button class=\"ph-tour-button ph-tour-button--secondary\" onClick={onPrevious}>\n Back\n </button>\n )}\n <button class=\"ph-tour-button ph-tour-button--primary\" onClick={onNext}>\n {isLastStep ? 'Done' : 'Next'}\n </button>\n </div>\n </div>\n\n {!appearance.whiteLabel && (\n <a\n href=\"https://posthog.com/product-tours\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"ph-tour-branding\"\n >\n Tour by {IconPosthogLogo}\n </a>\n )}\n </div>\n </div>\n )\n }\n\n return (\n <div class=\"ph-tour-container\" style={containerStyle}>\n <div class=\"ph-tour-click-overlay\" onClick={handleOverlayClick} />\n\n <div\n class=\"ph-tour-spotlight\"\n style={\n isVisible && spotlightStyle\n ? spotlightStyle\n : {\n top: '50%',\n left: '50%',\n width: '0px',\n height: '0px',\n }\n }\n />\n\n <div\n class={`ph-tour-tooltip ${isVisible ? 'ph-tour-tooltip--visible' : 'ph-tour-tooltip--hidden'}`}\n style={{\n top: `${position!.top}px`,\n left: `${position!.left}px`,\n opacity: isVisible ? 1 : 0,\n transform: isVisible ? 'translateY(0)' : 'translateY(10px)',\n transition: 'opacity 0.15s ease-out, transform 0.15s ease-out',\n }}\n onClick={handleTooltipClick}\n >\n <div class={`ph-tour-arrow ph-tour-arrow--${getOppositePosition(position!.position)}`} />\n\n <button class=\"ph-tour-dismiss\" onClick={() => onDismiss('user_clicked_skip')} aria-label=\"Close tour\">\n {cancelSVG}\n </button>\n\n <div\n class=\"ph-tour-content\"\n dangerouslySetInnerHTML={{ __html: renderTipTapContent(displayedStep.content) }}\n />\n\n <div class=\"ph-tour-footer\">\n <span class=\"ph-tour-progress\">\n {displayedStepIndex + 1} of {totalSteps}\n </span>\n\n <div class=\"ph-tour-buttons\">\n {!isFirstStep && (\n <button class=\"ph-tour-button ph-tour-button--secondary\" onClick={onPrevious}>\n Back\n </button>\n )}\n <button class=\"ph-tour-button ph-tour-button--primary\" onClick={onNext}>\n {isLastStep ? 'Done' : 'Next'}\n </button>\n </div>\n </div>\n\n {!appearance.whiteLabel && (\n <a\n href=\"https://posthog.com/product-tours\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"ph-tour-branding\"\n >\n Tour by {IconPosthogLogo}\n </a>\n )}\n </div>\n </div>\n )\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PostHog } from '../../posthog-core';
|
|
2
|
-
import { ProductTour, ProductTourDismissReason, ProductTourRenderReason } from '../../posthog-product-tours-types';
|
|
2
|
+
import { ProductTour, ProductTourCallback, ProductTourDismissReason, ProductTourRenderReason } from '../../posthog-product-tours-types';
|
|
3
3
|
export declare class ProductTourManager {
|
|
4
4
|
private _instance;
|
|
5
5
|
private _activeTour;
|
|
@@ -7,6 +7,7 @@ export declare class ProductTourManager {
|
|
|
7
7
|
private _renderReason;
|
|
8
8
|
private _checkInterval;
|
|
9
9
|
private _triggerSelectorListeners;
|
|
10
|
+
private _surveyEventUnsubscribe;
|
|
10
11
|
constructor(instance: PostHog);
|
|
11
12
|
start(): void;
|
|
12
13
|
stop(): void;
|
|
@@ -21,9 +22,14 @@ export declare class ProductTourManager {
|
|
|
21
22
|
private _completeTour;
|
|
22
23
|
private _renderCurrentStep;
|
|
23
24
|
private _renderTooltipWithPreact;
|
|
25
|
+
private _renderSurveyStep;
|
|
26
|
+
private _cleanupSurveyListener;
|
|
24
27
|
private _cleanup;
|
|
25
28
|
private _manageTriggerSelectorListener;
|
|
26
29
|
private _removeTriggerSelectorListener;
|
|
27
30
|
private _removeAllTriggerListeners;
|
|
28
31
|
private _captureEvent;
|
|
32
|
+
getActiveProductTours(callback: ProductTourCallback): void;
|
|
33
|
+
resetTour(tourId: string): void;
|
|
34
|
+
resetAllTours(): void;
|
|
29
35
|
}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
2
13
|
var __values = (this && this.__values) || function(o) {
|
|
3
14
|
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
4
15
|
if (m) return m.call(o);
|
|
@@ -14,15 +25,74 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
14
25
|
exports.ProductTourManager = void 0;
|
|
15
26
|
var jsx_runtime_1 = require("preact/jsx-runtime");
|
|
16
27
|
var preact_1 = require("preact");
|
|
17
|
-
var
|
|
28
|
+
var posthog_surveys_types_1 = require("../../posthog-surveys-types");
|
|
18
29
|
var product_tours_utils_1 = require("./product-tours-utils");
|
|
19
30
|
var ProductTourTooltip_1 = require("./components/ProductTourTooltip");
|
|
20
31
|
var logger_1 = require("../../utils/logger");
|
|
21
32
|
var globals_1 = require("../../utils/globals");
|
|
22
33
|
var storage_1 = require("../../storage");
|
|
23
34
|
var utils_1 = require("../../utils");
|
|
35
|
+
var core_1 = require("@posthog/core");
|
|
24
36
|
var logger = (0, logger_1.createLogger)('[Product Tours]');
|
|
25
37
|
var document = globals_1.document;
|
|
38
|
+
var window = globals_1.window;
|
|
39
|
+
// Tour condition checking utilities (moved from utils/product-tour-utils.ts)
|
|
40
|
+
function doesTourUrlMatch(tour) {
|
|
41
|
+
var conditions = tour.conditions;
|
|
42
|
+
if (!(conditions === null || conditions === void 0 ? void 0 : conditions.url)) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
var currentUrl = window.location.href;
|
|
46
|
+
var targetUrl = conditions.url;
|
|
47
|
+
var matchType = conditions.urlMatchType || 'contains';
|
|
48
|
+
switch (matchType) {
|
|
49
|
+
case 'exact':
|
|
50
|
+
return currentUrl === targetUrl;
|
|
51
|
+
case 'contains':
|
|
52
|
+
return currentUrl.includes(targetUrl);
|
|
53
|
+
case 'regex':
|
|
54
|
+
try {
|
|
55
|
+
var regex = new RegExp(targetUrl);
|
|
56
|
+
return regex.test(currentUrl);
|
|
57
|
+
}
|
|
58
|
+
catch (_a) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
default:
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function doesTourSelectorMatch(tour) {
|
|
66
|
+
var conditions = tour.conditions;
|
|
67
|
+
if (!(conditions === null || conditions === void 0 ? void 0 : conditions.selector)) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
return !(0, core_1.isNull)(document.querySelector(conditions.selector));
|
|
72
|
+
}
|
|
73
|
+
catch (_a) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function isTourInDateRange(tour) {
|
|
78
|
+
var now = new Date();
|
|
79
|
+
if (tour.start_date) {
|
|
80
|
+
var startDate = new Date(tour.start_date);
|
|
81
|
+
if (now < startDate) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (tour.end_date) {
|
|
86
|
+
var endDate = new Date(tour.end_date);
|
|
87
|
+
if (now > endDate) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
function checkTourConditions(tour) {
|
|
94
|
+
return isTourInDateRange(tour) && doesTourUrlMatch(tour) && doesTourSelectorMatch(tour);
|
|
95
|
+
}
|
|
26
96
|
var CONTAINER_CLASS = 'ph-product-tour-container';
|
|
27
97
|
var TRIGGER_LISTENER_ATTRIBUTE = 'data-ph-tour-trigger';
|
|
28
98
|
var CHECK_INTERVAL_MS = 1000;
|
|
@@ -64,6 +134,7 @@ var ProductTourManager = /** @class */ (function () {
|
|
|
64
134
|
this._renderReason = 'auto';
|
|
65
135
|
this._checkInterval = null;
|
|
66
136
|
this._triggerSelectorListeners = new Map();
|
|
137
|
+
this._surveyEventUnsubscribe = null;
|
|
67
138
|
this._handleVisibilityChange = function () {
|
|
68
139
|
if (document.hidden && _this._checkInterval) {
|
|
69
140
|
clearInterval(_this._checkInterval);
|
|
@@ -145,6 +216,7 @@ var ProductTourManager = /** @class */ (function () {
|
|
|
145
216
|
// should work even if completed/dismissed
|
|
146
217
|
(_a = this._instance.productTours) === null || _a === void 0 ? void 0 : _a.getProductTours(function (tours) {
|
|
147
218
|
var e_1, _a;
|
|
219
|
+
var _b;
|
|
148
220
|
if (tours.length === 0) {
|
|
149
221
|
_this._removeAllTriggerListeners();
|
|
150
222
|
return;
|
|
@@ -153,15 +225,17 @@ var ProductTourManager = /** @class */ (function () {
|
|
|
153
225
|
try {
|
|
154
226
|
for (var tours_1 = __values(tours), tours_1_1 = tours_1.next(); !tours_1_1.done; tours_1_1 = tours_1.next()) {
|
|
155
227
|
var tour = tours_1_1.value;
|
|
156
|
-
//
|
|
228
|
+
// Determine the trigger selector - explicit trigger_selector takes precedence,
|
|
229
|
+
// otherwise use conditions.selector for click-only tours (auto_launch=false)
|
|
230
|
+
var triggerSelector = tour.trigger_selector || (!tour.auto_launch ? (_b = tour.conditions) === null || _b === void 0 ? void 0 : _b.selector : null);
|
|
231
|
+
// Tours with a trigger selector: always attach listener
|
|
157
232
|
// These are "on-demand" tours that show when clicked
|
|
158
|
-
if (
|
|
233
|
+
if (triggerSelector) {
|
|
159
234
|
activeTriggerTourIds.add(tour.id);
|
|
160
|
-
_this._manageTriggerSelectorListener(tour);
|
|
161
|
-
continue;
|
|
235
|
+
_this._manageTriggerSelectorListener(__assign(__assign({}, tour), { trigger_selector: triggerSelector }));
|
|
162
236
|
}
|
|
163
|
-
//
|
|
164
|
-
if (!_this._activeTour && _this._isTourEligible(tour)) {
|
|
237
|
+
// Only auto-show if auto_launch is enabled
|
|
238
|
+
if (tour.auto_launch && !_this._activeTour && _this._isTourEligible(tour)) {
|
|
165
239
|
_this.showTour(tour);
|
|
166
240
|
}
|
|
167
241
|
}
|
|
@@ -183,7 +257,7 @@ var ProductTourManager = /** @class */ (function () {
|
|
|
183
257
|
};
|
|
184
258
|
ProductTourManager.prototype._isTourEligible = function (tour) {
|
|
185
259
|
var _a;
|
|
186
|
-
if (!
|
|
260
|
+
if (!checkTourConditions(tour)) {
|
|
187
261
|
logger.info("Tour ".concat(tour.id, " failed conditions check"));
|
|
188
262
|
return false;
|
|
189
263
|
}
|
|
@@ -206,9 +280,14 @@ var ProductTourManager = /** @class */ (function () {
|
|
|
206
280
|
var e_2, _a;
|
|
207
281
|
if (reason === void 0) { reason = 'auto'; }
|
|
208
282
|
// Validate all step selectors before showing the tour
|
|
283
|
+
// Steps without selectors are modal steps and don't need validation
|
|
209
284
|
var selectorFailures = [];
|
|
210
285
|
for (var i = 0; i < tour.steps.length; i++) {
|
|
211
286
|
var step = tour.steps[i];
|
|
287
|
+
// Skip validation for modal steps (no selector)
|
|
288
|
+
if (!step.selector) {
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
212
291
|
var result = (0, product_tours_utils_1.findElementBySelector)(step.selector);
|
|
213
292
|
if (result.error === 'not_found' || result.error === 'not_visible') {
|
|
214
293
|
selectorFailures.push({
|
|
@@ -295,6 +374,22 @@ var ProductTourManager = /** @class */ (function () {
|
|
|
295
374
|
return;
|
|
296
375
|
}
|
|
297
376
|
var step = this._activeTour.steps[this._currentStepIndex];
|
|
377
|
+
// Survey step - display the linked survey and listen for completion
|
|
378
|
+
if (step.linkedSurveyId) {
|
|
379
|
+
this._renderSurveyStep(step.linkedSurveyId);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
// Modal step (no selector) - render without a target element
|
|
383
|
+
if (!step.selector) {
|
|
384
|
+
this._captureEvent('product tour step shown', {
|
|
385
|
+
$product_tour_id: this._activeTour.id,
|
|
386
|
+
$product_tour_step_id: step.id,
|
|
387
|
+
$product_tour_step_order: this._currentStepIndex,
|
|
388
|
+
$product_tour_step_type: 'modal',
|
|
389
|
+
});
|
|
390
|
+
this._renderTooltipWithPreact(null);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
298
393
|
var result = (0, product_tours_utils_1.findElementBySelector)(step.selector);
|
|
299
394
|
if (result.error === 'not_found' || result.error === 'not_visible') {
|
|
300
395
|
this._captureEvent('product tour step selector failed', {
|
|
@@ -348,10 +443,59 @@ var ProductTourManager = /** @class */ (function () {
|
|
|
348
443
|
var shadow = retrieveTourShadow(this._activeTour.id).shadow;
|
|
349
444
|
(0, preact_1.render)((0, jsx_runtime_1.jsx)(ProductTourTooltip_1.ProductTourTooltip, { tour: this._activeTour, step: step, stepIndex: this._currentStepIndex, totalSteps: this._activeTour.steps.length, targetElement: element, onNext: this.nextStep, onPrevious: this.previousStep, onDismiss: this.dismissTour }), shadow);
|
|
350
445
|
};
|
|
446
|
+
ProductTourManager.prototype._renderSurveyStep = function (surveyId) {
|
|
447
|
+
var _this = this;
|
|
448
|
+
var _a;
|
|
449
|
+
if (!this._activeTour) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
var step = this._activeTour.steps[this._currentStepIndex];
|
|
453
|
+
// Emit tour step shown event
|
|
454
|
+
this._captureEvent('product tour step shown', {
|
|
455
|
+
$product_tour_id: this._activeTour.id,
|
|
456
|
+
$product_tour_step_id: step.id,
|
|
457
|
+
$product_tour_step_order: this._currentStepIndex,
|
|
458
|
+
$product_tour_step_type: 'survey',
|
|
459
|
+
$product_tour_linked_survey_id: surveyId,
|
|
460
|
+
});
|
|
461
|
+
// Clean up any existing survey event listener
|
|
462
|
+
this._cleanupSurveyListener();
|
|
463
|
+
// Set up listener for survey events
|
|
464
|
+
this._surveyEventUnsubscribe = this._instance.on('eventCaptured', function (data) {
|
|
465
|
+
var _a;
|
|
466
|
+
var eventSurveyId = (_a = data.properties) === null || _a === void 0 ? void 0 : _a[posthog_surveys_types_1.SurveyEventProperties.SURVEY_ID];
|
|
467
|
+
if (eventSurveyId !== surveyId) {
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
if (data.event === posthog_surveys_types_1.SurveyEventName.SENT) {
|
|
471
|
+
logger.info("Survey ".concat(surveyId, " completed, advancing tour"));
|
|
472
|
+
_this._cleanupSurveyListener();
|
|
473
|
+
_this.nextStep();
|
|
474
|
+
}
|
|
475
|
+
else if (data.event === posthog_surveys_types_1.SurveyEventName.DISMISSED) {
|
|
476
|
+
logger.info("Survey ".concat(surveyId, " dismissed, dismissing tour"));
|
|
477
|
+
_this._cleanupSurveyListener();
|
|
478
|
+
_this.dismissTour('user_clicked_skip');
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
// Display the survey
|
|
482
|
+
(_a = this._instance.surveys) === null || _a === void 0 ? void 0 : _a.displaySurvey(surveyId, {
|
|
483
|
+
ignoreConditions: true,
|
|
484
|
+
ignoreDelay: true,
|
|
485
|
+
displayType: posthog_surveys_types_1.DisplaySurveyType.Popover,
|
|
486
|
+
});
|
|
487
|
+
logger.info("Displayed survey ".concat(surveyId, " for tour step ").concat(this._currentStepIndex));
|
|
488
|
+
};
|
|
489
|
+
ProductTourManager.prototype._cleanupSurveyListener = function () {
|
|
490
|
+
var _a;
|
|
491
|
+
(_a = this._surveyEventUnsubscribe) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
492
|
+
this._surveyEventUnsubscribe = null;
|
|
493
|
+
};
|
|
351
494
|
ProductTourManager.prototype._cleanup = function () {
|
|
352
495
|
if (this._activeTour) {
|
|
353
496
|
removeTourFromDom(this._activeTour.id);
|
|
354
497
|
}
|
|
498
|
+
this._cleanupSurveyListener();
|
|
355
499
|
this._activeTour = null;
|
|
356
500
|
this._currentStepIndex = 0;
|
|
357
501
|
this._renderReason = 'auto';
|
|
@@ -412,6 +556,37 @@ var ProductTourManager = /** @class */ (function () {
|
|
|
412
556
|
ProductTourManager.prototype._captureEvent = function (eventName, properties) {
|
|
413
557
|
this._instance.capture(eventName, properties);
|
|
414
558
|
};
|
|
559
|
+
// Public API methods delegated from PostHogProductTours
|
|
560
|
+
ProductTourManager.prototype.getActiveProductTours = function (callback) {
|
|
561
|
+
var _this = this;
|
|
562
|
+
var _a;
|
|
563
|
+
(_a = this._instance.productTours) === null || _a === void 0 ? void 0 : _a.getProductTours(function (tours, context) {
|
|
564
|
+
if (!(context === null || context === void 0 ? void 0 : context.isLoaded)) {
|
|
565
|
+
callback([], context);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
var activeTours = tours.filter(function (tour) { return _this._isTourEligible(tour); });
|
|
569
|
+
callback(activeTours, context);
|
|
570
|
+
});
|
|
571
|
+
};
|
|
572
|
+
ProductTourManager.prototype.resetTour = function (tourId) {
|
|
573
|
+
storage_1.localStore._remove("ph_product_tour_completed_".concat(tourId));
|
|
574
|
+
storage_1.localStore._remove("ph_product_tour_dismissed_".concat(tourId));
|
|
575
|
+
};
|
|
576
|
+
ProductTourManager.prototype.resetAllTours = function () {
|
|
577
|
+
var storage = window === null || window === void 0 ? void 0 : window.localStorage;
|
|
578
|
+
if (!storage) {
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
var keysToRemove = [];
|
|
582
|
+
for (var i = 0; i < storage.length; i++) {
|
|
583
|
+
var key = storage.key(i);
|
|
584
|
+
if ((key === null || key === void 0 ? void 0 : key.startsWith('ph_product_tour_completed_')) || (key === null || key === void 0 ? void 0 : key.startsWith('ph_product_tour_dismissed_'))) {
|
|
585
|
+
keysToRemove.push(key);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
keysToRemove.forEach(function (key) { return storage_1.localStore._remove(key); });
|
|
589
|
+
};
|
|
415
590
|
return ProductTourManager;
|
|
416
591
|
}());
|
|
417
592
|
exports.ProductTourManager = ProductTourManager;
|