@aladinbs/react-guided-tour 1.0.2 → 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.
Files changed (39) hide show
  1. package/README.md +11 -1
  2. package/dist/components/ErrorBoundary.d.ts +31 -0
  3. package/dist/components/ErrorBoundary.d.ts.map +1 -0
  4. package/dist/components/Toast.d.ts +14 -0
  5. package/dist/components/Toast.d.ts.map +1 -0
  6. package/dist/components/ToastProvider.d.ts +28 -0
  7. package/dist/components/ToastProvider.d.ts.map +1 -0
  8. package/dist/components/TourOverlay.d.ts +2 -1
  9. package/dist/components/TourOverlay.d.ts.map +1 -1
  10. package/dist/components/TourPopover.d.ts +2 -1
  11. package/dist/components/TourPopover.d.ts.map +1 -1
  12. package/dist/components/TourProvider.d.ts +10 -2
  13. package/dist/components/TourProvider.d.ts.map +1 -1
  14. package/dist/components/TourRunner.d.ts +2 -1
  15. package/dist/components/TourRunner.d.ts.map +1 -1
  16. package/dist/core/TourActions.d.ts +10 -0
  17. package/dist/core/TourActions.d.ts.map +1 -1
  18. package/dist/core/TourEngine.d.ts +32 -0
  19. package/dist/core/TourEngine.d.ts.map +1 -1
  20. package/dist/hooks/useErrorHandler.d.ts +26 -0
  21. package/dist/hooks/useErrorHandler.d.ts.map +1 -0
  22. package/dist/hooks/useToastErrorHandler.d.ts +15 -0
  23. package/dist/hooks/useToastErrorHandler.d.ts.map +1 -0
  24. package/dist/hooks/useTourEngine.d.ts +4 -0
  25. package/dist/hooks/useTourEngine.d.ts.map +1 -1
  26. package/dist/hooks/useTourHighlight.d.ts +4 -0
  27. package/dist/hooks/useTourHighlight.d.ts.map +1 -1
  28. package/dist/index.d.ts +136 -6
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.esm.js +418 -137
  31. package/dist/index.esm.js.map +1 -1
  32. package/dist/index.js +442 -156
  33. package/dist/index.js.map +1 -1
  34. package/dist/integrations/TabIntegration.d.ts.map +1 -1
  35. package/dist/types/index.d.ts +3 -0
  36. package/dist/types/index.d.ts.map +1 -1
  37. package/dist/utils/positioning.d.ts +13 -0
  38. package/dist/utils/positioning.d.ts.map +1 -1
  39. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var require$$0 = require('react');
3
+ var React = require('react');
4
4
 
