@tent-official/react-walkthrough 1.3.5 → 1.4.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/README.md CHANGED
@@ -6,6 +6,7 @@ Lightweight React walkthrough/tour component with auto-positioning, dependency c
6
6
 
7
7
  - SVG-based spotlight overlay with smooth animated transitions
8
8
  - Auto-positioning popover (top/bottom/left/right) with viewport detection
9
+ - Inner positions (`inner-top`, `inner-bottom`, `inner-left`, `inner-right`) — place the popover inside the highlight area
9
10
  - Dependency chains — start a walkthrough only after another completes
10
11
  - Conditional start — `startWhenCondition` prop to gate walkthrough on custom logic (e.g. data loaded)
11
12
  - Auto-cleanup on navigation — highlight is automatically removed when the component unmounts (e.g. browser back/forward)
@@ -104,7 +105,7 @@ Hook to register a walkthrough tour.
104
105
  | `el` | `string` | **required** | DOM element ID to highlight (with or without `#` prefix) |
105
106
  | `title` | `string` | — | Popover title |
106
107
  | `description` | `IStepDescription[]` | **required** | Description blocks |
107
- | `position` | `"top" \| "bottom" \| "left" \| "right"` | auto | Preferred popover position |
108
+ | `position` | `"top" \| "bottom" \| "left" \| "right" \| "inner-top" \| "inner-bottom" \| "inner-left" \| "inner-right"` | auto | Preferred popover position. `inner-*` positions place the popover inside the highlight area (12 px inset) |
108
109
  | `padding` | `number` | `8` | Padding around highlighted element (px) |
109
110
  | `borderRadius` | `number` | `10` | Border radius of highlight cutout (px) |
110
111
  | `width` | `number \| string` | `"auto"` | Popover width |
@@ -118,6 +119,7 @@ Hook to register a walkthrough tour.
118
119
  | `displayStep` | `number` | — | Override the displayed step number for this step (display-only) |
119
120
  | `displayTotal` | `number` | — | Override the displayed total for this step (display-only) |
120
121
  | `forceRecompute` | `boolean` | — | When `true`, forces a DOM re-read before advancing to the next step. Useful when the next element is conditionally rendered and needs a layout update to appear |
122
+ | `delayAfterNext` | `number` | `0` | Delay in ms after clicking "Next" (after `onStepNext` and `triggerElOnNext` have fired) before advancing to the next step. The overlay stays visible with the popover hidden during the delay |
121
123
 
122
124
  ### `IStepDescription`
123
125
 
@@ -259,6 +261,21 @@ The popover automatically positions itself to stay within the viewport:
259
261
 
260
262
  The popover also waits for the target element to be scrolled into view before appearing.
261
263
 
264
+ ### Inner Positions
265
+
266
+ Use `inner-top`, `inner-bottom`, `inner-left`, or `inner-right` to place the popover **inside** the highlight area, inset 12 px from the corresponding edge. Inner positions never auto-fallback — they always stay exactly where specified.
267
+
268
+ This is useful when the highlighted area is large (e.g. a table or a panel) and you want the popover to appear within it rather than outside.
269
+
270
+ ```jsx
271
+ {
272
+ el: "large-table",
273
+ title: "Table Overview",
274
+ description: [{ description: "Here is your data table." }],
275
+ position: "inner-bottom", // popover sits inside the highlight, near the bottom-right corner
276
+ }
277
+ ```
278
+
262
279
  ## Instant Dismiss
263
280
 
264
281
  When the user clicks **Done** on the last step (or **Skip** at any step), the highlight and popover vanish **instantly** in the same render frame — no lingering overlay or flash.
package/dist/index.d.mts CHANGED
@@ -3,8 +3,11 @@ import { ReactNode, ReactPortal } from 'react';
3
3
  /**
4
4
  * Position of the popover relative to the target element.
5
5
  * If the preferred position doesn't fit in the viewport, it will auto-fallback.
6
+ *
7
+ * "inner-*" positions place the popover **inside** the highlight area,
8
+ * inset 12 px from the corresponding edge. These never auto-fallback.
6
9
  */
