@flowsterix/react 0.9.0 → 0.10.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/dist/index.mjs CHANGED
@@ -25,12 +25,12 @@ import {
25
25
  serializeVersion
26
26
  } from "@flowsterix/core";
27
27
  import {
28
- createContext as createContext3,
29
- useCallback,
30
- useContext as useContext3,
31
- useEffect as useEffect2,
32
- useMemo as useMemo2,
33
- useRef,
28
+ createContext as createContext4,
29
+ useCallback as useCallback2,
30
+ useContext as useContext4,
31
+ useEffect as useEffect3,
32
+ useMemo as useMemo3,
33
+ useRef as useRef3,
34
34
  useState as useState2
35
35
  } from "react";
36
36
 
@@ -63,10 +63,162 @@ function useTourLabels() {
63
63
  return useContext(LabelsContext);
64
64
  }
65
65
 
66
+ // src/dialog/DialogRegistryContext.tsx
67
+ import {
68
+ createContext as createContext2,
69
+ useCallback,
70
+ useContext as useContext2,
71
+ useMemo,
72
+ useRef
73
+ } from "react";
74
+ import { jsx } from "react/jsx-runtime";
75
+ var DialogRegistryContext = createContext2(void 0);
76
+ var DialogRegistryProvider = ({ children }) => {
77
+ const controllersRef = useRef(/* @__PURE__ */ new Map());
78
+ const register = useCallback(
79
+ (dialogId, controller) => {
80
+ controllersRef.current.set(dialogId, controller);
81
+ },
82
+ []
83
+ );
84
+ const unregister = useCallback((dialogId) => {
85
+ controllersRef.current.delete(dialogId);
86
+ }, []);
87
+ const getController = useCallback((dialogId) => {
88
+ return controllersRef.current.get(dialogId);
89
+ }, []);
90
+ const isRegistered = useCallback((dialogId) => {
91
+ return controllersRef.current.has(dialogId);
92
+ }, []);
93
+ const value = useMemo(
94
+ () => ({
95
+ register,
96
+ unregister,
97
+ getController,
98
+ isRegistered
99
+ }),
100
+ [register, unregister, getController, isRegistered]
101
+ );
102
+ return /* @__PURE__ */ jsx(DialogRegistryContext.Provider, { value, children });
103
+ };
104
+ var useDialogRegistry = () => {
105
+ const context = useContext2(DialogRegistryContext);
106
+ if (!context) {
107
+ throw new Error(
108
+ "useDialogRegistry must be used within a DialogRegistryProvider"
109
+ );
110
+ }
111
+ return context;
112
+ };
113
+ var useDialogRegistryOptional = () => {
114
+ return useContext2(DialogRegistryContext);
115
+ };
116
+
117
+ // src/hooks/useDialogAutomation.ts
118
+ import { useEffect, useRef as useRef2 } from "react";
119
+ var resolveAutoOpen = (config) => {
120
+ if (!config) return { onEnter: true, onResume: true };
121
+ const { autoOpen } = config;
122
+ if (autoOpen === false) return { onEnter: false, onResume: false };
123
+ if (autoOpen === true || autoOpen === void 0) {
124
+ return { onEnter: true, onResume: true };
125
+ }
126
+ return {
127
+ onEnter: autoOpen.onEnter ?? true,
128
+ onResume: autoOpen.onResume ?? true
129
+ };
130
+ };
131
+ var useDialogAutomation = (params) => {
132
+ const { flow, state, events, registry, onDialogNotMounted } = params;
133
+ const previousDialogIdRef = useRef2(void 0);
134
+ useEffect(() => {
135
+ if (!events || !flow || !registry) return;
136
+ const unsubscribeEnter = events.on("stepEnter", (payload) => {
137
+ const step = payload.currentStep;
138
+ const dialogId = step.dialogId;
139
+ const previousDialogId = previousDialogIdRef.current;
140
+ if (previousDialogId && previousDialogId !== dialogId && flow.dialogs?.[previousDialogId]) {
141
+ const config = flow.dialogs[previousDialogId];
142
+ const autoClose = config.autoClose ?? "differentDialog";
143
+ if (autoClose === "always" || autoClose === "differentDialog") {
144
+ const controller = registry.getController(previousDialogId);
145
+ if (controller) {
146
+ requestAnimationFrame(() => {
147
+ controller.close();
148
+ });
149
+ }
150
+ }
151
+ }
152
+ if (dialogId && flow.dialogs?.[dialogId]) {
153
+ const config = flow.dialogs[dialogId];
154
+ const autoOpenConfig = resolveAutoOpen(config);
155
+ const isResume = payload.reason === "resume";
156
+ const shouldAutoOpen = isResume ? autoOpenConfig.onResume : autoOpenConfig.onEnter;
157
+ if (shouldAutoOpen) {
158
+ const controller = registry.getController(dialogId);
159
+ if (controller) {
160
+ requestAnimationFrame(() => {
161
+ controller.open();
162
+ });
163
+ } else if (onDialogNotMounted) {
164
+ onDialogNotMounted(dialogId, step.id);
165
+ }
166
+ }
167
+ }
168
+ previousDialogIdRef.current = dialogId;
169
+ });
170
+ const unsubscribeExit = events.on("stepExit", (payload) => {
171
+ const step = payload.previousStep;
172
+ const dialogId = step.dialogId;
173
+ const nextStep = payload.currentStep;
174
+ if (nextStep?.dialogId === dialogId) return;
175
+ if (dialogId && flow.dialogs?.[dialogId]) {
176
+ const config = flow.dialogs[dialogId];
177
+ const autoClose = config.autoClose ?? "differentDialog";
178
+ if (autoClose === "never") return;
179
+ const controller = registry.getController(dialogId);
180
+ if (controller) {
181
+ requestAnimationFrame(() => {
182
+ controller.close();
183
+ });
184
+ }
185
+ }
186
+ });
187
+ const handleFlowEnd = () => {
188
+ const dialogId = previousDialogIdRef.current;
189
+ if (dialogId && flow.dialogs?.[dialogId]) {
190
+ const config = flow.dialogs[dialogId];
191
+ const autoClose = config.autoClose ?? "differentDialog";
192
+ if (autoClose !== "never") {
193
+ const controller = registry.getController(dialogId);
194
+ controller?.close();
195
+ }
196
+ }
197
+ previousDialogIdRef.current = void 0;
198
+ };
199
+ const unsubscribePause = events.on("flowPause", handleFlowEnd);
200
+ const unsubscribeCancel = events.on("flowCancel", handleFlowEnd);
201
+ const unsubscribeComplete = events.on("flowComplete", handleFlowEnd);
202
+ return () => {
203
+ unsubscribeEnter();
204
+ unsubscribeExit();
205
+ unsubscribePause();
206
+ unsubscribeCancel();
207
+ unsubscribeComplete();
208
+ };
209
+ }, [events, flow, registry, onDialogNotMounted]);
210
+ useEffect(() => {
211
+ if (!flow || !state || state.status !== "running") return;
212
+ if (state.stepIndex < 0 || state.stepIndex >= flow.steps.length) return;
213
+ const currentStep = flow.steps[state.stepIndex];
214
+ previousDialogIdRef.current = currentStep.dialogId;
215
+ }, [flow, state]);
216
+ };
217
+
66
218
  // src/motion/animationAdapter.tsx
67
219
  import { motion } from "motion/react";
68
- import { createContext as createContext2, useContext as useContext2, useEffect, useMemo, useState } from "react";
69
- import { jsx } from "react/jsx-runtime";
220
+ import { createContext as createContext3, useContext as useContext3, useEffect as useEffect2, useMemo as useMemo2, useState } from "react";
221
+ import { jsx as jsx2 } from "react/jsx-runtime";
70
222
  var defaultAdapter = {
71
223
  components: {
72
224
  MotionDiv: motion.div,
@@ -109,16 +261,16 @@ var defaultAdapter = {
109
261
  }
110
262
  }
111
263
  };
112
- var AnimationAdapterContext = createContext2(defaultAdapter);
264
+ var AnimationAdapterContext = createContext3(defaultAdapter);
113
265
  var AnimationAdapterProvider = ({
114
266
  adapter,
115
267
  children
116
268
  }) => {
117
- const value = useMemo(() => adapter ?? defaultAdapter, [adapter]);
118
- return /* @__PURE__ */ jsx(AnimationAdapterContext.Provider, { value, children });
269
+ const value = useMemo2(() => adapter ?? defaultAdapter, [adapter]);
270
+ return /* @__PURE__ */ jsx2(AnimationAdapterContext.Provider, { value, children });
119
271
  };
120
272
  var useAnimationAdapter = () => {
121
- return useContext2(AnimationAdapterContext);
273
+ return useContext3(AnimationAdapterContext);
122
274
  };
123
275
  var defaultAnimationAdapter = defaultAdapter;
124
276
  var reducedMotionAnimationAdapter = {
@@ -162,7 +314,7 @@ var usePreferredAnimationAdapter = (options) => {
162
314
  if (!enabled || typeof window === "undefined") return false;
163
315
  return window.matchMedia(REDUCED_MOTION_QUERY).matches;
164
316
  });
