@flowsterix/react 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -72,7 +72,17 @@ var defaultLabels = {
72
72
  ariaStepProgress: ({ current, total }) => `Step ${current} of ${total}`,
73
73
  ariaTimeRemaining: ({ ms }) => `${Math.ceil(ms / 1e3)} seconds remaining`,
74
74
  ariaDelayProgress: "Auto-advance progress",
75
- formatTimeRemaining: ({ ms }) => `${Math.ceil(ms / 1e3)}s remaining`
75
+ formatTimeRemaining: ({ ms }) => `${Math.ceil(ms / 1e3)}s remaining`,
76
+ targetIssue: {
77
+ missingTitle: "Target not visible",
78
+ missingBody: "The target element is not currently visible. Make sure the UI piece is mounted and displayed.",
79
+ missingHint: "Showing the last known position until the element returns.",
80
+ hiddenTitle: "Target not visible",
81
+ hiddenBody: "The target element is not currently visible. Make sure the UI piece is mounted and displayed.",
82
+ hiddenHint: "Showing the last known position until the element returns.",
83
+ detachedTitle: "Target left the page",
84
+ detachedBody: "Navigate back to the screen that contains this element or reopen it before continuing the tour."
85
+ }
76
86
  };
77
87
  var LabelsContext = (0, import_react.createContext)(defaultLabels);
78
88
  var LabelsProvider = LabelsContext.Provider;
@@ -1663,7 +1673,7 @@ var useTourTarget = () => {
1663
1673
  };
1664
1674
 
1665
1675
  // src/hooks/useHudState.ts
1666
- var import_react9 = require("react");
1676
+ var import_react10 = require("react");
1667
1677
 
1668
1678
  // src/hooks/useAdvanceRules.ts
1669
1679
  var import_react6 = require("react");
