@flowsterix/react 0.5.0 → 0.7.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.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ import "./chunk-WCLT3A6G.mjs";
2
+ import "./chunk-2ZX2Y3JL.mjs";
1
3
  import {
2
4
  createPathString,
3
5
  expandRect,
@@ -44,7 +46,17 @@ var defaultLabels = {
44
46
  ariaStepProgress: ({ current, total }) => `Step ${current} of ${total}`,
45
47
  ariaTimeRemaining: ({ ms }) => `${Math.ceil(ms / 1e3)} seconds remaining`,
46
48
  ariaDelayProgress: "Auto-advance progress",
47
- formatTimeRemaining: ({ ms }) => `${Math.ceil(ms / 1e3)}s remaining`
49
+ formatTimeRemaining: ({ ms }) => `${Math.ceil(ms / 1e3)}s remaining`,
50
+ targetIssue: {
51
+ missingTitle: "Target not visible",
52
+ missingBody: "The target element is not currently visible. Make sure the UI piece is mounted and displayed.",
53
+ missingHint: "Showing the last known position until the element returns.",
54
+ hiddenTitle: "Target not visible",
55
+ hiddenBody: "The target element is not currently visible. Make sure the UI piece is mounted and displayed.",
56
+ hiddenHint: "Showing the last known position until the element returns.",
57
+ detachedTitle: "Target left the page",
58
+ detachedBody: "Navigate back to the screen that contains this element or reopen it before continuing the tour."
59
+ }
48
60
  };
49
61
  var LabelsContext = createContext(defaultLabels);
50
62
  var LabelsProvider = LabelsContext.Provider;
@@ -548,6 +560,10 @@ var TourProvider = ({
548
560
  () => getActiveStore().complete(),
549
561
  [getActiveStore]
550
562
  );
563
+ const advanceStep = useCallback(
564
+ (stepId) => getActiveStore().advanceStep(stepId),
565
+ [getActiveStore]
566
+ );
551
567
  const toggleDebug = useCallback(() => {
552
568
  setDebugEnabled((previous) => !previous);
553
569
  }, []);
@@ -585,6 +601,7 @@ var TourProvider = ({
585
601
  resume,
586
602
  cancel,
587
603
  complete,
604
+ advanceStep,
588
605
  events,
589
606
  debugEnabled,
590
607
  setDebugEnabled,
@@ -597,6 +614,7 @@ var TourProvider = ({
597
614
  [
598
615
  activeFlowId,
599
616
  activeStep,
617
+ advanceStep,
600
618
  back,
601
619
  cancel,
602
620
  complete,
@@ -1404,7 +1422,7 @@ var useTourTarget = () => {
1404
1422
  };
1405
1423
 
1406
1424
  // src/hooks/useHudState.ts
1407
- import { useCallback as useCallback2, useEffect as useEffect7, useMemo as useMemo4, useState as useState6 } from "react";
1425
+ import { useCallback as useCallback2, useEffect as useEffect8, useMemo as useMemo4, useRef as useRef5, useState as useState7 } from "react";
1408
1426
 
1409
1427
  // src/hooks/useAdvanceRules.ts
1410
1428
  import { useEffect as useEffect4 } from "react";
@@ -1666,7 +1684,8 @@ var useHiddenTargetFallback = ({
1666
1684
  clearGraceTimeout();
1667
1685
  const isHiddenOrDetached = (target.visibility === "hidden" || target.visibility === "detached") && target.status === "ready";
1668
1686
  const isMissingWithNoRect = target.visibility === "missing" && target.status === "resolving" && target.rect === null && target.lastResolvedRect === null;
1669
- const shouldHandleHiddenTarget = !target.isScreen && (isHiddenOrDetached || isMissingWithNoRect);
1687
+ const isMissingAfterNavigation = target.visibility === "missing" && target.status === "resolving" && target.rect === null;
1688
+ const shouldHandleHiddenTarget = !target.isScreen && (isHiddenOrDetached || isMissingWithNoRect || isMissingAfterNavigation);
1670
1689
  if (!shouldHandleHiddenTarget) {
1671
1690
  setUsingScreenFallback(false);
1672
1691
  setIsInGracePeriod(false);
@@ -1725,14 +1744,32 @@ var useHiddenTargetFallback = ({
1725
1744
  };
1726
1745
  };
1727
1746
 
1747
+ // src/hooks/useRouteMismatch.ts
1748
+ import { useEffect as useEffect6, useState as useState5 } from "react";
1749
+ var useRouteMismatch = (step) => {
1750
+ const [currentPath, setCurrentPath] = useState5(() => getCurrentRoutePath());
1751
+ useEffect6(() => {
1752
+ return subscribeToRouteChanges((path) => {
1753
+ setCurrentPath(path);
1754
+ });
1755
+ }, []);
1756
+ const expectedRoute = step?.route;
1757
+ const isRouteMismatch = step !== null && expectedRoute !== void 0 && !matchRoute({ pattern: expectedRoute, path: currentPath });
1758
+ return {
1759
+ isRouteMismatch,
1760
+ currentPath,
1761
+ expectedRoute
1762
+ };
1763
+ };
1764
+
1728
1765
  // src/hooks/useViewportRect.ts
1729
- import { useEffect as useEffect6, useRef as useRef4, useState as useState5 } from "react";
1766
+ import { useEffect as useEffect7, useRef as useRef4, useState as useState6 } from "react";
1730
1767
  var useViewportRect = () => {
1731
- const [viewport, setViewport] = useState5(
1768
+ const [viewport, setViewport] = useState6(
1732
1769
  () => getViewportRect()
1733
1770
  );
1734
1771
  const rafRef = useRef4(null);
1735
- useEffect6(() => {
1772
+ useEffect7(() => {
1736
1773
  if (!isBrowser) return;
1737
1774
  const updateViewport = () => {
1738
1775
  rafRef.current = null;
@@ -1775,7 +1812,7 @@ var normalizeFlowFilter = (value) => {
1775
1812
  var useHudState = (options = {}) => {
1776
1813
  const { flowId } = options;
1777
1814
  const flowFilter = useMemo4(() => normalizeFlowFilter(flowId), [flowId]);
1778
- const { state, activeStep, activeFlowId, flows, next, complete } = useTour();
1815
+ const { state, activeStep, activeFlowId, flows, next, complete, pause, resume } = useTour();
1779
1816
  const target = useTourTarget();
1780
1817
  const viewportRect = useViewportRect();
1781
1818
  useAdvanceRules(target);
@@ -1787,15 +1824,15 @@ var useHudState = (options = {}) => {
1787
1824
  const isRunning = state?.status === "running";
1788
1825
  const runningState = isRunning && matchesFlowFilter ? state : null;
1789
1826
  const runningStep = runningState && activeStep ? activeStep : null;
1790
- const [shouldRender, setShouldRender] = useState6(
1827
+ const [shouldRender, setShouldRender] = useState7(
1791
1828
  Boolean(runningStep)
1792
1829
  );
1793
- useEffect7(() => {
1830
+ useEffect8(() => {
1794
1831
  if (runningStep) {
1795
1832
  setShouldRender(true);
1796
1833
  }
1797
1834
  }, [runningStep?.id]);
1798
- useEffect7(() => {
1835
+ useEffect8(() => {
1799
1836
  if (!shouldRender) return;
1800
1837
  if (runningStep) return;
1801
1838
  if (target.status !== "idle") return;
@@ -1806,6 +1843,19 @@ var useHudState = (options = {}) => {
1806
1843
  window.clearTimeout(timeoutId);
1807
1844
  };
1808
1845
  }, [runningStep, shouldRender, target.status]);
1846
+ const { isRouteMismatch, currentPath } = useRouteMismatch(activeStep);
1847
+ const pausedForMissingTargetRef = useRef5(null);
1848
+ useEffect8(() => {
1849
+ if (!isRouteMismatch) return;
1850
+ if (!runningState || runningState.status !== "running") return;
1851
+ pause();
1852
+ }, [isRouteMismatch, runningState, pause]);
1853
+ useEffect8(() => {
1854
+ if (isRouteMismatch) return;
1855
+ if (pausedForMissingTargetRef.current !== null) return;
1856
+ if (!state || state.status !== "paused") return;
1857
+ resume();
1858
+ }, [isRouteMismatch, state, resume]);
1809
1859
  const skipHiddenStep = useCallback2(() => {
1810
1860
  if (!runningState || runningState.status !== "running") return;
1811
1861
  if (!activeFlowId) return;
@@ -1824,6 +1874,35 @@ var useHudState = (options = {}) => {
1824
1874
  viewportRect,
1825
1875
  onSkip: skipHiddenStep
1826
1876
  });
1877
+ useEffect8(() => {
1878
+ if (isRouteMismatch) return;
1879
+ if (activeStep?.route !== void 0) return;
1880
+ if (isInGracePeriod) return;
1881
+ if (target.visibility !== "missing") return;
1882
+ if (target.isScreen) return;
1883
+ if (!runningState || runningState.status !== "running") return;
1884
+ pausedForMissingTargetRef.current = currentPath;
1885
+ pause();
1886
+ }, [
1887
+ isRouteMismatch,
1888
+ activeStep?.route,
1889
+ isInGracePeriod,
1890
+ target.visibility,
1891
+ target.isScreen,
1892
+ runningState,
1893
+ currentPath,
1894
+ pause
1895
+ ]);
1896
+ useEffect8(() => {
1897
+ if (pausedForMissingTargetRef.current === null) return;
1898
+ if (!state || state.status !== "paused") return;
1899
+ if (currentPath === pausedForMissingTargetRef.current) return;
1900
+ pausedForMissingTargetRef.current = null;
1901
+ resume();
1902
+ }, [currentPath, state, resume]);
1903
+ useEffect8(() => {
1904
+ pausedForMissingTargetRef.current = null;
1905
+ }, [activeStep?.id]);
1827
1906
  const canRenderStep = Boolean(runningStep && runningState);
1828
1907
  const focusTrapActive = canRenderStep;
1829
1908
  const flowHudOptions = matchesFlowFilter && activeFlowId ? flows.get(activeFlowId)?.hud ?? null : null;
@@ -1875,7 +1954,7 @@ var useHudDescription = (options) => {
1875
1954
  };
1876
1955
 
1877
1956
  // src/hooks/useHudShortcuts.ts
1878
- import { useEffect as useEffect8 } from "react";
1957
+ import { useEffect as useEffect9 } from "react";
1879
1958
 
1880
1959
  // src/hooks/useTourControls.ts
1881
1960
  import { useCallback as useCallback3, useMemo as useMemo6 } from "react";
@@ -2000,7 +2079,7 @@ var useHudShortcuts = (target, options) => {
2000
2079
  const escapeEnabled = options?.escape ?? true;
2001
2080
  const { state } = useTour();
2002
2081
  const { cancel, canGoBack, goBack, canGoNext, goNext, isActive } = useTourControls();
2003
- useEffect8(() => {
2082
+ useEffect9(() => {
2004
2083
  if (!isBrowser) return void 0;
2005
2084
  if (!enabled) return void 0;
2006
2085
  if (!target) return void 0;
@@ -2064,10 +2143,10 @@ var useHudShortcuts = (target, options) => {
2064
2143
  };
2065
2144
 
2066
2145
  // src/hooks/useTourHud.ts
2067
- import { useMemo as useMemo8, useState as useState8 } from "react";
2146
+ import { useMemo as useMemo8, useState as useState9 } from "react";
2068
2147
 
2069
2148
  // src/hooks/useBodyScrollLock.ts
2070
- import { useEffect as useEffect9 } from "react";
2149
+ import { useEffect as useEffect10 } from "react";
2071
2150
  var lockCount = 0;
2072
2151
  var previousOverflow = null;
2073
2152
  var acquireLock = () => {
@@ -2088,7 +2167,7 @@ var releaseLock = () => {
2088
2167
  }
2089
2168
  };
2090
2169
  var useBodyScrollLock = (enabled) => {
2091
- useEffect9(() => {
2170
+ useEffect10(() => {
2092
2171
  if (!enabled) return;
2093
2172
  acquireLock();
2094
2173
  return () => {
@@ -2098,37 +2177,45 @@ var useBodyScrollLock = (enabled) => {
2098
2177
  };
2099
2178
 
2100
2179
  // src/hooks/useHudTargetIssue.ts
2101
- import { useEffect as useEffect10, useMemo as useMemo7, useState as useState7 } from "react";
2102
- var deriveTargetIssue = (target) => {
2180
+ import { useEffect as useEffect11, useMemo as useMemo7, useState as useState8 } from "react";
2181
+ var deriveTargetIssue = (params) => {
2182
+ const { target, labels } = params;
2103
2183
  if (target.isScreen) return null;
2104
2184
  if (target.status === "idle") return null;
2105
2185
  switch (target.visibility) {
2106
2186
  case "missing":
2187
+ return {
2188
+ type: "missing",
2189
+ title: labels.targetIssue.missingTitle,
2190
+ body: labels.targetIssue.missingBody,
2191
+ hint: target.rectSource === "stored" ? labels.targetIssue.missingHint : void 0
2192
+ };
2107
2193
  case "hidden":
2108
2194
  return {
2109
- type: target.visibility,
2110
- title: "Target not visible",
2111
- body: "The target element is not currently visible. Make sure the UI piece is mounted and displayed.",
2112
- hint: target.rectSource === "stored" ? "Showing the last known position until the element returns." : void 0
2195
+ type: "hidden",
2196
+ title: labels.targetIssue.hiddenTitle,
2197
+ body: labels.targetIssue.hiddenBody,
2198
+ hint: target.rectSource === "stored" ? labels.targetIssue.hiddenHint : void 0
2113
2199
  };
2114
2200
  case "detached":
2115
2201
  return {
2116
2202
  type: "detached",
2117
- title: "Target left the page",
2118
- body: "Navigate back to the screen that contains this element or reopen it before continuing the tour."
2203
+ title: labels.targetIssue.detachedTitle,
2204
+ body: labels.targetIssue.detachedBody
2119
2205
  };
2120
2206
  default:
2121
2207
  return null;
2122
2208
  }
2123
2209
  };
2124
2210
  var useHudTargetIssue = (target, options) => {
2211
+ const labels = useTourLabels();
2125
2212
  const delayMs = Math.max(0, options?.delayMs ?? 500);
2126
- const [armed, setArmed] = useState7(false);
2213
+ const [armed, setArmed] = useState8(false);
2127
2214
  const rawIssue = useMemo7(
2128
- () => deriveTargetIssue(target),
2129
- [target.isScreen, target.rectSource, target.status, target.visibility]
2215
+ () => deriveTargetIssue({ target, labels }),
2216
+ [target.isScreen, target.rectSource, target.status, target.visibility, labels]
2130
2217
  );
2131
- useEffect10(() => {
2218
+ useEffect11(() => {
2132
2219
  if (!rawIssue) {
2133
2220
  setArmed(false);
2134
2221
  return;
@@ -2162,7 +2249,7 @@ var useTourHud = (options = {}) => {
2162
2249
  const { backdropInteraction, lockBodyScroll } = useTour();
2163
2250
  const hudState = useHudState();
2164
2251
  const disableDefaultHud = hudState.hudRenderMode === "none";
2165
- const [popoverNode, setPopoverNode] = useState8(null);
2252
+ const [popoverNode, setPopoverNode] = useState9(null);
2166
2253
  const popoverOptions = hudState.flowHudOptions?.popover;
2167
2254
  const description = useHudDescription({
2168
2255
  step: hudState.runningStep,
@@ -2234,7 +2321,7 @@ var useTourHud = (options = {}) => {
2234
2321
  };
2235
2322
 
2236
2323
  // src/hooks/useTourOverlay.ts
2237
- import { useEffect as useEffect11, useMemo as useMemo9, useRef as useRef5 } from "react";
2324
+ import { useEffect as useEffect12, useMemo as useMemo9, useRef as useRef6 } from "react";
2238
2325
  var DEFAULT_PADDING = 12;
2239
2326
  var DEFAULT_RADIUS = 12;
2240
2327
  var DEFAULT_EDGE_BUFFER = 0;
@@ -2247,9 +2334,9 @@ var useTourOverlay = (options) => {
2247
2334
  interactionMode = "passthrough",
2248
2335
  isInGracePeriod = false
2249
2336
  } = options;
2250
- const hasShownRef = useRef5(false);
2251
- const lastReadyTargetRef = useRef5(null);
2252
- useEffect11(() => {
2337
+ const hasShownRef = useRef6(false);
2338
+ const lastReadyTargetRef = useRef6(null);
2339
+ useEffect12(() => {
2253
2340
  if (!isBrowser) return;
2254
2341
  if (target.status === "ready") {
2255
2342
  hasShownRef.current = true;
@@ -2485,12 +2572,12 @@ var useRadixDialogAdapter = (options = {}) => {
2485
2572
  };
2486
2573
 
2487
2574
  // src/hooks/useDelayAdvance.ts
2488
- import { useEffect as useEffect12, useMemo as useMemo10, useState as useState9 } from "react";
2575
+ import { useEffect as useEffect13, useMemo as useMemo10, useState as useState10 } from "react";
2489
2576
  var getTimestamp = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
2490
2577
  var useDelayAdvance = () => {
2491
2578
  const { delayInfo, activeStep, state } = useTour();
2492
- const [now, setNow] = useState9(() => getTimestamp());
2493
- useEffect12(() => {
2579
+ const [now, setNow] = useState10(() => getTimestamp());
2580
+ useEffect13(() => {
2494
2581
  if (!delayInfo) return;
2495
2582
  if (!activeStep || activeStep.id !== delayInfo.stepId) return;
2496
2583
  if (!state || state.status !== "running") return;
@@ -2507,7 +2594,7 @@ var useDelayAdvance = () => {
2507
2594
  }
2508
2595
  };
2509
2596
  }, [delayInfo, activeStep, state]);
2510
- useEffect12(() => {
2597
+ useEffect13(() => {
2511
2598
  if (!delayInfo) {
2512
2599
  setNow(getTimestamp());
2513
2600
  }
@@ -2565,7 +2652,7 @@ var useDelayAdvance = () => {
2565
2652
  };
2566
2653
 
2567
2654
  // src/components/OverlayBackdrop.tsx
2568
- import { useEffect as useEffect13, useRef as useRef6 } from "react";
2655
+ import { useEffect as useEffect14, useRef as useRef7 } from "react";
2569
2656
  import { createPortal } from "react-dom";
2570
2657
  import { AnimatePresence } from "motion/react";
2571
2658
  import { jsx as jsx3, jsxs } from "react/jsx-runtime";
@@ -2654,9 +2741,9 @@ var OverlayBackdrop = ({
2654
2741
  viewport
2655
2742
  } = overlay;
2656
2743
  const hasHighlightBounds = Boolean(highlight.rect);
2657
- const prevScreenTargetRef = useRef6(null);
2744
+ const prevScreenTargetRef = useRef7(null);
2658
2745
  const shouldSnapHighlight = prevScreenTargetRef.current === true && !highlight.isScreen && hasHighlightBounds;
2659
- useEffect13(() => {
2746
+ useEffect14(() => {
2660
2747
  prevScreenTargetRef.current = highlight.isScreen;
2661
2748
  }, [highlight.isScreen]);
2662
2749
  const resolvedBlur = typeof blurAmount === "number" ? `${blurAmount}px` : "0px";
@@ -2893,7 +2980,7 @@ var OverlayBackdrop = ({
2893
2980
  };
2894
2981
 
2895
2982
  // src/components/TourPopoverPortal.tsx
2896
- import { useEffect as useEffect14, useLayoutEffect as useLayoutEffect2, useMemo as useMemo11, useRef as useRef7, useState as useState10 } from "react";
2983
+ import { useEffect as useEffect15, useLayoutEffect as useLayoutEffect2, useMemo as useMemo11, useRef as useRef8, useState as useState11 } from "react";
2897
2984
  import { createPortal as createPortal2 } from "react-dom";
2898
2985
  import {
2899
2986
  autoPlacement,
@@ -2947,8 +3034,7 @@ var TourPopoverPortal = ({
2947
3034
  layoutId,
2948
3035
  containerComponent,
2949
3036
  contentComponent,
2950
- transitionsOverride,
2951
- isInGracePeriod = false
3037
+ transitionsOverride
2952
3038
  }) => {
2953
3039
  if (!isBrowser) return null;
2954
3040
  const host = portalHost();
@@ -2961,12 +3047,12 @@ var TourPopoverPortal = ({
2961
3047
  const popoverContentTransition = transitionsOverride?.popoverContent ?? adapter.transitions.popoverContent ?? DEFAULT_POPOVER_CONTENT_TRANSITION;
2962
3048
  const viewport = useViewportRect();
2963
3049
  const prefersMobileLayout = viewport.width <= MOBILE_BREAKPOINT || viewport.height <= MOBILE_HEIGHT_BREAKPOINT;
2964
- const prefersMobileRef = useRef7(prefersMobileLayout);
2965
- useEffect14(() => {
3050
+ const prefersMobileRef = useRef8(prefersMobileLayout);
3051
+ useEffect15(() => {
2966
3052
  prefersMobileRef.current = prefersMobileLayout;
2967
3053
  }, [prefersMobileLayout]);
2968
- const lastReadyTargetRef = useRef7(null);
2969
- useEffect14(() => {
3054
+ const lastReadyTargetRef = useRef8(null);
3055
+ useEffect15(() => {
2970
3056
  if (target.status === "ready" && target.rect) {
2971
3057
  lastReadyTargetRef.current = {
2972
3058
  rect: { ...target.rect },
@@ -2979,10 +3065,10 @@ var TourPopoverPortal = ({
2979
3065
  const cachedTarget = lastReadyTargetRef.current;
2980
3066
  const resolvedRect = target.rect ?? target.lastResolvedRect ?? cachedTarget?.rect ?? null;
2981
3067
  const resolvedIsScreen = target.status === "ready" ? target.isScreen : cachedTarget?.isScreen ?? target.isScreen;
2982
- const shouldHideForGracePeriod = isInGracePeriod && !resolvedRect;
3068
+ const shouldHidePopover = !resolvedRect && !target.isScreen;
2983
3069
  const fallbackRect = resolvedRect ?? viewport;
2984
3070
  const fallbackIsScreen = resolvedIsScreen;
2985
- const [floatingSize, setFloatingSize] = useState10(null);
3071
+ const [floatingSize, setFloatingSize] = useState11(null);
2986
3072
  const clampVertical = (value) => Math.min(viewport.height - 24, Math.max(24, value));
2987
3073
  const clampHorizontal = (value) => Math.min(viewport.width - 24, Math.max(24, value));
2988
3074
  const screenCenteredTop = viewport.height / 2 - (floatingSize?.height ?? 0) / 2;
@@ -3009,22 +3095,22 @@ var TourPopoverPortal = ({
3009
3095
  }),
3010
3096
  [viewport.height, viewport.width]
3011
3097
  );
3012
- const floatingRef = useRef7(null);
3013
- const cachedFloatingPositionRef = useRef7(null);
3014
- const appliedFloatingCacheRef = useRef7(null);
3015
- const deferredScreenSnapRef = useRef7(null);
3016
- const [layoutMode, setLayoutMode] = useState10(
3098
+ const floatingRef = useRef8(null);
3099
+ const cachedFloatingPositionRef = useRef8(null);
3100
+ const appliedFloatingCacheRef = useRef8(null);
3101
+ const deferredScreenSnapRef = useRef8(null);
3102
+ const [layoutMode, setLayoutMode] = useState11(
3017
3103
  () => prefersMobileLayout ? "mobile" : "floating"
3018
3104
  );
3019
- const [floatingPosition, setFloatingPosition] = useState10(fallbackPosition);
3020
- const [dragPosition, setDragPosition] = useState10(null);
3021
- const [isDragging, setIsDragging] = useState10(false);
3022
- const dragStateRef = useRef7(null);
3023
- const overflowRetryRef = useRef7({
3105
+ const [floatingPosition, setFloatingPosition] = useState11(fallbackPosition);
3106
+ const [dragPosition, setDragPosition] = useState11(null);
3107
+ const [isDragging, setIsDragging] = useState11(false);
3108
+ const dragStateRef = useRef8(null);
3109
+ const overflowRetryRef = useRef8({
3024
3110
  stepId: null,
3025
3111
  attempts: 0
3026
3112
  });
3027
- const overflowRetryTimeoutRef = useRef7(null);
3113
+ const overflowRetryTimeoutRef = useRef8(null);
3028
3114
  useLayoutEffect2(() => {
3029
3115
  if (!isBrowser) return;
3030
3116
  const node = floatingRef.current;
@@ -3044,18 +3130,18 @@ var TourPopoverPortal = ({
3044
3130
  const autoAlignment = resolvedPlacement.endsWith(
3045
3131
  "-start"
3046
3132
  ) ? "start" : resolvedPlacement.endsWith("-end") ? "end" : void 0;
3047
- useEffect14(() => {
3133
+ useEffect15(() => {
3048
3134
  setDragPosition(null);
3049
3135
  setLayoutMode(prefersMobileRef.current ? "mobile" : "floating");
3050
3136
  cachedFloatingPositionRef.current = null;
3051
3137
  appliedFloatingCacheRef.current = null;
3052
3138
  }, [target.stepId]);
3053
- useEffect14(() => {
3139
+ useEffect15(() => {
3054
3140
  if (layoutMode !== "manual") {
3055
3141
  setDragPosition(null);
3056
3142
  }
3057
3143
  }, [layoutMode]);
3058
- useEffect14(() => {
3144
+ useEffect15(() => {
3059
3145
  cachedFloatingPositionRef.current = floatingPosition;
3060
3146
  const cacheKey = getFloatingCacheKey(target);
3061
3147
  if (cacheKey) {
@@ -3078,17 +3164,17 @@ var TourPopoverPortal = ({
3078
3164
  }),
3079
3165
  [viewport.height, viewport.width]
3080
3166
  );
3081
- useEffect14(() => {
3167
+ useEffect15(() => {
3082
3168
  if (layoutMode === "docked") {
3083
3169
  setFloatingPosition(dockedPosition);
3084
3170
  }
3085
3171
  }, [dockedPosition, layoutMode]);
3086
- useEffect14(() => {
3172
+ useEffect15(() => {
3087
3173
  if (layoutMode === "mobile") {
3088
3174
  setFloatingPosition(mobilePosition);
3089
3175
  }
3090
3176
  }, [layoutMode, mobilePosition]);
3091
- useEffect14(() => {
3177
+ useEffect15(() => {
3092
3178
  if (prefersMobileLayout) {
3093
3179
  if (layoutMode !== "mobile") {
3094
3180
  setLayoutMode("mobile");
@@ -3101,7 +3187,7 @@ var TourPopoverPortal = ({
3101
3187
  setFloatingPosition(fallbackPosition);
3102
3188
  }
3103
3189
  }, [fallbackPosition, layoutMode, prefersMobileLayout]);
3104
- useEffect14(() => {
3190
+ useEffect15(() => {
3105
3191
  if (layoutMode !== "floating") return;
3106
3192
  const stepId = target.stepId;
3107
3193
  if (!stepId) return;
@@ -3125,7 +3211,7 @@ var TourPopoverPortal = ({
3125
3211
  target.stepId
3126
3212
  ]);
3127
3213
  const shouldDeferScreenSnap = layoutMode === "floating" && target.isScreen && Boolean(layoutId);
3128
- useEffect14(() => {
3214
+ useEffect15(() => {
3129
3215
  return () => {
3130
3216
  if (deferredScreenSnapRef.current !== null) {
3131
3217
  cancelAnimationFrame(deferredScreenSnapRef.current);
@@ -3145,7 +3231,7 @@ var TourPopoverPortal = ({
3145
3231
  target.isScreen,
3146
3232
  target.status
3147
3233
  ]);
3148
- useEffect14(() => {
3234
+ useEffect15(() => {
3149
3235
  if (!shouldDeferScreenSnap) return;
3150
3236
  if (deferredScreenSnapRef.current !== null) {
3151
3237
  cancelAnimationFrame(deferredScreenSnapRef.current);
@@ -3172,7 +3258,7 @@ var TourPopoverPortal = ({
3172
3258
  }
3173
3259
  };
3174
3260
  }, [fallbackPosition, shouldDeferScreenSnap]);
3175
- useEffect14(() => {
3261
+ useEffect15(() => {
3176
3262
  return () => {
3177
3263
  if (overflowRetryTimeoutRef.current !== null) {
3178
3264
  window.clearTimeout(overflowRetryTimeoutRef.current);
@@ -3398,7 +3484,7 @@ var TourPopoverPortal = ({
3398
3484
  }
3399
3485
  event.preventDefault();
3400
3486
  };
3401
- useEffect14(() => endDrag, []);
3487
+ useEffect15(() => endDrag, []);
3402
3488
  const shouldUseFallbackInitial = layoutMode !== "mobile" && (Boolean(target.lastResolvedRect) || Boolean(cachedTarget));
3403
3489
  const floatingCacheKey = layoutMode === "mobile" ? null : getFloatingCacheKey(target);
3404
3490
  const persistedFloatingInitial = floatingCacheKey && floatingPositionCache.has(floatingCacheKey) ? floatingPositionCache.get(floatingCacheKey) ?? null : null;
@@ -3485,12 +3571,12 @@ var TourPopoverPortal = ({
3485
3571
  dragHandleProps,
3486
3572
  descriptionProps
3487
3573
  };
3488
- if (shouldHideForGracePeriod) return null;
3574
+ if (shouldHidePopover) return null;
3489
3575
  return createPortal2(children(context), host);
3490
3576
  };
3491
3577
 
3492
3578
  // src/components/TourFocusManager.tsx
3493
- import { useEffect as useEffect15, useLayoutEffect as useLayoutEffect3, useRef as useRef8, useState as useState11 } from "react";
3579
+ import { useEffect as useEffect16, useLayoutEffect as useLayoutEffect3, useRef as useRef9, useState as useState12 } from "react";
3494
3580
  import { createPortal as createPortal3 } from "react-dom";
3495
3581
 
3496
3582
  // src/utils/focus.ts
@@ -3567,18 +3653,18 @@ var TourFocusManager = ({
3567
3653
  highlightRect,
3568
3654
  guardElementFocusRing
3569
3655
  }) => {
3570
- const previousFocusRef = useRef8(null);
3571
- const guardNodesRef = useRef8({
3656
+ const previousFocusRef = useRef9(null);
3657
+ const guardNodesRef = useRef9({
3572
3658
  "target-start": null,
3573
3659
  "target-end": null,
3574
3660
  "popover-start": null,
3575
3661
  "popover-end": null
3576
3662
  });
3577
- const lastTabDirectionRef = useRef8("forward");
3578
- const suppressGuardHopRef = useRef8(null);
3579
- const [targetRingActive, setTargetRingActive] = useState11(false);
3580
- const [popoverRingActive, setPopoverRingActive] = useState11(false);
3581
- const [popoverRect, setPopoverRect] = useState11(null);
3663
+ const lastTabDirectionRef = useRef9("forward");
3664
+ const suppressGuardHopRef = useRef9(null);
3665
+ const [targetRingActive, setTargetRingActive] = useState12(false);
3666
+ const [popoverRingActive, setPopoverRingActive] = useState12(false);
3667
+ const [popoverRect, setPopoverRect] = useState12(null);
3582
3668
  const restoreFocus = () => {
3583
3669
  const previous = previousFocusRef.current;
3584
3670
  previousFocusRef.current = null;
@@ -3604,7 +3690,7 @@ var TourFocusManager = ({
3604
3690
  restoreFocus();
3605
3691
  };
3606
3692
  }, [active, popoverNode, target.element]);
3607
- useEffect15(() => {
3693
+ useEffect16(() => {
3608
3694
  if (!isBrowser) return;
3609
3695
  if (!active) return;
3610
3696
  const doc = popoverNode?.ownerDocument ?? target.element?.ownerDocument ?? document;
package/dist/labels.d.ts CHANGED
@@ -15,6 +15,16 @@ export interface TourLabels {
15
15
  formatTimeRemaining: (params: {
16
16
  ms: number;
17
17
  }) => string;
18
+ targetIssue: {
19
+ missingTitle: string;
20
+ missingBody: string;
21
+ missingHint: string;
22
+ hiddenTitle: string;
23
+ hiddenBody: string;
24
+ hiddenHint: string;
25
+ detachedTitle: string;
26
+ detachedBody: string;
27
+ };
18
28
  }
19
29
  export declare const defaultLabels: TourLabels;
20
30
  export declare const LabelsProvider: import("react").Provider<TourLabels>;
@@ -1 +1 @@
1
- {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../src/labels.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IAEzB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,CAAA;IAGrB,gBAAgB,EAAE,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAA;IACxE,iBAAiB,EAAE,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAA;IACrD,iBAAiB,EAAE,MAAM,CAAA;IAGzB,mBAAmB,EAAE,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAA;CACxD;AAED,eAAO,MAAM,aAAa,EAAE,UAa3B,CAAA;AAID,eAAO,MAAM,cAAc,sCAAyB,CAAA;AAEpD,wBAAgB,aAAa,IAAI,UAAU,CAE1C"}
1
+ {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../src/labels.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IAEzB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,CAAA;IAGrB,gBAAgB,EAAE,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAA;IACxE,iBAAiB,EAAE,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAA;IACrD,iBAAiB,EAAE,MAAM,CAAA;IAGzB,mBAAmB,EAAE,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAA;IAGvD,WAAW,EAAE;QACX,YAAY,EAAE,MAAM,CAAA;QACpB,WAAW,EAAE,MAAM,CAAA;QACnB,WAAW,EAAE,MAAM,CAAA;QACnB,WAAW,EAAE,MAAM,CAAA;QACnB,UAAU,EAAE,MAAM,CAAA;QAClB,UAAU,EAAE,MAAM,CAAA;QAClB,aAAa,EAAE,MAAM,CAAA;QACrB,YAAY,EAAE,MAAM,CAAA;KACrB,CAAA;CACF;AAED,eAAO,MAAM,aAAa,EAAE,UA2B3B,CAAA;AAID,eAAO,MAAM,cAAc,sCAAyB,CAAA;AAEpD,wBAAgB,aAAa,IAAI,UAAU,CAE1C"}
@@ -1,3 +1,4 @@
1
+ import "../chunk-WCLT3A6G.mjs";
1
2
  import {
2
3
  TanStackRouterSync,
3
4
  getTanStackRouter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowsterix/react",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "React bindings for Flowsterix - guided tours and onboarding flows",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -64,7 +64,7 @@
64
64
  ],
65
65
  "dependencies": {
66
66
  "@floating-ui/dom": "^1.7.4",
67
- "@flowsterix/core": "0.4.0"
67
+ "@flowsterix/core": "0.5.0"
68
68
  },
69
69
  "peerDependencies": {
70
70
  "react": ">=18",