posthog-js 1.316.0 → 1.317.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/all-external-dependencies.js +1 -1
- package/dist/all-external-dependencies.js.map +1 -1
- 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.no-external.js +1 -1
- package/dist/customizations.full.js +1 -1
- package/dist/element-inference.d.ts +21 -0
- package/dist/element-inference.js +2 -0
- package/dist/element-inference.js.map +1 -0
- 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 +12 -0
- package/dist/module.full.d.ts +12 -0
- package/dist/module.full.js +1 -1
- package/dist/module.full.js.map +1 -1
- package/dist/module.full.no-external.d.ts +12 -0
- 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 +12 -0
- 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-preview.d.ts +12 -0
- package/dist/product-tours-preview.js +1 -1
- package/dist/product-tours-preview.js.map +1 -1
- package/dist/product-tours.js +1 -1
- package/dist/product-tours.js.map +1 -1
- package/dist/src/entrypoints/element-inference.es.d.ts +1 -0
- package/dist/src/entrypoints/product-tours.d.ts +2 -0
- package/dist/src/extensions/product-tours/element-inference.d.ts +30 -0
- package/dist/src/extensions/product-tours/index.d.ts +2 -0
- package/dist/src/extensions/product-tours/product-tours-utils.d.ts +2 -1
- package/dist/src/extensions/surveys.d.ts +2 -2
- package/dist/src/posthog-product-tours-types.d.ts +7 -0
- package/dist/src/utils/survey-branching.d.ts +11 -0
- package/dist/src/utils/survey-url-prefill.d.ts +7 -5
- package/dist/surveys-preview.d.ts +18 -1
- package/dist/surveys-preview.js +1 -1
- package/dist/surveys-preview.js.map +1 -1
- package/dist/surveys.js +1 -1
- package/dist/surveys.js.map +1 -1
- package/lib/package.json +5 -1
- package/lib/src/entrypoints/element-inference.es.d.ts +1 -0
- package/lib/src/entrypoints/element-inference.es.js +8 -0
- package/lib/src/entrypoints/element-inference.es.js.map +1 -0
- package/lib/src/entrypoints/product-tours.d.ts +2 -0
- package/lib/src/entrypoints/product-tours.js +5 -0
- package/lib/src/entrypoints/product-tours.js.map +1 -1
- package/lib/src/extensions/product-tours/components/ProductTourTooltip.js +5 -2
- package/lib/src/extensions/product-tours/components/ProductTourTooltip.js.map +1 -1
- package/lib/src/extensions/product-tours/components/ProductTourTooltipInner.js +1 -1
- package/lib/src/extensions/product-tours/components/ProductTourTooltipInner.js.map +1 -1
- package/lib/src/extensions/product-tours/element-inference.d.ts +30 -0
- package/lib/src/extensions/product-tours/element-inference.js +296 -0
- package/lib/src/extensions/product-tours/element-inference.js.map +1 -0
- package/lib/src/extensions/product-tours/index.d.ts +2 -0
- package/lib/src/extensions/product-tours/index.js +4 -1
- package/lib/src/extensions/product-tours/index.js.map +1 -1
- package/lib/src/extensions/product-tours/preview.js +1 -1
- package/lib/src/extensions/product-tours/preview.js.map +1 -1
- package/lib/src/extensions/product-tours/product-tours-utils.d.ts +2 -1
- package/lib/src/extensions/product-tours/product-tours-utils.js +12 -0
- package/lib/src/extensions/product-tours/product-tours-utils.js.map +1 -1
- package/lib/src/extensions/product-tours/product-tours.js +15 -31
- package/lib/src/extensions/product-tours/product-tours.js.map +1 -1
- package/lib/src/extensions/surveys.d.ts +2 -2
- package/lib/src/extensions/surveys.js +5 -94
- package/lib/src/extensions/surveys.js.map +1 -1
- package/lib/src/posthog-product-tours-types.d.ts +7 -0
- package/lib/src/posthog-product-tours-types.js.map +1 -1
- package/lib/src/utils/survey-branching.d.ts +11 -0
- package/lib/src/utils/survey-branching.js +106 -0
- package/lib/src/utils/survey-branching.js.map +1 -0
- package/lib/src/utils/survey-url-prefill.d.ts +7 -5
- package/lib/src/utils/survey-url-prefill.js +30 -18
- package/lib/src/utils/survey-url-prefill.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -3
package/lib/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "posthog-js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.317.0",
|
|
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",
|
|
@@ -52,8 +52,10 @@
|
|
|
52
52
|
"@posthog/core": "workspace:*",
|
|
53
53
|
"@posthog/types": "workspace:*",
|
|
54
54
|
"core-js": "^3.38.1",
|
|
55
|
+
"dompurify": "^3.3.1",
|
|
55
56
|
"fflate": "^0.4.8",
|
|
56
57
|
"preact": "^10.19.3",
|
|
58
|
+
"query-selector-shadow-dom": "^1.0.1",
|
|
57
59
|
"web-vitals": "^4.2.4"
|
|
58
60
|
},
|
|
59
61
|
"devDependencies": {
|
|
@@ -83,9 +85,11 @@
|
|
|
83
85
|
"@testing-library/dom": "catalog:",
|
|
84
86
|
"@testing-library/jest-dom": "catalog:",
|
|
85
87
|
"@testing-library/preact": "catalog:",
|
|
88
|
+
"@types/dompurify": "^3.2.0",
|
|
86
89
|
"@types/dotenv": "^8.2.3",
|
|
87
90
|
"@types/jest": "catalog:",
|
|
88
91
|
"@types/node": "^22.5.0",
|
|
92
|
+
"@types/query-selector-shadow-dom": "^1.0.4",
|
|
89
93
|
"@types/sinon": "^17.0.1",
|
|
90
94
|
"@types/web": "^0.0.222",
|
|
91
95
|
"babel-jest": "^29.7.0",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { findElement, getElementPath, elementIsVisible } from '../extensions/product-tours/element-inference';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.elementIsVisible = exports.getElementPath = exports.findElement = void 0;
|
|
4
|
+
var element_inference_1 = require("../extensions/product-tours/element-inference");
|
|
5
|
+
Object.defineProperty(exports, "findElement", { enumerable: true, get: function () { return element_inference_1.findElement; } });
|
|
6
|
+
Object.defineProperty(exports, "getElementPath", { enumerable: true, get: function () { return element_inference_1.getElementPath; } });
|
|
7
|
+
Object.defineProperty(exports, "elementIsVisible", { enumerable: true, get: function () { return element_inference_1.elementIsVisible; } });
|
|
8
|
+
//# sourceMappingURL=element-inference.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"element-inference.es.js","sourceRoot":"","sources":["../../../src/entrypoints/element-inference.es.ts"],"names":[],"mappings":";;;AAAA,mFAA6G;AAApG,gHAAA,WAAW,OAAA;AAAE,mHAAA,cAAc,OAAA;AAAE,qHAAA,gBAAgB,OAAA","sourcesContent":["export { findElement, getElementPath, elementIsVisible } from '../extensions/product-tours/element-inference'\n"]}
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
import { generateProductTours } from '../extensions/product-tours';
|
|
2
|
+
export { findElement, getElementPath, elementIsVisible } from '../extensions/product-tours/element-inference';
|
|
3
|
+
export type { InferredSelector, AutoData, SelectorGroup } from '../extensions/product-tours/element-inference';
|
|
2
4
|
export default generateProductTours;
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.elementIsVisible = exports.getElementPath = exports.findElement = void 0;
|
|
3
4
|
var product_tours_1 = require("../extensions/product-tours");
|
|
4
5
|
var globals_1 = require("../utils/globals");
|
|
5
6
|
globals_1.assignableWindow.__PosthogExtensions__ = globals_1.assignableWindow.__PosthogExtensions__ || {};
|
|
6
7
|
globals_1.assignableWindow.__PosthogExtensions__.generateProductTours = product_tours_1.generateProductTours;
|
|
8
|
+
var element_inference_1 = require("../extensions/product-tours/element-inference");
|
|
9
|
+
Object.defineProperty(exports, "findElement", { enumerable: true, get: function () { return element_inference_1.findElement; } });
|
|
10
|
+
Object.defineProperty(exports, "getElementPath", { enumerable: true, get: function () { return element_inference_1.getElementPath; } });
|
|
11
|
+
Object.defineProperty(exports, "elementIsVisible", { enumerable: true, get: function () { return element_inference_1.elementIsVisible; } });
|
|
7
12
|
exports.default = product_tours_1.generateProductTours;
|
|
8
13
|
//# sourceMappingURL=product-tours.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-tours.js","sourceRoot":"","sources":["../../../src/entrypoints/product-tours.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"product-tours.js","sourceRoot":"","sources":["../../../src/entrypoints/product-tours.ts"],"names":[],"mappings":";;;AAAA,6DAAkE;AAClE,4CAAmD;AAEnD,0BAAgB,CAAC,qBAAqB,GAAG,0BAAgB,CAAC,qBAAqB,IAAI,EAAE,CAAA;AACrF,0BAAgB,CAAC,qBAAqB,CAAC,oBAAoB,GAAG,oCAAoB,CAAA;AAElF,mFAA6G;AAApG,gHAAA,WAAW,OAAA;AAAE,mHAAA,cAAc,OAAA;AAAE,qHAAA,gBAAgB,OAAA;AAGtD,kBAAe,oCAAoB,CAAA","sourcesContent":["import { generateProductTours } from '../extensions/product-tours'\nimport { assignableWindow } from '../utils/globals'\n\nassignableWindow.__PosthogExtensions__ = assignableWindow.__PosthogExtensions__ || {}\nassignableWindow.__PosthogExtensions__.generateProductTours = generateProductTours\n\nexport { findElement, getElementPath, elementIsVisible } from '../extensions/product-tours/element-inference'\nexport type { InferredSelector, AutoData, SelectorGroup } from '../extensions/product-tours/element-inference'\n\nexport default generateProductTours\n"]}
|
|
@@ -199,7 +199,10 @@ function ProductTourTooltip(_a) {
|
|
|
199
199
|
var isSurvey = displayedStep.type === 'survey';
|
|
200
200
|
// For element steps, don't render until position is calculated
|
|
201
201
|
var isPositionReady = isCentered || !(0, core_1.isNull)(position);
|
|
202
|
-
var tooltipStyle =
|
|
202
|
+
var tooltipStyle = __assign(__assign({}, (displayedStep.maxWidth && {
|
|
203
|
+
width: "".concat(displayedStep.maxWidth, "px"),
|
|
204
|
+
maxWidth: "".concat(displayedStep.maxWidth, "px"),
|
|
205
|
+
})), (isCentered
|
|
203
206
|
? {
|
|
204
207
|
top: '50%',
|
|
205
208
|
left: '50%',
|
|
@@ -208,7 +211,7 @@ function ProductTourTooltip(_a) {
|
|
|
208
211
|
: {
|
|
209
212
|
top: position ? "".concat(position.top, "px") : '0',
|
|
210
213
|
left: position ? "".concat(position.left, "px") : '0',
|
|
211
|
-
};
|
|
214
|
+
}));
|
|
212
215
|
return ((0, jsx_runtime_1.jsxs)("div", { class: "ph-tour-container", 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", style: {
|
|
213
216
|
opacity: isCentered && isVisible ? 1 : 0,
|
|
214
217
|
transition: "opacity ".concat(TRANSITION_DURATION, "ms ease-out"),
|
|
@@ -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 { calculateTooltipPosition, getSpotlightStyle, TooltipPosition } from '../product-tours-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}\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}: 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 are both centered on screen\n const isCentered = 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' || isCentered) 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, isCentered])\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 = isCentered || !isNull(position)\n\n const tooltipStyle = isCentered\n ? {\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n }\n : {\n top: position ? `${position.top}px` : '0',\n left: position ? `${position.left}px` : '0',\n }\n\n return (\n <div class=\"ph-tour-container\">\n <div class=\"ph-tour-click-overlay\" onClick={handleOverlayClick} />\n\n {/* Modal overlay - visible for centered steps */}\n <div\n class=\"ph-tour-modal-overlay\"\n style={{\n opacity: isCentered && isVisible ? 1 : 0,\n transition: `opacity ${TRANSITION_DURATION}ms ease-out`,\n pointerEvents: isCentered ? 'auto' : '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: !isCentered && isVisible && isPositionReady ? 1 : 0,\n transition: `opacity ${TRANSITION_DURATION}ms ease-out`,\n ...(displayedStep.progressionTrigger === 'click' &&\n !isCentered && {\n pointerEvents: 'auto',\n cursor: 'pointer',\n }),\n }}\n onClick={displayedStep.progressionTrigger === 'click' && !isCentered ? handleSpotlightClick : undefined}\n />\n\n <div\n class={`ph-tour-tooltip ${isCentered ? '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 {!isCentered && 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 />\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 { calculateTooltipPosition, getSpotlightStyle, TooltipPosition } from '../product-tours-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}\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}: 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 are both centered on screen\n const isCentered = 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' || isCentered) 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, isCentered])\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 = isCentered || !isNull(position)\n\n const tooltipStyle = {\n ...(displayedStep.maxWidth && {\n width: `${displayedStep.maxWidth}px`,\n maxWidth: `${displayedStep.maxWidth}px`,\n }),\n ...(isCentered\n ? {\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\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 <div class=\"ph-tour-click-overlay\" onClick={handleOverlayClick} />\n\n {/* Modal overlay - visible for centered steps */}\n <div\n class=\"ph-tour-modal-overlay\"\n style={{\n opacity: isCentered && isVisible ? 1 : 0,\n transition: `opacity ${TRANSITION_DURATION}ms ease-out`,\n pointerEvents: isCentered ? 'auto' : '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: !isCentered && isVisible && isPositionReady ? 1 : 0,\n transition: `opacity ${TRANSITION_DURATION}ms ease-out`,\n ...(displayedStep.progressionTrigger === 'click' &&\n !isCentered && {\n pointerEvents: 'auto',\n cursor: 'pointer',\n }),\n }}\n onClick={displayedStep.progressionTrigger === 'click' && !isCentered ? handleSpotlightClick : undefined}\n />\n\n <div\n class={`ph-tour-tooltip ${isCentered ? '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 {!isCentered && 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 />\n )}\n </div>\n </div>\n )\n}\n"]}
|
|
@@ -13,6 +13,6 @@ function ProductTourTooltipInner(_a) {
|
|
|
13
13
|
var showNextButton = step.progressionTrigger === 'button' || step.type === 'modal';
|
|
14
14
|
var isInteractive = !!(onNext || onPrevious || onDismiss);
|
|
15
15
|
var cursorStyle = isInteractive ? undefined : { cursor: 'default' };
|
|
16
|
-
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("button", { class: "ph-tour-dismiss", onClick: onDismiss, "aria-label": "Close tour", style: cursorStyle, children: icons_1.cancelSVG }), (0, jsx_runtime_1.jsx)("div", { class: "ph-tour-content", dangerouslySetInnerHTML: { __html: (0, product_tours_utils_1.
|
|
16
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("button", { class: "ph-tour-dismiss", onClick: onDismiss, "aria-label": "Close tour", style: cursorStyle, children: icons_1.cancelSVG }), (0, jsx_runtime_1.jsx)("div", { class: "ph-tour-content", dangerouslySetInnerHTML: { __html: (0, product_tours_utils_1.getStepHtml)(step) } }), (0, jsx_runtime_1.jsxs)("div", { class: "ph-tour-footer", children: [(0, jsx_runtime_1.jsxs)("span", { class: "ph-tour-progress", children: [stepIndex + 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, style: cursorStyle, children: "Back" })), showNextButton && ((0, jsx_runtime_1.jsx)("button", { class: "ph-tour-button ph-tour-button--primary", onClick: onNext, style: cursorStyle, children: isLastStep ? 'Done' : 'Next' }))] })] }), !whiteLabel && ((0, jsx_runtime_1.jsxs)("a", { href: isInteractive ? 'https://posthog.com/product-tours' : undefined, target: isInteractive ? '_blank' : undefined, rel: isInteractive ? 'noopener noreferrer' : undefined, class: "ph-tour-branding", style: isInteractive ? undefined : { cursor: 'default', pointerEvents: 'none' }, children: ["Tour by ", icons_1.IconPosthogLogo] }))] }));
|
|
17
17
|
}
|
|
18
18
|
//# sourceMappingURL=ProductTourTooltipInner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductTourTooltipInner.js","sourceRoot":"","sources":["../../../../../src/extensions/product-tours/components/ProductTourTooltipInner.tsx"],"names":[],"mappings":";;AAeA,0DA6DC;;AA1ED,
|
|
1
|
+
{"version":3,"file":"ProductTourTooltipInner.js","sourceRoot":"","sources":["../../../../../src/extensions/product-tours/components/ProductTourTooltipInner.tsx"],"names":[],"mappings":";;AAeA,0DA6DC;;AA1ED,8DAAoD;AACpD,6CAAgE;AAYhE,SAAgB,uBAAuB,CAAC,EAQT;;QAP3B,IAAI,UAAA,EACJ,UAAU,gBAAA,EACV,SAAS,eAAA,EACT,UAAU,gBAAA,EACV,MAAM,YAAA,EACN,UAAU,gBAAA,EACV,SAAS,eAAA;IAET,IAAM,UAAU,GAAG,MAAA,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,UAAU,mCAAI,KAAK,CAAA;IAClD,IAAM,UAAU,GAAG,SAAS,IAAI,UAAU,GAAG,CAAC,CAAA;IAC9C,IAAM,WAAW,GAAG,SAAS,KAAK,CAAC,CAAA;IACnC,IAAM,cAAc,GAAG,IAAI,CAAC,kBAAkB,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,CAAA;IAEpF,IAAM,aAAa,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,UAAU,IAAI,SAAS,CAAC,CAAA;IAC3D,IAAM,WAAW,GAAG,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;IAErE,OAAO,CACH,6DACI,mCAAQ,KAAK,EAAC,iBAAiB,EAAC,OAAO,EAAE,SAAS,gBAAa,YAAY,EAAC,KAAK,EAAE,WAAW,YACzF,iBAAS,GACL,EAET,gCAAK,KAAK,EAAC,iBAAiB,EAAC,uBAAuB,EAAE,EAAE,MAAM,EAAE,IAAA,iCAAW,EAAC,IAAI,CAAC,EAAE,GAAI,EAEvF,iCAAK,KAAK,EAAC,gBAAgB,aACvB,kCAAM,KAAK,EAAC,kBAAkB,aACzB,SAAS,GAAG,CAAC,UAAM,UAAU,IAC3B,EAEP,iCAAK,KAAK,EAAC,iBAAiB,aACvB,CAAC,WAAW,IAAI,CACb,mCACI,KAAK,EAAC,0CAA0C,EAChD,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,WAAW,qBAGb,CACZ,EACA,cAAc,IAAI,CACf,mCAAQ,KAAK,EAAC,wCAAwC,EAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,YACrF,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,GACxB,CACZ,IACC,IACJ,EAEL,CAAC,UAAU,IAAI,CACZ,+BACI,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC,SAAS,EACrE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EAC5C,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,EACtD,KAAK,EAAC,kBAAkB,EACxB,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,yBAEtE,uBAAe,IACxB,CACP,IACF,CACN,CAAA;AACL,CAAC","sourcesContent":["import { h } from 'preact'\nimport { ProductTourStep, ProductTourAppearance } from '../../../posthog-product-tours-types'\nimport { getStepHtml } from '../product-tours-utils'\nimport { IconPosthogLogo, cancelSVG } from '../../surveys/icons'\n\nexport interface ProductTourTooltipInnerProps {\n step: ProductTourStep\n appearance?: ProductTourAppearance\n stepIndex: number\n totalSteps: number\n onNext?: () => void\n onPrevious?: () => void\n onDismiss?: () => void\n}\n\nexport function ProductTourTooltipInner({\n step,\n appearance,\n stepIndex,\n totalSteps,\n onNext,\n onPrevious,\n onDismiss,\n}: ProductTourTooltipInnerProps): h.JSX.Element {\n const whiteLabel = appearance?.whiteLabel ?? false\n const isLastStep = stepIndex >= totalSteps - 1\n const isFirstStep = stepIndex === 0\n const showNextButton = step.progressionTrigger === 'button' || step.type === 'modal'\n\n const isInteractive = !!(onNext || onPrevious || onDismiss)\n const cursorStyle = isInteractive ? undefined : { cursor: 'default' }\n\n return (\n <>\n <button class=\"ph-tour-dismiss\" onClick={onDismiss} aria-label=\"Close tour\" style={cursorStyle}>\n {cancelSVG}\n </button>\n\n <div class=\"ph-tour-content\" dangerouslySetInnerHTML={{ __html: getStepHtml(step) }} />\n\n <div class=\"ph-tour-footer\">\n <span class=\"ph-tour-progress\">\n {stepIndex + 1} of {totalSteps}\n </span>\n\n <div class=\"ph-tour-buttons\">\n {!isFirstStep && (\n <button\n class=\"ph-tour-button ph-tour-button--secondary\"\n onClick={onPrevious}\n style={cursorStyle}\n >\n Back\n </button>\n )}\n {showNextButton && (\n <button class=\"ph-tour-button ph-tour-button--primary\" onClick={onNext} style={cursorStyle}>\n {isLastStep ? 'Done' : 'Next'}\n </button>\n )}\n </div>\n </div>\n\n {!whiteLabel && (\n <a\n href={isInteractive ? 'https://posthog.com/product-tours' : undefined}\n target={isInteractive ? '_blank' : undefined}\n rel={isInteractive ? 'noopener noreferrer' : undefined}\n class=\"ph-tour-branding\"\n style={isInteractive ? undefined : { cursor: 'default', pointerEvents: 'none' }}\n >\n Tour by {IconPosthogLogo}\n </a>\n )}\n </>\n )\n}\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare function elementIsVisible(element: HTMLElement, cache: WeakMap<HTMLElement, boolean>): boolean;
|
|
2
|
+
export interface SelectorGroup {
|
|
3
|
+
cardinality: number;
|
|
4
|
+
cssSelectors: Array<{
|
|
5
|
+
css: string;
|
|
6
|
+
offset: number;
|
|
7
|
+
}>;
|
|
8
|
+
}
|
|
9
|
+
export interface AutoData {
|
|
10
|
+
notextGroups: SelectorGroup[];
|
|
11
|
+
textGroups: SelectorGroup[];
|
|
12
|
+
}
|
|
13
|
+
export interface InferredSelector {
|
|
14
|
+
autoData: string;
|
|
15
|
+
text: string | null;
|
|
16
|
+
excludeText?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* if inferSelector is the sauce, this is the nugget
|
|
20
|
+
*
|
|
21
|
+
* find an element in the dom using the element inference data
|
|
22
|
+
*
|
|
23
|
+
* 1. try each group of selectors, starting with most specific (lowest cardinality)
|
|
24
|
+
* 2. try each selector in the group - run the css query, go to offset
|
|
25
|
+
* 3. "vote" for the element if it was found
|
|
26
|
+
* 4. return early if any element gets majority votes
|
|
27
|
+
* 5. return element w/ most votes
|
|
28
|
+
*/
|
|
29
|
+
export declare function findElement(selector: InferredSelector): HTMLElement | null;
|
|
30
|
+
export declare function getElementPath(el: HTMLElement | null, depth?: number): string | null;
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
3
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
4
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
5
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
6
|
+
function step(op) {
|
|
7
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
8
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
9
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
10
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
11
|
+
switch (op[0]) {
|
|
12
|
+
case 0: case 1: t = op; break;
|
|
13
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
14
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
15
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
16
|
+
default:
|
|
17
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
18
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
19
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
20
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
21
|
+
if (t[2]) _.ops.pop();
|
|
22
|
+
_.trys.pop(); continue;
|
|
23
|
+
}
|
|
24
|
+
op = body.call(thisArg, _);
|
|
25
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
26
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
var __values = (this && this.__values) || function(o) {
|
|
30
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
31
|
+
if (m) return m.call(o);
|
|
32
|
+
if (o && typeof o.length === "number") return {
|
|
33
|
+
next: function () {
|
|
34
|
+
if (o && i >= o.length) o = void 0;
|
|
35
|
+
return { value: o && o[i++], done: !o };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
39
|
+
};
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.elementIsVisible = elementIsVisible;
|
|
42
|
+
exports.findElement = findElement;
|
|
43
|
+
exports.getElementPath = getElementPath;
|
|
44
|
+
var query_selector_shadow_dom_1 = require("query-selector-shadow-dom");
|
|
45
|
+
var globals_1 = require("../../utils/globals");
|
|
46
|
+
var core_1 = require("@posthog/core");
|
|
47
|
+
var window = globals_1.window;
|
|
48
|
+
var logger = (0, core_1.createLogger)('[Element Inference]');
|
|
49
|
+
// this is copied directly from the main repo: /frontend/src/toolbar/utils.ts
|
|
50
|
+
// TODO: once this is deployed, we can have the main repo reference this instead
|
|
51
|
+
function elementIsVisible(element, cache) {
|
|
52
|
+
try {
|
|
53
|
+
var alreadyCached = cache.get(element);
|
|
54
|
+
if (!(0, core_1.isUndefined)(alreadyCached)) {
|
|
55
|
+
return alreadyCached;
|
|
56
|
+
}
|
|
57
|
+
if (element.checkVisibility) {
|
|
58
|
+
var nativeIsVisible = element.checkVisibility({
|
|
59
|
+
checkOpacity: true,
|
|
60
|
+
checkVisibilityCSS: true,
|
|
61
|
+
});
|
|
62
|
+
cache.set(element, nativeIsVisible);
|
|
63
|
+
return nativeIsVisible;
|
|
64
|
+
}
|
|
65
|
+
var style = window.getComputedStyle(element);
|
|
66
|
+
var isInvisible = style.display === 'none' || style.visibility === 'hidden' || parseFloat(style.opacity) === 0;
|
|
67
|
+
if (isInvisible) {
|
|
68
|
+
cache.set(element, false);
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
// Check parent chain for display/visibility
|
|
72
|
+
var parent_1 = element.parentElement;
|
|
73
|
+
while (parent_1) {
|
|
74
|
+
// Check cache first
|
|
75
|
+
var cached = cache.get(parent_1);
|
|
76
|
+
if (!(0, core_1.isUndefined)(cached)) {
|
|
77
|
+
if (!cached) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
// If cached as visible, skip to next parent
|
|
81
|
+
parent_1 = parent_1.parentElement;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
var parentStyle = window.getComputedStyle(parent_1);
|
|
85
|
+
var parentVisible = parentStyle.display !== 'none' && parentStyle.visibility !== 'hidden';
|
|
86
|
+
cache.set(parent_1, parentVisible);
|
|
87
|
+
if (!parentVisible) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
parent_1 = parent_1.parentElement;
|
|
91
|
+
}
|
|
92
|
+
// Check if element has actual rendered dimensions
|
|
93
|
+
var rect = element.getBoundingClientRect();
|
|
94
|
+
var elementHasActualRenderedDimensions = rect.width > 0 ||
|
|
95
|
+
rect.height > 0 ||
|
|
96
|
+
// Some elements might be 0x0 but still visible (e.g., inline elements with content)
|
|
97
|
+
element.getClientRects().length > 0;
|
|
98
|
+
cache.set(element, elementHasActualRenderedDimensions);
|
|
99
|
+
return elementHasActualRenderedDimensions;
|
|
100
|
+
}
|
|
101
|
+
catch (_a) {
|
|
102
|
+
// if we can't get the computed style, we'll assume the element is visible
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function getElementText(element) {
|
|
107
|
+
var _a;
|
|
108
|
+
var text = (_a = element.innerText) === null || _a === void 0 ? void 0 : _a.trim();
|
|
109
|
+
// anything higher than 250 chars -> prob not a good selector / button / target
|
|
110
|
+
if (!text || text.length > 250) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
return text;
|
|
114
|
+
}
|
|
115
|
+
function elementMatchesText(element, text) {
|
|
116
|
+
var elementText = getElementText(element);
|
|
117
|
+
return (elementText === null || elementText === void 0 ? void 0 : elementText.toLowerCase()) === text.toLowerCase();
|
|
118
|
+
}
|
|
119
|
+
// generator to query elements, filtering by text and visibility
|
|
120
|
+
function queryElements(selector, text, visibilityCache) {
|
|
121
|
+
var elements, elements_1, elements_1_1, el, element, e_1_1;
|
|
122
|
+
var e_1, _a;
|
|
123
|
+
return __generator(this, function (_b) {
|
|
124
|
+
switch (_b.label) {
|
|
125
|
+
case 0:
|
|
126
|
+
try {
|
|
127
|
+
elements = (0, query_selector_shadow_dom_1.querySelectorAllDeep)(selector);
|
|
128
|
+
}
|
|
129
|
+
catch (_c) {
|
|
130
|
+
return [2 /*return*/];
|
|
131
|
+
}
|
|
132
|
+
_b.label = 1;
|
|
133
|
+
case 1:
|
|
134
|
+
_b.trys.push([1, 6, 7, 8]);
|
|
135
|
+
elements_1 = __values(elements), elements_1_1 = elements_1.next();
|
|
136
|
+
_b.label = 2;
|
|
137
|
+
case 2:
|
|
138
|
+
if (!!elements_1_1.done) return [3 /*break*/, 5];
|
|
139
|
+
el = elements_1_1.value;
|
|
140
|
+
element = el;
|
|
141
|
+
if (text && !elementMatchesText(element, text)) {
|
|
142
|
+
return [3 /*break*/, 4];
|
|
143
|
+
}
|
|
144
|
+
if (!elementIsVisible(element, visibilityCache)) {
|
|
145
|
+
return [3 /*break*/, 4];
|
|
146
|
+
}
|
|
147
|
+
return [4 /*yield*/, element];
|
|
148
|
+
case 3:
|
|
149
|
+
_b.sent();
|
|
150
|
+
_b.label = 4;
|
|
151
|
+
case 4:
|
|
152
|
+
elements_1_1 = elements_1.next();
|
|
153
|
+
return [3 /*break*/, 2];
|
|
154
|
+
case 5: return [3 /*break*/, 8];
|
|
155
|
+
case 6:
|
|
156
|
+
e_1_1 = _b.sent();
|
|
157
|
+
e_1 = { error: e_1_1 };
|
|
158
|
+
return [3 /*break*/, 8];
|
|
159
|
+
case 7:
|
|
160
|
+
try {
|
|
161
|
+
if (elements_1_1 && !elements_1_1.done && (_a = elements_1.return)) _a.call(elements_1);
|
|
162
|
+
}
|
|
163
|
+
finally { if (e_1) throw e_1.error; }
|
|
164
|
+
return [7 /*endfinally*/];
|
|
165
|
+
case 8: return [2 /*return*/];
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// could be inlined, but wanna keep lazy eval from queryElements
|
|
170
|
+
function nth(iterable, n) {
|
|
171
|
+
var e_2, _a;
|
|
172
|
+
var idx = 0;
|
|
173
|
+
try {
|
|
174
|
+
for (var iterable_1 = __values(iterable), iterable_1_1 = iterable_1.next(); !iterable_1_1.done; iterable_1_1 = iterable_1.next()) {
|
|
175
|
+
var item = iterable_1_1.value;
|
|
176
|
+
if (idx === n) {
|
|
177
|
+
return item;
|
|
178
|
+
}
|
|
179
|
+
idx++;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
183
|
+
finally {
|
|
184
|
+
try {
|
|
185
|
+
if (iterable_1_1 && !iterable_1_1.done && (_a = iterable_1.return)) _a.call(iterable_1);
|
|
186
|
+
}
|
|
187
|
+
finally { if (e_2) throw e_2.error; }
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* if inferSelector is the sauce, this is the nugget
|
|
193
|
+
*
|
|
194
|
+
* find an element in the dom using the element inference data
|
|
195
|
+
*
|
|
196
|
+
* 1. try each group of selectors, starting with most specific (lowest cardinality)
|
|
197
|
+
* 2. try each selector in the group - run the css query, go to offset
|
|
198
|
+
* 3. "vote" for the element if it was found
|
|
199
|
+
* 4. return early if any element gets majority votes
|
|
200
|
+
* 5. return element w/ most votes
|
|
201
|
+
*/
|
|
202
|
+
function findElement(selector) {
|
|
203
|
+
var e_3, _a, e_4, _b;
|
|
204
|
+
var _c;
|
|
205
|
+
try {
|
|
206
|
+
var autoData = JSON.parse(selector.autoData);
|
|
207
|
+
if (!(0, core_1.isArray)(autoData === null || autoData === void 0 ? void 0 : autoData.textGroups) || !(0, core_1.isArray)(autoData === null || autoData === void 0 ? void 0 : autoData.notextGroups)) {
|
|
208
|
+
logger.error('Invalid autoData structure:', autoData);
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
var text = selector.text, excludeText = selector.excludeText;
|
|
212
|
+
// excludeText -> user setting, usually if the target element
|
|
213
|
+
// has dynamic/localized text
|
|
214
|
+
var useText = text != null && !excludeText;
|
|
215
|
+
// choose appropriate group + sort
|
|
216
|
+
var groups = (useText ? autoData.textGroups : autoData.notextGroups).sort(function (a, b) { return a.cardinality - b.cardinality; });
|
|
217
|
+
if (groups.length === 0) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
var visibilityCache = new WeakMap();
|
|
221
|
+
try {
|
|
222
|
+
// try each selector group, starting w/ most specific (lowest cardinality)
|
|
223
|
+
for (var groups_1 = __values(groups), groups_1_1 = groups_1.next(); !groups_1_1.done; groups_1_1 = groups_1.next()) {
|
|
224
|
+
var group = groups_1_1.value;
|
|
225
|
+
var votes = new Map();
|
|
226
|
+
var winner = null;
|
|
227
|
+
var maxVotes = 0;
|
|
228
|
+
try {
|
|
229
|
+
// test each selector in the group
|
|
230
|
+
for (var _d = (e_4 = void 0, __values(group.cssSelectors)), _e = _d.next(); !_e.done; _e = _d.next()) {
|
|
231
|
+
var _f = _e.value, css = _f.css, offset = _f.offset;
|
|
232
|
+
// get matches, jump to offset to find our target
|
|
233
|
+
var element = nth(queryElements(css, useText ? text : null, visibilityCache), offset);
|
|
234
|
+
if (!element) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
// if we found something, this element gets a vote
|
|
238
|
+
var voteCount = ((_c = votes.get(element)) !== null && _c !== void 0 ? _c : 0) + 1;
|
|
239
|
+
votes.set(element, voteCount);
|
|
240
|
+
if (voteCount > maxVotes) {
|
|
241
|
+
maxVotes = voteCount;
|
|
242
|
+
winner = element;
|
|
243
|
+
// break early if we have a majority
|
|
244
|
+
if (voteCount >= Math.ceil(group.cssSelectors.length / 2)) {
|
|
245
|
+
return winner;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
251
|
+
finally {
|
|
252
|
+
try {
|
|
253
|
+
if (_e && !_e.done && (_b = _d.return)) _b.call(_d);
|
|
254
|
+
}
|
|
255
|
+
finally { if (e_4) throw e_4.error; }
|
|
256
|
+
}
|
|
257
|
+
if (winner) {
|
|
258
|
+
return winner;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
263
|
+
finally {
|
|
264
|
+
try {
|
|
265
|
+
if (groups_1_1 && !groups_1_1.done && (_a = groups_1.return)) _a.call(groups_1);
|
|
266
|
+
}
|
|
267
|
+
finally { if (e_3) throw e_3.error; }
|
|
268
|
+
}
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
logger.error('Error finding element:', error);
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function getElementPath(el, depth) {
|
|
277
|
+
if (depth === void 0) { depth = 4; }
|
|
278
|
+
if (!el) {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
var parts = [];
|
|
282
|
+
var current = el;
|
|
283
|
+
while (current && parts.length < depth && current.tagName !== 'BODY') {
|
|
284
|
+
var part = current.tagName.toLowerCase();
|
|
285
|
+
if (current.id) {
|
|
286
|
+
part += "#".concat(current.id);
|
|
287
|
+
}
|
|
288
|
+
else if (current.classList.length) {
|
|
289
|
+
part += ".".concat(current.classList[0]);
|
|
290
|
+
}
|
|
291
|
+
parts.unshift(part);
|
|
292
|
+
current = current.parentElement;
|
|
293
|
+
}
|
|
294
|
+
return parts.join(' > ');
|
|
295
|
+
}
|
|
296
|
+
//# sourceMappingURL=element-inference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"element-inference.js","sourceRoot":"","sources":["../../../../src/extensions/product-tours/element-inference.ts"],"names":[],"mappings":"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","sourcesContent":["import { querySelectorAllDeep } from 'query-selector-shadow-dom'\nimport { window as _window } from '../../utils/globals'\nimport { createLogger, isArray, isUndefined } from '@posthog/core'\n\nconst window = _window as Window & typeof globalThis\nconst logger = createLogger('[Element Inference]')\n\n// this is copied directly from the main repo: /frontend/src/toolbar/utils.ts\n// TODO: once this is deployed, we can have the main repo reference this instead\nexport function elementIsVisible(element: HTMLElement, cache: WeakMap<HTMLElement, boolean>): boolean {\n try {\n const alreadyCached = cache.get(element)\n if (!isUndefined(alreadyCached)) {\n return alreadyCached\n }\n\n if (element.checkVisibility) {\n const nativeIsVisible = element.checkVisibility({\n checkOpacity: true,\n checkVisibilityCSS: true,\n })\n cache.set(element, nativeIsVisible)\n return nativeIsVisible\n }\n\n const style = window.getComputedStyle(element)\n const isInvisible = style.display === 'none' || style.visibility === 'hidden' || parseFloat(style.opacity) === 0\n if (isInvisible) {\n cache.set(element, false)\n return false\n }\n\n // Check parent chain for display/visibility\n let parent = element.parentElement\n while (parent) {\n // Check cache first\n const cached = cache.get(parent)\n if (!isUndefined(cached)) {\n if (!cached) {\n return false\n }\n // If cached as visible, skip to next parent\n parent = parent.parentElement\n continue\n }\n\n const parentStyle = window.getComputedStyle(parent)\n const parentVisible = parentStyle.display !== 'none' && parentStyle.visibility !== 'hidden'\n\n cache.set(parent, parentVisible)\n\n if (!parentVisible) {\n return false\n }\n parent = parent.parentElement\n }\n\n // Check if element has actual rendered dimensions\n const rect = element.getBoundingClientRect()\n const elementHasActualRenderedDimensions =\n rect.width > 0 ||\n rect.height > 0 ||\n // Some elements might be 0x0 but still visible (e.g., inline elements with content)\n element.getClientRects().length > 0\n cache.set(element, elementHasActualRenderedDimensions)\n return elementHasActualRenderedDimensions\n } catch {\n // if we can't get the computed style, we'll assume the element is visible\n return true\n }\n}\n\nexport interface SelectorGroup {\n cardinality: number\n cssSelectors: Array<{\n css: string\n offset: number\n }>\n}\n\nexport interface AutoData {\n notextGroups: SelectorGroup[]\n textGroups: SelectorGroup[]\n}\n\nexport interface InferredSelector {\n autoData: string\n text: string | null\n excludeText?: boolean\n}\n\nfunction getElementText(element: HTMLElement): string | null {\n const text = element.innerText?.trim()\n // anything higher than 250 chars -> prob not a good selector / button / target\n if (!text || text.length > 250) {\n return null\n }\n return text\n}\n\nfunction elementMatchesText(element: HTMLElement, text: string): boolean {\n const elementText = getElementText(element)\n return elementText?.toLowerCase() === text.toLowerCase()\n}\n\n// generator to query elements, filtering by text and visibility\nfunction* queryElements(\n selector: string,\n text: string | null,\n visibilityCache: WeakMap<HTMLElement, boolean>\n): Generator<HTMLElement, void, undefined> {\n let elements: HTMLElement[]\n\n try {\n elements = querySelectorAllDeep(selector) as unknown as HTMLElement[]\n } catch {\n return\n }\n\n for (const el of elements) {\n const element = el as HTMLElement\n if (text && !elementMatchesText(element, text)) {\n continue\n }\n if (!elementIsVisible(element, visibilityCache)) {\n continue\n }\n yield element\n }\n}\n\n// could be inlined, but wanna keep lazy eval from queryElements\nfunction nth<T>(iterable: Iterable<T>, n: number): T | null {\n let idx = 0\n for (const item of iterable) {\n if (idx === n) {\n return item\n }\n idx++\n }\n return null\n}\n\n/**\n * if inferSelector is the sauce, this is the nugget\n *\n * find an element in the dom using the element inference data\n *\n * 1. try each group of selectors, starting with most specific (lowest cardinality)\n * 2. try each selector in the group - run the css query, go to offset\n * 3. \"vote\" for the element if it was found\n * 4. return early if any element gets majority votes\n * 5. return element w/ most votes\n */\nexport function findElement(selector: InferredSelector): HTMLElement | null {\n try {\n const autoData = JSON.parse(selector.autoData) as AutoData\n if (!isArray(autoData?.textGroups) || !isArray(autoData?.notextGroups)) {\n logger.error('Invalid autoData structure:', autoData)\n return null\n }\n const { text, excludeText } = selector\n\n // excludeText -> user setting, usually if the target element\n // has dynamic/localized text\n const useText = text != null && !excludeText\n\n // choose appropriate group + sort\n const groups = (useText ? autoData.textGroups : autoData.notextGroups).sort(\n (a, b) => a.cardinality - b.cardinality\n )\n\n if (groups.length === 0) {\n return null\n }\n\n const visibilityCache = new WeakMap<HTMLElement, boolean>()\n\n // try each selector group, starting w/ most specific (lowest cardinality)\n for (const group of groups) {\n const votes = new Map<HTMLElement, number>()\n let winner: HTMLElement | null = null\n let maxVotes = 0\n\n // test each selector in the group\n for (const { css, offset } of group.cssSelectors) {\n // get matches, jump to offset to find our target\n const element = nth(queryElements(css, useText ? text : null, visibilityCache), offset)\n\n if (!element) {\n continue\n }\n\n // if we found something, this element gets a vote\n const voteCount = (votes.get(element) ?? 0) + 1\n votes.set(element, voteCount)\n\n if (voteCount > maxVotes) {\n maxVotes = voteCount\n winner = element\n\n // break early if we have a majority\n if (voteCount >= Math.ceil(group.cssSelectors.length / 2)) {\n return winner\n }\n }\n }\n\n if (winner) {\n return winner\n }\n }\n\n return null\n } catch (error) {\n logger.error('Error finding element:', error)\n return null\n }\n}\n\nexport function getElementPath(el: HTMLElement | null, depth = 4): string | null {\n if (!el) {\n return null\n }\n const parts: string[] = []\n let current: HTMLElement | null = el\n\n while (current && parts.length < depth && current.tagName !== 'BODY') {\n let part = current.tagName.toLowerCase()\n if (current.id) {\n part += `#${current.id}`\n } else if (current.classList.length) {\n part += `.${current.classList[0]}`\n }\n parts.unshift(part)\n current = current.parentElement\n }\n\n return parts.join(' > ')\n}\n"]}
|
|
@@ -2,4 +2,6 @@ import { PostHog } from '../../posthog-core';
|
|
|
2
2
|
import { ProductTourManager } from './product-tours';
|
|
3
3
|
export { ProductTourManager } from './product-tours';
|
|
4
4
|
export { findElementBySelector, getElementMetadata, getProductTourStylesheet } from './product-tours-utils';
|
|
5
|
+
export { findElement, getElementPath } from './element-inference';
|
|
6
|
+
export type { InferredSelector, AutoData, SelectorGroup } from './element-inference';
|
|
5
7
|
export declare function generateProductTours(posthog: PostHog, isEnabled: boolean): ProductTourManager | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getProductTourStylesheet = exports.getElementMetadata = exports.findElementBySelector = exports.ProductTourManager = void 0;
|
|
3
|
+
exports.getElementPath = exports.findElement = exports.getProductTourStylesheet = exports.getElementMetadata = exports.findElementBySelector = exports.ProductTourManager = void 0;
|
|
4
4
|
exports.generateProductTours = generateProductTours;
|
|
5
5
|
var globals_1 = require("../../utils/globals");
|
|
6
6
|
var product_tours_1 = require("./product-tours");
|
|
@@ -10,6 +10,9 @@ var product_tours_utils_1 = require("./product-tours-utils");
|
|
|
10
10
|
Object.defineProperty(exports, "findElementBySelector", { enumerable: true, get: function () { return product_tours_utils_1.findElementBySelector; } });
|
|
11
11
|
Object.defineProperty(exports, "getElementMetadata", { enumerable: true, get: function () { return product_tours_utils_1.getElementMetadata; } });
|
|
12
12
|
Object.defineProperty(exports, "getProductTourStylesheet", { enumerable: true, get: function () { return product_tours_utils_1.getProductTourStylesheet; } });
|
|
13
|
+
var element_inference_1 = require("./element-inference");
|
|
14
|
+
Object.defineProperty(exports, "findElement", { enumerable: true, get: function () { return element_inference_1.findElement; } });
|
|
15
|
+
Object.defineProperty(exports, "getElementPath", { enumerable: true, get: function () { return element_inference_1.getElementPath; } });
|
|
13
16
|
function generateProductTours(posthog, isEnabled) {
|
|
14
17
|
if (!globals_1.document) {
|
|
15
18
|
return;
|