165
- useEffect(() => {
317
+ useEffect2(() => {
166
318
  if (!enabled || typeof window === "undefined") return;
167
319
  const mediaQuery = window.matchMedia(REDUCED_MOTION_QUERY);
168
320
  const handleChange = (event) => {
@@ -179,11 +331,11 @@ var usePreferredAnimationAdapter = (options) => {
179
331
  };
180
332
 
181
333
  // src/context.tsx
182
- import { jsx as jsx2 } from "react/jsx-runtime";
183
- var TourContext = createContext3(void 0);
334
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
335
+ var TourContext = createContext4(void 0);
184
336
  var DEFAULT_STORAGE_PREFIX = "tour";
185
337
  var useFlowMap = (flows) => {
186
- return useMemo2(() => {
338
+ return useMemo3(() => {
187
339
  const map = /* @__PURE__ */ new Map();
188
340
  for (const flow of flows) {
189
341
  map.set(flow.id, flow);
@@ -207,17 +359,17 @@ var TourProvider = ({
207
359
  labels: labelsProp,
208
360
  onVersionMismatch
209
361
  }) => {
210
- const mergedLabels = useMemo2(
362
+ const mergedLabels = useMemo3(
211
363
  () => ({ ...defaultLabels, ...labelsProp }),
212
364
  [labelsProp]
213
365
  );
214
366
  const flowMap = useFlowMap(flows);
215
- const storeRef = useRef(null);
216
- const unsubscribeRef = useRef(null);
217
- const stepHooksUnsubscribeRef = useRef(null);
218
- const fallbackStorageRef = useRef(void 0);
219
- const pendingResumeRef = useRef(/* @__PURE__ */ new Set());
220
- const autoStartRequestedRef = useRef(null);
367
+ const storeRef = useRef3(null);
368
+ const unsubscribeRef = useRef3(null);
369
+ const stepHooksUnsubscribeRef = useRef3(null);
370
+ const fallbackStorageRef = useRef3(void 0);
371
+ const pendingResumeRef = useRef3(/* @__PURE__ */ new Set());
372
+ const autoStartRequestedRef = useRef3(null);
221
373
  const [activeFlowId, setActiveFlowId] = useState2(null);
222
374
  const [state, setState] = useState2(null);
223
375
  const [events, setEvents] = useState2(
@@ -225,7 +377,7 @@ var TourProvider = ({
225
377
  );
226
378
  const [debugEnabled, setDebugEnabled] = useState2(defaultDebug);
227
379
  const [delayInfo, setDelayInfo] = useState2(null);
228
- const teardownStore = useCallback(() => {
380
+ const teardownStore = useCallback2(() => {
229
381
  unsubscribeRef.current?.();
230
382
  unsubscribeRef.current = null;
231
383
  stepHooksUnsubscribeRef.current?.();
@@ -235,7 +387,7 @@ var TourProvider = ({
235
387
  setDelayInfo(null);
236
388
  pendingResumeRef.current.clear();
237
389
  }, []);
238
- useEffect2(() => {
390
+ useEffect3(() => {
239
391
  return () => {
240
392
  teardownStore();
241
393
  setState(null);
@@ -243,7 +395,7 @@ var TourProvider = ({
243
395
  setActiveFlowId(null);
244
396
  };
245
397
  }, [teardownStore]);
246
- useEffect2(() => {
398
+ useEffect3(() => {
247
399
  if (!activeFlowId) return;
248
400
  const definition = flowMap.get(activeFlowId);
249
401
  if (!definition) {
@@ -266,7 +418,7 @@ var TourProvider = ({
266
418
  console.warn(`[tour][step] ${phase} hook failed`, error);
267
419
  }
268
420
  };
269
- const ensureStore = useCallback(
421
+ const ensureStore = useCallback2(
270
422
  (flowId) => {
271
423
  const existing = storeRef.current;
272
424
  if (existing && existing.definition.id === flowId) {
@@ -325,7 +477,7 @@ var TourProvider = ({
325
477
  teardownStore
326
478
  ]
327
479
  );
328
- const getActiveStore = useCallback(() => {
480
+ const getActiveStore = useCallback2(() => {
329
481
  const store = storeRef.current;
330
482
  if (!store) {
331
483
  throw new Error(
@@ -337,7 +489,7 @@ var TourProvider = ({
337
489
  const isPromiseLike2 = (value) => {
338
490
  return typeof value === "object" && value !== null && typeof value.then === "function";
339
491
  };
340
- const invokeStepHook = useCallback(
492
+ const invokeStepHook = useCallback2(
341
493
  async (hook, context, phase) => {
342
494
  if (!hook) return;
343
495
  try {
@@ -351,7 +503,7 @@ var TourProvider = ({
351
503
  },
352
504
  []
353
505
  );
354
- const runResumeHooks = useCallback(
506
+ const runResumeHooks = useCallback2(
355
507
  async (definition, flowState, strategy) => {
356
508
  if (flowState.status !== "running") return;
357
509
  if (strategy === "current") {
@@ -391,13 +543,13 @@ var TourProvider = ({
391
543
  },
392
544
  [invokeStepHook]
393
545
  );
394
- const resolveResumeStrategy = useCallback(
546
+ const resolveResumeStrategy = useCallback2(
395
547
  (definition, options) => {
396
548
  return options?.resumeStrategy ?? definition.resumeStrategy ?? "chain";
397
549
  },
398
550
  []
399
551
  );
400
- const startFlow = useCallback(
552
+ const startFlow = useCallback2(
401
553
  (flowId, options) => {
402
554
  const store = ensureStore(flowId);
403
555
  const previousState = store.getState();
@@ -427,7 +579,7 @@ var TourProvider = ({
427
579
  [ensureStore, resolveResumeStrategy, runResumeHooks]
428
580
  );
429
581
  const [eligibleFlows, setEligibleFlows] = useState2([]);
430
- useEffect2(() => {
582
+ useEffect3(() => {
431
583
  const autoStartFlows = flows.filter((f) => f.autoStart);
432
584
  if (autoStartFlows.length === 0) {
433
585
  setEligibleFlows([]);
@@ -491,7 +643,7 @@ var TourProvider = ({
491
643
  cancelled = true;
492
644
  };
493
645
  }, [flows, storageAdapter, storageNamespace]);
494
- useEffect2(() => {
646
+ useEffect3(() => {
495
647
  if (eligibleFlows.length === 0) {
496
648
  autoStartRequestedRef.current = null;
497
649
  return;
@@ -526,14 +678,14 @@ var TourProvider = ({
526
678
  }
527
679
  };
528
680
  }, [activeFlowId, eligibleFlows, startFlow]);
529
- const next = useCallback(() => getActiveStore().next(), [getActiveStore]);
530
- const back = useCallback(() => getActiveStore().back(), [getActiveStore]);
531
- const goToStep = useCallback(
681
+ const next = useCallback2(() => getActiveStore().next(), [getActiveStore]);
682
+ const back = useCallback2(() => getActiveStore().back(), [getActiveStore]);
683
+ const goToStep = useCallback2(
532
684
  (step) => getActiveStore().goToStep(step),
533
685
  [getActiveStore]
534
686
  );
535
- const pause = useCallback(() => getActiveStore().pause(), [getActiveStore]);
536
- const resume = useCallback(() => {
687
+ const pause = useCallback2(() => getActiveStore().pause(), [getActiveStore]);
688
+ const resume = useCallback2(() => {
537
689
  const store = getActiveStore();
538
690
  const previousState = store.getState();
539
691
  if (previousState.status === "paused") {
@@ -551,27 +703,31 @@ var TourProvider = ({
551
703
  }
552
704
  return result;
553
705
  }, [getActiveStore, resolveResumeStrategy, runResumeHooks]);
554
- const cancel = useCallback(
706
+ const cancel = useCallback2(
555
707
  (reason) => getActiveStore().cancel(reason),
556
708
  [getActiveStore]
557
709
  );
558
- const complete = useCallback(
710
+ const complete = useCallback2(
559
711
  () => getActiveStore().complete(),
560
712
  [getActiveStore]
561
713
  );
562
- const advanceStep = useCallback(
714
+ const advanceStep = useCallback2(
563
715
  (stepId) => getActiveStore().advanceStep(stepId),
564
716
  [getActiveStore]
565
717
  );
566
- const toggleDebug = useCallback(() => {
718
+ const toggleDebug = useCallback2(() => {
567
719
  setDebugEnabled((previous) => !previous);
568
720
  }, []);
569
- const activeStep = useMemo2(() => {
721
+ const activeStep = useMemo3(() => {
570
722
  if (!state || !storeRef.current) return null;
571
723
  if (state.stepIndex < 0) return null;
572
724
  return storeRef.current.definition.steps[state.stepIndex] ?? null;
573
725
  }, [state]);
574
- useEffect2(() => {
726
+ const activeDialogConfig = useMemo3(() => {
727
+ if (!activeStep?.dialogId || !storeRef.current) return void 0;
728
+ return storeRef.current.definition.dialogs?.[activeStep.dialogId];
729
+ }, [activeStep]);
730
+ useEffect3(() => {
575
731
  if (!activeFlowId) return;
576
732
  if (!pendingResumeRef.current.has(activeFlowId)) return;
577
733
  if (!state || state.status !== "running") return;
@@ -586,12 +742,13 @@ var TourProvider = ({
586
742
  pendingResumeRef.current.delete(activeFlowId);
587
743
  void runResumeHooks(definition, state, resumeStrategy);
588
744
  }, [activeFlowId, flowMap, resolveResumeStrategy, runResumeHooks, state]);
589
- const contextValue = useMemo2(
745
+ const contextValue = useMemo3(
590
746
  () => ({
591
747
  flows: flowMap,
592
748
  activeFlowId,
593
749
  state,
594
750
  activeStep,
751
+ activeDialogConfig,
595
752
  startFlow,
596
753
  next,
597
754
  back,
@@ -613,6 +770,7 @@ var TourProvider = ({
613
770
  [
614
771
  activeFlowId,
615
772
  activeStep,
773
+ activeDialogConfig,
616
774
  advanceStep,
617
775
  back,
618
776
  cancel,
@@ -639,10 +797,41 @@ var TourProvider = ({
639
797
  reducedMotionAdapter,
640
798
  enabled: autoDetectReducedMotion
641
799
  });
642
- return /* @__PURE__ */ jsx2(AnimationAdapterProvider, { adapter: resolvedAnimationAdapter, children: /* @__PURE__ */ jsx2(LabelsProvider, { value: mergedLabels, children: /* @__PURE__ */ jsx2(TourContext.Provider, { value: contextValue, children }) }) });
800
+ return /* @__PURE__ */ jsx3(AnimationAdapterProvider, { adapter: resolvedAnimationAdapter, children: /* @__PURE__ */ jsx3(LabelsProvider, { value: mergedLabels, children: /* @__PURE__ */ jsx3(DialogRegistryProvider, { children: /* @__PURE__ */ jsxs(TourContext.Provider, { value: contextValue, children: [
801
+ /* @__PURE__ */ jsx3(
802
+ DialogAutomationBridge,
803
+ {
804
+ flow: activeFlowId ? flowMap.get(activeFlowId) : void 0,
805
+ state,
806
+ events
807
+ }
808
+ ),
809
+ children
810
+ ] }) }) }) });
811
+ };
812
+ var DialogAutomationBridge = ({
813
+ flow,
814
+ state,
815
+ events
816
+ }) => {
817
+ const registry = useDialogRegistryOptional();
818
+ useDialogAutomation({
819
+ flow,
820
+ state,
821
+ events,
822
+ registry,
823
+ onDialogNotMounted: (dialogId, stepId) => {
824
+ if (process.env.NODE_ENV !== "production") {
825
+ console.warn(
826
+ `[tour] Step "${stepId}" references dialogId "${dialogId}" but no dialog is mounted with that ID. Ensure your dialog uses useTourDialog({ dialogId: "${dialogId}" }).`
827
+ );
828
+ }
829
+ }
830
+ });
831
+ return null;
643
832
  };
644
833
  var useTour = () => {
645
- const context = useContext3(TourContext);
834
+ const context = useContext4(TourContext);
646
835
  if (!context) {
647
836
  throw new Error("useTour must be used within a TourProvider");
648
837
  }
@@ -650,14 +839,14 @@ var useTour = () => {
650
839
  };
651
840
  var useTourEvents = (event, handler) => {
652
841
  const { events } = useTour();
653
- useEffect2(() => {
842
+ useEffect3(() => {
654
843
  if (!events) return;
655
844
  return events.on(event, handler);
656
845
  }, [event, events, handler]);
657
846
  };
658
847
 
659
848
  // src/hooks/useTourTarget.ts
660
- import { useEffect as useEffect3, useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
849
+ import { useEffect as useEffect4, useLayoutEffect, useRef as useRef4, useState as useState3 } from "react";
661
850
 
662
851
  // src/hooks/scrollMargin.ts
663
852
  var DEFAULT_SCROLL_MARGIN = 16;
@@ -961,11 +1150,11 @@ var resolveStepTarget = (target) => {
961
1150
  var useTourTarget = () => {
962
1151
  const { activeStep, state, activeFlowId, flows } = useTour();
963
1152
  const [targetInfo, setTargetInfo] = useState3(INITIAL_TARGET_INFO);
964
- const autoScrollStateRef = useRef2({ stepId: null, checks: 0, stalledChecks: 0, done: false, lastRect: null });
965
- const autoScrollRafRef = useRef2(null);
966
- const autoScrollTimeoutRef = useRef2(null);
967
- const lastRectRef = useRef2(null);
968
- const initialScrollStepRef = useRef2(null);
1153
+ const autoScrollStateRef = useRef4({ stepId: null, checks: 0, stalledChecks: 0, done: false, lastRect: null });
1154
+ const autoScrollRafRef = useRef4(null);
1155
+ const autoScrollTimeoutRef = useRef4(null);
1156
+ const lastRectRef = useRef4(null);
1157
+ const initialScrollStepRef = useRef4(null);
969
1158
  const cancelAutoScrollLoop = () => {
970
1159
  if (!isBrowser) return;
971
1160
  if (autoScrollTimeoutRef.current !== null) {
@@ -977,7 +1166,7 @@ var useTourTarget = () => {
977
1166
  autoScrollRafRef.current = null;
978
1167
  }
979
1168
  };
980
- useEffect3(() => {
1169
+ useEffect4(() => {
981
1170
  if (!activeStep) {
982
1171
  initialScrollStepRef.current = null;
983
1172
  }
@@ -1017,7 +1206,7 @@ var useTourTarget = () => {
1017
1206
  targetInfo.status,
1018
1207
  targetInfo.rectSource
1019
1208
  ]);
1020
- useEffect3(() => {
1209
+ useEffect4(() => {
1021
1210
  if (!activeStep || !state || state.status !== "running") {
1022
1211
  setTargetInfo(INITIAL_TARGET_INFO);
1023
1212
  autoScrollStateRef.current = {
@@ -1340,7 +1529,7 @@ var useTourTarget = () => {
1340
1529
  waitForPredicateController = null;
1341
1530
  };
1342
1531
  }, [activeStep, activeFlowId, flows, state]);
1343
- useEffect3(() => {
1532
+ useEffect4(() => {
1344
1533
  if (!isBrowser) return;
1345
1534
  if (!activeStep) {
1346
1535
  cancelAutoScrollLoop();
@@ -1421,10 +1610,10 @@ var useTourTarget = () => {
1421
1610
  };
1422
1611
 
1423
1612
  // src/hooks/useHudState.ts
1424
- import { useCallback as useCallback2, useEffect as useEffect8, useMemo as useMemo4, useRef as useRef5, useState as useState7 } from "react";
1613
+ import { useCallback as useCallback3, useEffect as useEffect9, useMemo as useMemo5, useRef as useRef7, useState as useState7 } from "react";
1425
1614
 
1426
1615
  // src/hooks/useAdvanceRules.ts
1427
- import { useEffect as useEffect4 } from "react";
1616
+ import { useEffect as useEffect5 } from "react";
1428
1617
  var DEFAULT_POLL_MS = 250;
1429
1618
  var isListenerTarget = (value) => {
1430
1619
  return !!value && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function";
@@ -1463,7 +1652,7 @@ var useAdvanceRules = (target) => {
1463
1652
  complete,
1464
1653
  setDelayInfo
1465
1654
  } = useTour();
1466
- useEffect4(() => {
1655
+ useEffect5(() => {
1467
1656
  if (!isBrowser) return;
1468
1657
  if (!state || state.status !== "running") return;
1469
1658
  if (!activeStep) return;
@@ -1634,7 +1823,7 @@ var useAdvanceRules = (target) => {
1634
1823
  };
1635
1824
 
1636
1825
  // src/hooks/useHiddenTargetFallback.ts
1637
- import { useEffect as useEffect5, useMemo as useMemo3, useRef as useRef3, useState as useState4 } from "react";
1826
+ import { useEffect as useEffect6, useMemo as useMemo4, useRef as useRef5, useState as useState4 } from "react";
1638
1827
  var DEFAULT_DELAY_MS = 900;
1639
1828
  var DEFAULT_GRACE_PERIOD_MS = 400;
1640
1829
  var useHiddenTargetFallback = ({
@@ -1645,9 +1834,9 @@ var useHiddenTargetFallback = ({
1645
1834
  }) => {
1646
1835
  const [usingScreenFallback, setUsingScreenFallback] = useState4(false);
1647
1836
  const [isInGracePeriod, setIsInGracePeriod] = useState4(false);
1648
- const timeoutRef = useRef3(null);
1649
- const graceTimeoutRef = useRef3(null);
1650
- const skipTriggeredRef = useRef3(false);
1837
+ const timeoutRef = useRef5(null);
1838
+ const graceTimeoutRef = useRef5(null);
1839
+ const skipTriggeredRef = useRef5(false);
1651
1840
  const hiddenMode = step?.targetBehavior?.hidden ?? "screen";
1652
1841
  const hiddenDelayMs = Math.max(
1653
1842
  0,
@@ -1665,7 +1854,7 @@ var useHiddenTargetFallback = ({
1665
1854
  graceTimeoutRef.current = null;
1666
1855
  }
1667
1856
  };
1668
- useEffect5(() => {
1857
+ useEffect6(() => {
1669
1858
  skipTriggeredRef.current = false;
1670
1859
  setUsingScreenFallback(false);
1671
1860
  setIsInGracePeriod(false);
@@ -1676,7 +1865,7 @@ var useHiddenTargetFallback = ({
1676
1865
  clearGraceTimeout();
1677
1866
  };
1678
1867
  }, [step?.id]);
1679
- useEffect5(() => {
1868
+ useEffect6(() => {
1680
1869
  if (!isBrowser) return void 0;
1681
1870
  if (!step) return void 0;
1682
1871
  clearPendingTimeout();
@@ -1722,7 +1911,7 @@ var useHiddenTargetFallback = ({
1722
1911
  hiddenDelayMs,
1723
1912
  onSkip
1724
1913
  ]);
1725
- const resolvedTarget = useMemo3(() => {
1914
+ const resolvedTarget = useMemo4(() => {
1726
1915
  if (!usingScreenFallback) {
1727
1916
  return target;
1728
1917
  }
@@ -1744,10 +1933,10 @@ var useHiddenTargetFallback = ({
1744
1933
  };
1745
1934
 
1746
1935
  // src/hooks/useRouteMismatch.ts
1747
- import { useEffect as useEffect6, useState as useState5 } from "react";
1936
+ import { useEffect as useEffect7, useState as useState5 } from "react";
1748
1937
  var useRouteMismatch = (step) => {
1749
1938
  const [currentPath, setCurrentPath] = useState5(() => getCurrentRoutePath());
1750
- useEffect6(() => {
1939
+ useEffect7(() => {
1751
1940
  return subscribeToRouteChanges((path) => {
1752
1941
  setCurrentPath(path);
1753
1942
  });
@@ -1762,13 +1951,13 @@ var useRouteMismatch = (step) => {
1762
1951
  };
1763
1952
 
1764
1953
  // src/hooks/useViewportRect.ts
1765
- import { useEffect as useEffect7, useRef as useRef4, useState as useState6 } from "react";
1954
+ import { useEffect as useEffect8, useRef as useRef6, useState as useState6 } from "react";
1766
1955
  var useViewportRect = () => {
1767
1956
  const [viewport, setViewport] = useState6(
1768
1957
  () => getViewportRect()
1769
1958
  );
1770
- const rafRef = useRef4(null);
1771
- useEffect7(() => {
1959
+ const rafRef = useRef6(null);
1960
+ useEffect8(() => {
1772
1961
  if (!isBrowser) return;
1773
1962
  const updateViewport = () => {
1774
1963
  rafRef.current = null;
@@ -1810,12 +1999,12 @@ var normalizeFlowFilter = (value) => {
1810
1999
  };
1811
2000
  var useHudState = (options = {}) => {
1812
2001
  const { flowId } = options;
1813
- const flowFilter = useMemo4(() => normalizeFlowFilter(flowId), [flowId]);
2002
+ const flowFilter = useMemo5(() => normalizeFlowFilter(flowId), [flowId]);
1814
2003
  const { state, activeStep, activeFlowId, flows, next, complete, pause, resume } = useTour();
1815
2004
  const target = useTourTarget();
1816
2005
  const viewportRect = useViewportRect();
1817
2006
  useAdvanceRules(target);
1818
- const matchesFlowFilter = useMemo4(() => {
2007
+ const matchesFlowFilter = useMemo5(() => {
1819
2008
  if (!flowFilter || flowFilter.length === 0) return true;
1820
2009
  if (!activeFlowId) return false;
1821
2010
  return flowFilter.includes(activeFlowId);
@@ -1826,12 +2015,12 @@ var useHudState = (options = {}) => {
1826
2015
  const [shouldRender, setShouldRender] = useState7(
1827
2016
  Boolean(runningStep)
1828
2017
  );
1829
- useEffect8(() => {
2018
+ useEffect9(() => {
1830
2019
  if (runningStep) {
1831
2020
  setShouldRender(true);
1832
2021
  }
1833
2022
  }, [runningStep?.id]);
1834
- useEffect8(() => {
2023
+ useEffect9(() => {
1835
2024
  if (!shouldRender) return;
1836
2025
  if (runningStep) return;
1837
2026
  if (target.status !== "idle") return;
@@ -1843,19 +2032,19 @@ var useHudState = (options = {}) => {
1843
2032
  };
1844
2033
  }, [runningStep, shouldRender, target.status]);
1845
2034
  const { isRouteMismatch, currentPath } = useRouteMismatch(activeStep);
1846
- const pausedForMissingTargetRef = useRef5(null);
1847
- useEffect8(() => {
2035
+ const pausedForMissingTargetRef = useRef7(null);
2036
+ useEffect9(() => {
1848
2037
  if (!isRouteMismatch) return;
1849
2038
  if (!runningState || runningState.status !== "running") return;
1850
2039
  pause();
1851
2040
  }, [isRouteMismatch, runningState, pause]);
1852
- useEffect8(() => {
2041
+ useEffect9(() => {
1853
2042
  if (isRouteMismatch) return;
1854
2043
  if (pausedForMissingTargetRef.current !== null) return;
1855
2044
  if (!state || state.status !== "paused") return;
1856
2045
  resume();
1857
2046
  }, [isRouteMismatch, state, resume]);
1858
- const skipHiddenStep = useCallback2(() => {
2047
+ const skipHiddenStep = useCallback3(() => {
1859
2048
  if (!runningState || runningState.status !== "running") return;
1860
2049
  if (!activeFlowId) return;
1861
2050
  const flow = flows.get(activeFlowId);
@@ -1873,7 +2062,7 @@ var useHudState = (options = {}) => {
1873
2062
  viewportRect,
1874
2063
  onSkip: skipHiddenStep
1875
2064
  });
1876
- useEffect8(() => {
2065
+ useEffect9(() => {
1877
2066
  if (isRouteMismatch) return;
1878
2067
  if (activeStep?.route !== void 0) return;
1879
2068
  if (isInGracePeriod) return;
@@ -1892,14 +2081,14 @@ var useHudState = (options = {}) => {
1892
2081
  currentPath,
1893
2082
  pause
1894
2083
  ]);
1895
- useEffect8(() => {
2084
+ useEffect9(() => {
1896
2085
  if (pausedForMissingTargetRef.current === null) return;
1897
2086
  if (!state || state.status !== "paused") return;
1898
2087
  if (currentPath === pausedForMissingTargetRef.current) return;
1899
2088
  pausedForMissingTargetRef.current = null;
1900
2089
  resume();
1901
2090
  }, [currentPath, state, resume]);
1902
- useEffect8(() => {
2091
+ useEffect9(() => {
1903
2092
  pausedForMissingTargetRef.current = null;
1904
2093
  }, [activeStep?.id]);
1905
2094
  const canRenderStep = Boolean(runningStep && runningState);
@@ -1924,24 +2113,24 @@ var useHudState = (options = {}) => {
1924
2113
  };
1925
2114
 
1926
2115
  // src/hooks/useHudDescription.ts
1927
- import { useMemo as useMemo5 } from "react";
2116
+ import { useMemo as useMemo6 } from "react";
1928
2117
  var sanitizeForId = (value) => {
1929
2118
  const normalized = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1930
2119
  return normalized.length > 0 ? normalized : "step";
1931
2120
  };
1932
2121
  var useHudDescription = (options) => {
1933
2122
  const { step, fallbackAriaDescribedBy } = options;
1934
- const targetDescription = useMemo5(() => {
2123
+ const targetDescription = useMemo6(() => {
1935
2124
  if (!step) return null;
1936
2125
  if (typeof step.target !== "object") return null;
1937
2126
  const description = step.target.description;
1938
2127
  return typeof description === "string" ? description : null;
1939
2128
  }, [step]);
1940
- const descriptionId = useMemo5(() => {
2129
+ const descriptionId = useMemo6(() => {
1941
2130
  if (!step || !targetDescription) return void 0;
1942
2131
  return `tour-step-${sanitizeForId(step.id)}-description`;
1943
2132
  }, [step, targetDescription]);
1944
- const combinedAriaDescribedBy = useMemo5(() => {
2133
+ const combinedAriaDescribedBy = useMemo6(() => {
1945
2134
  const parts = [fallbackAriaDescribedBy, descriptionId].filter(Boolean);
1946
2135
  return parts.length > 0 ? parts.join(" ") : void 0;
1947
2136
  }, [descriptionId, fallbackAriaDescribedBy]);
@@ -1953,10 +2142,10 @@ var useHudDescription = (options) => {
1953
2142
  };
1954
2143
 
1955
2144
  // src/hooks/useHudShortcuts.ts
1956
- import { useEffect as useEffect9 } from "react";
2145
+ import { useEffect as useEffect10 } from "react";
1957
2146
 
1958
2147
  // src/hooks/useTourControls.ts
1959
- import { useCallback as useCallback3, useMemo as useMemo6 } from "react";
2148
+ import { useCallback as useCallback4, useMemo as useMemo7 } from "react";
1960
2149
  var hasManualAdvance = (rules) => rules.some((rule) => rule.type === "manual");
1961
2150
  var didPreviousAdvanceViaRoute = (rules) => rules.some((rule) => rule.type === "route");
1962
2151
  var useTourControls = () => {
@@ -1971,7 +2160,7 @@ var useTourControls = () => {
1971
2160
  flows,
1972
2161
  activeStep
1973
2162
  } = tour;
1974
- const computed = useMemo6(() => {
2163
+ const computed = useMemo7(() => {
1975
2164
  if (!state || state.status !== "running" || !activeStep) {
1976
2165
  return {
1977
2166
  isActive: false,
@@ -2020,11 +2209,11 @@ var useTourControls = () => {
2020
2209
  } = computed;
2021
2210
  const canGoBack = showBackButton && !backDisabled;
2022
2211
  const canGoNext = showNextButton && !nextDisabled;
2023
- const goBack = useCallback3(() => {
2212
+ const goBack = useCallback4(() => {
2024
2213
  if (!canGoBack) return;
2025
2214
  back();
2026
2215
  }, [back, canGoBack]);
2027
- const goNext = useCallback3(() => {
2216
+ const goNext = useCallback4(() => {
2028
2217
  if (!canGoNext) return;
2029
2218
  if (isLast) {
2030
2219
  complete();
@@ -2032,7 +2221,7 @@ var useTourControls = () => {
2032
2221
  next();
2033
2222
  }
2034
2223
  }, [canGoNext, complete, isLast, next]);
2035
- return useMemo6(
2224
+ return useMemo7(
2036
2225
  () => ({
2037
2226
  showBackButton,
2038
2227
  backDisabled,
@@ -2077,7 +2266,7 @@ var useHudShortcuts = (target, options) => {
2077
2266
  const escapeEnabled = options?.escape ?? true;
2078
2267
  const { state } = useTour();
2079
2268
  const { cancel, canGoBack, goBack, canGoNext, goNext, isActive } = useTourControls();
2080
- useEffect9(() => {
2269
+ useEffect10(() => {
2081
2270
  if (!isBrowser) return void 0;
2082
2271
  if (!enabled) return void 0;
2083
2272
  if (!target) return void 0;
@@ -2141,10 +2330,10 @@ var useHudShortcuts = (target, options) => {
2141
2330
  };
2142
2331
 
2143
2332
  // src/hooks/useTourHud.ts
2144
- import { useMemo as useMemo8, useState as useState9 } from "react";
2333
+ import { useMemo as useMemo9, useState as useState9 } from "react";
2145
2334
 
2146
2335
  // src/hooks/useBodyScrollLock.ts
2147
- import { useEffect as useEffect10 } from "react";
2336
+ import { useEffect as useEffect11 } from "react";
2148
2337
  var lockCount = 0;
2149
2338
  var previousOverflow = null;
2150
2339
  var acquireLock = () => {
@@ -2165,7 +2354,7 @@ var releaseLock = () => {
2165
2354
  }
2166
2355
  };
2167
2356
  var useBodyScrollLock = (enabled) => {
2168
- useEffect10(() => {
2357
+ useEffect11(() => {
2169
2358
  if (!enabled) return;
2170
2359
  acquireLock();
2171
2360
  return () => {
@@ -2175,7 +2364,7 @@ var useBodyScrollLock = (enabled) => {
2175
2364
  };
2176
2365
 
2177
2366
  // src/hooks/useHudTargetIssue.ts
2178
- import { useEffect as useEffect11, useMemo as useMemo7, useState as useState8 } from "react";
2367
+ import { useEffect as useEffect12, useMemo as useMemo8, useState as useState8 } from "react";
2179
2368
  var deriveTargetIssue = (params) => {
2180
2369
  const { target, labels } = params;
2181
2370
  if (target.isScreen) return null;
@@ -2209,11 +2398,11 @@ var useHudTargetIssue = (target, options) => {
2209
2398
  const labels = useTourLabels();
2210
2399
  const delayMs = Math.max(0, options?.delayMs ?? 500);
2211
2400
  const [armed, setArmed] = useState8(false);
2212
- const rawIssue = useMemo7(
2401
+ const rawIssue = useMemo8(
2213
2402
  () => deriveTargetIssue({ target, labels }),
2214
2403
  [target.isScreen, target.rectSource, target.status, target.visibility, labels]
2215
2404
  );
2216
- useEffect11(() => {
2405
+ useEffect12(() => {
2217
2406
  if (!rawIssue) {
2218
2407
  setArmed(false);
2219
2408
  return;
@@ -2271,7 +2460,7 @@ var useTourHud = (options = {}) => {
2271
2460
  radius: overlayRadius,
2272
2461
  interactionMode: hudState.flowHudOptions?.backdrop?.interaction ?? backdropInteraction
2273
2462
  };
2274
- const popover = useMemo8(() => {
2463
+ const popover = useMemo9(() => {
2275
2464
  return {
2276
2465
  offset: popoverOptions?.offset ?? 32,
2277
2466
  role: popoverOptions?.role ?? "dialog",
@@ -2283,13 +2472,13 @@ var useTourHud = (options = {}) => {
2283
2472
  placement: hudState.runningStep?.placement
2284
2473
  };
2285
2474
  }, [hudState.runningStep?.placement, popoverOptions]);
2286
- const descriptionResult = useMemo8(() => {
2475
+ const descriptionResult = useMemo9(() => {
2287
2476
  return {
2288
2477
  ...description,
2289
2478
  text: description.targetDescription
2290
2479
  };
2291
2480
  }, [description]);
2292
- const focusManager = useMemo8(
2481
+ const focusManager = useMemo9(
2293
2482
  () => ({
2294
2483
  active: hudState.focusTrapActive,
2295
2484
  target: hudState.hudTarget,
@@ -2319,7 +2508,7 @@ var useTourHud = (options = {}) => {
2319
2508
  };
2320
2509
 
2321
2510
  // src/hooks/useTourOverlay.ts
2322
- import { useEffect as useEffect12, useMemo as useMemo9, useRef as useRef6 } from "react";
2511
+ import { useEffect as useEffect13, useMemo as useMemo10, useRef as useRef8 } from "react";
2323
2512
  var DEFAULT_PADDING = 12;
2324
2513
  var DEFAULT_RADIUS = 12;
2325
2514
  var DEFAULT_EDGE_BUFFER = 0;
@@ -2332,9 +2521,9 @@ var useTourOverlay = (options) => {
2332
2521
  interactionMode = "passthrough",
2333
2522
  isInGracePeriod = false
2334
2523
  } = options;
2335
- const hasShownRef = useRef6(false);
2336
- const lastReadyTargetRef = useRef6(null);
2337
- useEffect12(() => {
2524
+ const hasShownRef = useRef8(false);
2525
+ const lastReadyTargetRef = useRef8(null);
2526
+ useEffect13(() => {
2338
2527
  if (!isBrowser) return;
2339
2528
  if (target.status === "ready") {
2340
2529
  hasShownRef.current = true;
@@ -2384,15 +2573,15 @@ var useTourOverlay = (options) => {
2384
2573
  height: highlightHeight,
2385
2574
  radius: highlightRadius
2386
2575
  } : null;
2387
- const maskCapable = useMemo9(() => supportsMasking(), []);
2576
+ const maskCapable = useMemo10(() => supportsMasking(), []);
2388
2577
  const isActive = target.status === "ready" || target.status === "resolving" && cachedTarget !== null || isInGracePeriod;
2389
2578
  const shouldMask = maskCapable && isActive;
2390
- const maskId = useMemo9(
2579
+ const maskId = useMemo10(
2391
2580
  () => `tour-overlay-mask-${Math.random().toString(36).slice(2, 10)}`,
2392
2581
  []
2393
2582
  );
2394
2583
  const maskUrl = shouldMask ? `url(#${maskId})` : void 0;
2395
- const fallbackSegments = useMemo9(() => {
2584
+ const fallbackSegments = useMemo10(() => {
2396
2585
  if (!isActive || shouldMask || !hasHighlightBounds || !highlightRect) {
2397
2586
  return null;
2398
2587
  }
@@ -2445,7 +2634,7 @@ var useTourOverlay = (options) => {
2445
2634
  viewport.height,
2446
2635
  viewport.width
2447
2636
  ]);
2448
- const blockerSegments = useMemo9(() => {
2637
+ const blockerSegments = useMemo10(() => {
2449
2638
  if (interactionMode !== "block") {
2450
2639
  return null;
2451
2640
  }
@@ -2573,37 +2762,202 @@ var useRadixDialogAdapter = (options = {}) => {
2573
2762
  var waitForDom = () => new Promise(
2574
2763
  (resolve) => requestAnimationFrame(() => setTimeout(resolve, 0))
2575
2764
  );
2576
- var createRadixDialogHelpers = (params) => {
2577
- const { contentSelector, triggerSelector } = params;
2578
- const isOpen = () => {
2579
- if (typeof document === "undefined") return false;
2580
- return document.querySelector(contentSelector) !== null;
2581
- };
2582
- const open = async () => {
2583
- if (typeof document === "undefined") return;
2584
- if (isOpen()) return;
2585
- await waitForDom();
2586
- if (isOpen()) return;
2587
- const trigger = document.querySelector(triggerSelector);
2588
- trigger?.click();
2589
- await waitForDom();
2765
+
2766
+ // src/hooks/useRadixTourDialog.ts
2767
+ import { useCallback as useCallback5, useEffect as useEffect14, useMemo as useMemo11, useRef as useRef9, useState as useState10 } from "react";
2768
+ var resolveAutoOpen2 = (config) => {
2769
+ if (!config) return { onEnter: true, onResume: true };
2770
+ const { autoOpen } = config;
2771
+ if (autoOpen === false) return { onEnter: false, onResume: false };
2772
+ if (autoOpen === true || autoOpen === void 0) {
2773
+ return { onEnter: true, onResume: true };
2774
+ }
2775
+ return {
2776
+ onEnter: autoOpen.onEnter ?? true,
2777
+ onResume: autoOpen.onResume ?? true
2590
2778
  };
2591
- const close = async () => {
2592
- if (typeof document === "undefined") return;
2593
- if (!isOpen()) return;
2594
- document.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" }));
2595
- await waitForDom();
2779
+ };
2780
+ var useRadixTourDialog = (params) => {
2781
+ const { dialogId } = params;
2782
+ const { activeFlowId, state, flows, goToStep, events } = useTour();
2783
+ const registry = useDialogRegistryOptional();
2784
+ const { suspendExternalFocusTrap } = useTourFocusDominance();
2785
+ const [internalOpen, setInternalOpen] = useState10(false);
2786
+ const lastStepIndexRef = useRef9(-1);
2787
+ const isResumeRef = useRef9(false);
2788
+ const flow = activeFlowId ? flows.get(activeFlowId) : void 0;
2789
+ const dialogConfig = flow?.dialogs?.[dialogId];
2790
+ const currentStep = flow && state && state.stepIndex >= 0 ? flow.steps[state.stepIndex] : void 0;
2791
+ const isStepActive = currentStep?.dialogId === dialogId;
2792
+ const autoOpenConfig = resolveAutoOpen2(dialogConfig);
2793
+ const autoClose = dialogConfig?.autoClose ?? "differentDialog";
2794
+ const shouldBeOpen = useMemo11(() => {
2795
+ if (!isStepActive) return false;
2796
+ return true;
2797
+ }, [isStepActive]);
2798
+ useEffect14(() => {
2799
+ if (!events) return;
2800
+ const unsubscribe = events.on("flowResume", () => {
2801
+ isResumeRef.current = true;
2802
+ });
2803
+ return unsubscribe;
2804
+ }, [events]);
2805
+ useEffect14(() => {
2806
+ if (!state || state.status !== "running") return;
2807
+ if (!flow) return;
2808
+ const currentStepIndex = state.stepIndex;
2809
+ const previousStepIndex = lastStepIndexRef.current;
2810
+ const wasResume = isResumeRef.current;
2811
+ isResumeRef.current = false;
2812
+ if (previousStepIndex === -1 && currentStepIndex >= 0) {
2813
+ lastStepIndexRef.current = currentStepIndex;
2814
+ if (isStepActive) {
2815
+ const shouldAutoOpen = wasResume ? autoOpenConfig.onResume : autoOpenConfig.onEnter;
2816
+ if (shouldAutoOpen) {
2817
+ setInternalOpen(true);
2818
+ }
2819
+ }
2820
+ return;
2821
+ }
2822
+ if (previousStepIndex === currentStepIndex) return;
2823
+ lastStepIndexRef.current = currentStepIndex;
2824
+ const previousStep = previousStepIndex >= 0 ? flow.steps[previousStepIndex] : void 0;
2825
+ const wasActive = previousStep?.dialogId === dialogId;
2826
+ if (isStepActive && !wasActive) {
2827
+ const shouldAutoOpen = wasResume ? autoOpenConfig.onResume : autoOpenConfig.onEnter;
2828
+ if (shouldAutoOpen) {
2829
+ setInternalOpen(true);
2830
+ }
2831
+ }
2832
+ if (wasActive && !isStepActive) {
2833
+ if (autoClose === "always" || autoClose === "differentDialog") {
2834
+ setInternalOpen(false);
2835
+ }
2836
+ }
2837
+ }, [
2838
+ state,
2839
+ flow,
2840
+ dialogId,
2841
+ isStepActive,
2842
+ autoOpenConfig.onEnter,
2843
+ autoOpenConfig.onResume,
2844
+ autoClose
2845
+ ]);
2846
+ useEffect14(() => {
2847
+ if (!events) return;
2848
+ const unsubscribeEnter = events.on("stepEnter", (payload) => {
2849
+ const step = payload.currentStep;
2850
+ if (step.dialogId !== dialogId) return;
2851
+ const isResume = payload.reason === "resume";
2852
+ const shouldAutoOpen = isResume ? autoOpenConfig.onResume : autoOpenConfig.onEnter;
2853
+ if (shouldAutoOpen) {
2854
+ requestAnimationFrame(() => {
2855
+ setInternalOpen(true);
2856
+ });
2857
+ }
2858
+ });
2859
+ const unsubscribeExit = events.on("stepExit", (payload) => {
2860
+ const step = payload.previousStep;
2861
+ if (step.dialogId !== dialogId) return;
2862
+ const nextStep = payload.currentStep;
2863
+ if (nextStep?.dialogId === dialogId) {
2864
+ return;
2865
+ }
2866
+ if (autoClose === "always" || autoClose === "differentDialog") {
2867
+ requestAnimationFrame(() => {
2868
+ setInternalOpen(false);
2869
+ });
2870
+ }
2871
+ });
2872
+ return () => {
2873
+ unsubscribeEnter();
2874
+ unsubscribeExit();
2875
+ };
2876
+ }, [events, dialogId, autoOpenConfig, autoClose]);
2877
+ const handleDismiss = useCallback5(() => {
2878
+ if (!dialogConfig) return;
2879
+ setInternalOpen(false);
2880
+ goToStep(dialogConfig.onDismissGoToStepId);
2881
+ }, [dialogConfig, goToStep]);
2882
+ const onOpenChange = useCallback5(
2883
+ (open) => {
2884
+ if (open) {
2885
+ setInternalOpen(true);
2886
+ } else {
2887
+ if (isStepActive && dialogConfig) {
2888
+ handleDismiss();
2889
+ } else {
2890
+ setInternalOpen(false);
2891
+ }
2892
+ }
2893
+ },
2894
+ [isStepActive, dialogConfig, handleDismiss]
2895
+ );
2896
+ useEffect14(() => {
2897
+ if (!registry) return;
2898
+ const controller = {
2899
+ open: () => setInternalOpen(true),
2900
+ close: () => setInternalOpen(false),
2901
+ isOpen: () => internalOpen
2902
+ };
2903
+ registry.register(dialogId, controller);
2904
+ return () => registry.unregister(dialogId);
2905
+ }, [registry, dialogId, internalOpen]);
2906
+ const preventDismiss = useCallback5(
2907
+ (event) => {
2908
+ if (suspendExternalFocusTrap) {
2909
+ event.preventDefault();
2910
+ }
2911
+ },
2912
+ [suspendExternalFocusTrap]
2913
+ );
2914
+ const handleEscapeKeyDown = useCallback5(
2915
+ (event) => {
2916
+ if (isStepActive && dialogConfig) {
2917
+ event.preventDefault();
2918
+ handleDismiss();
2919
+ }
2920
+ },
2921
+ [isStepActive, dialogConfig, handleDismiss]
2922
+ );
2923
+ const handleInteractOutside = useCallback5(
2924
+ (event) => {
2925
+ if (suspendExternalFocusTrap) {
2926
+ event.preventDefault();
2927
+ return;
2928
+ }
2929
+ if (isStepActive && dialogConfig) {
2930
+ event.preventDefault();
2931
+ handleDismiss();
2932
+ }
2933
+ },
2934
+ [suspendExternalFocusTrap, isStepActive, dialogConfig, handleDismiss]
2935
+ );
2936
+ return {
2937
+ isStepActive,
2938
+ shouldBeOpen,
2939
+ onOpenChange,
2940
+ dialogProps: {
2941
+ open: internalOpen,
2942
+ onOpenChange,
2943
+ modal: !suspendExternalFocusTrap
2944
+ },
2945
+ contentProps: {
2946
+ trapFocus: !suspendExternalFocusTrap,
2947
+ onInteractOutside: handleInteractOutside,
2948
+ onFocusOutside: preventDismiss,
2949
+ onEscapeKeyDown: handleEscapeKeyDown
2950
+ }
2596
2951
  };
2597
- return { isOpen, open, close };
2598
2952
  };
2599
2953
 
2600
2954
  // src/hooks/useDelayAdvance.ts
2601
- import { useEffect as useEffect13, useMemo as useMemo10, useState as useState10 } from "react";
2955
+ import { useEffect as useEffect15, useMemo as useMemo12, useState as useState11 } from "react";
2602
2956
  var getTimestamp = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
2603
2957
  var useDelayAdvance = () => {
2604
2958
  const { delayInfo, activeStep, state } = useTour();
2605
- const [now, setNow] = useState10(() => getTimestamp());
2606
- useEffect13(() => {
2959
+ const [now, setNow] = useState11(() => getTimestamp());
2960
+ useEffect15(() => {
2607
2961
  if (!delayInfo) return;
2608
2962
  if (!activeStep || activeStep.id !== delayInfo.stepId) return;
2609
2963
  if (!state || state.status !== "running") return;
@@ -2620,12 +2974,12 @@ var useDelayAdvance = () => {
2620
2974
  }
2621
2975
  };
2622
2976
  }, [delayInfo, activeStep, state]);
2623
- useEffect13(() => {
2977
+ useEffect15(() => {
2624
2978
  if (!delayInfo) {
2625
2979
  setNow(getTimestamp());
2626
2980
  }
2627
2981
  }, [delayInfo]);
2628
- return useMemo10(() => {
2982
+ return useMemo12(() => {
2629
2983
  const matchingStep = !!delayInfo && !!activeStep && activeStep.id === delayInfo.stepId;
2630
2984
  const isRunning = matchingStep && state?.status === "running";
2631
2985
  if (!delayInfo) {
@@ -2678,10 +3032,10 @@ var useDelayAdvance = () => {
2678
3032
  };
2679
3033
 
2680
3034
  // src/components/OverlayBackdrop.tsx
2681
- import { useEffect as useEffect14, useRef as useRef7 } from "react";
3035
+ import { useEffect as useEffect16, useRef as useRef10 } from "react";
2682
3036
  import { createPortal } from "react-dom";
2683
3037
  import { AnimatePresence } from "motion/react";
2684
- import { jsx as jsx3, jsxs } from "react/jsx-runtime";
3038
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
2685
3039
  var styles = {
2686
3040
  root: {
2687
3041
  position: "fixed",
@@ -2767,9 +3121,9 @@ var OverlayBackdrop = ({
2767
3121
  viewport
2768
3122
  } = overlay;
2769
3123
  const hasHighlightBounds = Boolean(highlight.rect);
2770
- const prevScreenTargetRef = useRef7(null);
3124
+ const prevScreenTargetRef = useRef10(null);
2771
3125
  const shouldSnapHighlight = prevScreenTargetRef.current === true && !highlight.isScreen && hasHighlightBounds;
2772
- useEffect14(() => {
3126
+ useEffect16(() => {
2773
3127
  prevScreenTargetRef.current = highlight.isScreen;
2774
3128
  }, [highlight.isScreen]);
2775
3129
  const resolvedBlur = typeof blurAmount === "number" ? `${blurAmount}px` : "0px";
@@ -2829,7 +3183,7 @@ var OverlayBackdrop = ({
2829
3183
  overlayStyle.backgroundColor = color;
2830
3184
  }
2831
3185
  return createPortal(
2832
- /* @__PURE__ */ jsxs(
3186
+ /* @__PURE__ */ jsxs2(
2833
3187
  MotionDiv,
2834
3188
  {
2835
3189
  className: rootClassName,
@@ -2837,7 +3191,7 @@ var OverlayBackdrop = ({
2837
3191
  "aria-hidden": ariaHidden,
2838
3192
  "data-tour-overlay": "",
2839
3193
  children: [
2840
- /* @__PURE__ */ jsx3(AnimatePresence, { mode: "popLayout", children: shouldMask ? /* @__PURE__ */ jsx3(
3194
+ /* @__PURE__ */ jsx4(AnimatePresence, { mode: "popLayout", children: shouldMask ? /* @__PURE__ */ jsx4(
2841
3195
  MotionSvg,
2842
3196
  {
2843
3197
  width: "0",
@@ -2849,7 +3203,7 @@ var OverlayBackdrop = ({
2849
3203
  animate: { opacity: 1 },
2850
3204
  exit: { opacity: 0 },
2851
3205
  transition: overlayTransition,
2852
- children: /* @__PURE__ */ jsx3(MotionDefs, { children: /* @__PURE__ */ jsxs(
3206
+ children: /* @__PURE__ */ jsx4(MotionDefs, { children: /* @__PURE__ */ jsxs2(
2853
3207
  MotionMask,
2854
3208
  {
2855
3209
  id: maskId ?? void 0,
@@ -2861,7 +3215,7 @@ var OverlayBackdrop = ({
2861
3215
  animate: { width: viewport.width, height: viewport.height },
2862
3216
  transition: highlightTransition,
2863
3217
  children: [
2864
- /* @__PURE__ */ jsx3(
3218
+ /* @__PURE__ */ jsx4(
2865
3219
  MotionRect,
2866
3220
  {
2867
3221
  x: "0",
@@ -2877,7 +3231,7 @@ var OverlayBackdrop = ({
2877
3231
  exit: { opacity: 0 }
2878
3232
  }
2879
3233
  ),
2880
- /* @__PURE__ */ jsx3(
3234
+ /* @__PURE__ */ jsx4(
2881
3235
  MotionRect,
2882
3236
  {
2883
3237
  initial: false,
@@ -2896,7 +3250,7 @@ var OverlayBackdrop = ({
2896
3250
  },
2897
3251
  "tour-mask"
2898
3252
  ) : null }),
2899
- /* @__PURE__ */ jsx3(AnimatePresence, { mode: "popLayout", children: showBaseOverlay ? /* @__PURE__ */ jsx3(
3253
+ /* @__PURE__ */ jsx4(AnimatePresence, { mode: "popLayout", children: showBaseOverlay ? /* @__PURE__ */ jsx4(
2900
3254
  MotionDiv,
2901
3255
  {
2902
3256
  className: overlayClassName,
@@ -2924,7 +3278,7 @@ var OverlayBackdrop = ({
2924
3278
  },
2925
3279
  "tour-overlay"
2926
3280
  ) : null }),
2927
- /* @__PURE__ */ jsx3(AnimatePresence, { mode: "popLayout", children: fallbackSegments ? fallbackSegments.map((segment) => /* @__PURE__ */ jsx3(
3281
+ /* @__PURE__ */ jsx4(AnimatePresence, { mode: "popLayout", children: fallbackSegments ? fallbackSegments.map((segment) => /* @__PURE__ */ jsx4(
2928
3282
  MotionDiv,
2929
3283
  {
2930
3284
  className: segmentClassName,
@@ -2954,13 +3308,13 @@ var OverlayBackdrop = ({
2954
3308
  },
2955
3309
  `tour-overlay-fallback-${segment.key}`
2956
3310
  )) : null }),
2957
- showInteractionBlocker && blockerSegments ? /* @__PURE__ */ jsx3(
3311
+ showInteractionBlocker && blockerSegments ? /* @__PURE__ */ jsx4(
2958
3312
  "div",
2959
3313
  {
2960
3314
  style: { ...styles.blockerContainer, zIndex },
2961
3315
  "data-tour-overlay-layer": "interaction-blocker",
2962
3316
  "aria-hidden": true,
2963
- children: blockerSegments.map((segment) => /* @__PURE__ */ jsx3(
3317
+ children: blockerSegments.map((segment) => /* @__PURE__ */ jsx4(
2964
3318
  "div",
2965
3319
  {
2966
3320
  style: {
@@ -2975,7 +3329,7 @@ var OverlayBackdrop = ({
2975
3329
  ))
2976
3330
  }
2977
3331
  ) : null,
2978
- /* @__PURE__ */ jsx3(AnimatePresence, { mode: "popLayout", children: showHighlightRing && isActive && hasHighlightBounds ? /* @__PURE__ */ jsx3(
3332
+ /* @__PURE__ */ jsx4(AnimatePresence, { mode: "popLayout", children: showHighlightRing && isActive && hasHighlightBounds ? /* @__PURE__ */ jsx4(
2979
3333
  MotionDiv,
2980
3334
  {
2981
3335
  className: ringClassName,
@@ -3006,7 +3360,7 @@ var OverlayBackdrop = ({
3006
3360
  };
3007
3361
 
3008
3362
  // src/components/TourPopoverPortal.tsx
3009
- import { useEffect as useEffect15, useLayoutEffect as useLayoutEffect2, useMemo as useMemo11, useRef as useRef8, useState as useState11 } from "react";
3363
+ import { useEffect as useEffect17, useLayoutEffect as useLayoutEffect2, useMemo as useMemo13, useRef as useRef11, useState as useState12 } from "react";
3010
3364
  import { createPortal as createPortal2 } from "react-dom";
3011
3365
  import {
3012
3366
  autoPlacement,
@@ -3073,12 +3427,12 @@ var TourPopoverPortal = ({
3073
3427
  const popoverContentTransition = transitionsOverride?.popoverContent ?? adapter.transitions.popoverContent ?? DEFAULT_POPOVER_CONTENT_TRANSITION;
3074
3428
  const viewport = useViewportRect();
3075
3429
  const prefersMobileLayout = viewport.width <= MOBILE_BREAKPOINT || viewport.height <= MOBILE_HEIGHT_BREAKPOINT;
3076
- const prefersMobileRef = useRef8(prefersMobileLayout);
3077
- useEffect15(() => {
3430
+ const prefersMobileRef = useRef11(prefersMobileLayout);
3431
+ useEffect17(() => {
3078
3432
  prefersMobileRef.current = prefersMobileLayout;
3079
3433
  }, [prefersMobileLayout]);
3080
- const lastReadyTargetRef = useRef8(null);
3081
- useEffect15(() => {
3434
+ const lastReadyTargetRef = useRef11(null);
3435
+ useEffect17(() => {
3082
3436
  if (target.status === "ready" && target.rect) {
3083
3437
  lastReadyTargetRef.current = {
3084
3438
  rect: { ...target.rect },
@@ -3094,7 +3448,7 @@ var TourPopoverPortal = ({
3094
3448
  const shouldHidePopover = !resolvedRect && !target.isScreen;
3095
3449
  const fallbackRect = resolvedRect ?? viewport;
3096
3450
  const fallbackIsScreen = resolvedIsScreen;
3097
- const [floatingSize, setFloatingSize] = useState11(null);
3451
+ const [floatingSize, setFloatingSize] = useState12(null);
3098
3452
  const clampVertical = (value) => Math.min(viewport.height - 24, Math.max(24, value));
3099
3453
  const clampHorizontal = (value) => Math.min(viewport.width - 24, Math.max(24, value));
3100
3454
  const screenCenteredTop = viewport.height / 2 - (floatingSize?.height ?? 0) / 2;
@@ -3105,7 +3459,7 @@ var TourPopoverPortal = ({
3105
3459
  const leftBase = fallbackIsScreen ? screenCenteredLeft : fallbackRect.left + fallbackRect.width / 2 - floatingWidth / 2;
3106
3460
  const left = clampHorizontal(leftBase);
3107
3461
  const fallbackTransform = "translate3d(0px, 0px, 0px)";
3108
- const fallbackPosition = useMemo11(
3462
+ const fallbackPosition = useMemo13(
3109
3463
  () => ({
3110
3464
  top,
3111
3465
  left,
@@ -3113,7 +3467,7 @@ var TourPopoverPortal = ({
3113
3467
  }),
3114
3468
  [fallbackTransform, left, top]
3115
3469
  );
3116
- const centerInitialPosition = useMemo11(
3470
+ const centerInitialPosition = useMemo13(
3117
3471
  () => ({
3118
3472
  top: viewport.height / 2,
3119
3473
  left: viewport.width / 2,
@@ -3121,22 +3475,22 @@ var TourPopoverPortal = ({
3121
3475
  }),
3122
3476
  [viewport.height, viewport.width]
3123
3477
  );
3124
- const floatingRef = useRef8(null);
3125
- const cachedFloatingPositionRef = useRef8(null);
3126
- const appliedFloatingCacheRef = useRef8(null);
3127
- const deferredScreenSnapRef = useRef8(null);
3128
- const [layoutMode, setLayoutMode] = useState11(
3478
+ const floatingRef = useRef11(null);
3479
+ const cachedFloatingPositionRef = useRef11(null);
3480
+ const appliedFloatingCacheRef = useRef11(null);
3481
+ const deferredScreenSnapRef = useRef11(null);
3482
+ const [layoutMode, setLayoutMode] = useState12(
3129
3483
  () => prefersMobileLayout ? "mobile" : "floating"
3130
3484
  );
3131
- const [floatingPosition, setFloatingPosition] = useState11(fallbackPosition);
3132
- const [dragPosition, setDragPosition] = useState11(null);
3133
- const [isDragging, setIsDragging] = useState11(false);
3134
- const dragStateRef = useRef8(null);
3135
- const overflowRetryRef = useRef8({
3485
+ const [floatingPosition, setFloatingPosition] = useState12(fallbackPosition);
3486
+ const [dragPosition, setDragPosition] = useState12(null);
3487
+ const [isDragging, setIsDragging] = useState12(false);
3488
+ const dragStateRef = useRef11(null);
3489
+ const overflowRetryRef = useRef11({
3136
3490
  stepId: null,
3137
3491
  attempts: 0
3138
3492
  });
3139
- const overflowRetryTimeoutRef = useRef8(null);
3493
+ const overflowRetryTimeoutRef = useRef11(null);
3140
3494
  useLayoutEffect2(() => {
3141
3495
  if (!isBrowser) return;
3142
3496
  const node = floatingRef.current;
@@ -3156,25 +3510,25 @@ var TourPopoverPortal = ({
3156
3510
  const autoAlignment = resolvedPlacement.endsWith(
3157
3511
  "-start"
3158
3512
  ) ? "start" : resolvedPlacement.endsWith("-end") ? "end" : void 0;
3159
- useEffect15(() => {
3513
+ useEffect17(() => {
3160
3514
  setDragPosition(null);
3161
3515
  setLayoutMode(prefersMobileRef.current ? "mobile" : "floating");
3162
3516
  cachedFloatingPositionRef.current = null;
3163
3517
  appliedFloatingCacheRef.current = null;
3164
3518
  }, [target.stepId]);
3165
- useEffect15(() => {
3519
+ useEffect17(() => {
3166
3520
  if (layoutMode !== "manual") {
3167
3521
  setDragPosition(null);
3168
3522
  }
3169
3523
  }, [layoutMode]);
3170
- useEffect15(() => {
3524
+ useEffect17(() => {
3171
3525
  cachedFloatingPositionRef.current = floatingPosition;
3172
3526
  const cacheKey = getFloatingCacheKey(target);
3173
3527
  if (cacheKey) {
3174
3528
  floatingPositionCache.set(cacheKey, floatingPosition);
3175
3529
  }
3176
3530
  }, [floatingPosition, target.isScreen, target.stepId]);
3177
- const dockedPosition = useMemo11(
3531
+ const dockedPosition = useMemo13(
3178
3532
  () => ({
3179
3533
  top: viewport.height - DOCKED_MARGIN,
3180
3534
  left: viewport.width - DOCKED_MARGIN,
@@ -3182,7 +3536,7 @@ var TourPopoverPortal = ({
3182
3536
  }),
3183
3537
  [viewport.height, viewport.width]
3184
3538
  );
3185
- const mobilePosition = useMemo11(
3539
+ const mobilePosition = useMemo13(
3186
3540
  () => ({
3187
3541
  top: viewport.height - MOBILE_HORIZONTAL_GUTTER,
3188
3542
  left: viewport.width / 2,
@@ -3190,17 +3544,17 @@ var TourPopoverPortal = ({
3190
3544
  }),
3191
3545
  [viewport.height, viewport.width]
3192
3546
  );
3193
- useEffect15(() => {
3547
+ useEffect17(() => {
3194
3548
  if (layoutMode === "docked") {
3195
3549
  setFloatingPosition(dockedPosition);
3196
3550
  }
3197
3551
  }, [dockedPosition, layoutMode]);
3198
- useEffect15(() => {
3552
+ useEffect17(() => {
3199
3553
  if (layoutMode === "mobile") {
3200
3554
  setFloatingPosition(mobilePosition);
3201
3555
  }
3202
3556
  }, [layoutMode, mobilePosition]);
3203
- useEffect15(() => {
3557
+ useEffect17(() => {
3204
3558
  if (prefersMobileLayout) {
3205
3559
  if (layoutMode !== "mobile") {
3206
3560
  setLayoutMode("mobile");
@@ -3213,7 +3567,7 @@ var TourPopoverPortal = ({
3213
3567
  setFloatingPosition(fallbackPosition);
3214
3568
  }
3215
3569
  }, [fallbackPosition, layoutMode, prefersMobileLayout]);
3216
- useEffect15(() => {
3570
+ useEffect17(() => {
3217
3571
  if (layoutMode !== "floating") return;
3218
3572
  const stepId = target.stepId;
3219
3573
  if (!stepId) return;
@@ -3237,7 +3591,7 @@ var TourPopoverPortal = ({
3237
3591
  target.stepId
3238
3592
  ]);
3239
3593
  const shouldDeferScreenSnap = layoutMode === "floating" && target.isScreen && Boolean(layoutId);
3240
- useEffect15(() => {
3594
+ useEffect17(() => {
3241
3595
  return () => {
3242
3596
  if (deferredScreenSnapRef.current !== null) {
3243
3597
  cancelAnimationFrame(deferredScreenSnapRef.current);
@@ -3257,7 +3611,7 @@ var TourPopoverPortal = ({
3257
3611
  target.isScreen,
3258
3612
  target.status
3259
3613
  ]);
3260
- useEffect15(() => {
3614
+ useEffect17(() => {
3261
3615
  if (!shouldDeferScreenSnap) return;
3262
3616
  if (deferredScreenSnapRef.current !== null) {
3263
3617
  cancelAnimationFrame(deferredScreenSnapRef.current);
@@ -3284,7 +3638,7 @@ var TourPopoverPortal = ({
3284
3638
  }
3285
3639
  };
3286
3640
  }, [fallbackPosition, shouldDeferScreenSnap]);
3287
- useEffect15(() => {
3641
+ useEffect17(() => {
3288
3642
  return () => {
3289
3643
  if (overflowRetryTimeoutRef.current !== null) {
3290
3644
  window.clearTimeout(overflowRetryTimeoutRef.current);
@@ -3329,7 +3683,14 @@ var TourPopoverPortal = ({
3329
3683
  padding: FLOATING_OFFSET,
3330
3684
  alignment: autoAlignment
3331
3685
  })
3332
- ] : [flip({ padding: FLOATING_OFFSET, fallbackStrategy: "bestFit" })],
3686
+ ] : [
3687
+ flip({
3688
+ padding: FLOATING_OFFSET,
3689
+ fallbackStrategy: "bestFit",
3690
+ crossAxis: true,
3691
+ fallbackPlacements: ["bottom", "top", "right", "left"]
3692
+ })
3693
+ ],
3333
3694
  shift({ padding: FLOATING_OFFSET })
3334
3695
  ];
3335
3696
  const updatePosition = async () => {
@@ -3374,9 +3735,10 @@ var TourPopoverPortal = ({
3374
3735
  const spaceBelow = viewportBottom - targetRect.bottom;
3375
3736
  const spaceLeft = targetRect.left - viewportLeft;
3376
3737
  const spaceRight = viewportRight - targetRect.right;
3377
- const minSpaceNeeded = floatingBox.height + FLOATING_OFFSET * 2;
3378
- const hasVerticalSpace = spaceAbove >= minSpaceNeeded || spaceBelow >= minSpaceNeeded;
3379
- const hasHorizontalSpace = spaceLeft >= minSpaceNeeded || spaceRight >= minSpaceNeeded;
3738
+ const minVerticalSpaceNeeded = floatingBox.height + FLOATING_OFFSET * 2;
3739
+ const minHorizontalSpaceNeeded = floatingBox.width + FLOATING_OFFSET * 2;
3740
+ const hasVerticalSpace = spaceAbove >= minVerticalSpaceNeeded || spaceBelow >= minVerticalSpaceNeeded;
3741
+ const hasHorizontalSpace = spaceLeft >= minHorizontalSpaceNeeded || spaceRight >= minHorizontalSpaceNeeded;
3380
3742
  const targetNearlyFillsViewport = !target.isScreen && !hasVerticalSpace && !hasHorizontalSpace;
3381
3743
  const shouldDock = intersectsViewport && (targetNearlyFillsViewport || maxOverflow > overflowThreshold);
3382
3744
  if (shouldDock) {
@@ -3510,7 +3872,7 @@ var TourPopoverPortal = ({
3510
3872
  }
3511
3873
  event.preventDefault();
3512
3874
  };
3513
- useEffect15(() => endDrag, []);
3875
+ useEffect17(() => endDrag, []);
3514
3876
  const shouldUseFallbackInitial = layoutMode !== "mobile" && (Boolean(target.lastResolvedRect) || Boolean(cachedTarget));
3515
3877
  const floatingCacheKey = layoutMode === "mobile" ? null : getFloatingCacheKey(target);
3516
3878
  const persistedFloatingInitial = floatingCacheKey && floatingPositionCache.has(floatingCacheKey) ? floatingPositionCache.get(floatingCacheKey) ?? null : null;
@@ -3602,7 +3964,7 @@ var TourPopoverPortal = ({
3602
3964
  };
3603
3965
 
3604
3966
  // src/components/TourFocusManager.tsx
3605
- import { useEffect as useEffect16, useLayoutEffect as useLayoutEffect3, useRef as useRef9, useState as useState12 } from "react";
3967
+ import { useEffect as useEffect18, useLayoutEffect as useLayoutEffect3, useRef as useRef12, useState as useState13 } from "react";
3606
3968
  import { createPortal as createPortal3 } from "react-dom";
3607
3969
 
3608
3970
  // src/utils/focus.ts
@@ -3663,7 +4025,7 @@ var focusElement = (element, options) => {
3663
4025
  };
3664
4026
 
3665
4027
  // src/components/TourFocusManager.tsx
3666
- import { Fragment, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
4028
+ import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
3667
4029
  var runMicrotask = (callback) => {
3668
4030
  if (typeof queueMicrotask === "function") {
3669
4031
  queueMicrotask(callback);
@@ -3679,18 +4041,18 @@ var TourFocusManager = ({
3679
4041
  highlightRect,
3680
4042
  guardElementFocusRing
3681
4043
  }) => {
3682
- const previousFocusRef = useRef9(null);
3683
- const guardNodesRef = useRef9({
4044
+ const previousFocusRef = useRef12(null);
4045
+ const guardNodesRef = useRef12({
3684
4046
  "target-start": null,
3685
4047
  "target-end": null,
3686
4048
  "popover-start": null,
3687
4049
  "popover-end": null
3688
4050
  });
3689
- const lastTabDirectionRef = useRef9("forward");
3690
- const suppressGuardHopRef = useRef9(null);
3691
- const [targetRingActive, setTargetRingActive] = useState12(false);
3692
- const [popoverRingActive, setPopoverRingActive] = useState12(false);
3693
- const [popoverRect, setPopoverRect] = useState12(null);
4051
+ const lastTabDirectionRef = useRef12("forward");
4052
+ const suppressGuardHopRef = useRef12(null);
4053
+ const [targetRingActive, setTargetRingActive] = useState13(false);
4054
+ const [popoverRingActive, setPopoverRingActive] = useState13(false);
4055
+ const [popoverRect, setPopoverRect] = useState13(null);
3694
4056
  const restoreFocus = () => {
3695
4057
  const previous = previousFocusRef.current;
3696
4058
  previousFocusRef.current = null;
@@ -3716,7 +4078,7 @@ var TourFocusManager = ({
3716
4078
  restoreFocus();
3717
4079
  };
3718
4080
  }, [active, popoverNode, target.element]);
3719
- useEffect16(() => {
4081
+ useEffect18(() => {
3720
4082
  if (!isBrowser) return;
3721
4083
  if (!active) return;
3722
4084
  const doc = popoverNode?.ownerDocument ?? target.element?.ownerDocument ?? document;
@@ -3925,8 +4287,8 @@ var TourFocusManager = ({
3925
4287
  const showPopoverRing = popoverRingActive && popoverRect;
3926
4288
  if (!showTargetRing && !showPopoverRing) return null;
3927
4289
  return createPortal3(
3928
- /* @__PURE__ */ jsxs2(Fragment, { children: [
3929
- showTargetRing && /* @__PURE__ */ jsx4(
4290
+ /* @__PURE__ */ jsxs3(Fragment, { children: [
4291
+ showTargetRing && /* @__PURE__ */ jsx5(
3930
4292
  "div",
3931
4293
  {
3932
4294
  style: {
@@ -3943,7 +4305,7 @@ var TourFocusManager = ({
3943
4305
  "aria-hidden": true
3944
4306
  }
3945
4307
  ),
3946
- showPopoverRing && /* @__PURE__ */ jsx4(
4308
+ showPopoverRing && /* @__PURE__ */ jsx5(
3947
4309
  "div",
3948
4310
  {
3949
4311
  style: {
@@ -3966,7 +4328,7 @@ var TourFocusManager = ({
3966
4328
  };
3967
4329
 
3968
4330
  // src/motion/useHudMotion.ts
3969
- import { useMemo as useMemo12 } from "react";
4331
+ import { useMemo as useMemo14 } from "react";
3970
4332
  var DEFAULT_HIGHLIGHT_TRANSITION2 = {
3971
4333
  duration: 0.35,
3972
4334
  ease: "easeOut",
@@ -3993,7 +4355,7 @@ var DEFAULT_POPOVER_CONTENT_TRANSITION2 = {
3993
4355
  };
3994
4356
  var useHudMotion = () => {
3995
4357
  const adapter = useAnimationAdapter();
3996
- return useMemo12(() => {
4358
+ return useMemo14(() => {
3997
4359
  const components = {
3998
4360
  ...adapter.components
3999
4361
  };
@@ -4011,12 +4373,12 @@ var useHudMotion = () => {
4011
4373
  };
4012
4374
  export {
4013
4375
  AnimationAdapterProvider,
4376
+ DialogRegistryProvider,
4014
4377
  OverlayBackdrop,
4015
4378
  TourFocusManager,
4016
4379
  TourPopoverPortal,
4017
4380
  TourProvider,
4018
4381
  createPathString,
4019
- createRadixDialogHelpers,
4020
4382
  createWaitForPredicateController,
4021
4383
  defaultAnimationAdapter,
4022
4384
  defaultLabels,
@@ -4028,6 +4390,8 @@ export {
4028
4390
  useAnimationAdapter,
4029
4391
  useBodyScrollLock,
4030
4392
  useDelayAdvance,
4393
+ useDialogRegistry,
4394
+ useDialogRegistryOptional,
4031
4395
  useHiddenTargetFallback,
4032
4396
  useHudDescription,
4033
4397
  useHudMotion,
@@ -4036,6 +4400,7 @@ export {
4036
4400
  useHudTargetIssue,
4037
4401
  usePreferredAnimationAdapter,
4038
4402
  useRadixDialogAdapter,
4403
+ useRadixTourDialog,
4039
4404
  useTour,
4040
4405
  useTourControls,
4041
4406
  useTourEvents,