7
- type TPopoverPosition = "top" | "bottom" | "left" | "right";
10
+ type TPopoverPosition = "top" | "bottom" | "left" | "right" | "inner-top" | "inner-bottom" | "inner-left" | "inner-right";
8
11
  /**
9
12
  * Direction for description block layout.
10
13
  */
@@ -58,6 +61,8 @@ interface IWalkthroughStep {
58
61
  displayTotal?: number;
59
62
  /** When true, forces a recompute of valid steps after advancing from this step. Useful when the next step's element is hidden/conditional and needs DOM changes to become visible. Default: false */
60
63
  forceRecompute?: boolean;
64
+ /** Delay in milliseconds after clicking "Next" (after onStepNext and triggerElOnNext have fired) before advancing to the next step. The overlay stays visible with the popover hidden during the delay. Default: 0 (no delay) */
65
+ delayAfterNext?: number;
61
66
  }
62
67
  /**
63
68
  * Options for the useWalkthrough hook.
package/dist/index.d.ts CHANGED
@@ -3,8 +3,11 @@ import { ReactNode, ReactPortal } from 'react';
3
3
  /**
4
4
  * Position of the popover relative to the target element.
5
5
  * If the preferred position doesn't fit in the viewport, it will auto-fallback.
6
+ *
7
+ * "inner-*" positions place the popover **inside** the highlight area,
8
+ * inset 12 px from the corresponding edge. These never auto-fallback.
6
9
  */
7
- type TPopoverPosition = "top" | "bottom" | "left" | "right";
10
+ type TPopoverPosition = "top" | "bottom" | "left" | "right" | "inner-top" | "inner-bottom" | "inner-left" | "inner-right";
8
11
  /**
9
12
  * Direction for description block layout.
10
13
  */
@@ -58,6 +61,8 @@ interface IWalkthroughStep {
58
61
  displayTotal?: number;
59
62
  /** When true, forces a recompute of valid steps after advancing from this step. Useful when the next step's element is hidden/conditional and needs DOM changes to become visible. Default: false */
60
63
  forceRecompute?: boolean;
64
+ /** Delay in milliseconds after clicking "Next" (after onStepNext and triggerElOnNext have fired) before advancing to the next step. The overlay stays visible with the popover hidden during the delay. Default: 0 (no delay) */
65
+ delayAfterNext?: number;
61
66
  }