5
5
  class TourStorage {
6
6
  constructor(key) {
@@ -97,6 +97,10 @@ class TourStorage {
97
97
  }
98
98
  }
99
99
 
100
+ /**
101
+ * Core tour engine that manages tour state, navigation, and lifecycle.
102
+ * Handles step progression, state persistence, and event emission.
103
+ */
100
104
  class TourEngine {
101
105
  constructor(config) {
102
106
  this.listeners = new Map();
@@ -127,6 +131,9 @@ class TourEngine {
127
131
  getConfig() {
128
132
  return { ...this.config };
129
133
  }
134
+ /**
135
+ * Starts the tour from the current step index.
136
+ */
130
137
  async start() {
131
138
  try {
132
139
  this.setState({
@@ -136,14 +143,22 @@ class TourEngine {
136
143
  });
137
144
  this.emit('tour-start', { tourId: this.config.id });
138
145
  await this.goToStep(this.state.currentStepIndex);
139
- // STOP HERE - don't auto-advance
140
146
  return;
141
147
  }
142
148
  catch (error) {
143
- console.error('Error in TourEngine.start():', error);
144
- this.handleError(error);
149
+ const errorObj = error;
150
+ console.error('Error in TourEngine.start():', errorObj);
151
+ this.handleError(errorObj);
152
+ this.setState({
153
+ isRunning: false,
154
+ isLoading: false
155
+ });
156
+ throw errorObj;
145
157
  }
146
158
  }
159
+ /**
160
+ * Advances to the next step in the tour.
161
+ */
147
162
  async next() {
148
163
  if (!this.state.isRunning) {
149
164
  return;
@@ -151,28 +166,34 @@ class TourEngine {
151
166
  try {
152
167
  const currentStep = this.getCurrentStep();
153
168
  if (!currentStep) {
154
- return;
169
+ throw new Error('No current step available for next operation');
155
170
  }
156
- // Execute after step hook
157
171
  if (currentStep.afterStep) {
158
- await currentStep.afterStep();
172
+ try {
173
+ await currentStep.afterStep();
174
+ }
175
+ catch (hookError) {
176
+ console.warn('Error in afterStep hook:', hookError);
177
+ }
159
178
  }
160
- // Mark step as completed
161
179
  this.markStepCompleted(currentStep.id);
162
- // Check if this is the last step
163
180
  if (this.state.currentStepIndex >= this.state.totalSteps - 1) {
164
181
  await this.complete();
165
182
  return;
166
183
  }
167
- // Go to next step
168
184
  const nextStepIndex = this.state.currentStepIndex + 1;
169
185
  await this.goToStep(nextStepIndex);
170
186
  }
171
187
  catch (error) {
172
- console.error('Error in TourEngine.next():', error);
173
- this.handleError(error);
188
+ const errorObj = error;
189
+ console.error('Error in TourEngine.next():', errorObj);
190
+ this.handleError(errorObj);
191
+ throw errorObj;
174
192
  }
175
193
  }
194
+ /**
195
+ * Goes back to the previous step in the tour.
196
+ */
176
197
  async previous() {
177
198
  if (!this.state.isRunning || this.state.currentStepIndex <= 0)
178
199
  return;
@@ -183,40 +204,65 @@ class TourEngine {
183
204
  this.handleError(error);
184
205
  }
185
206
  }
207
+ /**
208
+ * Navigates to a specific step by index.
209
+ */
186
210
  async goToStep(index) {
187
- if (index < 0 || index >= this.state.totalSteps)
188
- return;
211
+ if (index < 0 || index >= this.state.totalSteps) {
212
+ throw new Error(`Invalid step index: ${index}. Must be between 0 and ${this.state.totalSteps - 1}`);
213
+ }
189
214
  try {
190
215
  this.setState({ isLoading: true });
191
216
  const step = this.config.steps[index];
192
- // Execute before step hook
193
217
  if (step.beforeStep) {
194
- await step.beforeStep();
218
+ try {
219
+ await step.beforeStep();
220
+ }
221
+ catch (hookError) {
222
+ console.warn('Error in beforeStep hook:', hookError);
223
+ }
195
224
  }
196
- // Wait for element if specified
197
225
  if (step.waitForElement && step.target) {
198
- await this.waitForElement(step.target, step.waitTimeout || 5000);
226
+ try {
227
+ await this.waitForElement(step.target, step.waitTimeout || 5000);
228
+ }
229
+ catch (waitError) {
230
+ console.warn(`Element not found: ${step.target}. Continuing anyway.`);
231
+ }
199
232
  }
200
233
  this.setState({
201
234
  currentStepIndex: index,
202
235
  currentStep: step,
203
236
  isLoading: false,
204
237
  });
205
- // Save state if persistence is enabled
206
238
  if (this.config.storage?.remember) {
207
- this.storage.saveState(this.state);
239
+ try {
240
+ this.storage.saveState(this.state);
241
+ }
242
+ catch (storageError) {
243
+ console.warn('Failed to save tour state:', storageError);
244
+ }
208
245
  }
209
- // Emit step change event
210
246
  this.emit('step-change', { step, index });
211
247
  if (this.config.onStepChange) {
212
- this.config.onStepChange(step, index);
248
+ try {
249
+ this.config.onStepChange(step, index);
250
+ }
251
+ catch (callbackError) {
252
+ console.warn('Error in onStepChange callback:', callbackError);
253
+ }
213
254
  }
214
255
  }
215
256
  catch (error) {
216
257
  this.setState({ isLoading: false });
217
- this.handleError(error);
258
+ const errorObj = error;
259
+ this.handleError(errorObj);
260
+ throw errorObj;
218
261
  }
219
262
  }
263
+ /**
264
+ * Skips the current tour and marks it as skipped.
265
+ */
220
266
  async skip() {
221
267
  if (!this.state.isRunning)
222
268
  return;
@@ -230,7 +276,6 @@ class TourEngine {
230
276
  if (this.config.onSkip) {
231
277
  this.config.onSkip();
232
278
  }
233
- // Save skip state to localStorage
234
279
  if (this.config.storage?.remember) {
235
280
  this.storage.saveSkip();
236
281
  }
@@ -241,6 +286,9 @@ class TourEngine {
241
286
  this.handleError(error);
242
287
  }
243
288
  }
289
+ /**
290
+ * Completes the tour and marks it as finished.
291
+ */
244
292
  async complete() {
245
293
  try {
246
294
  this.setState({ isRunning: false, isCompleted: true });
@@ -248,7 +296,6 @@ class TourEngine {
248
296
  if (this.config.onComplete) {
249
297
  this.config.onComplete();
250
298
  }
251
- // Save completion state to localStorage
252
299
  if (this.config.storage?.remember) {
253
300
  this.storage.saveCompletion();
254
301
  }
@@ -279,11 +326,17 @@ class TourEngine {
279
326
  canGoPrevious() {
280
327
  return this.state.isRunning && !this.isFirstStep() && !this.state.isLoading;
281
328
  }
329
+ /**
330
+ * Determines if the tour should be shown based on completion/skip state.
331
+ */
282
332
  shouldShowTour() {
283
333
  if (!this.config.storage?.remember)
284
334
  return true;
285
335
  return !this.storage.isCompleted() && !this.storage.isSkipped();
286
336
  }
337
+ /**
338
+ * Resets tour state and clears localStorage.
339
+ */
287
340
  resetTourState() {
288
341
  if (this.config.storage?.remember) {
289
342
  this.storage.clearState();
@@ -330,18 +383,32 @@ class TourEngine {
330
383
  }
331
384
  }
332
385
  handleError(error) {
386
+ const errorMessage = error.message || 'Unknown error occurred';
387
+ const currentStep = this.getCurrentStep();
333
388
  this.setState({
334
- error: error.message,
389
+ error: errorMessage,
335
390
  isLoading: false,
336
391
  });
337
- this.emit('error', { error, step: this.getCurrentStep() || undefined });
392
+ this.emit('error', {
393
+ error,
394
+ step: currentStep || undefined,
395
+ tourId: this.config.id,
396
+ stepIndex: this.state.currentStepIndex,
397
+ timestamp: new Date().toISOString()
398
+ });
399
+ console.error('TourEngine Error Details:', {
400
+ message: errorMessage,
401
+ stack: error.stack,
402
+ tourId: this.config.id,
403
+ currentStep: currentStep?.id,
404
+ stepIndex: this.state.currentStepIndex,
405
+ state: this.state
406
+ });
338
407
  }
339
408
  setState(updates) {
340
409
  this.state = { ...this.state, ...updates };
341
- // Emit state change event to notify subscribers
342
410
  this.emit('state-change', this.state);
343
411
  }
344
- // Event system
345
412
  on(event, callback) {
346
413
  if (!this.listeners.has(event)) {
347
414
  this.listeners.set(event, new Set());
@@ -360,16 +427,18 @@ class TourEngine {
360
427
  callbacks.forEach(callback => callback(data));
361
428
  }
362
429
  }
430
+ /**
431
+ * Subscribes to tour state changes.
432
+ * Returns an unsubscribe function.
433
+ */
363
434
  subscribe(callback) {
364
435
  const handler = () => callback(this.getState());
365
- // Listen to all events that might change state
366
436
  this.on('step-change', handler);
367
437
  this.on('tour-start', handler);
368
438
  this.on('tour-complete', handler);
369
439
  this.on('tour-skip', handler);
370
440
  this.on('error', handler);
371
441
  this.on('state-change', handler);
372
- // Return unsubscribe function
373
442
  return () => {
374
443
  this.off('step-change', handler);
375
444
  this.off('tour-start', handler);
@@ -381,6 +450,10 @@ class TourEngine {
381
450
  }
382
451
  }
383
452
 
453
+ /**
454
+ * Manages and executes tour actions with pluggable integration support.
455
+ * Handles clicks, navigation, and custom actions through registered integrations.
456
+ */
384
457
  class TourActions {
385
458
  constructor() {
386
459
  this.integrations = new Map();
@@ -391,11 +464,12 @@ class TourActions {
391
464
  unregisterIntegration(name) {
392
465
  this.integrations.delete(name);
393
466
  }
467
+ /**
468
+ * Executes a tour action using the appropriate integration or default handler.
469
+ */
394
470
  async execute(action, element) {
395
- // Find the appropriate integration for this action
396
471
  const integration = this.findIntegration(action);
397
472
  if (!integration) {
398
- // Fallback to default action handling
399
473
  await this.executeDefault(action, element);
400
474
  return;
401
475
  }
@@ -404,7 +478,6 @@ class TourActions {
404
478
  }
405
479
  catch (error) {
406
480
  console.error(`Integration ${integration.name} failed to execute action:`, error);
407
- // Fallback to default action handling
408
481
  await this.executeDefault(action, element);
409
482
  }
410
483
  }
@@ -416,6 +489,9 @@ class TourActions {
416
489
  }
417
490
  return null;
418
491
  }
492
+ /**
493
+ * Default action handler for built-in action types.
494
+ */
419
495
  async executeDefault(action, element) {
420
496
  const delay = action.delay || 0;
421
497
  if (delay > 0) {
@@ -429,7 +505,6 @@ class TourActions {
429
505
  await this.handleNavigate(action);
430
506
  break;
431
507
  case 'highlight':
432
- // Highlighting is handled by the UI components
433
508
  break;
434
509
  case 'custom':
435
510
  if (action.handler) {
@@ -448,11 +523,8 @@ class TourActions {
448
523
  if (!targetElement) {
449
524
  throw new Error(`Click target not found: ${action.target}`);
450
525
  }
451
- // Ensure element is visible and clickable
452
526
  targetElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
453
- // Wait a bit for scroll to complete
454
527
  await this.sleep(300);
455
- // Dispatch click event
456
528
  const clickEvent = new MouseEvent('click', {
457
529
  bubbles: true,
458
530
  cancelable: true,
@@ -464,17 +536,14 @@ class TourActions {
464
536
  if (!action.target) {
465
537
  throw new Error('Navigate action requires a target URL');
466
538
  }
467
- // Check if it's a hash navigation (same page)
468
539
  if (action.target.startsWith('#')) {
469
540
  window.location.hash = action.target;
470
541
  return;
471
542
  }
472
- // Check if it's a relative path
473
543
  if (action.target.startsWith('/')) {
474
544
  window.location.pathname = action.target;
475
545
  return;
476
546
  }
477
- // Full URL navigation
478
547
  window.location.href = action.target;
479
548
  }
480
549
  sleep(ms) {
@@ -824,7 +893,7 @@ function requireReactJsxRuntime_development () {
824
893
  object.$$typeof === REACT_ELEMENT_TYPE
825
894
  );
826
895
  }
827
- var React = require$$0,
896
+ var React$1 = React,
828
897
  REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"),
829
898
  REACT_PORTAL_TYPE = Symbol.for("react.portal"),
830
899
  REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"),
@@ -840,7 +909,7 @@ function requireReactJsxRuntime_development () {
840
909
  REACT_ACTIVITY_TYPE = Symbol.for("react.activity"),
841
910
  REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"),
842
911
  ReactSharedInternals =
843
- React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
912
+ React$1.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
844
913
  hasOwnProperty = Object.prototype.hasOwnProperty,
845
914
  isArrayImpl = Array.isArray,
846
915
  createTask = console.createTask
@@ -848,15 +917,15 @@ function requireReactJsxRuntime_development () {
848
917
  : function () {
849
918
  return null;
850
919
  };
851
- React = {
920
+ React$1 = {
852
921
  react_stack_bottom_frame: function (callStackForError) {
853
922
  return callStackForError();
854
923
  }
855
924
  };
856
925
  var specialPropKeyWarningShown;
857
926
  var didWarnAboutElementRef = {};
858
- var unknownOwnerDebugStack = React.react_stack_bottom_frame.bind(
859
- React,
927
+ var unknownOwnerDebugStack = React$1.react_stack_bottom_frame.bind(
928
+ React$1,
860
929
  UnknownOwner
861
930
  )();
862
931
  var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
@@ -902,46 +971,160 @@ if (process.env.NODE_ENV === 'production') {
902
971
 
903
972
  var jsxRuntimeExports = jsxRuntime.exports;
904
973
 
974
+ function useErrorHandler(options = {}) {
975
+ const { onError, logErrors = true, retryAttempts = 0, retryDelay = 1000, } = options;
976
+ const retryCountRef = React.useRef(new Map());
977
+ const handleError = React.useCallback((error, context) => {
978
+ if (logErrors) {
979
+ console.error(`Tour Error${context ? ` in ${context}` : ''}:`, error);
980
+ }
981
+ if (onError) {
982
+ try {
983
+ onError(error, context);
984
+ }
985
+ catch (handlerError) {
986
+ console.error('Error in custom error handler:', handlerError);
987
+ }
988
+ }
989
+ }, [onError, logErrors]);
990
+ const handleAsyncError = React.useCallback(async (asyncFn, context, fallback) => {
991
+ const contextKey = context || 'unknown';
992
+ const currentRetries = retryCountRef.current.get(contextKey) || 0;
993
+ try {
994
+ const result = await asyncFn();
995
+ retryCountRef.current.delete(contextKey);
996
+ return result;
997
+ }
998
+ catch (error) {
999
+ handleError(error, context);
1000
+ if (currentRetries < retryAttempts) {
1001
+ retryCountRef.current.set(contextKey, currentRetries + 1);
1002
+ await new Promise(resolve => setTimeout(resolve, retryDelay));
1003
+ return handleAsyncError(asyncFn, context, fallback);
1004
+ }
1005
+ retryCountRef.current.delete(contextKey);
1006
+ return fallback;
1007
+ }
1008
+ }, [handleError, retryAttempts, retryDelay]);
1009
+ const wrapFunction = React.useCallback((fn, context) => {
1010
+ return ((...args) => {
1011
+ try {
1012
+ return fn(...args);
1013
+ }
1014
+ catch (error) {
1015
+ handleError(error, context);
1016
+ throw error;
1017
+ }
1018
+ });
1019
+ }, [handleError]);
1020
+ const wrapAsyncFunction = React.useCallback((fn, context) => {
1021
+ return (async (...args) => {
1022
+ try {
1023
+ return await fn(...args);
1024
+ }
1025
+ catch (error) {
1026
+ handleError(error, context);
1027
+ throw error; // Re-throw to maintain original behavior
1028
+ }
1029
+ });
1030
+ }, [handleError]);
1031
+ return {
1032
+ handleError,
1033
+ handleAsyncError,
1034
+ wrapFunction,
1035
+ wrapAsyncFunction,
1036
+ };
1037
+ }
1038
+ // Utility function for creating error-safe async operations
1039
+ function createSafeAsyncOperation(operation, options = {}) {
1040
+ const { context, fallback, onError, retryAttempts = 0, retryDelay = 1000, } = options;
1041
+ return async () => {
1042
+ let attempts = 0;
1043
+ while (attempts <= retryAttempts) {
1044
+ try {
1045
+ return await operation();
1046
+ }
1047
+ catch (error) {
1048
+ const errorObj = error;
1049
+ // Log error
1050
+ console.error(`Error in ${context || 'async operation'} (attempt ${attempts + 1}):`, errorObj);
1051
+ // Call custom error handler
1052
+ if (onError) {
1053
+ onError(errorObj);
1054
+ }
1055
+ attempts++;
1056
+ // If we've exhausted retries, return fallback
1057
+ if (attempts > retryAttempts) {
1058
+ return fallback;
1059
+ }
1060
+ // Wait before retrying
1061
+ if (retryDelay > 0) {
1062
+ await new Promise(resolve => setTimeout(resolve, retryDelay));
1063
+ }
1064
+ }
1065
+ }
1066
+ return fallback;
1067
+ };
1068
+ }
1069
+ // Error boundary hook for functional components
1070
+ function useErrorBoundary() {
1071
+ const handleError = React.useCallback((error, _errorInfo) => {
1072
+ // This will be caught by the nearest ErrorBoundary
1073
+ throw error;
1074
+ }, []);
1075
+ return { handleError };
1076
+ }
1077
+
1078
+ /**
1079
+ * Hook that creates and manages a tour engine instance.
1080
+ * Provides tour control methods and state management with error handling.
1081
+ */
905
1082
  function useTourEngine(config) {
906
- const actions = require$$0.useMemo(() => new TourActions(), []);
907
- const engine = require$$0.useMemo(() => {
1083
+ // Use regular error handler to avoid ToastProvider dependency issues
1084
+ const errorHandler = useErrorHandler({
1085
+ onError: (error, context) => {
1086
+ console.error(`Tour Engine Error in ${context}:`, error);
1087
+ },
1088
+ retryAttempts: 1,
1089
+ retryDelay: 500,
1090
+ });
1091
+ const { handleAsyncError } = errorHandler;
1092
+ const actions = React.useMemo(() => new TourActions(), []);
1093
+ const engine = React.useMemo(() => {
908
1094
  const tourEngine = new TourEngine(config);
909
1095
  return tourEngine;
910
1096
  }, [config]);
911
- const [state, setState] = require$$0.useState(engine.getState());
912
- require$$0.useEffect(() => {
1097
+ const [state, setState] = React.useState(engine.getState());
1098
+ React.useEffect(() => {
913
1099
  const unsubscribe = engine.subscribe(setState);
914
1100
  return unsubscribe;
915
1101
  }, [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 () => {
1102
+ const start = React.useCallback(async () => {
1103
+ await handleAsyncError(() => engine.start(), 'tour start');
1104
+ }, [engine, handleAsyncError]);
1105
+ const stop = React.useCallback(async () => {
925
1106
  await engine.stop();
926
1107
  }, [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 {
1108
+ const next = React.useCallback(async () => {
1109
+ await handleAsyncError(async () => {
1110
+ const currentStep = engine.getCurrentStep();
1111
+ if (currentStep?.action) {
1112
+ // Execute the step action first
1113
+ await actions.execute(currentStep.action);
1114
+ }
1115
+ await engine.next();
1116
+ }, 'tour next');
1117
+ }, [engine, actions, handleAsyncError]);
1118
+ const previous = React.useCallback(async () => {
1119
+ await handleAsyncError(() => engine.previous(), 'tour previous');
1120
+ }, [engine, handleAsyncError]);
1121
+ const skip = React.useCallback(async () => {
1122
+ await handleAsyncError(() => engine.skip(), 'tour skip');
1123
+ }, [engine, handleAsyncError]);
1124
+ const goToStep = React.useCallback(async (index) => {
1125
+ await handleAsyncError(() => engine.goToStep(index), `tour goToStep(${index})`);
1126
+ }, [engine, handleAsyncError]);
1127
+ const memoizedReturn = React.useMemo(() => ({
945
1128
  state,
946
1129
  start,
947
1130
  stop,
@@ -956,10 +1139,11 @@ function useTourEngine(config) {
956
1139
  currentStep: engine.getCurrentStep(),
957
1140
  engine,
958
1141
  actions,
959
- };
1142
+ }), [state, start, stop, next, previous, skip, goToStep, engine, actions]);
1143
+ return memoizedReturn;
960
1144
  }
961
1145
 
962
- const TourContext = require$$0.createContext(null);
1146
+ const TourContext = React.createContext(null);
963
1147
  const defaultTheme = {
964
1148
  primaryColor: '#3b82f6',
965
1149
  backgroundColor: '#ffffff',
@@ -985,24 +1169,35 @@ const defaultTheme = {
985
1169
  maxWidth: '384px',
986
1170
  },
987
1171
  };
988
- function TourProvider({ config, children }) {
1172
+ /**
1173
+ * Main provider component that initializes the tour system and provides context.
1174
+ * Wraps the application with tour functionality.
1175
+ */
1176
+ const TourProvider = React.memo(function TourProvider({ config, children }) {
989
1177
  const tourEngine = useTourEngine(config);
990
- const theme = { ...defaultTheme, ...config.theme };
991
- const contextValue = {
1178
+ const theme = React.useMemo(() => ({ ...defaultTheme, ...config.theme }), [config.theme]);
1179
+ const contextValue = React.useMemo(() => ({
992
1180
  ...tourEngine,
993
1181
  config,
994
1182
  theme,
995
- };
1183
+ }), [tourEngine, config, theme]);
996
1184
  return (jsxRuntimeExports.jsx(TourContext.Provider, { value: contextValue, children: children }));
997
- }
1185
+ });
1186
+ /**
1187
+ * Hook to access tour functionality and state.
1188
+ * Must be used within a TourProvider.
1189
+ */
998
1190
  function useTour() {
999
- const context = require$$0.useContext(TourContext);
1191
+ const context = React.useContext(TourContext);
1000
1192
  if (!context) {
1001
1193
  throw new Error('useTour must be used within a TourProvider');
1002
1194
  }
1003
1195
  return context;
1004
1196
  }
1005
1197
 
1198
+ /**
1199
+ * Gets the absolute position of an element relative to the document.
1200
+ */
1006
1201
  function getElementPosition(element) {
1007
1202
  const rect = element.getBoundingClientRect();
1008
1203
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
@@ -1016,6 +1211,10 @@ function getElementPosition(element) {
1016
1211
  bottom: rect.bottom + scrollTop,
1017
1212
  };
1018
1213
  }
1214
+ /**
1215
+ * Calculates the optimal position for a popover relative to a target element.
1216
+ * Falls back to alternative placements if the preferred placement doesn't fit.
1217
+ */
1019
1218
  function calculatePopoverPosition(targetElement, popoverElement, preferredPlacement = 'top') {
1020
1219
  const targetPos = getElementPosition(targetElement);
1021
1220
  const popoverRect = popoverElement.getBoundingClientRect();
@@ -1025,7 +1224,7 @@ function calculatePopoverPosition(targetElement, popoverElement, preferredPlacem
1025
1224
  scrollTop: window.pageYOffset || document.documentElement.scrollTop,
1026
1225
  scrollLeft: window.pageXOffset || document.documentElement.scrollLeft,
1027
1226
  };
1028
- const spacing = 12; // Gap between target and popover
1227
+ const spacing = 12;
1029
1228
  const positions = {
1030
1229
  top: {
1031
1230
  top: targetPos.top - popoverRect.height - spacing,
@@ -1053,12 +1252,12 @@ function calculatePopoverPosition(targetElement, popoverElement, preferredPlacem
1053
1252
  placement: 'center',
1054
1253
  },
1055
1254
  };
1056
- // Check if preferred placement fits in viewport
1255
+ // Try preferred placement first
1057
1256
  const preferred = positions[preferredPlacement];
1058
1257
  if (isPositionInViewport(preferred, popoverRect, viewport)) {
1059
1258
  return preferred;
1060
1259
  }
1061
- // Try other placements in order of preference
1260
+ // Try fallback placements in order of preference
1062
1261
  const fallbackOrder = ['bottom', 'top', 'right', 'left', 'center'];
1063
1262
  for (const placement of fallbackOrder) {
1064
1263
  if (placement === preferredPlacement)
@@ -1068,16 +1267,18 @@ function calculatePopoverPosition(targetElement, popoverElement, preferredPlacem
1068
1267
  return position;
1069
1268
  }
1070
1269
  }
1071
- // If nothing fits, use center as fallback
1072
1270
  return positions.center;
1073
1271
  }
1074
1272
  function isPositionInViewport(position, popoverRect, viewport) {
1075
- const margin = 16; // Minimum margin from viewport edges
1273
+ const margin = 16;
1076
1274
  return (position.left >= viewport.scrollLeft + margin &&
1077
1275
  position.left + popoverRect.width <= viewport.scrollLeft + viewport.width - margin &&
1078
1276
  position.top >= viewport.scrollTop + margin &&
1079
1277
  position.top + popoverRect.height <= viewport.scrollTop + viewport.height - margin);
1080
1278
  }
1279
+ /**
1280
+ * Smoothly scrolls an element into view.
1281
+ */
1081
1282
  function scrollToElement(element, behavior = 'smooth') {
1082
1283
  element.scrollIntoView({
1083
1284
  behavior,
@@ -1085,6 +1286,9 @@ function scrollToElement(element, behavior = 'smooth') {
1085
1286
  inline: 'center',
1086
1287
  });
1087
1288
  }
1289
+ /**
1290
+ * Checks if an element is currently visible in the viewport.
1291
+ */
1088
1292
  function isElementInViewport(element) {
1089
1293
  const rect = element.getBoundingClientRect();
1090
1294
  return (rect.top >= 0 &&
@@ -1099,17 +1303,22 @@ function getViewportCenter() {
1099
1303
  };
1100
1304
  }
1101
1305
 
1306
+ /**
1307
+ * Hook that manages element highlighting for tour steps.
1308
+ * Finds target elements, positions highlights, and handles dynamic content.
1309
+ */
1102
1310
  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(() => {
1311
+ const [targetElement, setTargetElement] = React.useState(null);
1312
+ const [highlightStyle, setHighlightStyle] = React.useState({});
1313
+ const [isVisible, setIsVisible] = React.useState(false);
1314
+ const observerRef = React.useRef(null);
1315
+ React.useEffect(() => {
1108
1316
  if (!step?.target) {
1109
1317
  setTargetElement(null);
1110
1318
  setIsVisible(false);
1111
1319
  return;
1112
1320
  }
1321
+ // Find target element and update highlight styling
1113
1322
  const findAndHighlightElement = () => {
1114
1323
  const element = step.highlight?.element ||
1115
1324
  document.querySelector(step.target);
@@ -1117,7 +1326,6 @@ function useTourHighlight(step) {
1117
1326
  setTargetElement(element);
1118
1327
  updateHighlightStyle(element, step.highlight);
1119
1328
  setIsVisible(true);
1120
- // Scroll to element if not in viewport
1121
1329
  if (!isElementInViewport(element)) {
1122
1330
  scrollToElement(element);
1123
1331
  }
@@ -1127,9 +1335,8 @@ function useTourHighlight(step) {
1127
1335
  setIsVisible(false);
1128
1336
  }
1129
1337
  };
1130
- // Initial attempt to find element
1131
1338
  findAndHighlightElement();
1132
- // Set up mutation observer to watch for DOM changes
1339
+ // Watch for DOM changes if element not found initially
1133
1340
  if (!targetElement && step.waitForElement !== false) {
1134
1341
  observerRef.current = new MutationObserver(() => {
1135
1342
  findAndHighlightElement();
@@ -1148,8 +1355,8 @@ function useTourHighlight(step) {
1148
1355
  }
1149
1356
  };
1150
1357
  }, [step?.target, step?.highlight, step?.waitForElement, targetElement]);
1151
- // Update highlight position when element moves (e.g., during animations)
1152
- require$$0.useEffect(() => {
1358
+ // Update highlight position when element moves
1359
+ React.useEffect(() => {
1153
1360
  if (!targetElement || !isVisible)
1154
1361
  return;
1155
1362
  const updatePosition = () => {
@@ -1159,7 +1366,6 @@ function useTourHighlight(step) {
1159
1366
  const handleResize = () => updatePosition();
1160
1367
  window.addEventListener('scroll', handleScroll, { passive: true });
1161
1368
  window.addEventListener('resize', handleResize, { passive: true });
1162
- // Use ResizeObserver to watch for element size changes
1163
1369
  let resizeObserver = null;
1164
1370
  if (window.ResizeObserver) {
1165
1371
  resizeObserver = new ResizeObserver(updatePosition);
@@ -1173,6 +1379,9 @@ function useTourHighlight(step) {
1173
1379
  }
1174
1380
  };
1175
1381
  }, [targetElement, isVisible, step?.highlight]);
1382
+ /**
1383
+ * Updates the highlight style based on element position and configuration.
1384
+ */
1176
1385
  const updateHighlightStyle = (element, config) => {
1177
1386
  const position = getElementPosition(element);
1178
1387
  const padding = config?.padding || 4;
@@ -1206,13 +1415,10 @@ function useTourHighlight(step) {
1206
1415
  };
1207
1416
  }
1208
1417
 
1209
- function TourOverlay({ className }) {
1418
+ const TourOverlay = React.memo(function TourOverlay({ className }) {
1210
1419
  const { state, theme, stop } = useTour();
1211
1420
  const { targetElement, highlightStyle, isVisible } = useTourHighlight(state.currentStep);
1212
- if (!state.isRunning || !state.currentStep) {
1213
- return null;
1214
- }
1215
- const overlayStyle = {
1421
+ const overlayStyle = React.useMemo(() => ({
1216
1422
  position: 'fixed',
1217
1423
  top: 0,
1218
1424
  left: 0,
@@ -1222,12 +1428,15 @@ function TourOverlay({ className }) {
1222
1428
  opacity: theme.overlay?.opacity || 0.5,
1223
1429
  zIndex: (theme.zIndex || 9999) - 1,
1224
1430
  pointerEvents: 'auto',
1225
- };
1226
- const handleOverlayClick = () => {
1431
+ }), [theme.overlay?.backgroundColor, theme.overlay?.opacity, theme.zIndex]);
1432
+ const handleOverlayClick = React.useCallback(() => {
1227
1433
  if (state.currentStep?.canSkip !== false) {
1228
1434
  stop();
1229
1435
  }
1230
- };
1436
+ }, [state.currentStep?.canSkip, stop]);
1437
+ if (!state.isRunning || !state.currentStep) {
1438
+ return null;
1439
+ }
1231
1440
  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
1441
  @keyframes tour-highlight-pulse {
1233
1442
  0%, 100% {
@@ -1257,38 +1466,24 @@ function TourOverlay({ className }) {
1257
1466
  animation: tour-fade-in 0.3s ease-out;
1258
1467
  }
1259
1468
  ` })] }));
1260
- }
1469
+ });
1261
1470
 
1262
1471
  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
1472
 
1264
- function TourPopover({ className }) {
1473
+ const TourPopover = React.memo(function TourPopover({ className }) {
1265
1474
  const { state, theme, next, previous, skip, stop, isFirstStep, isLastStep, canGoNext, canGoPrevious } = useTour();
1266
1475
  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(() => {
1476
+ const popoverRef = React.useRef(null);
1477
+ const [position, setPosition] = React.useState({ top: 0, left: 0, placement: 'top' });
1478
+ const updatePosition = React.useCallback(() => {
1270
1479
  if (!popoverRef.current || !targetElement || !state.currentStep)
1271
1480
  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
- };
1481
+ const newPosition = calculatePopoverPosition(targetElement, popoverRef.current, state.currentStep.placement || 'top');
1482
+ setPosition(newPosition);
1285
1483
  }, [targetElement, state.currentStep]);
1286
- if (!state.isRunning || !state.currentStep) {
1287
- return null;
1288
- }
1289
1484
  const step = state.currentStep;
1290
- const popoverConfig = step.popover || {};
1291
- const popoverStyle = {
1485
+ const popoverConfig = React.useMemo(() => step?.popover || {}, [step?.popover]);
1486
+ const popoverStyle = React.useMemo(() => ({
1292
1487
  position: 'absolute',
1293
1488
  top: position.top,
1294
1489
  left: position.left,
@@ -1313,23 +1508,37 @@ function TourPopover({ className }) {
1313
1508
  color: theme.textColor || '#1f2937',
1314
1509
  zIndex: theme.zIndex || 9999,
1315
1510
  animation: 'tour-fade-in 0.3s ease-out',
1316
- };
1317
- const handleNext = async () => {
1511
+ }), [position.top, position.left, theme]);
1512
+ const handleNext = React.useCallback(async () => {
1318
1513
  if (canGoNext || isLastStep) {
1319
1514
  await next();
1320
1515
  }
1321
- };
1322
- const handlePrevious = async () => {
1516
+ }, [canGoNext, isLastStep, next]);
1517
+ const handlePrevious = React.useCallback(async () => {
1323
1518
  if (canGoPrevious) {
1324
1519
  await previous();
1325
1520
  }
1326
- };
1327
- const handleSkip = async () => {
1521
+ }, [canGoPrevious, previous]);
1522
+ const handleSkip = React.useCallback(async () => {
1328
1523
  await skip();
1329
- };
1330
- const handleClose = async () => {
1524
+ }, [skip]);
1525
+ const handleClose = React.useCallback(async () => {
1331
1526
  await stop();
1332
- };
1527
+ }, [stop]);
1528
+ React.useEffect(() => {
1529
+ updatePosition();
1530
+ const handleResize = () => updatePosition();
1531
+ const handleScroll = () => updatePosition();
1532
+ window.addEventListener('resize', handleResize);
1533
+ window.addEventListener('scroll', handleScroll, { passive: true });
1534
+ return () => {
1535
+ window.removeEventListener('resize', handleResize);
1536
+ window.removeEventListener('scroll', handleScroll);
1537
+ };
1538
+ }, [updatePosition]);
1539
+ if (!state.isRunning || !state.currentStep) {
1540
+ return null;
1541
+ }
1333
1542
  return (jsxRuntimeExports.jsxs("div", { ref: popoverRef, style: {
1334
1543
  ...popoverStyle,
1335
1544
  pointerEvents: 'auto',
@@ -1364,22 +1573,22 @@ function TourPopover({ className }) {
1364
1573
  borderRadius: '12px',
1365
1574
  fontSize: '12px',
1366
1575
  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: {
1576
+ }, children: [state.currentStepIndex + 1, " of ", state.totalSteps] }))] }), jsxRuntimeExports.jsxs("div", { style: { padding: '16px 20px' }, children: [(popoverConfig.title || step?.title) && (jsxRuntimeExports.jsx("h3", { style: {
1368
1577
  margin: '0 0 8px 0',
1369
1578
  fontSize: '16px',
1370
1579
  fontWeight: '600',
1371
1580
  color: theme.textColor || '#1f2937',
1372
- }, children: popoverConfig.title || step.title })), jsxRuntimeExports.jsx("div", { style: {
1581
+ }, children: popoverConfig.title || step?.title })), jsxRuntimeExports.jsx("div", { style: {
1373
1582
  margin: '0 0 16px 0',
1374
1583
  lineHeight: '1.5',
1375
1584
  color: theme.textColor || '#374151',
1376
- }, children: popoverConfig.content || step.content })] }), jsxRuntimeExports.jsxs("div", { style: {
1585
+ }, children: popoverConfig.content || step?.content })] }), jsxRuntimeExports.jsxs("div", { style: {
1377
1586
  display: 'flex',
1378
1587
  justifyContent: 'space-between',
1379
1588
  alignItems: 'center',
1380
1589
  padding: '0 20px 20px 20px',
1381
1590
  gap: '12px',
1382
- }, children: [(popoverConfig.showSkip !== false && step.canSkip !== false) && (jsxRuntimeExports.jsx("button", { onClick: (_e) => {
1591
+ }, children: [(popoverConfig.showSkip !== false && step?.canSkip !== false) && (jsxRuntimeExports.jsx("button", { onClick: (_e) => {
1383
1592
  handleSkip();
1384
1593
  }, style: {
1385
1594
  background: 'none',
@@ -1462,7 +1671,7 @@ function TourPopover({ className }) {
1462
1671
  transform: 'rotate(45deg)',
1463
1672
  ...getArrowPosition(position.placement),
1464
1673
  }, "data-tour-arrow": true }))] }));
1465
- }
1674
+ });
1466
1675
  function getArrowPosition(placement) {
1467
1676
  switch (placement) {
1468
1677
  case 'top':
@@ -1502,13 +1711,92 @@ function getArrowPosition(placement) {
1502
1711
  }
1503
1712
  }
1504
1713
 
1505
- function TourRunner({ className }) {
1714
+ class ErrorBoundary extends React.Component {
1715
+ constructor(props) {
1716
+ super(props);
1717
+ this.retryTimeoutId = null;
1718
+ this.retry = () => {
1719
+ this.setState({
1720
+ hasError: false,
1721
+ error: null,
1722
+ errorInfo: null,
1723
+ });
1724
+ };
1725
+ this.state = {
1726
+ hasError: false,
1727
+ error: null,
1728
+ errorInfo: null,
1729
+ };
1730
+ }
1731
+ static getDerivedStateFromError(error) {
1732
+ return {
1733
+ hasError: true,
1734
+ error,
1735
+ };
1736
+ }
1737
+ componentDidCatch(error, errorInfo) {
1738
+ this.setState({
1739
+ error,
1740
+ errorInfo,
1741
+ });
1742
+ if (this.props.onError) {
1743
+ this.props.onError(error, errorInfo);
1744
+ }
1745
+ console.error('Tour ErrorBoundary caught an error:', error, errorInfo);
1746
+ }
1747
+ componentWillUnmount() {
1748
+ if (this.retryTimeoutId) {
1749
+ clearTimeout(this.retryTimeoutId);
1750
+ }
1751
+ }
1752
+ render() {
1753
+ if (this.state.hasError && this.state.error && this.state.errorInfo) {
1754
+ if (this.props.fallback) {
1755
+ return this.props.fallback(this.state.error, this.state.errorInfo, this.retry);
1756
+ }
1757
+ return (jsxRuntimeExports.jsxs("div", { style: {
1758
+ padding: '20px',
1759
+ margin: '20px',
1760
+ border: '2px solid #ff6b6b',
1761
+ borderRadius: '8px',
1762
+ backgroundColor: '#fff5f5',
1763
+ color: '#c92a2a',
1764
+ fontFamily: 'system-ui, sans-serif'
1765
+ }, children: [jsxRuntimeExports.jsx("h2", { style: { margin: '0 0 10px 0', fontSize: '18px' }, children: "Something went wrong" }), jsxRuntimeExports.jsxs("details", { style: { marginBottom: '15px' }, children: [jsxRuntimeExports.jsx("summary", { style: { cursor: 'pointer', fontWeight: 'bold' }, children: "Error Details" }), jsxRuntimeExports.jsxs("pre", { style: {
1766
+ marginTop: '10px',
1767
+ padding: '10px',
1768
+ backgroundColor: '#f8f8f8',
1769
+ borderRadius: '4px',
1770
+ fontSize: '12px',
1771
+ overflow: 'auto'
1772
+ }, children: [this.state.error.message, this.state.error.stack && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: ['\n\n', this.state.error.stack] })), this.state.errorInfo.componentStack && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: ['\n\nComponent Stack:', this.state.errorInfo.componentStack] }))] })] }), jsxRuntimeExports.jsx("button", { onClick: this.retry, style: {
1773
+ padding: '8px 16px',
1774
+ backgroundColor: '#228be6',
1775
+ color: 'white',
1776
+ border: 'none',
1777
+ borderRadius: '4px',
1778
+ cursor: 'pointer',
1779
+ fontSize: '14px'
1780
+ }, children: "Try Again" })] }));
1781
+ }
1782
+ return this.props.children;
1783
+ }
1784
+ }
1785
+ function withErrorBoundary(Component, errorBoundaryProps) {
1786
+ const WrappedComponent = (props) => (jsxRuntimeExports.jsx(ErrorBoundary, { ...errorBoundaryProps, children: jsxRuntimeExports.jsx(Component, { ...props }) }));
1787
+ WrappedComponent.displayName = `withErrorBoundary(${Component.displayName || Component.name})`;
1788
+ return WrappedComponent;
1789
+ }
1790
+
1791
+ const TourRunner = React.memo(function TourRunner({ className }) {
1506
1792
  const { state } = useTour();
1507
1793
  if (!state.isRunning) {
1508
1794
  return null;
1509
1795
  }
1510
- return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(TourOverlay, { className: className }), jsxRuntimeExports.jsx(TourPopover, { className: className })] }));
1511
- }
1796
+ return (jsxRuntimeExports.jsxs(ErrorBoundary, { onError: (error, errorInfo) => {
1797
+ console.error('TourRunner error:', error, errorInfo);
1798
+ }, children: [jsxRuntimeExports.jsx(TourOverlay, { className: className }), jsxRuntimeExports.jsx(TourPopover, { className: className })] }));
1799
+ });
1512
1800
 
1513
1801
  class TabIntegration {
1514
1802
  constructor() {
@@ -1525,33 +1813,26 @@ class TabIntegration {
1525
1813
  if (!targetElement) {
1526
1814
  throw new Error(`Tab element not found: ${action.target}`);
1527
1815
  }
1528
- // Handle different tab implementations
1529
1816
  const tabValue = typeof action.value === 'string' ? action.value : undefined;
1530
1817
  await this.handleTabClick(targetElement, tabValue);
1531
1818
  }
1532
1819
  async handleTabClick(tabElement, tabValue) {
1533
- // Check for common tab patterns
1534
- // 1. Radix UI Tabs
1535
1820
  if (this.isRadixTab(tabElement)) {
1536
1821
  await this.handleRadixTab(tabElement);
1537
1822
  return;
1538
1823
  }
1539
- // 2. Material UI Tabs
1540
1824
  if (this.isMaterialUITab(tabElement)) {
1541
1825
  await this.handleMaterialUITab(tabElement);
1542
1826
  return;
1543
1827
  }
1544
- // 3. React Router tabs (links)
1545
1828
  if (this.isRouterTab(tabElement)) {
1546
1829
  await this.handleRouterTab(tabElement);
1547
1830
  return;
1548
1831
  }
1549
- // 4. Custom tabs with data attributes
1550
1832
  if (this.isCustomTab(tabElement)) {
1551
1833
  await this.handleCustomTab(tabElement, tabValue);
1552
1834
  return;
1553
1835
  }
1554
- // 5. Generic button/clickable tab
1555
1836
  await this.handleGenericTab(tabElement);
1556
1837
  }
1557
1838
  isRadixTab(element) {
@@ -2095,6 +2376,7 @@ class NavigationIntegration {
2095
2376
  }
2096
2377
  }
2097
2378
 
2379
+ exports.ErrorBoundary = ErrorBoundary;
2098
2380
  exports.NavigationIntegration = NavigationIntegration;
2099
2381
  exports.TabIntegration = TabIntegration;
2100
2382
  exports.TourActions = TourActions;
@@ -2106,11 +2388,15 @@ exports.TourRunner = TourRunner;
2106
2388
  exports.TourStorage = TourStorage;
2107
2389
  exports.WizardIntegration = WizardIntegration;
2108
2390
  exports.calculatePopoverPosition = calculatePopoverPosition;
2391
+ exports.createSafeAsyncOperation = createSafeAsyncOperation;
2109
2392
  exports.getElementPosition = getElementPosition;
2110
2393
  exports.getViewportCenter = getViewportCenter;
2111
2394
  exports.isElementInViewport = isElementInViewport;
2112
2395
  exports.scrollToElement = scrollToElement;
2396
+ exports.useErrorBoundary = useErrorBoundary;
2397
+ exports.useErrorHandler = useErrorHandler;
2113
2398
  exports.useTour = useTour;
2114
2399
  exports.useTourEngine = useTourEngine;
2115
2400
  exports.useTourHighlight = useTourHighlight;
2401
+ exports.withErrorBoundary = withErrorBoundary;
2116
2402
  //# sourceMappingURL=index.js.map