@aladinbs/react-guided-tour 1.0.1
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/LICENSE +21 -0
- package/README.md +581 -0
- package/dist/components/TourOverlay.d.ts +5 -0
- package/dist/components/TourOverlay.d.ts.map +1 -0
- package/dist/components/TourPopover.d.ts +5 -0
- package/dist/components/TourPopover.d.ts.map +1 -0
- package/dist/components/TourProvider.d.ts +15 -0
- package/dist/components/TourProvider.d.ts.map +1 -0
- package/dist/components/TourRunner.d.ts +5 -0
- package/dist/components/TourRunner.d.ts.map +1 -0
- package/dist/core/TourActions.d.ts +15 -0
- package/dist/core/TourActions.d.ts.map +1 -0
- package/dist/core/TourEngine.d.ts +35 -0
- package/dist/core/TourEngine.d.ts.map +1 -0
- package/dist/core/TourStorage.d.ts +14 -0
- package/dist/core/TourStorage.d.ts.map +1 -0
- package/dist/hooks/useTourEngine.d.ts +21 -0
- package/dist/hooks/useTourEngine.d.ts.map +1 -0
- package/dist/hooks/useTourHighlight.d.ts +8 -0
- package/dist/hooks/useTourHighlight.d.ts.map +1 -0
- package/dist/index.d.ts +326 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +2097 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +2116 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/NavigationIntegration.d.ts +24 -0
- package/dist/integrations/NavigationIntegration.d.ts.map +1 -0
- package/dist/integrations/TabIntegration.d.ts +19 -0
- package/dist/integrations/TabIntegration.d.ts.map +1 -0
- package/dist/integrations/WizardIntegration.d.ts +23 -0
- package/dist/integrations/WizardIntegration.d.ts.map +1 -0
- package/dist/types/index.d.ts +137 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/positioning.d.ts +10 -0
- package/dist/utils/positioning.d.ts.map +1 -0
- package/package.json +75 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2116 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var require$$0 = require('react');
|
|
4
|
+
|
|
5
|
+
class TourStorage {
|
|
6
|
+
constructor(key) {
|
|
7
|
+
this.key = key;
|
|
8
|
+
}
|
|
9
|
+
saveState(state) {
|
|
10
|
+
try {
|
|
11
|
+
const stateToSave = {
|
|
12
|
+
currentStepIndex: state.currentStepIndex,
|
|
13
|
+
completedSteps: state.completedSteps,
|
|
14
|
+
skippedSteps: state.skippedSteps,
|
|
15
|
+
isCompleted: false,
|
|
16
|
+
isSkipped: false,
|
|
17
|
+
};
|
|
18
|
+
localStorage.setItem(this.key, JSON.stringify(stateToSave));
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
console.warn('Failed to save tour state to localStorage:', error);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
getState() {
|
|
25
|
+
try {
|
|
26
|
+
const saved = localStorage.getItem(this.key);
|
|
27
|
+
if (!saved)
|
|
28
|
+
return null;
|
|
29
|
+
return JSON.parse(saved);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.warn('Failed to load tour state from localStorage:', error);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
clearState() {
|
|
37
|
+
try {
|
|
38
|
+
localStorage.removeItem(this.key);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.warn('Failed to clear tour state from localStorage:', error);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
hasState() {
|
|
45
|
+
try {
|
|
46
|
+
return localStorage.getItem(this.key) !== null;
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
saveCompletion() {
|
|
53
|
+
try {
|
|
54
|
+
const existing = this.getState() || {};
|
|
55
|
+
const stateToSave = {
|
|
56
|
+
...existing,
|
|
57
|
+
isCompleted: true,
|
|
58
|
+
completedAt: new Date().toISOString(),
|
|
59
|
+
};
|
|
60
|
+
localStorage.setItem(this.key, JSON.stringify(stateToSave));
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.warn('Failed to save tour completion to localStorage:', error);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
saveSkip() {
|
|
67
|
+
try {
|
|
68
|
+
const existing = this.getState() || {};
|
|
69
|
+
const stateToSave = {
|
|
70
|
+
...existing,
|
|
71
|
+
isSkipped: true,
|
|
72
|
+
skippedAt: new Date().toISOString(),
|
|
73
|
+
};
|
|
74
|
+
localStorage.setItem(this.key, JSON.stringify(stateToSave));
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
console.warn('Failed to save tour skip to localStorage:', error);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
isCompleted() {
|
|
81
|
+
try {
|
|
82
|
+
const saved = this.getState();
|
|
83
|
+
return saved?.isCompleted === true;
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
isSkipped() {
|
|
90
|
+
try {
|
|
91
|
+
const saved = this.getState();
|
|
92
|
+
return saved?.isSkipped === true;
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
class TourEngine {
|
|
101
|
+
constructor(config) {
|
|
102
|
+
this.listeners = new Map();
|
|
103
|
+
this.config = config;
|
|
104
|
+
this.storage = new TourStorage(config.storage?.key || `tour-${config.id}`);
|
|
105
|
+
this.state = this.initializeState();
|
|
106
|
+
}
|
|
107
|
+
initializeState() {
|
|
108
|
+
const savedState = this.config.storage?.remember ? this.storage.getState() : null;
|
|
109
|
+
return {
|
|
110
|
+
isRunning: false,
|
|
111
|
+
currentStepIndex: savedState?.currentStepIndex || 0,
|
|
112
|
+
currentStep: null,
|
|
113
|
+
totalSteps: this.config.steps.length,
|
|
114
|
+
isLoading: false,
|
|
115
|
+
error: null,
|
|
116
|
+
completedSteps: savedState?.completedSteps || [],
|
|
117
|
+
skippedSteps: savedState?.skippedSteps || [],
|
|
118
|
+
isCompleted: savedState?.isCompleted || false,
|
|
119
|
+
isSkipped: savedState?.isSkipped || false,
|
|
120
|
+
completedAt: savedState?.completedAt,
|
|
121
|
+
skippedAt: savedState?.skippedAt,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
getState() {
|
|
125
|
+
return { ...this.state };
|
|
126
|
+
}
|
|
127
|
+
getConfig() {
|
|
128
|
+
return { ...this.config };
|
|
129
|
+
}
|
|
130
|
+
async start() {
|
|
131
|
+
try {
|
|
132
|
+
this.setState({
|
|
133
|
+
isRunning: true,
|
|
134
|
+
isLoading: true,
|
|
135
|
+
error: null
|
|
136
|
+
});
|
|
137
|
+
this.emit('tour-start', { tourId: this.config.id });
|
|
138
|
+
await this.goToStep(this.state.currentStepIndex);
|
|
139
|
+
// STOP HERE - don't auto-advance
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
console.error('Error in TourEngine.start():', error);
|
|
144
|
+
this.handleError(error);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async next() {
|
|
148
|
+
if (!this.state.isRunning) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
const currentStep = this.getCurrentStep();
|
|
153
|
+
if (!currentStep) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
// Execute after step hook
|
|
157
|
+
if (currentStep.afterStep) {
|
|
158
|
+
await currentStep.afterStep();
|
|
159
|
+
}
|
|
160
|
+
// Mark step as completed
|
|
161
|
+
this.markStepCompleted(currentStep.id);
|
|
162
|
+
// Check if this is the last step
|
|
163
|
+
if (this.state.currentStepIndex >= this.state.totalSteps - 1) {
|
|
164
|
+
await this.complete();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
// Go to next step
|
|
168
|
+
const nextStepIndex = this.state.currentStepIndex + 1;
|
|
169
|
+
await this.goToStep(nextStepIndex);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
console.error('Error in TourEngine.next():', error);
|
|
173
|
+
this.handleError(error);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async previous() {
|
|
177
|
+
if (!this.state.isRunning || this.state.currentStepIndex <= 0)
|
|
178
|
+
return;
|
|
179
|
+
try {
|
|
180
|
+
await this.goToStep(this.state.currentStepIndex - 1);
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
this.handleError(error);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async goToStep(index) {
|
|
187
|
+
if (index < 0 || index >= this.state.totalSteps)
|
|
188
|
+
return;
|
|
189
|
+
try {
|
|
190
|
+
this.setState({ isLoading: true });
|
|
191
|
+
const step = this.config.steps[index];
|
|
192
|
+
// Execute before step hook
|
|
193
|
+
if (step.beforeStep) {
|
|
194
|
+
await step.beforeStep();
|
|
195
|
+
}
|
|
196
|
+
// Wait for element if specified
|
|
197
|
+
if (step.waitForElement && step.target) {
|
|
198
|
+
await this.waitForElement(step.target, step.waitTimeout || 5000);
|
|
199
|
+
}
|
|
200
|
+
this.setState({
|
|
201
|
+
currentStepIndex: index,
|
|
202
|
+
currentStep: step,
|
|
203
|
+
isLoading: false,
|
|
204
|
+
});
|
|
205
|
+
// Save state if persistence is enabled
|
|
206
|
+
if (this.config.storage?.remember) {
|
|
207
|
+
this.storage.saveState(this.state);
|
|
208
|
+
}
|
|
209
|
+
// Emit step change event
|
|
210
|
+
this.emit('step-change', { step, index });
|
|
211
|
+
if (this.config.onStepChange) {
|
|
212
|
+
this.config.onStepChange(step, index);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
this.setState({ isLoading: false });
|
|
217
|
+
this.handleError(error);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async skip() {
|
|
221
|
+
if (!this.state.isRunning)
|
|
222
|
+
return;
|
|
223
|
+
try {
|
|
224
|
+
const currentStep = this.getCurrentStep();
|
|
225
|
+
if (currentStep) {
|
|
226
|
+
this.markStepSkipped(currentStep.id);
|
|
227
|
+
}
|
|
228
|
+
this.setState({ isSkipped: true });
|
|
229
|
+
this.emit('tour-skip', { tourId: this.config.id, stepIndex: this.state.currentStepIndex });
|
|
230
|
+
if (this.config.onSkip) {
|
|
231
|
+
this.config.onSkip();
|
|
232
|
+
}
|
|
233
|
+
// Save skip state to localStorage
|
|
234
|
+
if (this.config.storage?.remember) {
|
|
235
|
+
this.storage.saveSkip();
|
|
236
|
+
}
|
|
237
|
+
await this.stop();
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
console.error('Error in TourEngine.skip():', error);
|
|
241
|
+
this.handleError(error);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
async complete() {
|
|
245
|
+
try {
|
|
246
|
+
this.setState({ isRunning: false, isCompleted: true });
|
|
247
|
+
this.emit('tour-complete', { tourId: this.config.id });
|
|
248
|
+
if (this.config.onComplete) {
|
|
249
|
+
this.config.onComplete();
|
|
250
|
+
}
|
|
251
|
+
// Save completion state to localStorage
|
|
252
|
+
if (this.config.storage?.remember) {
|
|
253
|
+
this.storage.saveCompletion();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
console.error('Error in TourEngine.complete():', error);
|
|
258
|
+
this.handleError(error);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async stop() {
|
|
262
|
+
this.setState({
|
|
263
|
+
isRunning: false,
|
|
264
|
+
currentStep: null,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
getCurrentStep() {
|
|
268
|
+
return this.state.currentStep;
|
|
269
|
+
}
|
|
270
|
+
isFirstStep() {
|
|
271
|
+
return this.state.currentStepIndex === 0;
|
|
272
|
+
}
|
|
273
|
+
isLastStep() {
|
|
274
|
+
return this.state.currentStepIndex === this.state.totalSteps - 1;
|
|
275
|
+
}
|
|
276
|
+
canGoNext() {
|
|
277
|
+
return this.state.isRunning && !this.isLastStep() && !this.state.isLoading;
|
|
278
|
+
}
|
|
279
|
+
canGoPrevious() {
|
|
280
|
+
return this.state.isRunning && !this.isFirstStep() && !this.state.isLoading;
|
|
281
|
+
}
|
|
282
|
+
shouldShowTour() {
|
|
283
|
+
if (!this.config.storage?.remember)
|
|
284
|
+
return true;
|
|
285
|
+
return !this.storage.isCompleted() && !this.storage.isSkipped();
|
|
286
|
+
}
|
|
287
|
+
resetTourState() {
|
|
288
|
+
if (this.config.storage?.remember) {
|
|
289
|
+
this.storage.clearState();
|
|
290
|
+
}
|
|
291
|
+
this.state = this.initializeState();
|
|
292
|
+
}
|
|
293
|
+
async waitForElement(selector, timeout) {
|
|
294
|
+
return new Promise((resolve, reject) => {
|
|
295
|
+
const element = document.querySelector(selector);
|
|
296
|
+
if (element) {
|
|
297
|
+
resolve(element);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
const observer = new MutationObserver(() => {
|
|
301
|
+
const element = document.querySelector(selector);
|
|
302
|
+
if (element) {
|
|
303
|
+
observer.disconnect();
|
|
304
|
+
clearTimeout(timeoutId);
|
|
305
|
+
resolve(element);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
const timeoutId = setTimeout(() => {
|
|
309
|
+
observer.disconnect();
|
|
310
|
+
reject(new Error(`Element not found: ${selector}`));
|
|
311
|
+
}, timeout);
|
|
312
|
+
observer.observe(document.body, {
|
|
313
|
+
childList: true,
|
|
314
|
+
subtree: true,
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
markStepCompleted(stepId) {
|
|
319
|
+
if (!this.state.completedSteps.includes(stepId)) {
|
|
320
|
+
this.setState({
|
|
321
|
+
completedSteps: [...this.state.completedSteps, stepId],
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
markStepSkipped(stepId) {
|
|
326
|
+
if (!this.state.skippedSteps.includes(stepId)) {
|
|
327
|
+
this.setState({
|
|
328
|
+
skippedSteps: [...this.state.skippedSteps, stepId],
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
handleError(error) {
|
|
333
|
+
this.setState({
|
|
334
|
+
error: error.message,
|
|
335
|
+
isLoading: false,
|
|
336
|
+
});
|
|
337
|
+
this.emit('error', { error, step: this.getCurrentStep() || undefined });
|
|
338
|
+
}
|
|
339
|
+
setState(updates) {
|
|
340
|
+
this.state = { ...this.state, ...updates };
|
|
341
|
+
// Emit state change event to notify subscribers
|
|
342
|
+
this.emit('state-change', this.state);
|
|
343
|
+
}
|
|
344
|
+
// Event system
|
|
345
|
+
on(event, callback) {
|
|
346
|
+
if (!this.listeners.has(event)) {
|
|
347
|
+
this.listeners.set(event, new Set());
|
|
348
|
+
}
|
|
349
|
+
this.listeners.get(event).add(callback);
|
|
350
|
+
}
|
|
351
|
+
off(event, callback) {
|
|
352
|
+
const callbacks = this.listeners.get(event);
|
|
353
|
+
if (callbacks) {
|
|
354
|
+
callbacks.delete(callback);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
emit(event, data) {
|
|
358
|
+
const callbacks = this.listeners.get(event);
|
|
359
|
+
if (callbacks) {
|
|
360
|
+
callbacks.forEach(callback => callback(data));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
subscribe(callback) {
|
|
364
|
+
const handler = () => callback(this.getState());
|
|
365
|
+
// Listen to all events that might change state
|
|
366
|
+
this.on('step-change', handler);
|
|
367
|
+
this.on('tour-start', handler);
|
|
368
|
+
this.on('tour-complete', handler);
|
|
369
|
+
this.on('tour-skip', handler);
|
|
370
|
+
this.on('error', handler);
|
|
371
|
+
this.on('state-change', handler);
|
|
372
|
+
// Return unsubscribe function
|
|
373
|
+
return () => {
|
|
374
|
+
this.off('step-change', handler);
|
|
375
|
+
this.off('tour-start', handler);
|
|
376
|
+
this.off('tour-complete', handler);
|
|
377
|
+
this.off('tour-skip', handler);
|
|
378
|
+
this.off('error', handler);
|
|
379
|
+
this.off('state-change', handler);
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
class TourActions {
|
|
385
|
+
constructor() {
|
|
386
|
+
this.integrations = new Map();
|
|
387
|
+
}
|
|
388
|
+
registerIntegration(integration) {
|
|
389
|
+
this.integrations.set(integration.name, integration);
|
|
390
|
+
}
|
|
391
|
+
unregisterIntegration(name) {
|
|
392
|
+
this.integrations.delete(name);
|
|
393
|
+
}
|
|
394
|
+
async execute(action, element) {
|
|
395
|
+
// Find the appropriate integration for this action
|
|
396
|
+
const integration = this.findIntegration(action);
|
|
397
|
+
if (!integration) {
|
|
398
|
+
// Fallback to default action handling
|
|
399
|
+
await this.executeDefault(action, element);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
try {
|
|
403
|
+
await integration.execute(action, element);
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
console.error(`Integration ${integration.name} failed to execute action:`, error);
|
|
407
|
+
// Fallback to default action handling
|
|
408
|
+
await this.executeDefault(action, element);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
findIntegration(action) {
|
|
412
|
+
for (const integration of this.integrations.values()) {
|
|
413
|
+
if (integration.canHandle(action)) {
|
|
414
|
+
return integration;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
async executeDefault(action, element) {
|
|
420
|
+
const delay = action.delay || 0;
|
|
421
|
+
if (delay > 0) {
|
|
422
|
+
await this.sleep(delay);
|
|
423
|
+
}
|
|
424
|
+
switch (action.type) {
|
|
425
|
+
case 'click':
|
|
426
|
+
await this.handleClick(action, element);
|
|
427
|
+
break;
|
|
428
|
+
case 'navigate':
|
|
429
|
+
await this.handleNavigate(action);
|
|
430
|
+
break;
|
|
431
|
+
case 'highlight':
|
|
432
|
+
// Highlighting is handled by the UI components
|
|
433
|
+
break;
|
|
434
|
+
case 'custom':
|
|
435
|
+
if (action.handler) {
|
|
436
|
+
await action.handler();
|
|
437
|
+
}
|
|
438
|
+
break;
|
|
439
|
+
default:
|
|
440
|
+
console.warn(`Unknown action type: ${action.type}`);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
async handleClick(action, element) {
|
|
444
|
+
let targetElement = element;
|
|
445
|
+
if (!targetElement && action.target) {
|
|
446
|
+
targetElement = document.querySelector(action.target);
|
|
447
|
+
}
|
|
448
|
+
if (!targetElement) {
|
|
449
|
+
throw new Error(`Click target not found: ${action.target}`);
|
|
450
|
+
}
|
|
451
|
+
// Ensure element is visible and clickable
|
|
452
|
+
targetElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
453
|
+
// Wait a bit for scroll to complete
|
|
454
|
+
await this.sleep(300);
|
|
455
|
+
// Dispatch click event
|
|
456
|
+
const clickEvent = new MouseEvent('click', {
|
|
457
|
+
bubbles: true,
|
|
458
|
+
cancelable: true,
|
|
459
|
+
view: window,
|
|
460
|
+
});
|
|
461
|
+
targetElement.dispatchEvent(clickEvent);
|
|
462
|
+
}
|
|
463
|
+
async handleNavigate(action) {
|
|
464
|
+
if (!action.target) {
|
|
465
|
+
throw new Error('Navigate action requires a target URL');
|
|
466
|
+
}
|
|
467
|
+
// Check if it's a hash navigation (same page)
|
|
468
|
+
if (action.target.startsWith('#')) {
|
|
469
|
+
window.location.hash = action.target;
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
// Check if it's a relative path
|
|
473
|
+
if (action.target.startsWith('/')) {
|
|
474
|
+
window.location.pathname = action.target;
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
// Full URL navigation
|
|
478
|
+
window.location.href = action.target;
|
|
479
|
+
}
|
|
480
|
+
sleep(ms) {
|
|
481
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
482
|
+
}
|
|
483
|
+
getRegisteredIntegrations() {
|
|
484
|
+
return Array.from(this.integrations.keys());
|
|
485
|
+
}
|
|
486
|
+
hasIntegration(name) {
|
|
487
|
+
return this.integrations.has(name);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
var jsxRuntime = {exports: {}};
|
|
492
|
+
|
|
493
|
+
var reactJsxRuntime_production = {};
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* @license React
|
|
497
|
+
* react-jsx-runtime.production.js
|
|
498
|
+
*
|
|
499
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
500
|
+
*
|
|
501
|
+
* This source code is licensed under the MIT license found in the
|
|
502
|
+
* LICENSE file in the root directory of this source tree.
|
|
503
|
+
*/
|
|
504
|
+
|
|
505
|
+
var hasRequiredReactJsxRuntime_production;
|
|
506
|
+
|
|
507
|
+
function requireReactJsxRuntime_production () {
|
|
508
|
+
if (hasRequiredReactJsxRuntime_production) return reactJsxRuntime_production;
|
|
509
|
+
hasRequiredReactJsxRuntime_production = 1;
|
|
510
|
+
var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"),
|
|
511
|
+
REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
512
|
+
function jsxProd(type, config, maybeKey) {
|
|
513
|
+
var key = null;
|
|
514
|
+
void 0 !== maybeKey && (key = "" + maybeKey);
|
|
515
|
+
void 0 !== config.key && (key = "" + config.key);
|
|
516
|
+
if ("key" in config) {
|
|
517
|
+
maybeKey = {};
|
|
518
|
+
for (var propName in config)
|
|
519
|
+
"key" !== propName && (maybeKey[propName] = config[propName]);
|
|
520
|
+
} else maybeKey = config;
|
|
521
|
+
config = maybeKey.ref;
|
|
522
|
+
return {
|
|
523
|
+
$$typeof: REACT_ELEMENT_TYPE,
|
|
524
|
+
type: type,
|
|
525
|
+
key: key,
|
|
526
|
+
ref: void 0 !== config ? config : null,
|
|
527
|
+
props: maybeKey
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
reactJsxRuntime_production.Fragment = REACT_FRAGMENT_TYPE;
|
|
531
|
+
reactJsxRuntime_production.jsx = jsxProd;
|
|
532
|
+
reactJsxRuntime_production.jsxs = jsxProd;
|
|
533
|
+
return reactJsxRuntime_production;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
var reactJsxRuntime_development = {};
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* @license React
|
|
540
|
+
* react-jsx-runtime.development.js
|
|
541
|
+
*
|
|
542
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
543
|
+
*
|
|
544
|
+
* This source code is licensed under the MIT license found in the
|
|
545
|
+
* LICENSE file in the root directory of this source tree.
|
|
546
|
+
*/
|
|
547
|
+
|
|
548
|
+
var hasRequiredReactJsxRuntime_development;
|
|
549
|
+
|
|
550
|
+
function requireReactJsxRuntime_development () {
|
|
551
|
+
if (hasRequiredReactJsxRuntime_development) return reactJsxRuntime_development;
|
|
552
|
+
hasRequiredReactJsxRuntime_development = 1;
|
|
553
|
+
"production" !== process.env.NODE_ENV &&
|
|
554
|
+
(function () {
|
|
555
|
+
function getComponentNameFromType(type) {
|
|
556
|
+
if (null == type) return null;
|
|
557
|
+
if ("function" === typeof type)
|
|
558
|
+
return type.$$typeof === REACT_CLIENT_REFERENCE
|
|
559
|
+
? null
|
|
560
|
+
: type.displayName || type.name || null;
|
|
561
|
+
if ("string" === typeof type) return type;
|
|
562
|
+
switch (type) {
|
|
563
|
+
case REACT_FRAGMENT_TYPE:
|
|
564
|
+
return "Fragment";
|
|
565
|
+
case REACT_PROFILER_TYPE:
|
|
566
|
+
return "Profiler";
|
|
567
|
+
case REACT_STRICT_MODE_TYPE:
|
|
568
|
+
return "StrictMode";
|
|
569
|
+
case REACT_SUSPENSE_TYPE:
|
|
570
|
+
return "Suspense";
|
|
571
|
+
case REACT_SUSPENSE_LIST_TYPE:
|
|
572
|
+
return "SuspenseList";
|
|
573
|
+
case REACT_ACTIVITY_TYPE:
|
|
574
|
+
return "Activity";
|
|
575
|
+
}
|
|
576
|
+
if ("object" === typeof type)
|
|
577
|
+
switch (
|
|
578
|
+
("number" === typeof type.tag &&
|
|
579
|
+
console.error(
|
|
580
|
+
"Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
|
|
581
|
+
),
|
|
582
|
+
type.$$typeof)
|
|
583
|
+
) {
|
|
584
|
+
case REACT_PORTAL_TYPE:
|
|
585
|
+
return "Portal";
|
|
586
|
+
case REACT_CONTEXT_TYPE:
|
|
587
|
+
return type.displayName || "Context";
|
|
588
|
+
case REACT_CONSUMER_TYPE:
|
|
589
|
+
return (type._context.displayName || "Context") + ".Consumer";
|
|
590
|
+
case REACT_FORWARD_REF_TYPE:
|
|
591
|
+
var innerType = type.render;
|
|
592
|
+
type = type.displayName;
|
|
593
|
+
type ||
|
|
594
|
+
((type = innerType.displayName || innerType.name || ""),
|
|
595
|
+
(type = "" !== type ? "ForwardRef(" + type + ")" : "ForwardRef"));
|
|
596
|
+
return type;
|
|
597
|
+
case REACT_MEMO_TYPE:
|
|
598
|
+
return (
|
|
599
|
+
(innerType = type.displayName || null),
|
|
600
|
+
null !== innerType
|
|
601
|
+
? innerType
|
|
602
|
+
: getComponentNameFromType(type.type) || "Memo"
|
|
603
|
+
);
|
|
604
|
+
case REACT_LAZY_TYPE:
|
|
605
|
+
innerType = type._payload;
|
|
606
|
+
type = type._init;
|
|
607
|
+
try {
|
|
608
|
+
return getComponentNameFromType(type(innerType));
|
|
609
|
+
} catch (x) {}
|
|
610
|
+
}
|
|
611
|
+
return null;
|
|
612
|
+
}
|
|
613
|
+
function testStringCoercion(value) {
|
|
614
|
+
return "" + value;
|
|
615
|
+
}
|
|
616
|
+
function checkKeyStringCoercion(value) {
|
|
617
|
+
try {
|
|
618
|
+
testStringCoercion(value);
|
|
619
|
+
var JSCompiler_inline_result = !1;
|
|
620
|
+
} catch (e) {
|
|
621
|
+
JSCompiler_inline_result = true;
|
|
622
|
+
}
|
|
623
|
+
if (JSCompiler_inline_result) {
|
|
624
|
+
JSCompiler_inline_result = console;
|
|
625
|
+
var JSCompiler_temp_const = JSCompiler_inline_result.error;
|
|
626
|
+
var JSCompiler_inline_result$jscomp$0 =
|
|
627
|
+
("function" === typeof Symbol &&
|
|
628
|
+
Symbol.toStringTag &&
|
|
629
|
+
value[Symbol.toStringTag]) ||
|
|
630
|
+
value.constructor.name ||
|
|
631
|
+
"Object";
|
|
632
|
+
JSCompiler_temp_const.call(
|
|
633
|
+
JSCompiler_inline_result,
|
|
634
|
+
"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
|
|
635
|
+
JSCompiler_inline_result$jscomp$0
|
|
636
|
+
);
|
|
637
|
+
return testStringCoercion(value);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
function getTaskName(type) {
|
|
641
|
+
if (type === REACT_FRAGMENT_TYPE) return "<>";
|
|
642
|
+
if (
|
|
643
|
+
"object" === typeof type &&
|
|
644
|
+
null !== type &&
|
|
645
|
+
type.$$typeof === REACT_LAZY_TYPE
|
|
646
|
+
)
|
|
647
|
+
return "<...>";
|
|
648
|
+
try {
|
|
649
|
+
var name = getComponentNameFromType(type);
|
|
650
|
+
return name ? "<" + name + ">" : "<...>";
|
|
651
|
+
} catch (x) {
|
|
652
|
+
return "<...>";
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
function getOwner() {
|
|
656
|
+
var dispatcher = ReactSharedInternals.A;
|
|
657
|
+
return null === dispatcher ? null : dispatcher.getOwner();
|
|
658
|
+
}
|
|
659
|
+
function UnknownOwner() {
|
|
660
|
+
return Error("react-stack-top-frame");
|
|
661
|
+
}
|
|
662
|
+
function hasValidKey(config) {
|
|
663
|
+
if (hasOwnProperty.call(config, "key")) {
|
|
664
|
+
var getter = Object.getOwnPropertyDescriptor(config, "key").get;
|
|
665
|
+
if (getter && getter.isReactWarning) return false;
|
|
666
|
+
}
|
|
667
|
+
return void 0 !== config.key;
|
|
668
|
+
}
|
|
669
|
+
function defineKeyPropWarningGetter(props, displayName) {
|
|
670
|
+
function warnAboutAccessingKey() {
|
|
671
|
+
specialPropKeyWarningShown ||
|
|
672
|
+
((specialPropKeyWarningShown = true),
|
|
673
|
+
console.error(
|
|
674
|
+
"%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
|
|
675
|
+
displayName
|
|
676
|
+
));
|
|
677
|
+
}
|
|
678
|
+
warnAboutAccessingKey.isReactWarning = true;
|
|
679
|
+
Object.defineProperty(props, "key", {
|
|
680
|
+
get: warnAboutAccessingKey,
|
|
681
|
+
configurable: true
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
function elementRefGetterWithDeprecationWarning() {
|
|
685
|
+
var componentName = getComponentNameFromType(this.type);
|
|
686
|
+
didWarnAboutElementRef[componentName] ||
|
|
687
|
+
((didWarnAboutElementRef[componentName] = true),
|
|
688
|
+
console.error(
|
|
689
|
+
"Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."
|
|
690
|
+
));
|
|
691
|
+
componentName = this.props.ref;
|
|
692
|
+
return void 0 !== componentName ? componentName : null;
|
|
693
|
+
}
|
|
694
|
+
function ReactElement(type, key, props, owner, debugStack, debugTask) {
|
|
695
|
+
var refProp = props.ref;
|
|
696
|
+
type = {
|
|
697
|
+
$$typeof: REACT_ELEMENT_TYPE,
|
|
698
|
+
type: type,
|
|
699
|
+
key: key,
|
|
700
|
+
props: props,
|
|
701
|
+
_owner: owner
|
|
702
|
+
};
|
|
703
|
+
null !== (void 0 !== refProp ? refProp : null)
|
|
704
|
+
? Object.defineProperty(type, "ref", {
|
|
705
|
+
enumerable: false,
|
|
706
|
+
get: elementRefGetterWithDeprecationWarning
|
|
707
|
+
})
|
|
708
|
+
: Object.defineProperty(type, "ref", { enumerable: false, value: null });
|
|
709
|
+
type._store = {};
|
|
710
|
+
Object.defineProperty(type._store, "validated", {
|
|
711
|
+
configurable: false,
|
|
712
|
+
enumerable: false,
|
|
713
|
+
writable: true,
|
|
714
|
+
value: 0
|
|
715
|
+
});
|
|
716
|
+
Object.defineProperty(type, "_debugInfo", {
|
|
717
|
+
configurable: false,
|
|
718
|
+
enumerable: false,
|
|
719
|
+
writable: true,
|
|
720
|
+
value: null
|
|
721
|
+
});
|
|
722
|
+
Object.defineProperty(type, "_debugStack", {
|
|
723
|
+
configurable: false,
|
|
724
|
+
enumerable: false,
|
|
725
|
+
writable: true,
|
|
726
|
+
value: debugStack
|
|
727
|
+
});
|
|
728
|
+
Object.defineProperty(type, "_debugTask", {
|
|
729
|
+
configurable: false,
|
|
730
|
+
enumerable: false,
|
|
731
|
+
writable: true,
|
|
732
|
+
value: debugTask
|
|
733
|
+
});
|
|
734
|
+
Object.freeze && (Object.freeze(type.props), Object.freeze(type));
|
|
735
|
+
return type;
|
|
736
|
+
}
|
|
737
|
+
function jsxDEVImpl(
|
|
738
|
+
type,
|
|
739
|
+
config,
|
|
740
|
+
maybeKey,
|
|
741
|
+
isStaticChildren,
|
|
742
|
+
debugStack,
|
|
743
|
+
debugTask
|
|
744
|
+
) {
|
|
745
|
+
var children = config.children;
|
|
746
|
+
if (void 0 !== children)
|
|
747
|
+
if (isStaticChildren)
|
|
748
|
+
if (isArrayImpl(children)) {
|
|
749
|
+
for (
|
|
750
|
+
isStaticChildren = 0;
|
|
751
|
+
isStaticChildren < children.length;
|
|
752
|
+
isStaticChildren++
|
|
753
|
+
)
|
|
754
|
+
validateChildKeys(children[isStaticChildren]);
|
|
755
|
+
Object.freeze && Object.freeze(children);
|
|
756
|
+
} else
|
|
757
|
+
console.error(
|
|
758
|
+
"React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
|
|
759
|
+
);
|
|
760
|
+
else validateChildKeys(children);
|
|
761
|
+
if (hasOwnProperty.call(config, "key")) {
|
|
762
|
+
children = getComponentNameFromType(type);
|
|
763
|
+
var keys = Object.keys(config).filter(function (k) {
|
|
764
|
+
return "key" !== k;
|
|
765
|
+
});
|
|
766
|
+
isStaticChildren =
|
|
767
|
+
0 < keys.length
|
|
768
|
+
? "{key: someKey, " + keys.join(": ..., ") + ": ...}"
|
|
769
|
+
: "{key: someKey}";
|
|
770
|
+
didWarnAboutKeySpread[children + isStaticChildren] ||
|
|
771
|
+
((keys =
|
|
772
|
+
0 < keys.length ? "{" + keys.join(": ..., ") + ": ...}" : "{}"),
|
|
773
|
+
console.error(
|
|
774
|
+
'A props object containing a "key" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />',
|
|
775
|
+
isStaticChildren,
|
|
776
|
+
children,
|
|
777
|
+
keys,
|
|
778
|
+
children
|
|
779
|
+
),
|
|
780
|
+
(didWarnAboutKeySpread[children + isStaticChildren] = true));
|
|
781
|
+
}
|
|
782
|
+
children = null;
|
|
783
|
+
void 0 !== maybeKey &&
|
|
784
|
+
(checkKeyStringCoercion(maybeKey), (children = "" + maybeKey));
|
|
785
|
+
hasValidKey(config) &&
|
|
786
|
+
(checkKeyStringCoercion(config.key), (children = "" + config.key));
|
|
787
|
+
if ("key" in config) {
|
|
788
|
+
maybeKey = {};
|
|
789
|
+
for (var propName in config)
|
|
790
|
+
"key" !== propName && (maybeKey[propName] = config[propName]);
|
|
791
|
+
} else maybeKey = config;
|
|
792
|
+
children &&
|
|
793
|
+
defineKeyPropWarningGetter(
|
|
794
|
+
maybeKey,
|
|
795
|
+
"function" === typeof type
|
|
796
|
+
? type.displayName || type.name || "Unknown"
|
|
797
|
+
: type
|
|
798
|
+
);
|
|
799
|
+
return ReactElement(
|
|
800
|
+
type,
|
|
801
|
+
children,
|
|
802
|
+
maybeKey,
|
|
803
|
+
getOwner(),
|
|
804
|
+
debugStack,
|
|
805
|
+
debugTask
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
function validateChildKeys(node) {
|
|
809
|
+
isValidElement(node)
|
|
810
|
+
? node._store && (node._store.validated = 1)
|
|
811
|
+
: "object" === typeof node &&
|
|
812
|
+
null !== node &&
|
|
813
|
+
node.$$typeof === REACT_LAZY_TYPE &&
|
|
814
|
+
("fulfilled" === node._payload.status
|
|
815
|
+
? isValidElement(node._payload.value) &&
|
|
816
|
+
node._payload.value._store &&
|
|
817
|
+
(node._payload.value._store.validated = 1)
|
|
818
|
+
: node._store && (node._store.validated = 1));
|
|
819
|
+
}
|
|
820
|
+
function isValidElement(object) {
|
|
821
|
+
return (
|
|
822
|
+
"object" === typeof object &&
|
|
823
|
+
null !== object &&
|
|
824
|
+
object.$$typeof === REACT_ELEMENT_TYPE
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
var React = require$$0,
|
|
828
|
+
REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"),
|
|
829
|
+
REACT_PORTAL_TYPE = Symbol.for("react.portal"),
|
|
830
|
+
REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"),
|
|
831
|
+
REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"),
|
|
832
|
+
REACT_PROFILER_TYPE = Symbol.for("react.profiler"),
|
|
833
|
+
REACT_CONSUMER_TYPE = Symbol.for("react.consumer"),
|
|
834
|
+
REACT_CONTEXT_TYPE = Symbol.for("react.context"),
|
|
835
|
+
REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"),
|
|
836
|
+
REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"),
|
|
837
|
+
REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"),
|
|
838
|
+
REACT_MEMO_TYPE = Symbol.for("react.memo"),
|
|
839
|
+
REACT_LAZY_TYPE = Symbol.for("react.lazy"),
|
|
840
|
+
REACT_ACTIVITY_TYPE = Symbol.for("react.activity"),
|
|
841
|
+
REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"),
|
|
842
|
+
ReactSharedInternals =
|
|
843
|
+
React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
|
|
844
|
+
hasOwnProperty = Object.prototype.hasOwnProperty,
|
|
845
|
+
isArrayImpl = Array.isArray,
|
|
846
|
+
createTask = console.createTask
|
|
847
|
+
? console.createTask
|
|
848
|
+
: function () {
|
|
849
|
+
return null;
|
|
850
|
+
};
|
|
851
|
+
React = {
|
|
852
|
+
react_stack_bottom_frame: function (callStackForError) {
|
|
853
|
+
return callStackForError();
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
var specialPropKeyWarningShown;
|
|
857
|
+
var didWarnAboutElementRef = {};
|
|
858
|
+
var unknownOwnerDebugStack = React.react_stack_bottom_frame.bind(
|
|
859
|
+
React,
|
|
860
|
+
UnknownOwner
|
|
861
|
+
)();
|
|
862
|
+
var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
|
|
863
|
+
var didWarnAboutKeySpread = {};
|
|
864
|
+
reactJsxRuntime_development.Fragment = REACT_FRAGMENT_TYPE;
|
|
865
|
+
reactJsxRuntime_development.jsx = function (type, config, maybeKey) {
|
|
866
|
+
var trackActualOwner =
|
|
867
|
+
1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;
|
|
868
|
+
return jsxDEVImpl(
|
|
869
|
+
type,
|
|
870
|
+
config,
|
|
871
|
+
maybeKey,
|
|
872
|
+
false,
|
|
873
|
+
trackActualOwner
|
|
874
|
+
? Error("react-stack-top-frame")
|
|
875
|
+
: unknownOwnerDebugStack,
|
|
876
|
+
trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask
|
|
877
|
+
);
|
|
878
|
+
};
|
|
879
|
+
reactJsxRuntime_development.jsxs = function (type, config, maybeKey) {
|
|
880
|
+
var trackActualOwner =
|
|
881
|
+
1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;
|
|
882
|
+
return jsxDEVImpl(
|
|
883
|
+
type,
|
|
884
|
+
config,
|
|
885
|
+
maybeKey,
|
|
886
|
+
true,
|
|
887
|
+
trackActualOwner
|
|
888
|
+
? Error("react-stack-top-frame")
|
|
889
|
+
: unknownOwnerDebugStack,
|
|
890
|
+
trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask
|
|
891
|
+
);
|
|
892
|
+
};
|
|
893
|
+
})();
|
|
894
|
+
return reactJsxRuntime_development;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
if (process.env.NODE_ENV === 'production') {
|
|
898
|
+
jsxRuntime.exports = requireReactJsxRuntime_production();
|
|
899
|
+
} else {
|
|
900
|
+
jsxRuntime.exports = requireReactJsxRuntime_development();
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
var jsxRuntimeExports = jsxRuntime.exports;
|
|
904
|
+
|
|
905
|
+
function useTourEngine(config) {
|
|
906
|
+
const actions = require$$0.useMemo(() => new TourActions(), []);
|
|
907
|
+
const engine = require$$0.useMemo(() => {
|
|
908
|
+
const tourEngine = new TourEngine(config);
|
|
909
|
+
return tourEngine;
|
|
910
|
+
}, [config]);
|
|
911
|
+
const [state, setState] = require$$0.useState(engine.getState());
|
|
912
|
+
require$$0.useEffect(() => {
|
|
913
|
+
const unsubscribe = engine.subscribe(setState);
|
|
914
|
+
return unsubscribe;
|
|
915
|
+
}, [engine]);
|
|
916
|
+
const start = require$$0.useCallback(async () => {
|
|
917
|
+
try {
|
|
918
|
+
await engine.start();
|
|
919
|
+
}
|
|
920
|
+
catch (error) {
|
|
921
|
+
console.error('Error in useTourEngine.start():', error);
|
|
922
|
+
}
|
|
923
|
+
}, [engine]);
|
|
924
|
+
const stop = require$$0.useCallback(async () => {
|
|
925
|
+
await engine.stop();
|
|
926
|
+
}, [engine]);
|
|
927
|
+
const next = require$$0.useCallback(async () => {
|
|
928
|
+
const currentStep = engine.getCurrentStep();
|
|
929
|
+
if (currentStep?.action) {
|
|
930
|
+
// Execute the step action first
|
|
931
|
+
await actions.execute(currentStep.action);
|
|
932
|
+
}
|
|
933
|
+
await engine.next();
|
|
934
|
+
}, [engine, actions]);
|
|
935
|
+
const previous = require$$0.useCallback(async () => {
|
|
936
|
+
await engine.previous();
|
|
937
|
+
}, [engine]);
|
|
938
|
+
const skip = require$$0.useCallback(async () => {
|
|
939
|
+
await engine.skip();
|
|
940
|
+
}, [engine]);
|
|
941
|
+
const goToStep = require$$0.useCallback(async (index) => {
|
|
942
|
+
await engine.goToStep(index);
|
|
943
|
+
}, [engine]);
|
|
944
|
+
return {
|
|
945
|
+
state,
|
|
946
|
+
start,
|
|
947
|
+
stop,
|
|
948
|
+
next,
|
|
949
|
+
previous,
|
|
950
|
+
skip,
|
|
951
|
+
goToStep,
|
|
952
|
+
isFirstStep: engine.isFirstStep(),
|
|
953
|
+
isLastStep: engine.isLastStep(),
|
|
954
|
+
canGoNext: engine.canGoNext(),
|
|
955
|
+
canGoPrevious: engine.canGoPrevious(),
|
|
956
|
+
currentStep: engine.getCurrentStep(),
|
|
957
|
+
engine,
|
|
958
|
+
actions,
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
const TourContext = require$$0.createContext(null);
|
|
963
|
+
const defaultTheme = {
|
|
964
|
+
primaryColor: '#3b82f6',
|
|
965
|
+
backgroundColor: '#ffffff',
|
|
966
|
+
textColor: '#1f2937',
|
|
967
|
+
borderRadius: '12px',
|
|
968
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
969
|
+
fontSize: '14px',
|
|
970
|
+
zIndex: 9999,
|
|
971
|
+
overlay: {
|
|
972
|
+
backgroundColor: '#000000',
|
|
973
|
+
opacity: 0.5,
|
|
974
|
+
},
|
|
975
|
+
highlight: {
|
|
976
|
+
borderColor: '#3b82f6',
|
|
977
|
+
borderWidth: '4px',
|
|
978
|
+
glowColor: 'rgba(59, 130, 246, 0.3)',
|
|
979
|
+
animation: 'tour-highlight-pulse 2s infinite',
|
|
980
|
+
},
|
|
981
|
+
popover: {
|
|
982
|
+
backgroundColor: '#ffffff',
|
|
983
|
+
borderColor: '#e5e7eb',
|
|
984
|
+
shadow: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
|
|
985
|
+
maxWidth: '384px',
|
|
986
|
+
},
|
|
987
|
+
};
|
|
988
|
+
function TourProvider({ config, children }) {
|
|
989
|
+
const tourEngine = useTourEngine(config);
|
|
990
|
+
const theme = { ...defaultTheme, ...config.theme };
|
|
991
|
+
const contextValue = {
|
|
992
|
+
...tourEngine,
|
|
993
|
+
config,
|
|
994
|
+
theme,
|
|
995
|
+
};
|
|
996
|
+
return (jsxRuntimeExports.jsx(TourContext.Provider, { value: contextValue, children: children }));
|
|
997
|
+
}
|
|
998
|
+
function useTour() {
|
|
999
|
+
const context = require$$0.useContext(TourContext);
|
|
1000
|
+
if (!context) {
|
|
1001
|
+
throw new Error('useTour must be used within a TourProvider');
|
|
1002
|
+
}
|
|
1003
|
+
return context;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
function getElementPosition(element) {
|
|
1007
|
+
const rect = element.getBoundingClientRect();
|
|
1008
|
+
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
1009
|
+
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
|
|
1010
|
+
return {
|
|
1011
|
+
top: rect.top + scrollTop,
|
|
1012
|
+
left: rect.left + scrollLeft,
|
|
1013
|
+
width: rect.width,
|
|
1014
|
+
height: rect.height,
|
|
1015
|
+
right: rect.right + scrollLeft,
|
|
1016
|
+
bottom: rect.bottom + scrollTop,
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
function calculatePopoverPosition(targetElement, popoverElement, preferredPlacement = 'top') {
|
|
1020
|
+
const targetPos = getElementPosition(targetElement);
|
|
1021
|
+
const popoverRect = popoverElement.getBoundingClientRect();
|
|
1022
|
+
const viewport = {
|
|
1023
|
+
width: window.innerWidth,
|
|
1024
|
+
height: window.innerHeight,
|
|
1025
|
+
scrollTop: window.pageYOffset || document.documentElement.scrollTop,
|
|
1026
|
+
scrollLeft: window.pageXOffset || document.documentElement.scrollLeft,
|
|
1027
|
+
};
|
|
1028
|
+
const spacing = 12; // Gap between target and popover
|
|
1029
|
+
const positions = {
|
|
1030
|
+
top: {
|
|
1031
|
+
top: targetPos.top - popoverRect.height - spacing,
|
|
1032
|
+
left: targetPos.left + (targetPos.width - popoverRect.width) / 2,
|
|
1033
|
+
placement: 'top',
|
|
1034
|
+
},
|
|
1035
|
+
bottom: {
|
|
1036
|
+
top: targetPos.bottom + spacing,
|
|
1037
|
+
left: targetPos.left + (targetPos.width - popoverRect.width) / 2,
|
|
1038
|
+
placement: 'bottom',
|
|
1039
|
+
},
|
|
1040
|
+
left: {
|
|
1041
|
+
top: targetPos.top + (targetPos.height - popoverRect.height) / 2,
|
|
1042
|
+
left: targetPos.left - popoverRect.width - spacing,
|
|
1043
|
+
placement: 'left',
|
|
1044
|
+
},
|
|
1045
|
+
right: {
|
|
1046
|
+
top: targetPos.top + (targetPos.height - popoverRect.height) / 2,
|
|
1047
|
+
left: targetPos.right + spacing,
|
|
1048
|
+
placement: 'right',
|
|
1049
|
+
},
|
|
1050
|
+
center: {
|
|
1051
|
+
top: viewport.scrollTop + (viewport.height - popoverRect.height) / 2,
|
|
1052
|
+
left: viewport.scrollLeft + (viewport.width - popoverRect.width) / 2,
|
|
1053
|
+
placement: 'center',
|
|
1054
|
+
},
|
|
1055
|
+
};
|
|
1056
|
+
// Check if preferred placement fits in viewport
|
|
1057
|
+
const preferred = positions[preferredPlacement];
|
|
1058
|
+
if (isPositionInViewport(preferred, popoverRect, viewport)) {
|
|
1059
|
+
return preferred;
|
|
1060
|
+
}
|
|
1061
|
+
// Try other placements in order of preference
|
|
1062
|
+
const fallbackOrder = ['bottom', 'top', 'right', 'left', 'center'];
|
|
1063
|
+
for (const placement of fallbackOrder) {
|
|
1064
|
+
if (placement === preferredPlacement)
|
|
1065
|
+
continue;
|
|
1066
|
+
const position = positions[placement];
|
|
1067
|
+
if (isPositionInViewport(position, popoverRect, viewport)) {
|
|
1068
|
+
return position;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
// If nothing fits, use center as fallback
|
|
1072
|
+
return positions.center;
|
|
1073
|
+
}
|
|
1074
|
+
function isPositionInViewport(position, popoverRect, viewport) {
|
|
1075
|
+
const margin = 16; // Minimum margin from viewport edges
|
|
1076
|
+
return (position.left >= viewport.scrollLeft + margin &&
|
|
1077
|
+
position.left + popoverRect.width <= viewport.scrollLeft + viewport.width - margin &&
|
|
1078
|
+
position.top >= viewport.scrollTop + margin &&
|
|
1079
|
+
position.top + popoverRect.height <= viewport.scrollTop + viewport.height - margin);
|
|
1080
|
+
}
|
|
1081
|
+
function scrollToElement(element, behavior = 'smooth') {
|
|
1082
|
+
element.scrollIntoView({
|
|
1083
|
+
behavior,
|
|
1084
|
+
block: 'center',
|
|
1085
|
+
inline: 'center',
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1088
|
+
function isElementInViewport(element) {
|
|
1089
|
+
const rect = element.getBoundingClientRect();
|
|
1090
|
+
return (rect.top >= 0 &&
|
|
1091
|
+
rect.left >= 0 &&
|
|
1092
|
+
rect.bottom <= window.innerHeight &&
|
|
1093
|
+
rect.right <= window.innerWidth);
|
|
1094
|
+
}
|
|
1095
|
+
function getViewportCenter() {
|
|
1096
|
+
return {
|
|
1097
|
+
x: window.innerWidth / 2,
|
|
1098
|
+
y: window.innerHeight / 2,
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
function useTourHighlight(step) {
|
|
1103
|
+
const [targetElement, setTargetElement] = require$$0.useState(null);
|
|
1104
|
+
const [highlightStyle, setHighlightStyle] = require$$0.useState({});
|
|
1105
|
+
const [isVisible, setIsVisible] = require$$0.useState(false);
|
|
1106
|
+
const observerRef = require$$0.useRef(null);
|
|
1107
|
+
require$$0.useEffect(() => {
|
|
1108
|
+
if (!step?.target) {
|
|
1109
|
+
setTargetElement(null);
|
|
1110
|
+
setIsVisible(false);
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
1113
|
+
const findAndHighlightElement = () => {
|
|
1114
|
+
const element = step.highlight?.element ||
|
|
1115
|
+
document.querySelector(step.target);
|
|
1116
|
+
if (element) {
|
|
1117
|
+
setTargetElement(element);
|
|
1118
|
+
updateHighlightStyle(element, step.highlight);
|
|
1119
|
+
setIsVisible(true);
|
|
1120
|
+
// Scroll to element if not in viewport
|
|
1121
|
+
if (!isElementInViewport(element)) {
|
|
1122
|
+
scrollToElement(element);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
else {
|
|
1126
|
+
setTargetElement(null);
|
|
1127
|
+
setIsVisible(false);
|
|
1128
|
+
}
|
|
1129
|
+
};
|
|
1130
|
+
// Initial attempt to find element
|
|
1131
|
+
findAndHighlightElement();
|
|
1132
|
+
// Set up mutation observer to watch for DOM changes
|
|
1133
|
+
if (!targetElement && step.waitForElement !== false) {
|
|
1134
|
+
observerRef.current = new MutationObserver(() => {
|
|
1135
|
+
findAndHighlightElement();
|
|
1136
|
+
});
|
|
1137
|
+
observerRef.current.observe(document.body, {
|
|
1138
|
+
childList: true,
|
|
1139
|
+
subtree: true,
|
|
1140
|
+
attributes: true,
|
|
1141
|
+
attributeFilter: ['class', 'id', 'data-tour'],
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
return () => {
|
|
1145
|
+
if (observerRef.current) {
|
|
1146
|
+
observerRef.current.disconnect();
|
|
1147
|
+
observerRef.current = null;
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
}, [step?.target, step?.highlight, step?.waitForElement, targetElement]);
|
|
1151
|
+
// Update highlight position when element moves (e.g., during animations)
|
|
1152
|
+
require$$0.useEffect(() => {
|
|
1153
|
+
if (!targetElement || !isVisible)
|
|
1154
|
+
return;
|
|
1155
|
+
const updatePosition = () => {
|
|
1156
|
+
updateHighlightStyle(targetElement, step?.highlight);
|
|
1157
|
+
};
|
|
1158
|
+
const handleScroll = () => updatePosition();
|
|
1159
|
+
const handleResize = () => updatePosition();
|
|
1160
|
+
window.addEventListener('scroll', handleScroll, { passive: true });
|
|
1161
|
+
window.addEventListener('resize', handleResize, { passive: true });
|
|
1162
|
+
// Use ResizeObserver to watch for element size changes
|
|
1163
|
+
let resizeObserver = null;
|
|
1164
|
+
if (window.ResizeObserver) {
|
|
1165
|
+
resizeObserver = new ResizeObserver(updatePosition);
|
|
1166
|
+
resizeObserver.observe(targetElement);
|
|
1167
|
+
}
|
|
1168
|
+
return () => {
|
|
1169
|
+
window.removeEventListener('scroll', handleScroll);
|
|
1170
|
+
window.removeEventListener('resize', handleResize);
|
|
1171
|
+
if (resizeObserver) {
|
|
1172
|
+
resizeObserver.disconnect();
|
|
1173
|
+
}
|
|
1174
|
+
};
|
|
1175
|
+
}, [targetElement, isVisible, step?.highlight]);
|
|
1176
|
+
const updateHighlightStyle = (element, config) => {
|
|
1177
|
+
const position = getElementPosition(element);
|
|
1178
|
+
const padding = config?.padding || 4;
|
|
1179
|
+
const borderRadius = config?.borderRadius || 8;
|
|
1180
|
+
const borderWidth = config?.borderWidth || 4;
|
|
1181
|
+
setHighlightStyle({
|
|
1182
|
+
position: 'absolute',
|
|
1183
|
+
top: position.top - padding,
|
|
1184
|
+
left: position.left - padding,
|
|
1185
|
+
width: position.width + (padding * 2),
|
|
1186
|
+
height: position.height + (padding * 2),
|
|
1187
|
+
border: `${borderWidth}px solid var(--tour-highlight-color, #3b82f6)`,
|
|
1188
|
+
borderRadius: `${borderRadius}px`,
|
|
1189
|
+
boxShadow: config?.animate !== false
|
|
1190
|
+
? '0 0 0 4px rgba(59, 130, 246, 0.2), 0 0 20px rgba(59, 130, 246, 0.3)'
|
|
1191
|
+
: '0 0 0 4px rgba(59, 130, 246, 0.2)',
|
|
1192
|
+
pointerEvents: 'none',
|
|
1193
|
+
zIndex: 9998,
|
|
1194
|
+
transition: config?.animate !== false
|
|
1195
|
+
? 'all 0.3s ease-in-out'
|
|
1196
|
+
: 'none',
|
|
1197
|
+
animation: config?.animate !== false
|
|
1198
|
+
? 'tour-highlight-pulse 2s infinite'
|
|
1199
|
+
: 'none',
|
|
1200
|
+
});
|
|
1201
|
+
};
|
|
1202
|
+
return {
|
|
1203
|
+
targetElement,
|
|
1204
|
+
highlightStyle,
|
|
1205
|
+
isVisible,
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
function TourOverlay({ className }) {
|
|
1210
|
+
const { state, theme, stop } = useTour();
|
|
1211
|
+
const { targetElement, highlightStyle, isVisible } = useTourHighlight(state.currentStep);
|
|
1212
|
+
if (!state.isRunning || !state.currentStep) {
|
|
1213
|
+
return null;
|
|
1214
|
+
}
|
|
1215
|
+
const overlayStyle = {
|
|
1216
|
+
position: 'fixed',
|
|
1217
|
+
top: 0,
|
|
1218
|
+
left: 0,
|
|
1219
|
+
width: '100%',
|
|
1220
|
+
height: '100%',
|
|
1221
|
+
backgroundColor: theme.overlay?.backgroundColor || '#000000',
|
|
1222
|
+
opacity: theme.overlay?.opacity || 0.5,
|
|
1223
|
+
zIndex: (theme.zIndex || 9999) - 1,
|
|
1224
|
+
pointerEvents: 'auto',
|
|
1225
|
+
};
|
|
1226
|
+
const handleOverlayClick = () => {
|
|
1227
|
+
if (state.currentStep?.canSkip !== false) {
|
|
1228
|
+
stop();
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("div", { style: overlayStyle, onClick: handleOverlayClick, className: className, "data-tour-overlay": true }), isVisible && targetElement && (jsxRuntimeExports.jsx("div", { style: highlightStyle, "data-tour-highlight": true })), jsxRuntimeExports.jsx("style", { children: `
|
|
1232
|
+
@keyframes tour-highlight-pulse {
|
|
1233
|
+
0%, 100% {
|
|
1234
|
+
box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.2), 0 0 20px rgba(59, 130, 246, 0.3);
|
|
1235
|
+
}
|
|
1236
|
+
50% {
|
|
1237
|
+
box-shadow: 0 0 0 8px rgba(59, 130, 246, 0.3), 0 0 30px rgba(59, 130, 246, 0.5);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
@keyframes tour-fade-in {
|
|
1242
|
+
from {
|
|
1243
|
+
opacity: 0;
|
|
1244
|
+
transform: scale(0.95);
|
|
1245
|
+
}
|
|
1246
|
+
to {
|
|
1247
|
+
opacity: 1;
|
|
1248
|
+
transform: scale(1);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
[data-tour-overlay] {
|
|
1253
|
+
animation: tour-fade-in 0.2s ease-out;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
[data-tour-highlight] {
|
|
1257
|
+
animation: tour-fade-in 0.3s ease-out;
|
|
1258
|
+
}
|
|
1259
|
+
` })] }));
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
|
|
1263
|
+
|
|
1264
|
+
function TourPopover({ className }) {
|
|
1265
|
+
const { state, theme, next, previous, skip, stop, isFirstStep, isLastStep, canGoNext, canGoPrevious } = useTour();
|
|
1266
|
+
const { targetElement } = useTourHighlight(state.currentStep);
|
|
1267
|
+
const popoverRef = require$$0.useRef(null);
|
|
1268
|
+
const [position, setPosition] = require$$0.useState({ top: 0, left: 0, placement: 'top' });
|
|
1269
|
+
require$$0.useEffect(() => {
|
|
1270
|
+
if (!popoverRef.current || !targetElement || !state.currentStep)
|
|
1271
|
+
return;
|
|
1272
|
+
const updatePosition = () => {
|
|
1273
|
+
const newPosition = calculatePopoverPosition(targetElement, popoverRef.current, state.currentStep.placement || 'top');
|
|
1274
|
+
setPosition(newPosition);
|
|
1275
|
+
};
|
|
1276
|
+
updatePosition();
|
|
1277
|
+
const handleResize = () => updatePosition();
|
|
1278
|
+
const handleScroll = () => updatePosition();
|
|
1279
|
+
window.addEventListener('resize', handleResize);
|
|
1280
|
+
window.addEventListener('scroll', handleScroll, { passive: true });
|
|
1281
|
+
return () => {
|
|
1282
|
+
window.removeEventListener('resize', handleResize);
|
|
1283
|
+
window.removeEventListener('scroll', handleScroll);
|
|
1284
|
+
};
|
|
1285
|
+
}, [targetElement, state.currentStep]);
|
|
1286
|
+
if (!state.isRunning || !state.currentStep) {
|
|
1287
|
+
return null;
|
|
1288
|
+
}
|
|
1289
|
+
const step = state.currentStep;
|
|
1290
|
+
const popoverConfig = step.popover || {};
|
|
1291
|
+
const popoverStyle = {
|
|
1292
|
+
position: 'absolute',
|
|
1293
|
+
top: position.top,
|
|
1294
|
+
left: position.left,
|
|
1295
|
+
maxWidth: theme.popover?.maxWidth || '384px',
|
|
1296
|
+
backgroundColor: theme.popover?.backgroundColor || theme.backgroundColor || '#ffffff',
|
|
1297
|
+
borderTopWidth: '1px',
|
|
1298
|
+
borderRightWidth: '1px',
|
|
1299
|
+
borderBottomWidth: '1px',
|
|
1300
|
+
borderLeftWidth: '1px',
|
|
1301
|
+
borderTopStyle: 'solid',
|
|
1302
|
+
borderRightStyle: 'solid',
|
|
1303
|
+
borderBottomStyle: 'solid',
|
|
1304
|
+
borderLeftStyle: 'solid',
|
|
1305
|
+
borderTopColor: theme.popover?.borderColor || '#e5e7eb',
|
|
1306
|
+
borderRightColor: theme.popover?.borderColor || '#e5e7eb',
|
|
1307
|
+
borderBottomColor: theme.popover?.borderColor || '#e5e7eb',
|
|
1308
|
+
borderLeftColor: theme.popover?.borderColor || '#e5e7eb',
|
|
1309
|
+
borderRadius: theme.borderRadius || '12px',
|
|
1310
|
+
boxShadow: theme.popover?.shadow || '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
|
|
1311
|
+
fontFamily: theme.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
1312
|
+
fontSize: theme.fontSize || '14px',
|
|
1313
|
+
color: theme.textColor || '#1f2937',
|
|
1314
|
+
zIndex: theme.zIndex || 9999,
|
|
1315
|
+
animation: 'tour-fade-in 0.3s ease-out',
|
|
1316
|
+
};
|
|
1317
|
+
const handleNext = async () => {
|
|
1318
|
+
if (canGoNext || isLastStep) {
|
|
1319
|
+
await next();
|
|
1320
|
+
}
|
|
1321
|
+
};
|
|
1322
|
+
const handlePrevious = async () => {
|
|
1323
|
+
if (canGoPrevious) {
|
|
1324
|
+
await previous();
|
|
1325
|
+
}
|
|
1326
|
+
};
|
|
1327
|
+
const handleSkip = async () => {
|
|
1328
|
+
await skip();
|
|
1329
|
+
};
|
|
1330
|
+
const handleClose = async () => {
|
|
1331
|
+
await stop();
|
|
1332
|
+
};
|
|
1333
|
+
return (jsxRuntimeExports.jsxs("div", { ref: popoverRef, style: {
|
|
1334
|
+
...popoverStyle,
|
|
1335
|
+
pointerEvents: 'auto',
|
|
1336
|
+
userSelect: 'none',
|
|
1337
|
+
}, className: clsx('tour-popover', className, popoverConfig.className), "data-tour-popover": true, "data-placement": position.placement, onClick: (e) => {
|
|
1338
|
+
e.stopPropagation();
|
|
1339
|
+
}, children: [jsxRuntimeExports.jsxs("div", { style: {
|
|
1340
|
+
display: 'flex',
|
|
1341
|
+
justifyContent: 'space-between',
|
|
1342
|
+
alignItems: 'center',
|
|
1343
|
+
padding: '16px 20px 0 20px'
|
|
1344
|
+
}, children: [jsxRuntimeExports.jsx("button", { onClick: handleClose, style: {
|
|
1345
|
+
background: 'none',
|
|
1346
|
+
borderTopWidth: '0',
|
|
1347
|
+
borderRightWidth: '0',
|
|
1348
|
+
borderBottomWidth: '0',
|
|
1349
|
+
borderLeftWidth: '0',
|
|
1350
|
+
fontSize: '18px',
|
|
1351
|
+
cursor: 'pointer',
|
|
1352
|
+
color: '#6b7280',
|
|
1353
|
+
padding: '4px',
|
|
1354
|
+
borderRadius: '4px',
|
|
1355
|
+
display: 'flex',
|
|
1356
|
+
alignItems: 'center',
|
|
1357
|
+
justifyContent: 'center',
|
|
1358
|
+
width: '24px',
|
|
1359
|
+
height: '24px',
|
|
1360
|
+
}, "aria-label": "Close tour", children: "\u00D7" }), (popoverConfig.showProgress !== false && state.totalSteps > 1) && (jsxRuntimeExports.jsxs("div", { style: {
|
|
1361
|
+
backgroundColor: theme.primaryColor || '#3b82f6',
|
|
1362
|
+
color: 'white',
|
|
1363
|
+
padding: '4px 8px',
|
|
1364
|
+
borderRadius: '12px',
|
|
1365
|
+
fontSize: '12px',
|
|
1366
|
+
fontWeight: '500',
|
|
1367
|
+
}, children: [state.currentStepIndex + 1, " of ", state.totalSteps] }))] }), jsxRuntimeExports.jsxs("div", { style: { padding: '16px 20px' }, children: [(popoverConfig.title || step.title) && (jsxRuntimeExports.jsx("h3", { style: {
|
|
1368
|
+
margin: '0 0 8px 0',
|
|
1369
|
+
fontSize: '16px',
|
|
1370
|
+
fontWeight: '600',
|
|
1371
|
+
color: theme.textColor || '#1f2937',
|
|
1372
|
+
}, children: popoverConfig.title || step.title })), jsxRuntimeExports.jsx("div", { style: {
|
|
1373
|
+
margin: '0 0 16px 0',
|
|
1374
|
+
lineHeight: '1.5',
|
|
1375
|
+
color: theme.textColor || '#374151',
|
|
1376
|
+
}, children: popoverConfig.content || step.content })] }), jsxRuntimeExports.jsxs("div", { style: {
|
|
1377
|
+
display: 'flex',
|
|
1378
|
+
justifyContent: 'space-between',
|
|
1379
|
+
alignItems: 'center',
|
|
1380
|
+
padding: '0 20px 20px 20px',
|
|
1381
|
+
gap: '12px',
|
|
1382
|
+
}, children: [(popoverConfig.showSkip !== false && step.canSkip !== false) && (jsxRuntimeExports.jsx("button", { onClick: (_e) => {
|
|
1383
|
+
handleSkip();
|
|
1384
|
+
}, style: {
|
|
1385
|
+
background: 'none',
|
|
1386
|
+
borderTopWidth: '0',
|
|
1387
|
+
borderRightWidth: '0',
|
|
1388
|
+
borderBottomWidth: '0',
|
|
1389
|
+
borderLeftWidth: '0',
|
|
1390
|
+
color: '#6b7280',
|
|
1391
|
+
cursor: 'pointer',
|
|
1392
|
+
padding: '8px 16px',
|
|
1393
|
+
borderRadius: '8px',
|
|
1394
|
+
fontSize: '14px',
|
|
1395
|
+
fontWeight: '500',
|
|
1396
|
+
transition: 'all 0.2s ease',
|
|
1397
|
+
pointerEvents: 'auto',
|
|
1398
|
+
position: 'relative',
|
|
1399
|
+
zIndex: 99999,
|
|
1400
|
+
}, children: popoverConfig.skipLabel || 'Skip Tour' })), jsxRuntimeExports.jsxs("div", { style: { display: 'flex', gap: '8px', marginLeft: 'auto' }, children: [!isFirstStep && (jsxRuntimeExports.jsx("button", { onClick: handlePrevious, disabled: !canGoPrevious, style: {
|
|
1401
|
+
backgroundColor: 'transparent',
|
|
1402
|
+
borderTopWidth: '1px',
|
|
1403
|
+
borderRightWidth: '1px',
|
|
1404
|
+
borderBottomWidth: '1px',
|
|
1405
|
+
borderLeftWidth: '1px',
|
|
1406
|
+
borderTopStyle: 'solid',
|
|
1407
|
+
borderRightStyle: 'solid',
|
|
1408
|
+
borderBottomStyle: 'solid',
|
|
1409
|
+
borderLeftStyle: 'solid',
|
|
1410
|
+
borderTopColor: theme.primaryColor || '#3b82f6',
|
|
1411
|
+
borderRightColor: theme.primaryColor || '#3b82f6',
|
|
1412
|
+
borderBottomColor: theme.primaryColor || '#3b82f6',
|
|
1413
|
+
borderLeftColor: theme.primaryColor || '#3b82f6',
|
|
1414
|
+
color: theme.primaryColor || '#3b82f6',
|
|
1415
|
+
cursor: canGoPrevious ? 'pointer' : 'not-allowed',
|
|
1416
|
+
padding: '8px 16px',
|
|
1417
|
+
borderRadius: '8px',
|
|
1418
|
+
fontSize: '14px',
|
|
1419
|
+
fontWeight: '500',
|
|
1420
|
+
opacity: canGoPrevious ? 1 : 0.5,
|
|
1421
|
+
transition: 'all 0.2s ease',
|
|
1422
|
+
}, children: "Previous" })), jsxRuntimeExports.jsx("button", { onClick: (e) => {
|
|
1423
|
+
e.preventDefault();
|
|
1424
|
+
e.stopPropagation();
|
|
1425
|
+
handleNext();
|
|
1426
|
+
}, disabled: false, style: {
|
|
1427
|
+
backgroundColor: theme.primaryColor || '#3b82f6',
|
|
1428
|
+
borderTopWidth: '0',
|
|
1429
|
+
borderRightWidth: '0',
|
|
1430
|
+
borderBottomWidth: '0',
|
|
1431
|
+
borderLeftWidth: '0',
|
|
1432
|
+
color: 'white',
|
|
1433
|
+
cursor: 'pointer',
|
|
1434
|
+
padding: '8px 16px',
|
|
1435
|
+
borderRadius: '8px',
|
|
1436
|
+
fontSize: '14px',
|
|
1437
|
+
fontWeight: '500',
|
|
1438
|
+
opacity: 1,
|
|
1439
|
+
transition: 'all 0.2s ease',
|
|
1440
|
+
pointerEvents: 'auto',
|
|
1441
|
+
position: 'relative',
|
|
1442
|
+
zIndex: 99999,
|
|
1443
|
+
}, children: isLastStep
|
|
1444
|
+
? (popoverConfig.finishLabel || 'Finish')
|
|
1445
|
+
: (popoverConfig.nextLabel || 'Next') })] })] }), position.placement !== 'center' && (jsxRuntimeExports.jsx("div", { style: {
|
|
1446
|
+
position: 'absolute',
|
|
1447
|
+
width: '12px',
|
|
1448
|
+
height: '12px',
|
|
1449
|
+
backgroundColor: theme.popover?.backgroundColor || theme.backgroundColor || '#ffffff',
|
|
1450
|
+
borderTopWidth: '1px',
|
|
1451
|
+
borderRightWidth: '1px',
|
|
1452
|
+
borderBottomWidth: '1px',
|
|
1453
|
+
borderLeftWidth: '1px',
|
|
1454
|
+
borderTopStyle: 'solid',
|
|
1455
|
+
borderRightStyle: 'solid',
|
|
1456
|
+
borderBottomStyle: 'solid',
|
|
1457
|
+
borderLeftStyle: 'solid',
|
|
1458
|
+
borderTopColor: theme.popover?.borderColor || '#e5e7eb',
|
|
1459
|
+
borderRightColor: theme.popover?.borderColor || '#e5e7eb',
|
|
1460
|
+
borderBottomColor: theme.popover?.borderColor || '#e5e7eb',
|
|
1461
|
+
borderLeftColor: theme.popover?.borderColor || '#e5e7eb',
|
|
1462
|
+
transform: 'rotate(45deg)',
|
|
1463
|
+
...getArrowPosition(position.placement),
|
|
1464
|
+
}, "data-tour-arrow": true }))] }));
|
|
1465
|
+
}
|
|
1466
|
+
function getArrowPosition(placement) {
|
|
1467
|
+
switch (placement) {
|
|
1468
|
+
case 'top':
|
|
1469
|
+
return {
|
|
1470
|
+
bottom: '-6px',
|
|
1471
|
+
left: '50%',
|
|
1472
|
+
marginLeft: '-6px',
|
|
1473
|
+
borderTopWidth: '0',
|
|
1474
|
+
borderLeftWidth: '0',
|
|
1475
|
+
};
|
|
1476
|
+
case 'bottom':
|
|
1477
|
+
return {
|
|
1478
|
+
top: '-6px',
|
|
1479
|
+
left: '50%',
|
|
1480
|
+
marginLeft: '-6px',
|
|
1481
|
+
borderBottomWidth: '0',
|
|
1482
|
+
borderRightWidth: '0',
|
|
1483
|
+
};
|
|
1484
|
+
case 'left':
|
|
1485
|
+
return {
|
|
1486
|
+
right: '-6px',
|
|
1487
|
+
top: '50%',
|
|
1488
|
+
marginTop: '-6px',
|
|
1489
|
+
borderTopWidth: '0',
|
|
1490
|
+
borderLeftWidth: '0',
|
|
1491
|
+
};
|
|
1492
|
+
case 'right':
|
|
1493
|
+
return {
|
|
1494
|
+
left: '-6px',
|
|
1495
|
+
top: '50%',
|
|
1496
|
+
marginTop: '-6px',
|
|
1497
|
+
borderBottomWidth: '0',
|
|
1498
|
+
borderRightWidth: '0',
|
|
1499
|
+
};
|
|
1500
|
+
default:
|
|
1501
|
+
return {};
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
function TourRunner({ className }) {
|
|
1506
|
+
const { state } = useTour();
|
|
1507
|
+
if (!state.isRunning) {
|
|
1508
|
+
return null;
|
|
1509
|
+
}
|
|
1510
|
+
return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(TourOverlay, { className: className }), jsxRuntimeExports.jsx(TourPopover, { className: className })] }));
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
class TabIntegration {
|
|
1514
|
+
constructor() {
|
|
1515
|
+
this.name = 'tab-integration';
|
|
1516
|
+
}
|
|
1517
|
+
canHandle(action) {
|
|
1518
|
+
return action.type === 'tab-switch';
|
|
1519
|
+
}
|
|
1520
|
+
async execute(action, element) {
|
|
1521
|
+
if (!action.target && !element) {
|
|
1522
|
+
throw new Error('Tab integration requires either a target selector or element');
|
|
1523
|
+
}
|
|
1524
|
+
const targetElement = element || document.querySelector(action.target);
|
|
1525
|
+
if (!targetElement) {
|
|
1526
|
+
throw new Error(`Tab element not found: ${action.target}`);
|
|
1527
|
+
}
|
|
1528
|
+
// Handle different tab implementations
|
|
1529
|
+
const tabValue = typeof action.value === 'string' ? action.value : undefined;
|
|
1530
|
+
await this.handleTabClick(targetElement, tabValue);
|
|
1531
|
+
}
|
|
1532
|
+
async handleTabClick(tabElement, tabValue) {
|
|
1533
|
+
// Check for common tab patterns
|
|
1534
|
+
// 1. Radix UI Tabs
|
|
1535
|
+
if (this.isRadixTab(tabElement)) {
|
|
1536
|
+
await this.handleRadixTab(tabElement);
|
|
1537
|
+
return;
|
|
1538
|
+
}
|
|
1539
|
+
// 2. Material UI Tabs
|
|
1540
|
+
if (this.isMaterialUITab(tabElement)) {
|
|
1541
|
+
await this.handleMaterialUITab(tabElement);
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
// 3. React Router tabs (links)
|
|
1545
|
+
if (this.isRouterTab(tabElement)) {
|
|
1546
|
+
await this.handleRouterTab(tabElement);
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
// 4. Custom tabs with data attributes
|
|
1550
|
+
if (this.isCustomTab(tabElement)) {
|
|
1551
|
+
await this.handleCustomTab(tabElement, tabValue);
|
|
1552
|
+
return;
|
|
1553
|
+
}
|
|
1554
|
+
// 5. Generic button/clickable tab
|
|
1555
|
+
await this.handleGenericTab(tabElement);
|
|
1556
|
+
}
|
|
1557
|
+
isRadixTab(element) {
|
|
1558
|
+
return element.hasAttribute('data-radix-collection-item') ||
|
|
1559
|
+
element.getAttribute('role') === 'tab' ||
|
|
1560
|
+
element.closest('[data-radix-tabs-root]') !== null;
|
|
1561
|
+
}
|
|
1562
|
+
async handleRadixTab(element) {
|
|
1563
|
+
// Radix tabs use standard click events
|
|
1564
|
+
element.click();
|
|
1565
|
+
await this.waitForTabChange();
|
|
1566
|
+
}
|
|
1567
|
+
isMaterialUITab(element) {
|
|
1568
|
+
return element.classList.contains('MuiTab-root') ||
|
|
1569
|
+
element.closest('.MuiTabs-root') !== null;
|
|
1570
|
+
}
|
|
1571
|
+
async handleMaterialUITab(element) {
|
|
1572
|
+
// Material UI tabs use click events
|
|
1573
|
+
element.click();
|
|
1574
|
+
await this.waitForTabChange();
|
|
1575
|
+
}
|
|
1576
|
+
isRouterTab(element) {
|
|
1577
|
+
return element.tagName === 'A' ||
|
|
1578
|
+
element.hasAttribute('href') ||
|
|
1579
|
+
element.closest('a[href]') !== null;
|
|
1580
|
+
}
|
|
1581
|
+
async handleRouterTab(element) {
|
|
1582
|
+
const linkElement = element.tagName === 'A' ? element : element.closest('a');
|
|
1583
|
+
if (linkElement) {
|
|
1584
|
+
linkElement.click();
|
|
1585
|
+
await this.waitForNavigation();
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
isCustomTab(element) {
|
|
1589
|
+
return element.hasAttribute('data-tab') ||
|
|
1590
|
+
element.hasAttribute('data-tab-id') ||
|
|
1591
|
+
element.hasAttribute('data-value');
|
|
1592
|
+
}
|
|
1593
|
+
async handleCustomTab(element, tabValue) {
|
|
1594
|
+
// Try to find and activate the correct tab
|
|
1595
|
+
if (tabValue) {
|
|
1596
|
+
const tabContainer = element.closest('[role="tablist"]') ||
|
|
1597
|
+
element.closest('.tabs') ||
|
|
1598
|
+
element.parentElement;
|
|
1599
|
+
if (tabContainer) {
|
|
1600
|
+
const targetTab = tabContainer.querySelector(`[data-tab="${tabValue}"], [data-tab-id="${tabValue}"], [data-value="${tabValue}"]`);
|
|
1601
|
+
if (targetTab) {
|
|
1602
|
+
targetTab.click();
|
|
1603
|
+
await this.waitForTabChange();
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
// Fallback to clicking the provided element
|
|
1609
|
+
element.click();
|
|
1610
|
+
await this.waitForTabChange();
|
|
1611
|
+
}
|
|
1612
|
+
async handleGenericTab(element) {
|
|
1613
|
+
// Generic click handling
|
|
1614
|
+
element.click();
|
|
1615
|
+
await this.waitForTabChange();
|
|
1616
|
+
}
|
|
1617
|
+
async waitForTabChange() {
|
|
1618
|
+
// Wait for tab content to change
|
|
1619
|
+
return new Promise(resolve => {
|
|
1620
|
+
setTimeout(resolve, 300); // Allow time for tab transition
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
async waitForNavigation() {
|
|
1624
|
+
// Wait for potential page navigation
|
|
1625
|
+
return new Promise(resolve => {
|
|
1626
|
+
setTimeout(resolve, 500); // Allow time for navigation
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
class WizardIntegration {
|
|
1632
|
+
constructor() {
|
|
1633
|
+
this.name = 'wizard-integration';
|
|
1634
|
+
}
|
|
1635
|
+
canHandle(action) {
|
|
1636
|
+
return action.type === 'wizard-step';
|
|
1637
|
+
}
|
|
1638
|
+
async execute(action, element) {
|
|
1639
|
+
if (!action.target && !element) {
|
|
1640
|
+
throw new Error('Wizard integration requires either a target selector or element');
|
|
1641
|
+
}
|
|
1642
|
+
const targetElement = element || document.querySelector(action.target);
|
|
1643
|
+
if (!targetElement) {
|
|
1644
|
+
throw new Error(`Wizard element not found: ${action.target}`);
|
|
1645
|
+
}
|
|
1646
|
+
const stepValue = typeof action.value === 'string' || typeof action.value === 'number' ? action.value : undefined;
|
|
1647
|
+
await this.handleWizardNavigation(targetElement, stepValue);
|
|
1648
|
+
}
|
|
1649
|
+
async handleWizardNavigation(element, stepValue) {
|
|
1650
|
+
// Handle different wizard patterns
|
|
1651
|
+
// 1. Multi-step form wizards
|
|
1652
|
+
if (this.isFormWizard(element)) {
|
|
1653
|
+
await this.handleFormWizard(element, stepValue);
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1656
|
+
// 2. Stepper components (Material UI, Ant Design, etc.)
|
|
1657
|
+
if (this.isStepper(element)) {
|
|
1658
|
+
await this.handleStepper(element, stepValue);
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
// 3. Custom wizard with data attributes
|
|
1662
|
+
if (this.isCustomWizard(element)) {
|
|
1663
|
+
await this.handleCustomWizard(element, stepValue);
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
// 4. Generic next/previous buttons
|
|
1667
|
+
await this.handleGenericWizard(element);
|
|
1668
|
+
}
|
|
1669
|
+
isFormWizard(element) {
|
|
1670
|
+
return element.closest('form') !== null ||
|
|
1671
|
+
element.closest('.wizard') !== null ||
|
|
1672
|
+
element.closest('.multi-step') !== null;
|
|
1673
|
+
}
|
|
1674
|
+
async handleFormWizard(element, stepValue) {
|
|
1675
|
+
if (typeof stepValue === 'number') {
|
|
1676
|
+
// Navigate to specific step
|
|
1677
|
+
await this.navigateToStep(element, stepValue);
|
|
1678
|
+
}
|
|
1679
|
+
else if (this.isNextButton(element)) {
|
|
1680
|
+
// Click next button
|
|
1681
|
+
element.click();
|
|
1682
|
+
await this.waitForStepTransition();
|
|
1683
|
+
}
|
|
1684
|
+
else if (this.isPreviousButton(element)) {
|
|
1685
|
+
// Click previous button
|
|
1686
|
+
element.click();
|
|
1687
|
+
await this.waitForStepTransition();
|
|
1688
|
+
}
|
|
1689
|
+
else {
|
|
1690
|
+
// Generic click
|
|
1691
|
+
element.click();
|
|
1692
|
+
await this.waitForStepTransition();
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
isStepper(element) {
|
|
1696
|
+
return element.classList.contains('MuiStepper-root') ||
|
|
1697
|
+
element.classList.contains('ant-steps') ||
|
|
1698
|
+
element.closest('.stepper') !== null ||
|
|
1699
|
+
element.closest('[role="progressbar"]') !== null;
|
|
1700
|
+
}
|
|
1701
|
+
async handleStepper(element, stepValue) {
|
|
1702
|
+
if (typeof stepValue === 'number') {
|
|
1703
|
+
// Find and click specific step
|
|
1704
|
+
const stepElement = this.findStepByIndex(element, stepValue);
|
|
1705
|
+
if (stepElement) {
|
|
1706
|
+
stepElement.click();
|
|
1707
|
+
await this.waitForStepTransition();
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
// Click the provided element
|
|
1712
|
+
element.click();
|
|
1713
|
+
await this.waitForStepTransition();
|
|
1714
|
+
}
|
|
1715
|
+
isCustomWizard(element) {
|
|
1716
|
+
return element.hasAttribute('data-wizard-step') ||
|
|
1717
|
+
element.hasAttribute('data-step') ||
|
|
1718
|
+
element.closest('[data-wizard]') !== null;
|
|
1719
|
+
}
|
|
1720
|
+
async handleCustomWizard(element, stepValue) {
|
|
1721
|
+
const wizard = element.closest('[data-wizard]');
|
|
1722
|
+
if (stepValue && wizard) {
|
|
1723
|
+
// Try to find specific step
|
|
1724
|
+
const stepElement = wizard.querySelector(`[data-step="${stepValue}"], [data-wizard-step="${stepValue}"]`);
|
|
1725
|
+
if (stepElement) {
|
|
1726
|
+
stepElement.click();
|
|
1727
|
+
await this.waitForStepTransition();
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
// Click the provided element
|
|
1732
|
+
element.click();
|
|
1733
|
+
await this.waitForStepTransition();
|
|
1734
|
+
}
|
|
1735
|
+
async handleGenericWizard(element) {
|
|
1736
|
+
element.click();
|
|
1737
|
+
await this.waitForStepTransition();
|
|
1738
|
+
}
|
|
1739
|
+
isNextButton(element) {
|
|
1740
|
+
const text = element.textContent?.toLowerCase() || '';
|
|
1741
|
+
return text.includes('next') ||
|
|
1742
|
+
text.includes('continue') ||
|
|
1743
|
+
text.includes('proceed') ||
|
|
1744
|
+
element.classList.contains('next') ||
|
|
1745
|
+
element.hasAttribute('data-next');
|
|
1746
|
+
}
|
|
1747
|
+
isPreviousButton(element) {
|
|
1748
|
+
const text = element.textContent?.toLowerCase() || '';
|
|
1749
|
+
return text.includes('previous') ||
|
|
1750
|
+
text.includes('back') ||
|
|
1751
|
+
element.classList.contains('previous') ||
|
|
1752
|
+
element.classList.contains('back') ||
|
|
1753
|
+
element.hasAttribute('data-previous');
|
|
1754
|
+
}
|
|
1755
|
+
async navigateToStep(container, stepIndex) {
|
|
1756
|
+
// Try different methods to navigate to a specific step
|
|
1757
|
+
// Method 1: Find step by index in stepper
|
|
1758
|
+
const stepElement = this.findStepByIndex(container, stepIndex);
|
|
1759
|
+
if (stepElement) {
|
|
1760
|
+
stepElement.click();
|
|
1761
|
+
await this.waitForStepTransition();
|
|
1762
|
+
return;
|
|
1763
|
+
}
|
|
1764
|
+
// Method 2: Use next/previous buttons to reach target step
|
|
1765
|
+
const currentStep = this.getCurrentStepIndex(container);
|
|
1766
|
+
if (currentStep !== null) {
|
|
1767
|
+
const diff = stepIndex - currentStep;
|
|
1768
|
+
if (diff > 0) {
|
|
1769
|
+
// Go forward
|
|
1770
|
+
for (let i = 0; i < diff; i++) {
|
|
1771
|
+
const nextButton = this.findNextButton(container);
|
|
1772
|
+
if (nextButton) {
|
|
1773
|
+
nextButton.click();
|
|
1774
|
+
await this.waitForStepTransition();
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
else if (diff < 0) {
|
|
1779
|
+
// Go backward
|
|
1780
|
+
for (let i = 0; i < Math.abs(diff); i++) {
|
|
1781
|
+
const prevButton = this.findPreviousButton(container);
|
|
1782
|
+
if (prevButton) {
|
|
1783
|
+
prevButton.click();
|
|
1784
|
+
await this.waitForStepTransition();
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
findStepByIndex(container, index) {
|
|
1791
|
+
// Try different selectors for step elements
|
|
1792
|
+
const selectors = [
|
|
1793
|
+
`.step:nth-child(${index + 1})`,
|
|
1794
|
+
`[data-step="${index}"]`,
|
|
1795
|
+
`[data-wizard-step="${index}"]`,
|
|
1796
|
+
`.MuiStep-root:nth-child(${index + 1})`,
|
|
1797
|
+
`.ant-steps-item:nth-child(${index + 1})`,
|
|
1798
|
+
];
|
|
1799
|
+
for (const selector of selectors) {
|
|
1800
|
+
const element = container.querySelector(selector);
|
|
1801
|
+
if (element)
|
|
1802
|
+
return element;
|
|
1803
|
+
}
|
|
1804
|
+
return null;
|
|
1805
|
+
}
|
|
1806
|
+
getCurrentStepIndex(container) {
|
|
1807
|
+
// Try to determine current step index
|
|
1808
|
+
const activeStep = container.querySelector('.active, .current, .MuiStep-active, .ant-steps-item-active');
|
|
1809
|
+
if (activeStep) {
|
|
1810
|
+
const steps = container.querySelectorAll('.step, .MuiStep-root, .ant-steps-item');
|
|
1811
|
+
return Array.from(steps).indexOf(activeStep);
|
|
1812
|
+
}
|
|
1813
|
+
return null;
|
|
1814
|
+
}
|
|
1815
|
+
findNextButton(container) {
|
|
1816
|
+
const selectors = [
|
|
1817
|
+
'button[data-next]',
|
|
1818
|
+
'.next-button',
|
|
1819
|
+
'button:contains("Next")',
|
|
1820
|
+
'button:contains("Continue")',
|
|
1821
|
+
'.wizard-next',
|
|
1822
|
+
];
|
|
1823
|
+
for (const selector of selectors) {
|
|
1824
|
+
const element = container.querySelector(selector);
|
|
1825
|
+
if (element)
|
|
1826
|
+
return element;
|
|
1827
|
+
}
|
|
1828
|
+
// Fallback: find button with "next" text
|
|
1829
|
+
const buttons = container.querySelectorAll('button');
|
|
1830
|
+
for (const button of buttons) {
|
|
1831
|
+
const text = button.textContent?.toLowerCase() || '';
|
|
1832
|
+
if (text.includes('next') || text.includes('continue')) {
|
|
1833
|
+
return button;
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
return null;
|
|
1837
|
+
}
|
|
1838
|
+
findPreviousButton(container) {
|
|
1839
|
+
const selectors = [
|
|
1840
|
+
'button[data-previous]',
|
|
1841
|
+
'.previous-button',
|
|
1842
|
+
'.back-button',
|
|
1843
|
+
'button:contains("Previous")',
|
|
1844
|
+
'button:contains("Back")',
|
|
1845
|
+
'.wizard-previous',
|
|
1846
|
+
];
|
|
1847
|
+
for (const selector of selectors) {
|
|
1848
|
+
const element = container.querySelector(selector);
|
|
1849
|
+
if (element)
|
|
1850
|
+
return element;
|
|
1851
|
+
}
|
|
1852
|
+
// Fallback: find button with "previous" or "back" text
|
|
1853
|
+
const buttons = container.querySelectorAll('button');
|
|
1854
|
+
for (const button of buttons) {
|
|
1855
|
+
const text = button.textContent?.toLowerCase() || '';
|
|
1856
|
+
if (text.includes('previous') || text.includes('back')) {
|
|
1857
|
+
return button;
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
return null;
|
|
1861
|
+
}
|
|
1862
|
+
async waitForStepTransition() {
|
|
1863
|
+
// Wait for step transition animation/content change
|
|
1864
|
+
return new Promise(resolve => {
|
|
1865
|
+
setTimeout(resolve, 400); // Allow time for transition
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
class NavigationIntegration {
|
|
1871
|
+
constructor() {
|
|
1872
|
+
this.name = 'navigation-integration';
|
|
1873
|
+
}
|
|
1874
|
+
canHandle(action) {
|
|
1875
|
+
return action.type === 'navigate';
|
|
1876
|
+
}
|
|
1877
|
+
async execute(action, _element) {
|
|
1878
|
+
if (!action.target) {
|
|
1879
|
+
throw new Error('Navigation integration requires a target URL or path');
|
|
1880
|
+
}
|
|
1881
|
+
const options = typeof action.value === 'object' && action.value !== null ? action.value : undefined;
|
|
1882
|
+
await this.handleNavigation(action.target, options);
|
|
1883
|
+
}
|
|
1884
|
+
async handleNavigation(target, options) {
|
|
1885
|
+
// Handle different navigation patterns
|
|
1886
|
+
// 1. Hash navigation (same page)
|
|
1887
|
+
if (target.startsWith('#')) {
|
|
1888
|
+
await this.handleHashNavigation(target);
|
|
1889
|
+
return;
|
|
1890
|
+
}
|
|
1891
|
+
// 2. Relative path navigation
|
|
1892
|
+
if (target.startsWith('/')) {
|
|
1893
|
+
await this.handlePathNavigation(target, options);
|
|
1894
|
+
return;
|
|
1895
|
+
}
|
|
1896
|
+
// 3. Query parameter navigation
|
|
1897
|
+
if (target.includes('?') || target.includes('&')) {
|
|
1898
|
+
await this.handleQueryNavigation(target, options);
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
// 4. Full URL navigation
|
|
1902
|
+
if (target.startsWith('http')) {
|
|
1903
|
+
await this.handleUrlNavigation(target, options);
|
|
1904
|
+
return;
|
|
1905
|
+
}
|
|
1906
|
+
// 5. Router navigation (for SPAs)
|
|
1907
|
+
await this.handleRouterNavigation(target, options);
|
|
1908
|
+
}
|
|
1909
|
+
async handleHashNavigation(hash) {
|
|
1910
|
+
// Update hash without page reload
|
|
1911
|
+
window.location.hash = hash;
|
|
1912
|
+
// Wait for potential scroll or content change
|
|
1913
|
+
await this.waitForNavigation(200);
|
|
1914
|
+
// Try to scroll to element if it exists
|
|
1915
|
+
const targetElement = document.querySelector(hash);
|
|
1916
|
+
if (targetElement) {
|
|
1917
|
+
targetElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
async handlePathNavigation(path, options) {
|
|
1921
|
+
// Check if we're in a SPA with router
|
|
1922
|
+
if (this.isSPA()) {
|
|
1923
|
+
await this.handleSPANavigation(path, options);
|
|
1924
|
+
}
|
|
1925
|
+
else {
|
|
1926
|
+
// Traditional navigation
|
|
1927
|
+
if (options?.replace) {
|
|
1928
|
+
window.location.replace(path);
|
|
1929
|
+
}
|
|
1930
|
+
else {
|
|
1931
|
+
window.location.href = path;
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
async handleQueryNavigation(target, options) {
|
|
1936
|
+
const url = new URL(window.location.href);
|
|
1937
|
+
// Parse query parameters from target
|
|
1938
|
+
if (target.startsWith('?')) {
|
|
1939
|
+
// Replace entire query string
|
|
1940
|
+
url.search = target;
|
|
1941
|
+
}
|
|
1942
|
+
else if (target.startsWith('&')) {
|
|
1943
|
+
// Append to existing query string
|
|
1944
|
+
url.search += target;
|
|
1945
|
+
}
|
|
1946
|
+
else {
|
|
1947
|
+
// Parse key=value pairs
|
|
1948
|
+
const params = new URLSearchParams(target);
|
|
1949
|
+
params.forEach((value, key) => {
|
|
1950
|
+
url.searchParams.set(key, value);
|
|
1951
|
+
});
|
|
1952
|
+
}
|
|
1953
|
+
// Update URL
|
|
1954
|
+
if (options?.replace) {
|
|
1955
|
+
window.history.replaceState({}, '', url.toString());
|
|
1956
|
+
}
|
|
1957
|
+
else {
|
|
1958
|
+
window.history.pushState({}, '', url.toString());
|
|
1959
|
+
}
|
|
1960
|
+
// Trigger popstate event for SPAs
|
|
1961
|
+
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
1962
|
+
await this.waitForNavigation(300);
|
|
1963
|
+
}
|
|
1964
|
+
async handleUrlNavigation(url, options) {
|
|
1965
|
+
if (options?.newTab) {
|
|
1966
|
+
window.open(url, '_blank');
|
|
1967
|
+
}
|
|
1968
|
+
else if (options?.replace) {
|
|
1969
|
+
window.location.replace(url);
|
|
1970
|
+
}
|
|
1971
|
+
else {
|
|
1972
|
+
window.location.href = url;
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
async handleRouterNavigation(path, options) {
|
|
1976
|
+
// Try different router patterns
|
|
1977
|
+
// 1. React Router
|
|
1978
|
+
if (this.hasReactRouter()) {
|
|
1979
|
+
await this.handleReactRouter(path, options);
|
|
1980
|
+
return;
|
|
1981
|
+
}
|
|
1982
|
+
// 2. Vue Router
|
|
1983
|
+
if (this.hasVueRouter()) {
|
|
1984
|
+
await this.handleVueRouter(path, options);
|
|
1985
|
+
return;
|
|
1986
|
+
}
|
|
1987
|
+
// 3. Next.js Router
|
|
1988
|
+
if (this.hasNextRouter()) {
|
|
1989
|
+
await this.handleNextRouter(path, options);
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
1992
|
+
// 4. Generic SPA navigation
|
|
1993
|
+
await this.handleSPANavigation(path, options);
|
|
1994
|
+
}
|
|
1995
|
+
async handleSPANavigation(path, options) {
|
|
1996
|
+
// Generic SPA navigation using History API
|
|
1997
|
+
const url = new URL(path, window.location.origin);
|
|
1998
|
+
if (options?.replace) {
|
|
1999
|
+
window.history.replaceState({}, '', url.toString());
|
|
2000
|
+
}
|
|
2001
|
+
else {
|
|
2002
|
+
window.history.pushState({}, '', url.toString());
|
|
2003
|
+
}
|
|
2004
|
+
// Trigger popstate event
|
|
2005
|
+
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
2006
|
+
await this.waitForNavigation(500);
|
|
2007
|
+
}
|
|
2008
|
+
isSPA() {
|
|
2009
|
+
// Detect if we're in a Single Page Application
|
|
2010
|
+
return !!(window.history &&
|
|
2011
|
+
(this.hasReactRouter() || this.hasVueRouter() || this.hasNextRouter() || this.hasGenericSPA()));
|
|
2012
|
+
}
|
|
2013
|
+
hasReactRouter() {
|
|
2014
|
+
// Check for React Router presence
|
|
2015
|
+
return !!(window.__reactRouter ||
|
|
2016
|
+
document.querySelector('[data-reactroot]') ||
|
|
2017
|
+
document.querySelector('#root') ||
|
|
2018
|
+
document.querySelector('#__next'));
|
|
2019
|
+
}
|
|
2020
|
+
hasVueRouter() {
|
|
2021
|
+
// Check for Vue Router presence
|
|
2022
|
+
return !!(window.Vue ||
|
|
2023
|
+
document.querySelector('[data-v-]') ||
|
|
2024
|
+
document.querySelector('#app'));
|
|
2025
|
+
}
|
|
2026
|
+
hasNextRouter() {
|
|
2027
|
+
// Check for Next.js presence
|
|
2028
|
+
return !!(window.__NEXT_DATA__ ||
|
|
2029
|
+
document.querySelector('#__next'));
|
|
2030
|
+
}
|
|
2031
|
+
hasGenericSPA() {
|
|
2032
|
+
// Check for generic SPA indicators
|
|
2033
|
+
return !!(document.querySelector('[data-spa]') ||
|
|
2034
|
+
document.querySelector('[data-router]') ||
|
|
2035
|
+
window.location.pathname !== '/' && !window.location.pathname.includes('.'));
|
|
2036
|
+
}
|
|
2037
|
+
async detectAndCallRouter(path, options) {
|
|
2038
|
+
const router = window.router || window.__ROUTER__ || null;
|
|
2039
|
+
const method = options?.replace ? 'replace' : 'push';
|
|
2040
|
+
if (router && typeof router === 'object' && router !== null && method in router && typeof router[method] === 'function') {
|
|
2041
|
+
await router[method](path, options);
|
|
2042
|
+
return true;
|
|
2043
|
+
}
|
|
2044
|
+
return false;
|
|
2045
|
+
}
|
|
2046
|
+
async handleReactRouter(path, options) {
|
|
2047
|
+
// Try to use React Router's navigate function if available
|
|
2048
|
+
const navigate = window.__reactRouterNavigate;
|
|
2049
|
+
if (navigate) {
|
|
2050
|
+
await navigate(path, options);
|
|
2051
|
+
}
|
|
2052
|
+
else {
|
|
2053
|
+
// Fallback to history API
|
|
2054
|
+
await this.handleSPANavigation(path, options);
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
async handleVueRouter(path, options) {
|
|
2058
|
+
// Try to use Vue Router's push/replace methods
|
|
2059
|
+
const vueRouter = window.router || window.__ROUTER__ || null;
|
|
2060
|
+
if (vueRouter && typeof vueRouter === 'object' && vueRouter !== null) {
|
|
2061
|
+
const router = vueRouter;
|
|
2062
|
+
if (options?.replace && typeof router.replace === 'function') {
|
|
2063
|
+
await router.replace(path);
|
|
2064
|
+
}
|
|
2065
|
+
else if (typeof router.push === 'function') {
|
|
2066
|
+
await router.push(path);
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
else {
|
|
2070
|
+
// Fallback to history API
|
|
2071
|
+
await this.handleSPANavigation(path, options);
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
async handleNextRouter(path, options) {
|
|
2075
|
+
// Try to use Next.js router
|
|
2076
|
+
const nextRouter = window.__nextRouter;
|
|
2077
|
+
if (nextRouter && typeof nextRouter === 'object' && nextRouter !== null) {
|
|
2078
|
+
const router = nextRouter;
|
|
2079
|
+
if (options?.replace && typeof router.replace === 'function') {
|
|
2080
|
+
await router.replace(path);
|
|
2081
|
+
}
|
|
2082
|
+
else if (typeof router.push === 'function') {
|
|
2083
|
+
await router.push(path);
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
else {
|
|
2087
|
+
// Fallback to history API
|
|
2088
|
+
await this.handleSPANavigation(path, options);
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
async waitForNavigation(delay = 300) {
|
|
2092
|
+
return new Promise(resolve => {
|
|
2093
|
+
setTimeout(resolve, delay);
|
|
2094
|
+
});
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
exports.NavigationIntegration = NavigationIntegration;
|
|
2099
|
+
exports.TabIntegration = TabIntegration;
|
|
2100
|
+
exports.TourActions = TourActions;
|
|
2101
|
+
exports.TourEngine = TourEngine;
|
|
2102
|
+
exports.TourOverlay = TourOverlay;
|
|
2103
|
+
exports.TourPopover = TourPopover;
|
|
2104
|
+
exports.TourProvider = TourProvider;
|
|
2105
|
+
exports.TourRunner = TourRunner;
|
|
2106
|
+
exports.TourStorage = TourStorage;
|
|
2107
|
+
exports.WizardIntegration = WizardIntegration;
|
|
2108
|
+
exports.calculatePopoverPosition = calculatePopoverPosition;
|
|
2109
|
+
exports.getElementPosition = getElementPosition;
|
|
2110
|
+
exports.getViewportCenter = getViewportCenter;
|
|
2111
|
+
exports.isElementInViewport = isElementInViewport;
|
|
2112
|
+
exports.scrollToElement = scrollToElement;
|
|
2113
|
+
exports.useTour = useTour;
|
|
2114
|
+
exports.useTourEngine = useTourEngine;
|
|
2115
|
+
exports.useTourHighlight = useTourHighlight;
|
|
2116
|
+
//# sourceMappingURL=index.js.map
|