62
67
  /**
63
68
  * Options for the useWalkthrough hook.
package/dist/index.js CHANGED
@@ -531,7 +531,11 @@ var clampSize = (value, max) => {
531
531
  return clamped;
532
532
  };
533
533
  var EDGE_MARGIN = 8;
534
+ var INNER_INSET = 12;
534
535
  var choosePopoverDir = (rect, popoverW, popoverH, gap, preferred) => {
536
+ if (preferred && preferred.startsWith("inner-")) {
537
+ return { dir: preferred, align: "start", offsetX: 0, offsetY: 0 };
538
+ }
535
539
  const vw = window.innerWidth;
536
540
  const vh = window.innerHeight;
537
541
  const space = {
@@ -1007,13 +1011,21 @@ var WalkthroughOverlay = ({
1007
1011
  }
1008
1012
  };
1009
1013
  const next = () => {
1010
- var _a2;
1014
+ var _a2, _b2;
1011
1015
  const currentOrigIdx = validSteps[currentValidPos]._originalIdx;
1012
1016
  const stepNextCb = (_a2 = activeTour.onStepNext) == null ? void 0 : _a2[currentOrigIdx];
1013
1017
  if (typeof stepNextCb === "function") {
1014
1018
  stepNextCb();
1015
1019
  }
1016
1020
  const hasTrigger = !!step.triggerElOnNext;
1021
+ const afterNextDelay = (_b2 = step.delayAfterNext) != null ? _b2 : 0;
1022
+ const withDelay = (fn) => {
1023
+ if (afterNextDelay > 0) {
1024
+ setTimeout(fn, afterNextDelay);
1025
+ } else {
1026
+ fn();
1027
+ }
1028
+ };
1017
1029
  if (hasTrigger) {
1018
1030
  setPopoverHidden(true);
1019
1031
  setPopoverPos(null);
@@ -1046,7 +1058,7 @@ var WalkthroughOverlay = ({
1046
1058
  const SETTLE_DELAY = 150;
1047
1059
  const alreadyExists = document.getElementById(nextElId);
1048
1060
  if (alreadyExists) {
1049
- setTimeout(() => injectAndAdvance(), SETTLE_DELAY);
1061
+ withDelay(() => setTimeout(() => injectAndAdvance(), SETTLE_DELAY));
1050
1062
  } else {
1051
1063
  waitingForElsRef.current = true;
1052
1064
  const observer = new MutationObserver(() => {
@@ -1054,7 +1066,7 @@ var WalkthroughOverlay = ({
1054
1066
  if (found) {
1055
1067
  observer.disconnect();
1056
1068
  waitingForElsRef.current = false;
1057
- setTimeout(() => injectAndAdvance(), SETTLE_DELAY);
1069
+ withDelay(() => setTimeout(() => injectAndAdvance(), SETTLE_DELAY));
1058
1070
  }
1059
1071
  });
1060
1072
  observer.observe(document.body, { childList: true, subtree: true });
@@ -1062,7 +1074,7 @@ var WalkthroughOverlay = ({
1062
1074
  observer.disconnect();
1063
1075
  if (waitingForElsRef.current) {
1064
1076
  waitingForElsRef.current = false;
1065
- advanceStep(hasTrigger);
1077
+ withDelay(() => advanceStep(hasTrigger));
1066
1078
  }
1067
1079
  }, 3e3);
1068
1080
  }
@@ -1073,7 +1085,13 @@ var WalkthroughOverlay = ({
1073
1085
  setTimeout(() => completeTour(), 300);
1074
1086
  return;
1075
1087
  }
1076
- advanceStep(hasTrigger);
1088
+ if (afterNextDelay > 0) {
1089
+ setPopoverHidden(true);
1090
+ setPopoverPos(null);
1091
+ withDelay(() => advanceStep(hasTrigger));
1092
+ } else {
1093
+ advanceStep(hasTrigger);
1094
+ }
1077
1095
  };
1078
1096
  const prev = () => {
1079
1097
  var _a2;
@@ -1143,7 +1161,12 @@ var WalkthroughOverlay = ({
1143
1161
  bottom: { top: `calc(100% + ${$popoverGap}px)`, ...hAlign },
1144
1162
  top: { bottom: `calc(100% + ${$popoverGap}px)`, ...hAlign },
1145
1163
  right: { left: `calc(100% + ${$popoverGap}px)`, ...vAlign },
1146
- left: { right: `calc(100% + ${$popoverGap}px)`, ...vAlign }
1164
+ left: { right: `calc(100% + ${$popoverGap}px)`, ...vAlign },
1165
+ // inner-* : popover sits INSIDE the highlight rect, inset 12px from the edge
1166
+ "inner-bottom": { bottom: INNER_INSET, right: INNER_INSET },
1167
+ "inner-top": { top: INNER_INSET, right: INNER_INSET },
1168
+ "inner-left": { left: INNER_INSET, bottom: INNER_INSET },
1169
+ "inner-right": { right: INNER_INSET, bottom: INNER_INSET }
1147
1170
  };
1148
1171
  const maxHeightStyle = (popoverPos == null ? void 0 : popoverPos.maxHeight) != null ? { maxHeight: popoverPos.maxHeight, overflowY: "auto" } : {};
1149
1172
  const popoverStyle = popoverReady ? {