@@ -1878,6 +1888,7 @@ var useAdvanceRules = (target) => {
1878
1888
  // src/hooks/useHiddenTargetFallback.ts
1879
1889
  var import_react7 = require("react");
1880
1890
  var DEFAULT_DELAY_MS = 900;
1891
+ var DEFAULT_GRACE_PERIOD_MS = 400;
1881
1892
  var useHiddenTargetFallback = ({
1882
1893
  step,
1883
1894
  target,
@@ -1885,7 +1896,9 @@ var useHiddenTargetFallback = ({
1885
1896
  onSkip
1886
1897
  }) => {
1887
1898
  const [usingScreenFallback, setUsingScreenFallback] = (0, import_react7.useState)(false);
1899
+ const [isInGracePeriod, setIsInGracePeriod] = (0, import_react7.useState)(false);
1888
1900
  const timeoutRef = (0, import_react7.useRef)(null);
1901
+ const graceTimeoutRef = (0, import_react7.useRef)(null);
1889
1902
  const skipTriggeredRef = (0, import_react7.useRef)(false);
1890
1903
  const hiddenMode = step?.targetBehavior?.hidden ?? "screen";
1891
1904
  const hiddenDelayMs = Math.max(
@@ -1898,26 +1911,44 @@ var useHiddenTargetFallback = ({
1898
1911
  timeoutRef.current = null;
1899
1912
  }
1900
1913
  };
1914
+ const clearGraceTimeout = () => {
1915
+ if (graceTimeoutRef.current !== null) {
1916
+ globalThis.clearTimeout(graceTimeoutRef.current);
1917
+ graceTimeoutRef.current = null;
1918
+ }
1919
+ };
1901
1920
  (0, import_react7.useEffect)(() => {
1902
1921
  skipTriggeredRef.current = false;
1903
1922
  setUsingScreenFallback(false);
1923
+ setIsInGracePeriod(false);
1904
1924
  clearPendingTimeout();
1905
- return clearPendingTimeout;
1925
+ clearGraceTimeout();
1926
+ return () => {
1927
+ clearPendingTimeout();
1928
+ clearGraceTimeout();
1929
+ };
1906
1930
  }, [step?.id]);
1907
1931
  (0, import_react7.useEffect)(() => {
1908
1932
  if (!isBrowser) return void 0;
1909
1933
  if (!step) return void 0;
1910
1934
  clearPendingTimeout();
1935
+ clearGraceTimeout();
1911
1936
  const isHiddenOrDetached = (target.visibility === "hidden" || target.visibility === "detached") && target.status === "ready";
1912
1937
  const isMissingWithNoRect = target.visibility === "missing" && target.status === "resolving" && target.rect === null && target.lastResolvedRect === null;
1913
- const shouldHandleHiddenTarget = !target.isScreen && (isHiddenOrDetached || isMissingWithNoRect);
1938
+ const isMissingAfterNavigation = target.visibility === "missing" && target.status === "resolving" && target.rect === null;
1939
+ const shouldHandleHiddenTarget = !target.isScreen && (isHiddenOrDetached || isMissingWithNoRect || isMissingAfterNavigation);
1914
1940
  if (!shouldHandleHiddenTarget) {
1915
1941
  setUsingScreenFallback(false);
1942
+ setIsInGracePeriod(false);
1916
1943
  return void 0;
1917
1944
  }
1945
+ setIsInGracePeriod(true);
1918
1946
  if (hiddenMode !== "screen") {
1919
1947
  setUsingScreenFallback(false);
1920
1948
  }
1949
+ graceTimeoutRef.current = globalThis.setTimeout(() => {
1950
+ setIsInGracePeriod(false);
1951
+ }, DEFAULT_GRACE_PERIOD_MS);
1921
1952
  timeoutRef.current = globalThis.setTimeout(() => {
1922
1953
  if (hiddenMode === "screen") {
1923
1954
  setUsingScreenFallback(true);
@@ -1928,7 +1959,10 @@ var useHiddenTargetFallback = ({
1928
1959
  onSkip();
1929
1960
  }
1930
1961
  }, hiddenDelayMs);
1931
- return clearPendingTimeout;
1962
+ return () => {
1963
+ clearPendingTimeout();
1964
+ clearGraceTimeout();
1965
+ };
1932
1966
  }, [
1933
1967
  step,
1934
1968
  target.visibility,
@@ -1956,18 +1990,82 @@ var useHiddenTargetFallback = ({
1956
1990
  }, [target, usingScreenFallback, viewportRect]);
1957
1991
  return {
1958
1992
  target: resolvedTarget,
1959
- usingScreenFallback
1993
+ usingScreenFallback,
1994
+ isInGracePeriod
1960
1995
  };
1961
1996
  };
1962
1997
 
1963
- // src/hooks/useViewportRect.ts
1998
+ // src/hooks/useRouteMismatch.ts
1964
1999
  var import_react8 = require("react");
2000
+
2001
+ // src/router/utils.ts
2002
+ var ensurePrefix = (value, prefix) => value.startsWith(prefix) ? value : `${prefix}${value}`;
2003
+ var isNonEmptyString = (value) => typeof value === "string" && value.length > 0;
2004
+ var toSearchString = (value) => {
2005
+ if (!isNonEmptyString(value)) {
2006
+ if (value instanceof URLSearchParams) {
2007
+ const serialized = value.toString();
2008
+ return serialized.length > 0 ? `?${serialized}` : "";
2009
+ }
2010
+ if (typeof value === "object" && value !== null) {
2011
+ try {
2012
+ const params = new URLSearchParams();
2013
+ for (const [key, raw] of Object.entries(
2014
+ value
2015
+ )) {
2016
+ if (raw === void 0 || raw === null) continue;
2017
+ params.set(key, String(raw));
2018
+ }
2019
+ const serialized = params.toString();
2020
+ return serialized.length > 0 ? `?${serialized}` : "";
2021
+ } catch {
2022
+ return "";
2023
+ }
2024
+ }
2025
+ return "";
2026
+ }
2027
+ if (value === "?") return "";
2028
+ return value.startsWith("?") ? value : ensurePrefix(value, "?");
2029
+ };
2030
+ var toHashString = (value) => {
2031
+ if (!isNonEmptyString(value)) {
2032
+ return "";
2033
+ }
2034
+ if (value === "#") return "";
2035
+ return value.startsWith("#") ? value : ensurePrefix(value, "#");
2036
+ };
2037
+ var createPathString = (pathname, search, hash) => {
2038
+ const normalizedPath = isNonEmptyString(pathname) ? pathname.startsWith("/") ? pathname : `/${pathname}` : "/";
2039
+ const searchPart = toSearchString(search);
2040
+ const hashPart = toHashString(hash);
2041
+ return `${normalizedPath}${searchPart}${hashPart}`;
2042
+ };
2043
+
2044
+ // src/hooks/useRouteMismatch.ts
2045
+ var useRouteMismatch = (step) => {
2046
+ const [currentPath, setCurrentPath] = (0, import_react8.useState)(() => getCurrentRoutePath());
2047
+ (0, import_react8.useEffect)(() => {
2048
+ return subscribeToRouteChanges((path) => {
2049
+ setCurrentPath(path);
2050
+ });
2051
+ }, []);
2052
+ const expectedRoute = step?.route;
2053
+ const isRouteMismatch = step !== null && expectedRoute !== void 0 && !matchRoute({ pattern: expectedRoute, path: currentPath });
2054
+ return {
2055
+ isRouteMismatch,
2056
+ currentPath,
2057
+ expectedRoute
2058
+ };
2059
+ };
2060
+
2061
+ // src/hooks/useViewportRect.ts
2062
+ var import_react9 = require("react");
1965
2063
  var useViewportRect = () => {
1966
- const [viewport, setViewport] = (0, import_react8.useState)(
2064
+ const [viewport, setViewport] = (0, import_react9.useState)(
1967
2065
  () => getViewportRect()
1968
2066
  );
1969
- const rafRef = (0, import_react8.useRef)(null);
1970
- (0, import_react8.useEffect)(() => {
2067
+ const rafRef = (0, import_react9.useRef)(null);
2068
+ (0, import_react9.useEffect)(() => {
1971
2069
  if (!isBrowser) return;
1972
2070
  const updateViewport = () => {
1973
2071
  rafRef.current = null;
@@ -2009,12 +2107,12 @@ var normalizeFlowFilter = (value) => {
2009
2107
  };
2010
2108
  var useHudState = (options = {}) => {
2011
2109
  const { flowId } = options;
2012
- const flowFilter = (0, import_react9.useMemo)(() => normalizeFlowFilter(flowId), [flowId]);
2013
- const { state, activeStep, activeFlowId, flows, next, complete } = useTour();
2110
+ const flowFilter = (0, import_react10.useMemo)(() => normalizeFlowFilter(flowId), [flowId]);
2111
+ const { state, activeStep, activeFlowId, flows, next, complete, pause, resume } = useTour();
2014
2112
  const target = useTourTarget();
2015
2113
  const viewportRect = useViewportRect();
2016
2114
  useAdvanceRules(target);
2017
- const matchesFlowFilter = (0, import_react9.useMemo)(() => {
2115
+ const matchesFlowFilter = (0, import_react10.useMemo)(() => {
2018
2116
  if (!flowFilter || flowFilter.length === 0) return true;
2019
2117
  if (!activeFlowId) return false;
2020
2118
  return flowFilter.includes(activeFlowId);
@@ -2022,15 +2120,15 @@ var useHudState = (options = {}) => {
2022
2120
  const isRunning = state?.status === "running";
2023
2121
  const runningState = isRunning && matchesFlowFilter ? state : null;
2024
2122
  const runningStep = runningState && activeStep ? activeStep : null;
2025
- const [shouldRender, setShouldRender] = (0, import_react9.useState)(
2123
+ const [shouldRender, setShouldRender] = (0, import_react10.useState)(
2026
2124
  Boolean(runningStep)
2027
2125
  );
2028
- (0, import_react9.useEffect)(() => {
2126
+ (0, import_react10.useEffect)(() => {
2029
2127
  if (runningStep) {
2030
2128
  setShouldRender(true);
2031
2129
  }
2032
2130
  }, [runningStep?.id]);
2033
- (0, import_react9.useEffect)(() => {
2131
+ (0, import_react10.useEffect)(() => {
2034
2132
  if (!shouldRender) return;
2035
2133
  if (runningStep) return;
2036
2134
  if (target.status !== "idle") return;
@@ -2041,7 +2139,20 @@ var useHudState = (options = {}) => {
2041
2139
  window.clearTimeout(timeoutId);
2042
2140
  };
2043
2141
  }, [runningStep, shouldRender, target.status]);
2044
- const skipHiddenStep = (0, import_react9.useCallback)(() => {
2142
+ const { isRouteMismatch, currentPath } = useRouteMismatch(activeStep);
2143
+ const pausedForMissingTargetRef = (0, import_react10.useRef)(null);
2144
+ (0, import_react10.useEffect)(() => {
2145
+ if (!isRouteMismatch) return;
2146
+ if (!runningState || runningState.status !== "running") return;
2147
+ pause();
2148
+ }, [isRouteMismatch, runningState, pause]);
2149
+ (0, import_react10.useEffect)(() => {
2150
+ if (isRouteMismatch) return;
2151
+ if (pausedForMissingTargetRef.current !== null) return;
2152
+ if (!state || state.status !== "paused") return;
2153
+ resume();
2154
+ }, [isRouteMismatch, state, resume]);
2155
+ const skipHiddenStep = (0, import_react10.useCallback)(() => {
2045
2156
  if (!runningState || runningState.status !== "running") return;
2046
2157
  if (!activeFlowId) return;
2047
2158
  const flow = flows.get(activeFlowId);
@@ -2053,12 +2164,41 @@ var useHudState = (options = {}) => {
2053
2164
  next();
2054
2165
  }
2055
2166
  }, [activeFlowId, complete, flows, next, runningState]);
2056
- const { target: hudTarget } = useHiddenTargetFallback({
2167
+ const { target: hudTarget, isInGracePeriod } = useHiddenTargetFallback({
2057
2168
  step: runningStep,
2058
2169
  target,
2059
2170
  viewportRect,
2060
2171
  onSkip: skipHiddenStep
2061
2172
  });
2173
+ (0, import_react10.useEffect)(() => {
2174
+ if (isRouteMismatch) return;
2175
+ if (activeStep?.route !== void 0) return;
2176
+ if (isInGracePeriod) return;
2177
+ if (target.visibility !== "missing") return;
2178
+ if (target.isScreen) return;
2179
+ if (!runningState || runningState.status !== "running") return;
2180
+ pausedForMissingTargetRef.current = currentPath;
2181
+ pause();
2182
+ }, [
2183
+ isRouteMismatch,
2184
+ activeStep?.route,
2185
+ isInGracePeriod,
2186
+ target.visibility,
2187
+ target.isScreen,
2188
+ runningState,
2189
+ currentPath,
2190
+ pause
2191
+ ]);
2192
+ (0, import_react10.useEffect)(() => {
2193
+ if (pausedForMissingTargetRef.current === null) return;
2194
+ if (!state || state.status !== "paused") return;
2195
+ if (currentPath === pausedForMissingTargetRef.current) return;
2196
+ pausedForMissingTargetRef.current = null;
2197
+ resume();
2198
+ }, [currentPath, state, resume]);
2199
+ (0, import_react10.useEffect)(() => {
2200
+ pausedForMissingTargetRef.current = null;
2201
+ }, [activeStep?.id]);
2062
2202
  const canRenderStep = Boolean(runningStep && runningState);
2063
2203
  const focusTrapActive = canRenderStep;
2064
2204
  const flowHudOptions = matchesFlowFilter && activeFlowId ? flows.get(activeFlowId)?.hud ?? null : null;
@@ -2075,29 +2215,30 @@ var useHudState = (options = {}) => {
2075
2215
  flowHudOptions,
2076
2216
  hudRenderMode,
2077
2217
  matchesFlowFilter,
2078
- activeFlowId
2218
+ activeFlowId,
2219
+ isInGracePeriod
2079
2220
  };
2080
2221
  };
2081
2222
 
2082
2223
  // src/hooks/useHudDescription.ts
2083
- var import_react10 = require("react");
2224
+ var import_react11 = require("react");
2084
2225
  var sanitizeForId = (value) => {
2085
2226
  const normalized = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
2086
2227
  return normalized.length > 0 ? normalized : "step";
2087
2228
  };
2088
2229
  var useHudDescription = (options) => {
2089
2230
  const { step, fallbackAriaDescribedBy } = options;
2090
- const targetDescription = (0, import_react10.useMemo)(() => {
2231
+ const targetDescription = (0, import_react11.useMemo)(() => {
2091
2232
  if (!step) return null;
2092
2233
  if (typeof step.target !== "object") return null;
2093
2234
  const description = step.target.description;
2094
2235
  return typeof description === "string" ? description : null;
2095
2236
  }, [step]);
2096
- const descriptionId = (0, import_react10.useMemo)(() => {
2237
+ const descriptionId = (0, import_react11.useMemo)(() => {
2097
2238
  if (!step || !targetDescription) return void 0;
2098
2239
  return `tour-step-${sanitizeForId(step.id)}-description`;
2099
2240
  }, [step, targetDescription]);
2100
- const combinedAriaDescribedBy = (0, import_react10.useMemo)(() => {
2241
+ const combinedAriaDescribedBy = (0, import_react11.useMemo)(() => {
2101
2242
  const parts = [fallbackAriaDescribedBy, descriptionId].filter(Boolean);
2102
2243
  return parts.length > 0 ? parts.join(" ") : void 0;
2103
2244
  }, [descriptionId, fallbackAriaDescribedBy]);
@@ -2109,10 +2250,10 @@ var useHudDescription = (options) => {
2109
2250
  };
2110
2251
 
2111
2252
  // src/hooks/useHudShortcuts.ts
2112
- var import_react12 = require("react");
2253
+ var import_react13 = require("react");
2113
2254
 
2114
2255
  // src/hooks/useTourControls.ts
2115
- var import_react11 = require("react");
2256
+ var import_react12 = require("react");
2116
2257
  var hasManualAdvance = (rules) => rules.some((rule) => rule.type === "manual");
2117
2258
  var didPreviousAdvanceViaRoute = (rules) => rules.some((rule) => rule.type === "route");
2118
2259
  var didPreviousAdvanceViaTargetEvent = (rules) => rules.some((rule) => rule.type === "event" && rule.on === "target");
@@ -2128,7 +2269,7 @@ var useTourControls = () => {
2128
2269
  flows,
2129
2270
  activeStep
2130
2271
  } = tour;
2131
- const computed = (0, import_react11.useMemo)(() => {
2272
+ const computed = (0, import_react12.useMemo)(() => {
2132
2273
  if (!state || state.status !== "running" || !activeStep) {
2133
2274
  return {
2134
2275
  isActive: false,
@@ -2177,11 +2318,11 @@ var useTourControls = () => {
2177
2318
  } = computed;
2178
2319
  const canGoBack = showBackButton && !backDisabled;
2179
2320
  const canGoNext = showNextButton && !nextDisabled;
2180
- const goBack = (0, import_react11.useCallback)(() => {
2321
+ const goBack = (0, import_react12.useCallback)(() => {
2181
2322
  if (!canGoBack) return;
2182
2323
  back();
2183
2324
  }, [back, canGoBack]);
2184
- const goNext = (0, import_react11.useCallback)(() => {
2325
+ const goNext = (0, import_react12.useCallback)(() => {
2185
2326
  if (!canGoNext) return;
2186
2327
  if (isLast) {
2187
2328
  complete();
@@ -2189,7 +2330,7 @@ var useTourControls = () => {
2189
2330
  next();
2190
2331
  }
2191
2332
  }, [canGoNext, complete, isLast, next]);
2192
- return (0, import_react11.useMemo)(
2333
+ return (0, import_react12.useMemo)(
2193
2334
  () => ({
2194
2335
  showBackButton,
2195
2336
  backDisabled,
@@ -2234,7 +2375,7 @@ var useHudShortcuts = (target, options) => {
2234
2375
  const escapeEnabled = options?.escape ?? true;
2235
2376
  const { state } = useTour();
2236
2377
  const { cancel, canGoBack, goBack, canGoNext, goNext, isActive } = useTourControls();
2237
- (0, import_react12.useEffect)(() => {
2378
+ (0, import_react13.useEffect)(() => {
2238
2379
  if (!isBrowser) return void 0;
2239
2380
  if (!enabled) return void 0;
2240
2381
  if (!target) return void 0;
@@ -2298,10 +2439,10 @@ var useHudShortcuts = (target, options) => {
2298
2439
  };
2299
2440
 
2300
2441
  // src/hooks/useTourHud.ts
2301
- var import_react15 = require("react");
2442
+ var import_react16 = require("react");
2302
2443
 
2303
2444
  // src/hooks/useBodyScrollLock.ts
2304
- var import_react13 = require("react");
2445
+ var import_react14 = require("react");
2305
2446
  var lockCount = 0;
2306
2447
  var previousOverflow = null;
2307
2448
  var acquireLock = () => {
@@ -2322,7 +2463,7 @@ var releaseLock = () => {
2322
2463
  }
2323
2464
  };
2324
2465
  var useBodyScrollLock = (enabled) => {
2325
- (0, import_react13.useEffect)(() => {
2466
+ (0, import_react14.useEffect)(() => {
2326
2467
  if (!enabled) return;
2327
2468
  acquireLock();
2328
2469
  return () => {
@@ -2332,42 +2473,45 @@ var useBodyScrollLock = (enabled) => {
2332
2473
  };
2333
2474
 
2334
2475
  // src/hooks/useHudTargetIssue.ts
2335
- var import_react14 = require("react");
2336
- var deriveTargetIssue = (target) => {
2476
+ var import_react15 = require("react");
2477
+ var deriveTargetIssue = (params) => {
2478
+ const { target, labels } = params;
2337
2479
  if (target.isScreen) return null;
2338
2480
  if (target.status === "idle") return null;
2339
2481
  switch (target.visibility) {
2340
2482
  case "missing":
2341
2483
  return {
2342
2484
  type: "missing",
2343
- title: "Looking for the target",
2344
- body: "Flowsterix is still trying to find this element. Make sure the UI piece is mounted or adjust the selector.",
2345
- hint: target.rectSource === "stored" ? "Showing the last known position until the element returns." : void 0
2485
+ title: labels.targetIssue.missingTitle,
2486
+ body: labels.targetIssue.missingBody,
2487
+ hint: target.rectSource === "stored" ? labels.targetIssue.missingHint : void 0
2346
2488
  };
2347
2489
  case "hidden":
2348
2490
  return {
2349
2491
  type: "hidden",
2350
- title: "Target is hidden",
2351
- body: "The element exists but is currently hidden, collapsed, or zero-sized. Expand it so the highlight can lock on."
2492
+ title: labels.targetIssue.hiddenTitle,
2493
+ body: labels.targetIssue.hiddenBody,
2494
+ hint: target.rectSource === "stored" ? labels.targetIssue.hiddenHint : void 0
2352
2495
  };
2353
2496
  case "detached":
2354
2497
  return {
2355
2498
  type: "detached",
2356
- title: "Target left the page",
2357
- body: "Navigate back to the screen that contains this element or reopen it before continuing the tour."
2499
+ title: labels.targetIssue.detachedTitle,
2500
+ body: labels.targetIssue.detachedBody
2358
2501
  };
2359
2502
  default:
2360
2503
  return null;
2361
2504
  }
2362
2505
  };
2363
2506
  var useHudTargetIssue = (target, options) => {
2507
+ const labels = useTourLabels();
2364
2508
  const delayMs = Math.max(0, options?.delayMs ?? 500);
2365
- const [armed, setArmed] = (0, import_react14.useState)(false);
2366
- const rawIssue = (0, import_react14.useMemo)(
2367
- () => deriveTargetIssue(target),
2368
- [target.isScreen, target.rectSource, target.status, target.visibility]
2509
+ const [armed, setArmed] = (0, import_react15.useState)(false);
2510
+ const rawIssue = (0, import_react15.useMemo)(
2511
+ () => deriveTargetIssue({ target, labels }),
2512
+ [target.isScreen, target.rectSource, target.status, target.visibility, labels]
2369
2513
  );
2370
- (0, import_react14.useEffect)(() => {
2514
+ (0, import_react15.useEffect)(() => {
2371
2515
  if (!rawIssue) {
2372
2516
  setArmed(false);
2373
2517
  return;
@@ -2401,7 +2545,7 @@ var useTourHud = (options = {}) => {
2401
2545
  const { backdropInteraction, lockBodyScroll } = useTour();
2402
2546
  const hudState = useHudState();
2403
2547
  const disableDefaultHud = hudState.hudRenderMode === "none";
2404
- const [popoverNode, setPopoverNode] = (0, import_react15.useState)(null);
2548
+ const [popoverNode, setPopoverNode] = (0, import_react16.useState)(null);
2405
2549
  const popoverOptions = hudState.flowHudOptions?.popover;
2406
2550
  const description = useHudDescription({
2407
2551
  step: hudState.runningStep,
@@ -2425,7 +2569,7 @@ var useTourHud = (options = {}) => {
2425
2569
  radius: overlayRadius,
2426
2570
  interactionMode: hudState.flowHudOptions?.backdrop?.interaction ?? backdropInteraction
2427
2571
  };
2428
- const popover = (0, import_react15.useMemo)(() => {
2572
+ const popover = (0, import_react16.useMemo)(() => {
2429
2573
  return {
2430
2574
  offset: popoverOptions?.offset ?? 16,
2431
2575
  role: popoverOptions?.role ?? "dialog",
@@ -2437,13 +2581,13 @@ var useTourHud = (options = {}) => {
2437
2581
  placement: hudState.runningStep?.placement
2438
2582
  };
2439
2583
  }, [hudState.runningStep?.placement, popoverOptions]);
2440
- const descriptionResult = (0, import_react15.useMemo)(() => {
2584
+ const descriptionResult = (0, import_react16.useMemo)(() => {
2441
2585
  return {
2442
2586
  ...description,
2443
2587
  text: description.targetDescription
2444
2588
  };
2445
2589
  }, [description]);
2446
- const focusManager = (0, import_react15.useMemo)(
2590
+ const focusManager = (0, import_react16.useMemo)(
2447
2591
  () => ({
2448
2592
  active: hudState.focusTrapActive,
2449
2593
  target: hudState.hudTarget,
@@ -2473,7 +2617,7 @@ var useTourHud = (options = {}) => {
2473
2617
  };
2474
2618
 
2475
2619
  // src/hooks/useTourOverlay.ts
2476
- var import_react16 = require("react");
2620
+ var import_react17 = require("react");
2477
2621
  var DEFAULT_PADDING = 12;
2478
2622
  var DEFAULT_RADIUS = 12;
2479
2623
  var DEFAULT_EDGE_BUFFER = 0;
@@ -2483,11 +2627,12 @@ var useTourOverlay = (options) => {
2483
2627
  padding = DEFAULT_PADDING,
2484
2628
  radius = DEFAULT_RADIUS,
2485
2629
  edgeBuffer = DEFAULT_EDGE_BUFFER,
2486
- interactionMode = "passthrough"
2630
+ interactionMode = "passthrough",
2631
+ isInGracePeriod = false
2487
2632
  } = options;
2488
- const hasShownRef = (0, import_react16.useRef)(false);
2489
- const lastReadyTargetRef = (0, import_react16.useRef)(null);
2490
- (0, import_react16.useEffect)(() => {
2633
+ const hasShownRef = (0, import_react17.useRef)(false);
2634
+ const lastReadyTargetRef = (0, import_react17.useRef)(null);
2635
+ (0, import_react17.useEffect)(() => {
2491
2636
  if (!isBrowser) return;
2492
2637
  if (target.status === "ready") {
2493
2638
  hasShownRef.current = true;
@@ -2537,15 +2682,15 @@ var useTourOverlay = (options) => {
2537
2682
  height: highlightHeight,
2538
2683
  radius: highlightRadius
2539
2684
  } : null;
2540
- const maskCapable = (0, import_react16.useMemo)(() => supportsMasking(), []);
2541
- const isActive = target.status === "ready" || target.status === "resolving" && cachedTarget !== null;
2685
+ const maskCapable = (0, import_react17.useMemo)(() => supportsMasking(), []);
2686
+ const isActive = target.status === "ready" || target.status === "resolving" && cachedTarget !== null || isInGracePeriod;
2542
2687
  const shouldMask = maskCapable && isActive;
2543
- const maskId = (0, import_react16.useMemo)(
2688
+ const maskId = (0, import_react17.useMemo)(
2544
2689
  () => `tour-overlay-mask-${Math.random().toString(36).slice(2, 10)}`,
2545
2690
  []
2546
2691
  );
2547
2692
  const maskUrl = shouldMask ? `url(#${maskId})` : void 0;
2548
- const fallbackSegments = (0, import_react16.useMemo)(() => {
2693
+ const fallbackSegments = (0, import_react17.useMemo)(() => {
2549
2694
  if (!isActive || shouldMask || !hasHighlightBounds || !highlightRect) {
2550
2695
  return null;
2551
2696
  }
@@ -2598,7 +2743,7 @@ var useTourOverlay = (options) => {
2598
2743
  viewport.height,
2599
2744
  viewport.width
2600
2745
  ]);
2601
- const blockerSegments = (0, import_react16.useMemo)(() => {
2746
+ const blockerSegments = (0, import_react17.useMemo)(() => {
2602
2747
  if (interactionMode !== "block") {
2603
2748
  return null;
2604
2749
  }
@@ -2723,12 +2868,12 @@ var useRadixDialogAdapter = (options = {}) => {
2723
2868
  };
2724
2869
 
2725
2870
  // src/hooks/useDelayAdvance.ts
2726
- var import_react17 = require("react");
2871
+ var import_react18 = require("react");
2727
2872
  var getTimestamp = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
2728
2873
  var useDelayAdvance = () => {
2729
2874
  const { delayInfo, activeStep, state } = useTour();
2730
- const [now, setNow] = (0, import_react17.useState)(() => getTimestamp());
2731
- (0, import_react17.useEffect)(() => {
2875
+ const [now, setNow] = (0, import_react18.useState)(() => getTimestamp());
2876
+ (0, import_react18.useEffect)(() => {
2732
2877
  if (!delayInfo) return;
2733
2878
  if (!activeStep || activeStep.id !== delayInfo.stepId) return;
2734
2879
  if (!state || state.status !== "running") return;
@@ -2745,12 +2890,12 @@ var useDelayAdvance = () => {
2745
2890
  }
2746
2891
  };
2747
2892
  }, [delayInfo, activeStep, state]);
2748
- (0, import_react17.useEffect)(() => {
2893
+ (0, import_react18.useEffect)(() => {
2749
2894
  if (!delayInfo) {
2750
2895
  setNow(getTimestamp());
2751
2896
  }
2752
2897
  }, [delayInfo]);
2753
- return (0, import_react17.useMemo)(() => {
2898
+ return (0, import_react18.useMemo)(() => {
2754
2899
  const matchingStep = !!delayInfo && !!activeStep && activeStep.id === delayInfo.stepId;
2755
2900
  const isRunning = matchingStep && state?.status === "running";
2756
2901
  if (!delayInfo) {
@@ -2803,9 +2948,9 @@ var useDelayAdvance = () => {
2803
2948
  };
2804
2949
 
2805
2950
  // src/components/OverlayBackdrop.tsx
2806
- var import_react18 = require("react");
2951
+ var import_react19 = require("react");
2807
2952
  var import_react_dom = require("react-dom");
2808
- var import_react19 = require("motion/react");
2953
+ var import_react20 = require("motion/react");
2809
2954
  var import_jsx_runtime3 = require("react/jsx-runtime");
2810
2955
  var styles = {
2811
2956
  root: {
@@ -2892,9 +3037,9 @@ var OverlayBackdrop = ({
2892
3037
  viewport
2893
3038
  } = overlay;
2894
3039
  const hasHighlightBounds = Boolean(highlight.rect);
2895
- const prevScreenTargetRef = (0, import_react18.useRef)(null);
3040
+ const prevScreenTargetRef = (0, import_react19.useRef)(null);
2896
3041
  const shouldSnapHighlight = prevScreenTargetRef.current === true && !highlight.isScreen && hasHighlightBounds;
2897
- (0, import_react18.useEffect)(() => {
3042
+ (0, import_react19.useEffect)(() => {
2898
3043
  prevScreenTargetRef.current = highlight.isScreen;
2899
3044
  }, [highlight.isScreen]);
2900
3045
  const resolvedBlur = typeof blurAmount === "number" ? `${blurAmount}px` : "0px";
@@ -2962,7 +3107,7 @@ var OverlayBackdrop = ({
2962
3107
  "aria-hidden": ariaHidden,
2963
3108
  "data-tour-overlay": "",
2964
3109
  children: [
2965
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react19.AnimatePresence, { mode: "popLayout", children: shouldMask ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3110
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react20.AnimatePresence, { mode: "popLayout", children: shouldMask ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2966
3111
  MotionSvg,
2967
3112
  {
2968
3113
  width: "0",
@@ -3021,7 +3166,7 @@ var OverlayBackdrop = ({
3021
3166
  },
3022
3167
  "tour-mask"
3023
3168
  ) : null }),
3024
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react19.AnimatePresence, { mode: "popLayout", children: showBaseOverlay ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3169
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react20.AnimatePresence, { mode: "popLayout", children: showBaseOverlay ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3025
3170
  MotionDiv,
3026
3171
  {
3027
3172
  className: overlayClassName,
@@ -3049,7 +3194,7 @@ var OverlayBackdrop = ({
3049
3194
  },
3050
3195
  "tour-overlay"
3051
3196
  ) : null }),
3052
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react19.AnimatePresence, { mode: "popLayout", children: fallbackSegments ? fallbackSegments.map((segment) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3197
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react20.AnimatePresence, { mode: "popLayout", children: fallbackSegments ? fallbackSegments.map((segment) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3053
3198
  MotionDiv,
3054
3199
  {
3055
3200
  className: segmentClassName,
@@ -3100,7 +3245,7 @@ var OverlayBackdrop = ({
3100
3245
  ))
3101
3246
  }
3102
3247
  ) : null,
3103
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react19.AnimatePresence, { mode: "popLayout", children: showHighlightRing && isActive && hasHighlightBounds ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3248
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react20.AnimatePresence, { mode: "popLayout", children: showHighlightRing && isActive && hasHighlightBounds ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3104
3249
  MotionDiv,
3105
3250
  {
3106
3251
  className: ringClassName,
@@ -3131,7 +3276,7 @@ var OverlayBackdrop = ({
3131
3276
  };
3132
3277
 
3133
3278
  // src/components/TourPopoverPortal.tsx
3134
- var import_react20 = require("react");
3279
+ var import_react21 = require("react");
3135
3280
  var import_react_dom2 = require("react-dom");
3136
3281
  var import_dom13 = require("@floating-ui/dom");
3137
3282
  var FLOATING_OFFSET = 8;
@@ -3192,12 +3337,12 @@ var TourPopoverPortal = ({
3192
3337
  const popoverContentTransition = transitionsOverride?.popoverContent ?? adapter.transitions.popoverContent ?? DEFAULT_POPOVER_CONTENT_TRANSITION;
3193
3338
  const viewport = useViewportRect();
3194
3339
  const prefersMobileLayout = viewport.width <= MOBILE_BREAKPOINT || viewport.height <= MOBILE_HEIGHT_BREAKPOINT;
3195
- const prefersMobileRef = (0, import_react20.useRef)(prefersMobileLayout);
3196
- (0, import_react20.useEffect)(() => {
3340
+ const prefersMobileRef = (0, import_react21.useRef)(prefersMobileLayout);
3341
+ (0, import_react21.useEffect)(() => {
3197
3342
  prefersMobileRef.current = prefersMobileLayout;
3198
3343
  }, [prefersMobileLayout]);
3199
- const lastReadyTargetRef = (0, import_react20.useRef)(null);
3200
- (0, import_react20.useEffect)(() => {
3344
+ const lastReadyTargetRef = (0, import_react21.useRef)(null);
3345
+ (0, import_react21.useEffect)(() => {
3201
3346
  if (target.status === "ready" && target.rect) {
3202
3347
  lastReadyTargetRef.current = {
3203
3348
  rect: { ...target.rect },
@@ -3210,9 +3355,10 @@ var TourPopoverPortal = ({
3210
3355
  const cachedTarget = lastReadyTargetRef.current;
3211
3356
  const resolvedRect = target.rect ?? target.lastResolvedRect ?? cachedTarget?.rect ?? null;
3212
3357
  const resolvedIsScreen = target.status === "ready" ? target.isScreen : cachedTarget?.isScreen ?? target.isScreen;
3358
+ const shouldHidePopover = !resolvedRect && !target.isScreen;
3213
3359
  const fallbackRect = resolvedRect ?? viewport;
3214
3360
  const fallbackIsScreen = resolvedIsScreen;
3215
- const [floatingSize, setFloatingSize] = (0, import_react20.useState)(null);
3361
+ const [floatingSize, setFloatingSize] = (0, import_react21.useState)(null);
3216
3362
  const clampVertical = (value) => Math.min(viewport.height - 24, Math.max(24, value));
3217
3363
  const clampHorizontal = (value) => Math.min(viewport.width - 24, Math.max(24, value));
3218
3364
  const screenCenteredTop = viewport.height / 2 - (floatingSize?.height ?? 0) / 2;
@@ -3223,7 +3369,7 @@ var TourPopoverPortal = ({
3223
3369
  const leftBase = fallbackIsScreen ? screenCenteredLeft : fallbackRect.left + fallbackRect.width / 2 - floatingWidth / 2;
3224
3370
  const left = clampHorizontal(leftBase);
3225
3371
  const fallbackTransform = "translate3d(0px, 0px, 0px)";
3226
- const fallbackPosition = (0, import_react20.useMemo)(
3372
+ const fallbackPosition = (0, import_react21.useMemo)(
3227
3373
  () => ({
3228
3374
  top,
3229
3375
  left,
@@ -3231,7 +3377,7 @@ var TourPopoverPortal = ({
3231
3377
  }),
3232
3378
  [fallbackTransform, left, top]
3233
3379
  );
3234
- const centerInitialPosition = (0, import_react20.useMemo)(
3380
+ const centerInitialPosition = (0, import_react21.useMemo)(
3235
3381
  () => ({
3236
3382
  top: viewport.height / 2,
3237
3383
  left: viewport.width / 2,
@@ -3239,23 +3385,23 @@ var TourPopoverPortal = ({
3239
3385
  }),
3240
3386
  [viewport.height, viewport.width]
3241
3387
  );
3242
- const floatingRef = (0, import_react20.useRef)(null);
3243
- const cachedFloatingPositionRef = (0, import_react20.useRef)(null);
3244
- const appliedFloatingCacheRef = (0, import_react20.useRef)(null);
3245
- const deferredScreenSnapRef = (0, import_react20.useRef)(null);
3246
- const [layoutMode, setLayoutMode] = (0, import_react20.useState)(
3388
+ const floatingRef = (0, import_react21.useRef)(null);
3389
+ const cachedFloatingPositionRef = (0, import_react21.useRef)(null);
3390
+ const appliedFloatingCacheRef = (0, import_react21.useRef)(null);
3391
+ const deferredScreenSnapRef = (0, import_react21.useRef)(null);
3392
+ const [layoutMode, setLayoutMode] = (0, import_react21.useState)(
3247
3393
  () => prefersMobileLayout ? "mobile" : "floating"
3248
3394
  );
3249
- const [floatingPosition, setFloatingPosition] = (0, import_react20.useState)(fallbackPosition);
3250
- const [dragPosition, setDragPosition] = (0, import_react20.useState)(null);
3251
- const [isDragging, setIsDragging] = (0, import_react20.useState)(false);
3252
- const dragStateRef = (0, import_react20.useRef)(null);
3253
- const overflowRetryRef = (0, import_react20.useRef)({
3395
+ const [floatingPosition, setFloatingPosition] = (0, import_react21.useState)(fallbackPosition);
3396
+ const [dragPosition, setDragPosition] = (0, import_react21.useState)(null);
3397
+ const [isDragging, setIsDragging] = (0, import_react21.useState)(false);
3398
+ const dragStateRef = (0, import_react21.useRef)(null);
3399
+ const overflowRetryRef = (0, import_react21.useRef)({
3254
3400
  stepId: null,
3255
3401
  attempts: 0
3256
3402
  });
3257
- const overflowRetryTimeoutRef = (0, import_react20.useRef)(null);
3258
- (0, import_react20.useLayoutEffect)(() => {
3403
+ const overflowRetryTimeoutRef = (0, import_react21.useRef)(null);
3404
+ (0, import_react21.useLayoutEffect)(() => {
3259
3405
  if (!isBrowser) return;
3260
3406
  const node = floatingRef.current;
3261
3407
  if (!node) return;
@@ -3274,25 +3420,25 @@ var TourPopoverPortal = ({
3274
3420
  const autoAlignment = resolvedPlacement.endsWith(
3275
3421
  "-start"
3276
3422
  ) ? "start" : resolvedPlacement.endsWith("-end") ? "end" : void 0;
3277
- (0, import_react20.useEffect)(() => {
3423
+ (0, import_react21.useEffect)(() => {
3278
3424
  setDragPosition(null);
3279
3425
  setLayoutMode(prefersMobileRef.current ? "mobile" : "floating");
3280
3426
  cachedFloatingPositionRef.current = null;
3281
3427
  appliedFloatingCacheRef.current = null;
3282
3428
  }, [target.stepId]);
3283
- (0, import_react20.useEffect)(() => {
3429
+ (0, import_react21.useEffect)(() => {
3284
3430
  if (layoutMode !== "manual") {
3285
3431
  setDragPosition(null);
3286
3432
  }
3287
3433
  }, [layoutMode]);
3288
- (0, import_react20.useEffect)(() => {
3434
+ (0, import_react21.useEffect)(() => {
3289
3435
  cachedFloatingPositionRef.current = floatingPosition;
3290
3436
  const cacheKey = getFloatingCacheKey(target);
3291
3437
  if (cacheKey) {
3292
3438
  floatingPositionCache.set(cacheKey, floatingPosition);
3293
3439
  }
3294
3440
  }, [floatingPosition, target.isScreen, target.stepId]);
3295
- const dockedPosition = (0, import_react20.useMemo)(
3441
+ const dockedPosition = (0, import_react21.useMemo)(
3296
3442
  () => ({
3297
3443
  top: viewport.height - DOCKED_MARGIN,
3298
3444
  left: viewport.width - DOCKED_MARGIN,
@@ -3300,7 +3446,7 @@ var TourPopoverPortal = ({
3300
3446
  }),
3301
3447
  [viewport.height, viewport.width]
3302
3448
  );
3303
- const mobilePosition = (0, import_react20.useMemo)(
3449
+ const mobilePosition = (0, import_react21.useMemo)(
3304
3450
  () => ({
3305
3451
  top: viewport.height - MOBILE_HORIZONTAL_GUTTER,
3306
3452
  left: viewport.width / 2,
@@ -3308,17 +3454,17 @@ var TourPopoverPortal = ({
3308
3454
  }),
3309
3455
  [viewport.height, viewport.width]
3310
3456
  );
3311
- (0, import_react20.useEffect)(() => {
3457
+ (0, import_react21.useEffect)(() => {
3312
3458
  if (layoutMode === "docked") {
3313
3459
  setFloatingPosition(dockedPosition);
3314
3460
  }
3315
3461
  }, [dockedPosition, layoutMode]);
3316
- (0, import_react20.useEffect)(() => {
3462
+ (0, import_react21.useEffect)(() => {
3317
3463
  if (layoutMode === "mobile") {
3318
3464
  setFloatingPosition(mobilePosition);
3319
3465
  }
3320
3466
  }, [layoutMode, mobilePosition]);
3321
- (0, import_react20.useEffect)(() => {
3467
+ (0, import_react21.useEffect)(() => {
3322
3468
  if (prefersMobileLayout) {
3323
3469
  if (layoutMode !== "mobile") {
3324
3470
  setLayoutMode("mobile");
@@ -3331,7 +3477,7 @@ var TourPopoverPortal = ({
3331
3477
  setFloatingPosition(fallbackPosition);
3332
3478
  }
3333
3479
  }, [fallbackPosition, layoutMode, prefersMobileLayout]);
3334
- (0, import_react20.useEffect)(() => {
3480
+ (0, import_react21.useEffect)(() => {
3335
3481
  if (layoutMode !== "floating") return;
3336
3482
  const stepId = target.stepId;
3337
3483
  if (!stepId) return;
@@ -3355,7 +3501,7 @@ var TourPopoverPortal = ({
3355
3501
  target.stepId
3356
3502
  ]);
3357
3503
  const shouldDeferScreenSnap = layoutMode === "floating" && target.isScreen && Boolean(layoutId);
3358
- (0, import_react20.useEffect)(() => {
3504
+ (0, import_react21.useEffect)(() => {
3359
3505
  return () => {
3360
3506
  if (deferredScreenSnapRef.current !== null) {
3361
3507
  cancelAnimationFrame(deferredScreenSnapRef.current);
@@ -3363,7 +3509,7 @@ var TourPopoverPortal = ({
3363
3509
  }
3364
3510
  };
3365
3511
  }, []);
3366
- (0, import_react20.useLayoutEffect)(() => {
3512
+ (0, import_react21.useLayoutEffect)(() => {
3367
3513
  if (layoutMode !== "floating") return;
3368
3514
  if (target.status === "ready" && !target.isScreen) return;
3369
3515
  if (shouldDeferScreenSnap) return;
@@ -3375,7 +3521,7 @@ var TourPopoverPortal = ({
3375
3521
  target.isScreen,
3376
3522
  target.status
3377
3523
  ]);
3378
- (0, import_react20.useEffect)(() => {
3524
+ (0, import_react21.useEffect)(() => {
3379
3525
  if (!shouldDeferScreenSnap) return;
3380
3526
  if (deferredScreenSnapRef.current !== null) {
3381
3527
  cancelAnimationFrame(deferredScreenSnapRef.current);
@@ -3402,14 +3548,14 @@ var TourPopoverPortal = ({
3402
3548
  }
3403
3549
  };
3404
3550
  }, [fallbackPosition, shouldDeferScreenSnap]);
3405
- (0, import_react20.useEffect)(() => {
3551
+ (0, import_react21.useEffect)(() => {
3406
3552
  return () => {
3407
3553
  if (overflowRetryTimeoutRef.current !== null) {
3408
3554
  window.clearTimeout(overflowRetryTimeoutRef.current);
3409
3555
  }
3410
3556
  };
3411
3557
  }, []);
3412
- (0, import_react20.useLayoutEffect)(() => {
3558
+ (0, import_react21.useLayoutEffect)(() => {
3413
3559
  if (!isBrowser) return;
3414
3560
  const floatingEl = floatingRef.current;
3415
3561
  const rectInfo = target.rect;
@@ -3543,7 +3689,7 @@ var TourPopoverPortal = ({
3543
3689
  target.status,
3544
3690
  target.stepId
3545
3691
  ]);
3546
- (0, import_react20.useLayoutEffect)(() => {
3692
+ (0, import_react21.useLayoutEffect)(() => {
3547
3693
  if (layoutMode !== "manual" || !dragPosition) return;
3548
3694
  setFloatingPosition({
3549
3695
  top: dragPosition.top,
@@ -3628,7 +3774,7 @@ var TourPopoverPortal = ({
3628
3774
  }
3629
3775
  event.preventDefault();
3630
3776
  };
3631
- (0, import_react20.useEffect)(() => endDrag, []);
3777
+ (0, import_react21.useEffect)(() => endDrag, []);
3632
3778
  const shouldUseFallbackInitial = layoutMode !== "mobile" && (Boolean(target.lastResolvedRect) || Boolean(cachedTarget));
3633
3779
  const floatingCacheKey = layoutMode === "mobile" ? null : getFloatingCacheKey(target);
3634
3780
  const persistedFloatingInitial = floatingCacheKey && floatingPositionCache.has(floatingCacheKey) ? floatingPositionCache.get(floatingCacheKey) ?? null : null;
@@ -3715,11 +3861,12 @@ var TourPopoverPortal = ({
3715
3861
  dragHandleProps,
3716
3862
  descriptionProps
3717
3863
  };
3864
+ if (shouldHidePopover) return null;
3718
3865
  return (0, import_react_dom2.createPortal)(children(context), host);
3719
3866
  };
3720
3867
 
3721
3868
  // src/components/TourFocusManager.tsx
3722
- var import_react21 = require("react");
3869
+ var import_react22 = require("react");
3723
3870
  var import_react_dom3 = require("react-dom");
3724
3871
 
3725
3872
  // src/utils/focus.ts
@@ -3796,18 +3943,18 @@ var TourFocusManager = ({
3796
3943
  highlightRect,
3797
3944
  guardElementFocusRing
3798
3945
  }) => {
3799
- const previousFocusRef = (0, import_react21.useRef)(null);
3800
- const guardNodesRef = (0, import_react21.useRef)({
3946
+ const previousFocusRef = (0, import_react22.useRef)(null);
3947
+ const guardNodesRef = (0, import_react22.useRef)({
3801
3948
  "target-start": null,
3802
3949
  "target-end": null,
3803
3950
  "popover-start": null,
3804
3951
  "popover-end": null
3805
3952
  });
3806
- const lastTabDirectionRef = (0, import_react21.useRef)("forward");
3807
- const suppressGuardHopRef = (0, import_react21.useRef)(null);
3808
- const [targetRingActive, setTargetRingActive] = (0, import_react21.useState)(false);
3809
- const [popoverRingActive, setPopoverRingActive] = (0, import_react21.useState)(false);
3810
- const [popoverRect, setPopoverRect] = (0, import_react21.useState)(null);
3953
+ const lastTabDirectionRef = (0, import_react22.useRef)("forward");
3954
+ const suppressGuardHopRef = (0, import_react22.useRef)(null);
3955
+ const [targetRingActive, setTargetRingActive] = (0, import_react22.useState)(false);
3956
+ const [popoverRingActive, setPopoverRingActive] = (0, import_react22.useState)(false);
3957
+ const [popoverRect, setPopoverRect] = (0, import_react22.useState)(null);
3811
3958
  const restoreFocus = () => {
3812
3959
  const previous = previousFocusRef.current;
3813
3960
  previousFocusRef.current = null;
@@ -3817,7 +3964,7 @@ var TourFocusManager = ({
3817
3964
  });
3818
3965
  }
3819
3966
  };
3820
- (0, import_react21.useLayoutEffect)(() => {
3967
+ (0, import_react22.useLayoutEffect)(() => {
3821
3968
  if (!isBrowser) return;
3822
3969
  if (!active) {
3823
3970
  restoreFocus();
@@ -3833,7 +3980,7 @@ var TourFocusManager = ({
3833
3980
  restoreFocus();
3834
3981
  };
3835
3982
  }, [active, popoverNode, target.element]);
3836
- (0, import_react21.useEffect)(() => {
3983
+ (0, import_react22.useEffect)(() => {
3837
3984
  if (!isBrowser) return;
3838
3985
  if (!active) return;
3839
3986
  const doc = popoverNode?.ownerDocument ?? target.element?.ownerDocument ?? document;
@@ -4027,7 +4174,7 @@ var TourFocusManager = ({
4027
4174
  target.stepId,
4028
4175
  target.visibility
4029
4176
  ]);
4030
- (0, import_react21.useLayoutEffect)(() => {
4177
+ (0, import_react22.useLayoutEffect)(() => {
4031
4178
  if (popoverRingActive && popoverNode) {
4032
4179
  setPopoverRect(popoverNode.getBoundingClientRect());
4033
4180
  } else {
@@ -4083,7 +4230,7 @@ var TourFocusManager = ({
4083
4230
  };
4084
4231
 
4085
4232
  // src/motion/useHudMotion.ts
4086
- var import_react22 = require("react");
4233
+ var import_react23 = require("react");
4087
4234
  var DEFAULT_HIGHLIGHT_TRANSITION2 = {
4088
4235
  duration: 0.35,
4089
4236
  ease: "easeOut",
@@ -4110,7 +4257,7 @@ var DEFAULT_POPOVER_CONTENT_TRANSITION2 = {
4110
4257
  };
4111
4258
  var useHudMotion = () => {
4112
4259
  const adapter = useAnimationAdapter();
4113
- return (0, import_react22.useMemo)(() => {
4260
+ return (0, import_react23.useMemo)(() => {
4114
4261
  const components = {
4115
4262
  ...adapter.components
4116
4263
  };
@@ -4126,49 +4273,6 @@ var useHudMotion = () => {
4126
4273
  };
4127
4274
  }, [adapter]);
4128
4275
  };
4129
-
4130
- // src/router/utils.ts
4131
- var ensurePrefix = (value, prefix) => value.startsWith(prefix) ? value : `${prefix}${value}`;
4132
- var isNonEmptyString = (value) => typeof value === "string" && value.length > 0;
4133
- var toSearchString = (value) => {
4134
- if (!isNonEmptyString(value)) {
4135
- if (value instanceof URLSearchParams) {
4136
- const serialized = value.toString();
4137
- return serialized.length > 0 ? `?${serialized}` : "";
4138
- }
4139
- if (typeof value === "object" && value !== null) {
4140
- try {
4141
- const params = new URLSearchParams();
4142
- for (const [key, raw] of Object.entries(
4143
- value
4144
- )) {
4145
- if (raw === void 0 || raw === null) continue;
4146
- params.set(key, String(raw));
4147
- }
4148
- const serialized = params.toString();
4149
- return serialized.length > 0 ? `?${serialized}` : "";
4150
- } catch {
4151
- return "";
4152
- }
4153
- }
4154
- return "";
4155
- }
4156
- if (value === "?") return "";
4157
- return value.startsWith("?") ? value : ensurePrefix(value, "?");
4158
- };
4159
- var toHashString = (value) => {
4160
- if (!isNonEmptyString(value)) {
4161
- return "";
4162
- }
4163
- if (value === "#") return "";
4164
- return value.startsWith("#") ? value : ensurePrefix(value, "#");
4165
- };
4166
- var createPathString = (pathname, search, hash) => {
4167
- const normalizedPath = isNonEmptyString(pathname) ? pathname.startsWith("/") ? pathname : `/${pathname}` : "/";
4168
- const searchPart = toSearchString(search);
4169
- const hashPart = toHashString(hash);
4170
- return `${normalizedPath}${searchPart}${hashPart}`;
4171
- };
4172
4276
  // Annotate the CommonJS export names for ESM import in node:
4173
4277
  0 && (module.exports = {
4174
4278
  AnimationAdapterProvider,