@korsolutions/guidon 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/babel.config.js +15 -0
- package/dist/commonjs/babel.config.js.map +1 -0
- package/dist/commonjs/bob.config.js +11 -0
- package/dist/commonjs/bob.config.js.map +1 -0
- package/dist/commonjs/components/GuidonOverlay.js +206 -0
- package/dist/commonjs/components/GuidonOverlay.js.map +1 -0
- package/dist/commonjs/components/GuidonProvider.js +157 -0
- package/dist/commonjs/components/GuidonProvider.js.map +1 -0
- package/dist/commonjs/components/GuidonTarget.js +110 -0
- package/dist/commonjs/components/GuidonTarget.js.map +1 -0
- package/dist/commonjs/components/GuidonTooltip.js +422 -0
- package/dist/commonjs/components/GuidonTooltip.js.map +1 -0
- package/dist/commonjs/components/index.js +40 -0
- package/dist/commonjs/components/index.js.map +1 -0
- package/dist/commonjs/hooks/index.js +13 -0
- package/dist/commonjs/hooks/index.js.map +1 -0
- package/dist/commonjs/hooks/useGuidonRef.js +132 -0
- package/dist/commonjs/hooks/useGuidonRef.js.map +1 -0
- package/dist/commonjs/index.js +143 -0
- package/dist/commonjs/index.js.map +1 -0
- package/dist/commonjs/package.json +1 -0
- package/dist/commonjs/persistence/adapters.js +213 -0
- package/dist/commonjs/persistence/adapters.js.map +1 -0
- package/dist/commonjs/persistence/hooks.js +153 -0
- package/dist/commonjs/persistence/hooks.js.map +1 -0
- package/dist/commonjs/persistence/index.js +28 -0
- package/dist/commonjs/persistence/index.js.map +1 -0
- package/dist/commonjs/store.js +314 -0
- package/dist/commonjs/store.js.map +1 -0
- package/dist/commonjs/tsconfig.json +32 -0
- package/dist/commonjs/types.js +6 -0
- package/dist/commonjs/types.js.map +1 -0
- package/dist/module/babel.config.js +15 -0
- package/dist/module/babel.config.js.map +1 -0
- package/dist/module/bob.config.js +11 -0
- package/dist/module/bob.config.js.map +1 -0
- package/dist/module/components/GuidonOverlay.js +201 -0
- package/dist/module/components/GuidonOverlay.js.map +1 -0
- package/dist/module/components/GuidonProvider.js +152 -0
- package/dist/module/components/GuidonProvider.js.map +1 -0
- package/dist/module/components/GuidonTarget.js +106 -0
- package/dist/module/components/GuidonTarget.js.map +1 -0
- package/dist/module/components/GuidonTooltip.js +417 -0
- package/dist/module/components/GuidonTooltip.js.map +1 -0
- package/dist/module/components/index.js +7 -0
- package/dist/module/components/index.js.map +1 -0
- package/dist/module/hooks/index.js +4 -0
- package/dist/module/hooks/index.js.map +1 -0
- package/dist/module/hooks/useGuidonRef.js +129 -0
- package/dist/module/hooks/useGuidonRef.js.map +1 -0
- package/dist/module/index.js +17 -0
- package/dist/module/index.js.map +1 -0
- package/dist/module/package.json +1 -0
- package/dist/module/persistence/adapters.js +203 -0
- package/dist/module/persistence/adapters.js.map +1 -0
- package/dist/module/persistence/hooks.js +148 -0
- package/dist/module/persistence/hooks.js.map +1 -0
- package/dist/module/persistence/index.js +5 -0
- package/dist/module/persistence/index.js.map +1 -0
- package/dist/module/store.js +304 -0
- package/dist/module/store.js.map +1 -0
- package/dist/module/tsconfig.json +32 -0
- package/dist/module/types.js +4 -0
- package/dist/module/types.js.map +1 -0
- package/dist/typescript/commonjs/components/GuidonOverlay.d.ts +9 -0
- package/dist/typescript/commonjs/components/GuidonOverlay.d.ts.map +1 -0
- package/dist/typescript/commonjs/components/GuidonProvider.d.ts +14 -0
- package/dist/typescript/commonjs/components/GuidonProvider.d.ts.map +1 -0
- package/dist/typescript/commonjs/components/GuidonTarget.d.ts +7 -0
- package/dist/typescript/commonjs/components/GuidonTarget.d.ts.map +1 -0
- package/dist/typescript/commonjs/components/GuidonTooltip.d.ts +24 -0
- package/dist/typescript/commonjs/components/GuidonTooltip.d.ts.map +1 -0
- package/dist/typescript/commonjs/components/index.d.ts +5 -0
- package/dist/typescript/commonjs/components/index.d.ts.map +1 -0
- package/dist/typescript/commonjs/hooks/index.d.ts +2 -0
- package/dist/typescript/commonjs/hooks/index.d.ts.map +1 -0
- package/dist/typescript/commonjs/hooks/useGuidonRef.d.ts +35 -0
- package/dist/typescript/commonjs/hooks/useGuidonRef.d.ts.map +1 -0
- package/dist/typescript/commonjs/index.d.ts +7 -0
- package/dist/typescript/commonjs/index.d.ts.map +1 -0
- package/dist/typescript/commonjs/package.json +1 -0
- package/dist/typescript/commonjs/persistence/adapters.d.ts +57 -0
- package/dist/typescript/commonjs/persistence/adapters.d.ts.map +1 -0
- package/dist/typescript/commonjs/persistence/hooks.d.ts +29 -0
- package/dist/typescript/commonjs/persistence/hooks.d.ts.map +1 -0
- package/dist/typescript/commonjs/persistence/index.d.ts +3 -0
- package/dist/typescript/commonjs/persistence/index.d.ts.map +1 -0
- package/dist/typescript/commonjs/store.d.ts +89 -0
- package/dist/typescript/commonjs/store.d.ts.map +1 -0
- package/dist/{index-D_JFvCIg.d.mts → typescript/commonjs/types.d.ts} +40 -104
- package/dist/typescript/commonjs/types.d.ts.map +1 -0
- package/dist/typescript/module/components/GuidonOverlay.d.ts +9 -0
- package/dist/typescript/module/components/GuidonOverlay.d.ts.map +1 -0
- package/dist/typescript/module/components/GuidonProvider.d.ts +14 -0
- package/dist/typescript/module/components/GuidonProvider.d.ts.map +1 -0
- package/dist/typescript/module/components/GuidonTarget.d.ts +7 -0
- package/dist/typescript/module/components/GuidonTarget.d.ts.map +1 -0
- package/dist/typescript/module/components/GuidonTooltip.d.ts +24 -0
- package/dist/typescript/module/components/GuidonTooltip.d.ts.map +1 -0
- package/dist/typescript/module/components/index.d.ts +5 -0
- package/dist/typescript/module/components/index.d.ts.map +1 -0
- package/dist/typescript/module/hooks/index.d.ts +2 -0
- package/dist/typescript/module/hooks/index.d.ts.map +1 -0
- package/dist/typescript/module/hooks/useGuidonRef.d.ts +35 -0
- package/dist/typescript/module/hooks/useGuidonRef.d.ts.map +1 -0
- package/dist/typescript/module/index.d.ts +7 -0
- package/dist/typescript/module/index.d.ts.map +1 -0
- package/dist/typescript/module/package.json +1 -0
- package/dist/typescript/module/persistence/adapters.d.ts +57 -0
- package/dist/typescript/module/persistence/adapters.d.ts.map +1 -0
- package/dist/typescript/module/persistence/hooks.d.ts +29 -0
- package/dist/typescript/module/persistence/hooks.d.ts.map +1 -0
- package/dist/typescript/module/persistence/index.d.ts +3 -0
- package/dist/typescript/module/persistence/index.d.ts.map +1 -0
- package/dist/typescript/module/store.d.ts +89 -0
- package/dist/typescript/module/store.d.ts.map +1 -0
- package/dist/{index-D_JFvCIg.d.ts → typescript/module/types.d.ts} +40 -104
- package/dist/typescript/module/types.d.ts.map +1 -0
- package/package.json +25 -13
- package/src/babel.config.js +18 -0
- package/src/bob.config.js +14 -0
- package/src/components/GuidonOverlay.tsx +60 -4
- package/src/components/GuidonProvider.tsx +29 -1
- package/src/components/GuidonTarget.tsx +41 -25
- package/src/components/GuidonTooltip.tsx +143 -9
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useGuidonRef.ts +154 -0
- package/src/index.ts +6 -0
- package/src/store.ts +68 -15
- package/src/tsconfig.json +32 -0
- package/src/types.ts +32 -2
- package/dist/index.d.mts +0 -128
- package/dist/index.d.ts +0 -128
- package/dist/index.js +0 -1097
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -1072
- package/dist/index.mjs.map +0 -1
- package/dist/persistence/index.d.mts +0 -2
- package/dist/persistence/index.d.ts +0 -2
- package/dist/persistence/index.js +0 -300
- package/dist/persistence/index.js.map +0 -1
- package/dist/persistence/index.mjs +0 -291
- package/dist/persistence/index.mjs.map +0 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useCallback, useRef, createContext, useContext } from 'react';
|
|
4
|
+
import { useGuidonStore, useWaitingState } from "../store.js";
|
|
5
|
+
import { useGuidonPersistence } from "../persistence/hooks.js";
|
|
6
|
+
import { GuidonOverlay } from "./GuidonOverlay.js";
|
|
7
|
+
import { GuidonTooltip } from "./GuidonTooltip.js";
|
|
8
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
9
|
+
const GuidonContext = /*#__PURE__*/createContext(null);
|
|
10
|
+
export function useGuidonContext() {
|
|
11
|
+
const context = useContext(GuidonContext);
|
|
12
|
+
if (!context) {
|
|
13
|
+
throw new Error('useGuidonContext must be used within a GuidonProvider');
|
|
14
|
+
}
|
|
15
|
+
return context;
|
|
16
|
+
}
|
|
17
|
+
export function GuidonProvider({
|
|
18
|
+
children,
|
|
19
|
+
config,
|
|
20
|
+
autoStart = true,
|
|
21
|
+
shouldStart,
|
|
22
|
+
persistenceAdapter,
|
|
23
|
+
portalComponent: Portal,
|
|
24
|
+
renderTooltip,
|
|
25
|
+
tooltipLabels,
|
|
26
|
+
onBackdropPress
|
|
27
|
+
}) {
|
|
28
|
+
const hasInitialized = useRef(false);
|
|
29
|
+
const isActive = useGuidonStore(state => state.isActive);
|
|
30
|
+
const storeIsCompleted = useGuidonStore(state => state.isCompleted);
|
|
31
|
+
const currentStepIndex = useGuidonStore(state => state.currentStepIndex);
|
|
32
|
+
const configure = useGuidonStore(state => state.configure);
|
|
33
|
+
const start = useGuidonStore(state => state.start);
|
|
34
|
+
const next = useGuidonStore(state => state.next);
|
|
35
|
+
const skip = useGuidonStore(state => state.skip);
|
|
36
|
+
const reset = useGuidonStore(state => state.reset);
|
|
37
|
+
|
|
38
|
+
// Check for waiting state (target element not mounted)
|
|
39
|
+
const waitingState = useWaitingState();
|
|
40
|
+
const {
|
|
41
|
+
isLoading,
|
|
42
|
+
isCompleted: persistedCompleted,
|
|
43
|
+
markCompleted,
|
|
44
|
+
markStepViewed,
|
|
45
|
+
clearProgress
|
|
46
|
+
} = useGuidonPersistence(persistenceAdapter, config.id);
|
|
47
|
+
const isCompleted = storeIsCompleted || persistedCompleted;
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
const enhancedConfig = {
|
|
50
|
+
...config,
|
|
51
|
+
onComplete: async () => {
|
|
52
|
+
config.onComplete?.();
|
|
53
|
+
if (persistenceAdapter) {
|
|
54
|
+
await markCompleted();
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
onSkip: async () => {
|
|
58
|
+
config.onSkip?.();
|
|
59
|
+
if (persistenceAdapter) {
|
|
60
|
+
await markStepViewed(currentStepIndex);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
onStepChange: async (stepIndex, step) => {
|
|
64
|
+
config.onStepChange?.(stepIndex, step);
|
|
65
|
+
if (persistenceAdapter) {
|
|
66
|
+
await markStepViewed(stepIndex);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
configure(enhancedConfig);
|
|
71
|
+
}, [config, configure, persistenceAdapter, markCompleted, markStepViewed, currentStepIndex]);
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (!autoStart || hasInitialized.current || isLoading) return;
|
|
74
|
+
const checkAndStart = async () => {
|
|
75
|
+
hasInitialized.current = true;
|
|
76
|
+
if (persistedCompleted) return;
|
|
77
|
+
if (shouldStart) {
|
|
78
|
+
const should = await shouldStart();
|
|
79
|
+
if (!should) return;
|
|
80
|
+
}
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
start();
|
|
83
|
+
}, 500);
|
|
84
|
+
};
|
|
85
|
+
checkAndStart();
|
|
86
|
+
}, [autoStart, isLoading, persistedCompleted, shouldStart, start]);
|
|
87
|
+
|
|
88
|
+
// Handle wait timeout - auto-skip to next step if waiting too long
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
const currentStep = config.steps[currentStepIndex];
|
|
91
|
+
const waitTimeout = currentStep?.waitTimeout;
|
|
92
|
+
|
|
93
|
+
// Only set timeout if:
|
|
94
|
+
// - We have a timeout configured
|
|
95
|
+
// - The timeout is greater than 0
|
|
96
|
+
// - We are currently waiting for a target
|
|
97
|
+
if (!waitTimeout || waitTimeout <= 0 || !waitingState?.isWaiting) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const timer = setTimeout(() => {
|
|
101
|
+
// Check if we're still waiting when the timeout fires
|
|
102
|
+
const stillWaiting = useGuidonStore.getState().targetMeasurements[currentStep.targetId] === undefined;
|
|
103
|
+
if (stillWaiting) {
|
|
104
|
+
next(); // Skip to next step
|
|
105
|
+
}
|
|
106
|
+
}, waitTimeout);
|
|
107
|
+
return () => clearTimeout(timer);
|
|
108
|
+
}, [currentStepIndex, config.steps, waitingState?.isWaiting, next]);
|
|
109
|
+
const replay = useCallback(async () => {
|
|
110
|
+
if (persistenceAdapter) {
|
|
111
|
+
await clearProgress();
|
|
112
|
+
}
|
|
113
|
+
reset();
|
|
114
|
+
hasInitialized.current = false;
|
|
115
|
+
setTimeout(() => {
|
|
116
|
+
start();
|
|
117
|
+
}, 100);
|
|
118
|
+
}, [persistenceAdapter, clearProgress, reset, start]);
|
|
119
|
+
const manualStart = useCallback(() => {
|
|
120
|
+
if (!isActive && !isLoading) {
|
|
121
|
+
start();
|
|
122
|
+
}
|
|
123
|
+
}, [isActive, isLoading, start]);
|
|
124
|
+
const contextValue = {
|
|
125
|
+
start: manualStart,
|
|
126
|
+
skip,
|
|
127
|
+
reset,
|
|
128
|
+
replay,
|
|
129
|
+
isActive,
|
|
130
|
+
isCompleted,
|
|
131
|
+
isLoading
|
|
132
|
+
};
|
|
133
|
+
const overlayContent = /*#__PURE__*/_jsxs(_Fragment, {
|
|
134
|
+
children: [/*#__PURE__*/_jsx(GuidonOverlay, {
|
|
135
|
+
theme: config.theme,
|
|
136
|
+
animationDuration: config.animationDuration,
|
|
137
|
+
onBackdropPress: onBackdropPress
|
|
138
|
+
}), /*#__PURE__*/_jsx(GuidonTooltip, {
|
|
139
|
+
theme: config.theme,
|
|
140
|
+
animationDuration: config.animationDuration,
|
|
141
|
+
renderCustomTooltip: renderTooltip,
|
|
142
|
+
labels: tooltipLabels
|
|
143
|
+
})]
|
|
144
|
+
});
|
|
145
|
+
return /*#__PURE__*/_jsxs(GuidonContext.Provider, {
|
|
146
|
+
value: contextValue,
|
|
147
|
+
children: [children, Portal ? /*#__PURE__*/_jsx(Portal, {
|
|
148
|
+
children: overlayContent
|
|
149
|
+
}) : overlayContent]
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=GuidonProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useEffect","useCallback","useRef","createContext","useContext","useGuidonStore","useWaitingState","useGuidonPersistence","GuidonOverlay","GuidonTooltip","jsx","_jsx","Fragment","_Fragment","jsxs","_jsxs","GuidonContext","useGuidonContext","context","Error","GuidonProvider","children","config","autoStart","shouldStart","persistenceAdapter","portalComponent","Portal","renderTooltip","tooltipLabels","onBackdropPress","hasInitialized","isActive","state","storeIsCompleted","isCompleted","currentStepIndex","configure","start","next","skip","reset","waitingState","isLoading","persistedCompleted","markCompleted","markStepViewed","clearProgress","id","enhancedConfig","onComplete","onSkip","onStepChange","stepIndex","step","current","checkAndStart","should","setTimeout","currentStep","steps","waitTimeout","isWaiting","timer","stillWaiting","getState","targetMeasurements","targetId","undefined","clearTimeout","replay","manualStart","contextValue","overlayContent","theme","animationDuration","renderCustomTooltip","labels","Provider","value"],"sourceRoot":"../../../src","sources":["components/GuidonProvider.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
4
|
+
import { View, Platform } from "react-native";
|
|
5
|
+
import { useGuidonStore } from "../store.js";
|
|
6
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
+
/**
|
|
8
|
+
* Wrapper component that marks an element as a walkthrough target
|
|
9
|
+
* Automatically measures and reports its position to the walkthrough store
|
|
10
|
+
*/
|
|
11
|
+
export function GuidonTarget({
|
|
12
|
+
children,
|
|
13
|
+
targetId,
|
|
14
|
+
active = true
|
|
15
|
+
}) {
|
|
16
|
+
const viewRef = useRef(null);
|
|
17
|
+
const registerTarget = useGuidonStore(state => state.registerTarget);
|
|
18
|
+
const unregisterTarget = useGuidonStore(state => state.unregisterTarget);
|
|
19
|
+
const isActive = useGuidonStore(state => state.isActive);
|
|
20
|
+
const config = useGuidonStore(state => state.config);
|
|
21
|
+
|
|
22
|
+
// Check if this target is needed for the current walkthrough
|
|
23
|
+
const isTargetNeeded = isActive && config?.steps.some(step => step.targetId === targetId);
|
|
24
|
+
const measureElement = useCallback(() => {
|
|
25
|
+
if (!viewRef.current || !active || !isTargetNeeded) return;
|
|
26
|
+
if (Platform.OS === "web") {
|
|
27
|
+
// Web measurement using getBoundingClientRect
|
|
28
|
+
const element = viewRef.current;
|
|
29
|
+
if (element && typeof element.getBoundingClientRect === "function") {
|
|
30
|
+
const rect = element.getBoundingClientRect();
|
|
31
|
+
const measurements = {
|
|
32
|
+
x: rect.left + window.scrollX,
|
|
33
|
+
y: rect.top + window.scrollY,
|
|
34
|
+
width: rect.width,
|
|
35
|
+
height: rect.height
|
|
36
|
+
};
|
|
37
|
+
registerTarget(targetId, measurements);
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
// Native measurement using measureInWindow
|
|
41
|
+
// Cast to access the native measureInWindow method
|
|
42
|
+
const nativeRef = viewRef.current;
|
|
43
|
+
nativeRef.measureInWindow((x, y, width, height) => {
|
|
44
|
+
if (width > 0 && height > 0) {
|
|
45
|
+
const measurements = {
|
|
46
|
+
x,
|
|
47
|
+
y,
|
|
48
|
+
width,
|
|
49
|
+
height
|
|
50
|
+
};
|
|
51
|
+
registerTarget(targetId, measurements);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}, [targetId, active, isTargetNeeded, registerTarget]);
|
|
56
|
+
|
|
57
|
+
// Measure on layout change
|
|
58
|
+
const handleLayout = useCallback(_event => {
|
|
59
|
+
// Small delay to ensure layout is complete
|
|
60
|
+
requestAnimationFrame(() => {
|
|
61
|
+
measureElement();
|
|
62
|
+
});
|
|
63
|
+
}, [measureElement]);
|
|
64
|
+
|
|
65
|
+
// Re-measure when walkthrough becomes active or when this target becomes relevant
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (!isTargetNeeded) return;
|
|
68
|
+
|
|
69
|
+
// Delay to ensure the element is rendered
|
|
70
|
+
const timer = setTimeout(() => {
|
|
71
|
+
measureElement();
|
|
72
|
+
}, 100);
|
|
73
|
+
return () => clearTimeout(timer);
|
|
74
|
+
}, [isTargetNeeded, measureElement]);
|
|
75
|
+
|
|
76
|
+
// Re-measure on scroll (web only)
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (Platform.OS !== "web" || !isTargetNeeded) return;
|
|
79
|
+
const handleScroll = () => {
|
|
80
|
+
measureElement();
|
|
81
|
+
};
|
|
82
|
+
window.addEventListener("scroll", handleScroll, true);
|
|
83
|
+
window.addEventListener("resize", handleScroll);
|
|
84
|
+
return () => {
|
|
85
|
+
window.removeEventListener("scroll", handleScroll, true);
|
|
86
|
+
window.removeEventListener("resize", handleScroll);
|
|
87
|
+
};
|
|
88
|
+
}, [isTargetNeeded, measureElement]);
|
|
89
|
+
|
|
90
|
+
// Unregister on unmount
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
return () => {
|
|
93
|
+
unregisterTarget(targetId);
|
|
94
|
+
};
|
|
95
|
+
}, [targetId, unregisterTarget]);
|
|
96
|
+
return /*#__PURE__*/_jsx(View, {
|
|
97
|
+
ref: viewRef,
|
|
98
|
+
onLayout: handleLayout,
|
|
99
|
+
collapsable: false,
|
|
100
|
+
style: {
|
|
101
|
+
alignSelf: "flex-start"
|
|
102
|
+
},
|
|
103
|
+
children: children
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=GuidonTarget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useCallback","useEffect","useRef","View","Platform","useGuidonStore","jsx","_jsx","GuidonTarget","children","targetId","active","viewRef","registerTarget","state","unregisterTarget","isActive","config","isTargetNeeded","steps","some","step","measureElement","current","OS","element","getBoundingClientRect","rect","measurements","x","left","window","scrollX","y","top","scrollY","width","height","nativeRef","measureInWindow","handleLayout","_event","requestAnimationFrame","timer","setTimeout","clearTimeout","handleScroll","addEventListener","removeEventListener","ref","onLayout","collapsable","style","alignSelf"],"sourceRoot":"../../../src","sources":["components/GuidonTarget.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { View, Text, StyleSheet, Dimensions, TouchableOpacity, Platform, ActivityIndicator } from 'react-native';
|
|
5
|
+
import Animated, { useAnimatedStyle, withTiming, withSpring, Easing } from 'react-native-reanimated';
|
|
6
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
7
|
+
import { useGuidonStore, useWaitingState, useIsFloatingStep } from "../store.js";
|
|
8
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
9
|
+
const DEFAULT_THEME = {
|
|
10
|
+
tooltipBackgroundColor: '#ffffff',
|
|
11
|
+
tooltipBorderColor: '#e5e5e5',
|
|
12
|
+
tooltipBorderRadius: 12,
|
|
13
|
+
titleColor: '#1a1a1a',
|
|
14
|
+
descriptionColor: '#666666',
|
|
15
|
+
primaryColor: '#007AFF',
|
|
16
|
+
mutedColor: '#999999',
|
|
17
|
+
spotlightPadding: 8
|
|
18
|
+
};
|
|
19
|
+
const TOOLTIP_MARGIN = 16;
|
|
20
|
+
const TOOLTIP_WIDTH = 300;
|
|
21
|
+
const ESTIMATED_TOOLTIP_HEIGHT = 200;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Calculate position for floating tooltips (steps without a target element)
|
|
25
|
+
*/
|
|
26
|
+
function calculateFloatingPosition(floatingPosition, screenWidth, screenHeight, tooltipWidth, insets) {
|
|
27
|
+
const MARGIN = 32;
|
|
28
|
+
const centerX = (screenWidth - tooltipWidth) / 2;
|
|
29
|
+
const centerY = (screenHeight - ESTIMATED_TOOLTIP_HEIGHT) / 2;
|
|
30
|
+
switch (floatingPosition) {
|
|
31
|
+
case 'center':
|
|
32
|
+
return {
|
|
33
|
+
top: centerY,
|
|
34
|
+
left: centerX
|
|
35
|
+
};
|
|
36
|
+
case 'top':
|
|
37
|
+
return {
|
|
38
|
+
top: insets.top + MARGIN,
|
|
39
|
+
left: centerX
|
|
40
|
+
};
|
|
41
|
+
case 'bottom':
|
|
42
|
+
return {
|
|
43
|
+
top: screenHeight - ESTIMATED_TOOLTIP_HEIGHT - insets.bottom - MARGIN,
|
|
44
|
+
left: centerX
|
|
45
|
+
};
|
|
46
|
+
case 'top-left':
|
|
47
|
+
return {
|
|
48
|
+
top: insets.top + MARGIN,
|
|
49
|
+
left: MARGIN
|
|
50
|
+
};
|
|
51
|
+
case 'top-right':
|
|
52
|
+
return {
|
|
53
|
+
top: insets.top + MARGIN,
|
|
54
|
+
left: screenWidth - tooltipWidth - MARGIN
|
|
55
|
+
};
|
|
56
|
+
case 'bottom-left':
|
|
57
|
+
return {
|
|
58
|
+
top: screenHeight - ESTIMATED_TOOLTIP_HEIGHT - insets.bottom - MARGIN,
|
|
59
|
+
left: MARGIN
|
|
60
|
+
};
|
|
61
|
+
case 'bottom-right':
|
|
62
|
+
return {
|
|
63
|
+
top: screenHeight - ESTIMATED_TOOLTIP_HEIGHT - insets.bottom - MARGIN,
|
|
64
|
+
left: screenWidth - tooltipWidth - MARGIN
|
|
65
|
+
};
|
|
66
|
+
default:
|
|
67
|
+
return {
|
|
68
|
+
top: centerY,
|
|
69
|
+
left: centerX
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function GuidonTooltip({
|
|
74
|
+
theme = {},
|
|
75
|
+
animationDuration = 300,
|
|
76
|
+
renderCustomTooltip,
|
|
77
|
+
labels = {}
|
|
78
|
+
}) {
|
|
79
|
+
const insets = useSafeAreaInsets();
|
|
80
|
+
const {
|
|
81
|
+
width: screenWidth,
|
|
82
|
+
height: screenHeight
|
|
83
|
+
} = Dimensions.get('window');
|
|
84
|
+
const isActive = useGuidonStore(state => state.isActive);
|
|
85
|
+
const config = useGuidonStore(state => state.config);
|
|
86
|
+
const currentStepIndex = useGuidonStore(state => state.currentStepIndex);
|
|
87
|
+
const targetMeasurements = useGuidonStore(state => state.targetMeasurements);
|
|
88
|
+
const next = useGuidonStore(state => state.next);
|
|
89
|
+
const previous = useGuidonStore(state => state.previous);
|
|
90
|
+
const skip = useGuidonStore(state => state.skip);
|
|
91
|
+
|
|
92
|
+
// Check for floating or waiting states
|
|
93
|
+
const isFloatingStep = useIsFloatingStep();
|
|
94
|
+
const waitingState = useWaitingState();
|
|
95
|
+
const isWaiting = waitingState?.isWaiting ?? false;
|
|
96
|
+
const mergedTheme = {
|
|
97
|
+
...DEFAULT_THEME,
|
|
98
|
+
...theme
|
|
99
|
+
};
|
|
100
|
+
const mergedLabels = {
|
|
101
|
+
next: labels.next ?? 'Next',
|
|
102
|
+
previous: labels.previous ?? 'Back',
|
|
103
|
+
skip: labels.skip ?? 'Skip',
|
|
104
|
+
finish: labels.finish ?? 'Finish',
|
|
105
|
+
stepOf: labels.stepOf ?? ((c, t) => `${c} of ${t}`),
|
|
106
|
+
waitingDefault: labels.waitingDefault ?? 'Navigate to continue...'
|
|
107
|
+
};
|
|
108
|
+
const currentStep = config?.steps[currentStepIndex];
|
|
109
|
+
const totalSteps = config?.steps.length ?? 0;
|
|
110
|
+
const isFirstStep = currentStepIndex === 0;
|
|
111
|
+
const isLastStep = currentStepIndex === totalSteps - 1;
|
|
112
|
+
const measurements = currentStep?.targetId ? targetMeasurements[currentStep.targetId] : undefined;
|
|
113
|
+
|
|
114
|
+
// Calculate tooltip position
|
|
115
|
+
const tooltipPosition = useMemo(() => {
|
|
116
|
+
// Handle floating steps (no target element)
|
|
117
|
+
if (isFloatingStep) {
|
|
118
|
+
const floatingPos = currentStep?.floatingPosition ?? 'center';
|
|
119
|
+
return calculateFloatingPosition(floatingPos, screenWidth, screenHeight, TOOLTIP_WIDTH, insets);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Handle waiting state or no measurements - center the tooltip
|
|
123
|
+
if (!measurements) {
|
|
124
|
+
return {
|
|
125
|
+
top: screenHeight / 2 - ESTIMATED_TOOLTIP_HEIGHT / 2,
|
|
126
|
+
left: screenWidth / 2 - TOOLTIP_WIDTH / 2
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
const targetBottom = measurements.y + measurements.height + mergedTheme.spotlightPadding;
|
|
130
|
+
const targetTop = measurements.y - mergedTheme.spotlightPadding;
|
|
131
|
+
|
|
132
|
+
// Determine preferred position
|
|
133
|
+
let position = currentStep?.tooltipPosition ?? 'auto';
|
|
134
|
+
if (position === 'auto') {
|
|
135
|
+
// Auto-detect best position
|
|
136
|
+
const spaceAbove = targetTop - insets.top;
|
|
137
|
+
const spaceBelow = screenHeight - targetBottom - insets.bottom;
|
|
138
|
+
position = spaceBelow >= 200 ? 'bottom' : spaceAbove >= 200 ? 'top' : 'bottom';
|
|
139
|
+
}
|
|
140
|
+
let top;
|
|
141
|
+
let left = Math.max(TOOLTIP_MARGIN, Math.min(measurements.x + measurements.width / 2 - TOOLTIP_WIDTH / 2, screenWidth - TOOLTIP_WIDTH - TOOLTIP_MARGIN));
|
|
142
|
+
if (position === 'top') {
|
|
143
|
+
top = targetTop - TOOLTIP_MARGIN - 150; // Approximate tooltip height
|
|
144
|
+
} else {
|
|
145
|
+
top = targetBottom + TOOLTIP_MARGIN;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Ensure tooltip is within screen bounds
|
|
149
|
+
top = Math.max(insets.top + TOOLTIP_MARGIN, Math.min(top, screenHeight - 200 - insets.bottom));
|
|
150
|
+
return {
|
|
151
|
+
top,
|
|
152
|
+
left,
|
|
153
|
+
position
|
|
154
|
+
};
|
|
155
|
+
}, [measurements, screenWidth, screenHeight, insets, currentStep?.tooltipPosition, currentStep?.floatingPosition, mergedTheme.spotlightPadding, isFloatingStep]);
|
|
156
|
+
|
|
157
|
+
// Determine if tooltip should be visible
|
|
158
|
+
// Show for: normal steps with measurements, floating steps, or waiting states
|
|
159
|
+
const shouldShowTooltip = isActive && currentStep && (measurements || isFloatingStep || isWaiting);
|
|
160
|
+
|
|
161
|
+
// Animated styles
|
|
162
|
+
const animatedStyle = useAnimatedStyle(() => {
|
|
163
|
+
return {
|
|
164
|
+
opacity: withTiming(shouldShowTooltip ? 1 : 0, {
|
|
165
|
+
duration: animationDuration,
|
|
166
|
+
easing: Easing.inOut(Easing.ease)
|
|
167
|
+
}),
|
|
168
|
+
transform: [{
|
|
169
|
+
translateY: withSpring(shouldShowTooltip ? 0 : 20, {
|
|
170
|
+
damping: 15,
|
|
171
|
+
stiffness: 150
|
|
172
|
+
})
|
|
173
|
+
}]
|
|
174
|
+
};
|
|
175
|
+
}, [shouldShowTooltip, animationDuration]);
|
|
176
|
+
if (!isActive || !currentStep) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Show waiting indicator when target element isn't mounted yet
|
|
181
|
+
if (isWaiting) {
|
|
182
|
+
return /*#__PURE__*/_jsxs(Animated.View, {
|
|
183
|
+
style: [styles.tooltipContainer, {
|
|
184
|
+
top: tooltipPosition.top,
|
|
185
|
+
left: tooltipPosition.left,
|
|
186
|
+
width: TOOLTIP_WIDTH,
|
|
187
|
+
backgroundColor: mergedTheme.tooltipBackgroundColor,
|
|
188
|
+
borderColor: mergedTheme.tooltipBorderColor,
|
|
189
|
+
borderRadius: mergedTheme.tooltipBorderRadius
|
|
190
|
+
}, animatedStyle],
|
|
191
|
+
children: [/*#__PURE__*/_jsxs(View, {
|
|
192
|
+
style: styles.waitingContainer,
|
|
193
|
+
children: [/*#__PURE__*/_jsx(ActivityIndicator, {
|
|
194
|
+
color: mergedTheme.primaryColor
|
|
195
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
196
|
+
style: [styles.waitingText, {
|
|
197
|
+
color: mergedTheme.descriptionColor
|
|
198
|
+
}],
|
|
199
|
+
children: waitingState?.message || mergedLabels.waitingDefault
|
|
200
|
+
})]
|
|
201
|
+
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
202
|
+
onPress: skip,
|
|
203
|
+
style: styles.skipButton,
|
|
204
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
205
|
+
style: [styles.skipText, {
|
|
206
|
+
color: mergedTheme.mutedColor
|
|
207
|
+
}],
|
|
208
|
+
children: mergedLabels.skip
|
|
209
|
+
})
|
|
210
|
+
})]
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// For non-floating steps, we need measurements
|
|
215
|
+
if (!isFloatingStep && !measurements) {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Render custom tooltip if provided
|
|
220
|
+
if (renderCustomTooltip) {
|
|
221
|
+
return /*#__PURE__*/_jsx(Animated.View, {
|
|
222
|
+
style: [styles.tooltipContainer, {
|
|
223
|
+
top: tooltipPosition.top,
|
|
224
|
+
left: tooltipPosition.left,
|
|
225
|
+
width: TOOLTIP_WIDTH
|
|
226
|
+
}, animatedStyle],
|
|
227
|
+
children: renderCustomTooltip({
|
|
228
|
+
step: currentStep,
|
|
229
|
+
currentIndex: currentStepIndex,
|
|
230
|
+
totalSteps,
|
|
231
|
+
onNext: next,
|
|
232
|
+
onPrevious: previous,
|
|
233
|
+
onSkip: skip
|
|
234
|
+
})
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Default tooltip UI
|
|
239
|
+
return /*#__PURE__*/_jsxs(Animated.View, {
|
|
240
|
+
style: [styles.tooltipContainer, {
|
|
241
|
+
top: tooltipPosition.top,
|
|
242
|
+
left: tooltipPosition.left,
|
|
243
|
+
width: TOOLTIP_WIDTH,
|
|
244
|
+
backgroundColor: mergedTheme.tooltipBackgroundColor,
|
|
245
|
+
borderColor: mergedTheme.tooltipBorderColor,
|
|
246
|
+
borderRadius: mergedTheme.tooltipBorderRadius
|
|
247
|
+
}, animatedStyle],
|
|
248
|
+
children: [/*#__PURE__*/_jsxs(View, {
|
|
249
|
+
style: styles.progressContainer,
|
|
250
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
251
|
+
style: [styles.progressText, {
|
|
252
|
+
color: mergedTheme.mutedColor
|
|
253
|
+
}],
|
|
254
|
+
children: mergedLabels.stepOf(currentStepIndex + 1, totalSteps)
|
|
255
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
256
|
+
style: styles.progressDots,
|
|
257
|
+
children: Array.from({
|
|
258
|
+
length: totalSteps
|
|
259
|
+
}).map((_, i) => /*#__PURE__*/_jsx(View, {
|
|
260
|
+
style: [styles.progressDot, {
|
|
261
|
+
backgroundColor: i === currentStepIndex ? mergedTheme.primaryColor : mergedTheme.mutedColor,
|
|
262
|
+
opacity: i === currentStepIndex ? 1 : 0.3
|
|
263
|
+
}]
|
|
264
|
+
}, i))
|
|
265
|
+
})]
|
|
266
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
267
|
+
style: styles.content,
|
|
268
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
269
|
+
style: [styles.title, {
|
|
270
|
+
color: mergedTheme.titleColor
|
|
271
|
+
}],
|
|
272
|
+
children: currentStep.title
|
|
273
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
274
|
+
style: [styles.description, {
|
|
275
|
+
color: mergedTheme.descriptionColor
|
|
276
|
+
}],
|
|
277
|
+
children: currentStep.description
|
|
278
|
+
}), currentStep.customContent]
|
|
279
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
280
|
+
style: styles.buttonContainer,
|
|
281
|
+
children: [/*#__PURE__*/_jsx(TouchableOpacity, {
|
|
282
|
+
onPress: skip,
|
|
283
|
+
style: styles.skipButton,
|
|
284
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
285
|
+
style: [styles.skipText, {
|
|
286
|
+
color: mergedTheme.mutedColor
|
|
287
|
+
}],
|
|
288
|
+
children: mergedLabels.skip
|
|
289
|
+
})
|
|
290
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
291
|
+
style: styles.navButtons,
|
|
292
|
+
children: [!isFirstStep && /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
293
|
+
onPress: previous,
|
|
294
|
+
style: [styles.navButton, styles.backButton],
|
|
295
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
296
|
+
style: [styles.backButtonText, {
|
|
297
|
+
color: mergedTheme.primaryColor
|
|
298
|
+
}],
|
|
299
|
+
children: mergedLabels.previous
|
|
300
|
+
})
|
|
301
|
+
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
302
|
+
onPress: next,
|
|
303
|
+
style: [styles.navButton, styles.nextButton, {
|
|
304
|
+
backgroundColor: mergedTheme.primaryColor
|
|
305
|
+
}],
|
|
306
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
307
|
+
style: styles.nextButtonText,
|
|
308
|
+
children: isLastStep ? mergedLabels.finish : mergedLabels.next
|
|
309
|
+
})
|
|
310
|
+
})]
|
|
311
|
+
})]
|
|
312
|
+
})]
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
const styles = StyleSheet.create({
|
|
316
|
+
tooltipContainer: {
|
|
317
|
+
position: 'absolute',
|
|
318
|
+
zIndex: 1000,
|
|
319
|
+
borderWidth: 1,
|
|
320
|
+
padding: 16,
|
|
321
|
+
...Platform.select({
|
|
322
|
+
ios: {
|
|
323
|
+
shadowColor: '#000',
|
|
324
|
+
shadowOffset: {
|
|
325
|
+
width: 0,
|
|
326
|
+
height: 4
|
|
327
|
+
},
|
|
328
|
+
shadowOpacity: 0.15,
|
|
329
|
+
shadowRadius: 12
|
|
330
|
+
},
|
|
331
|
+
android: {
|
|
332
|
+
elevation: 8
|
|
333
|
+
},
|
|
334
|
+
web: {
|
|
335
|
+
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)'
|
|
336
|
+
}
|
|
337
|
+
})
|
|
338
|
+
},
|
|
339
|
+
progressContainer: {
|
|
340
|
+
flexDirection: 'row',
|
|
341
|
+
alignItems: 'center',
|
|
342
|
+
justifyContent: 'space-between',
|
|
343
|
+
marginBottom: 12
|
|
344
|
+
},
|
|
345
|
+
progressText: {
|
|
346
|
+
fontSize: 12,
|
|
347
|
+
fontWeight: '500'
|
|
348
|
+
},
|
|
349
|
+
progressDots: {
|
|
350
|
+
flexDirection: 'row',
|
|
351
|
+
gap: 4
|
|
352
|
+
},
|
|
353
|
+
progressDot: {
|
|
354
|
+
width: 6,
|
|
355
|
+
height: 6,
|
|
356
|
+
borderRadius: 3
|
|
357
|
+
},
|
|
358
|
+
content: {
|
|
359
|
+
marginBottom: 16
|
|
360
|
+
},
|
|
361
|
+
title: {
|
|
362
|
+
fontSize: 18,
|
|
363
|
+
fontWeight: '600',
|
|
364
|
+
marginBottom: 8
|
|
365
|
+
},
|
|
366
|
+
description: {
|
|
367
|
+
fontSize: 14,
|
|
368
|
+
lineHeight: 20
|
|
369
|
+
},
|
|
370
|
+
buttonContainer: {
|
|
371
|
+
flexDirection: 'row',
|
|
372
|
+
alignItems: 'center',
|
|
373
|
+
justifyContent: 'space-between'
|
|
374
|
+
},
|
|
375
|
+
skipButton: {
|
|
376
|
+
paddingVertical: 8,
|
|
377
|
+
paddingHorizontal: 4
|
|
378
|
+
},
|
|
379
|
+
skipText: {
|
|
380
|
+
fontSize: 14
|
|
381
|
+
},
|
|
382
|
+
navButtons: {
|
|
383
|
+
flexDirection: 'row',
|
|
384
|
+
gap: 8
|
|
385
|
+
},
|
|
386
|
+
navButton: {
|
|
387
|
+
paddingVertical: 10,
|
|
388
|
+
paddingHorizontal: 16,
|
|
389
|
+
borderRadius: 8
|
|
390
|
+
},
|
|
391
|
+
backButton: {
|
|
392
|
+
backgroundColor: 'transparent'
|
|
393
|
+
},
|
|
394
|
+
backButtonText: {
|
|
395
|
+
fontSize: 14,
|
|
396
|
+
fontWeight: '600'
|
|
397
|
+
},
|
|
398
|
+
nextButton: {},
|
|
399
|
+
nextButtonText: {
|
|
400
|
+
color: '#ffffff',
|
|
401
|
+
fontSize: 14,
|
|
402
|
+
fontWeight: '600'
|
|
403
|
+
},
|
|
404
|
+
waitingContainer: {
|
|
405
|
+
flexDirection: 'row',
|
|
406
|
+
alignItems: 'center',
|
|
407
|
+
justifyContent: 'center',
|
|
408
|
+
gap: 12,
|
|
409
|
+
paddingVertical: 8,
|
|
410
|
+
marginBottom: 12
|
|
411
|
+
},
|
|
412
|
+
waitingText: {
|
|
413
|
+
fontSize: 14,
|
|
414
|
+
lineHeight: 20
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
//# sourceMappingURL=GuidonTooltip.js.map
|