@tent-official/react-walkthrough 1.1.76 → 1.1.78

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.d.mts CHANGED
@@ -127,10 +127,24 @@ interface IResetWalkthroughOptions {
127
127
  /** List of walkthrough names to reset */
128
128
  walkthroughList?: string[];
129
129
  }
130
+ /**
131
+ * Options for the readElement function.
132
+ */
133
+ interface IReadElementOptions {
134
+ /** Optional AbortSignal to cancel waiting for the element */
135
+ signal?: AbortSignal;
136
+ }
130
137
  /**
131
138
  * Reset specified walkthroughs so they can be replayed without page refresh.
132
139
  */
133
140
  declare function resetWalkthrough(options?: IResetWalkthroughOptions): void;
141
+ /**
142
+ * Read (find) a DOM element by its ID.
143
+ * Returns immediately if the element already exists in the DOM.
144
+ * If not found, uses a MutationObserver to wait until it appears.
145
+ * Supports cancellation via AbortSignal.
146
+ */
147
+ declare function readElement(elementId: string, options?: IReadElementOptions): Promise<HTMLElement | null>;
134
148
  /**
135
149
  * Hook to register and control a walkthrough tour.
136
150
  */
@@ -141,4 +155,4 @@ declare function useWalkthrough(options: IUseWalkthroughOptions): IUseWalkthroug
141
155
  */
142
156
  declare function WalkthroughOverlay(props?: IWalkthroughOverlayProps): ReactPortal | null;
143
157
 
144
- export { type IResetWalkthroughOptions, type IStepDescription, type IUseWalkthroughOptions, type IUseWalkthroughReturn, type IWalkthroughOverlayProps, type IWalkthroughStep, type TDescriptionDirection, type TPopoverPosition, WalkthroughOverlay, resetWalkthrough, useWalkthrough };
158
+ export { type IReadElementOptions, type IResetWalkthroughOptions, type IStepDescription, type IUseWalkthroughOptions, type IUseWalkthroughReturn, type IWalkthroughOverlayProps, type IWalkthroughStep, type TDescriptionDirection, type TPopoverPosition, WalkthroughOverlay, readElement, resetWalkthrough, useWalkthrough };
package/dist/index.d.ts CHANGED
@@ -127,10 +127,24 @@ interface IResetWalkthroughOptions {
127
127
  /** List of walkthrough names to reset */
128
128
  walkthroughList?: string[];
129
129
  }
130
+ /**
131
+ * Options for the readElement function.
132
+ */
133
+ interface IReadElementOptions {
134
+ /** Optional AbortSignal to cancel waiting for the element */
135
+ signal?: AbortSignal;
136
+ }
130
137
  /**
131
138
  * Reset specified walkthroughs so they can be replayed without page refresh.
132
139
  */
133
140
  declare function resetWalkthrough(options?: IResetWalkthroughOptions): void;
141
+ /**
142
+ * Read (find) a DOM element by its ID.
143
+ * Returns immediately if the element already exists in the DOM.
144
+ * If not found, uses a MutationObserver to wait until it appears.
145
+ * Supports cancellation via AbortSignal.
146
+ */
147
+ declare function readElement(elementId: string, options?: IReadElementOptions): Promise<HTMLElement | null>;
134
148
  /**
135
149
  * Hook to register and control a walkthrough tour.
136
150
  */
@@ -141,4 +155,4 @@ declare function useWalkthrough(options: IUseWalkthroughOptions): IUseWalkthroug
141
155
  */
142
156
  declare function WalkthroughOverlay(props?: IWalkthroughOverlayProps): ReactPortal | null;
143
157
 
144
- export { type IResetWalkthroughOptions, type IStepDescription, type IUseWalkthroughOptions, type IUseWalkthroughReturn, type IWalkthroughOverlayProps, type IWalkthroughStep, type TDescriptionDirection, type TPopoverPosition, WalkthroughOverlay, resetWalkthrough, useWalkthrough };
158
+ export { type IReadElementOptions, type IResetWalkthroughOptions, type IStepDescription, type IUseWalkthroughOptions, type IUseWalkthroughReturn, type IWalkthroughOverlayProps, type IWalkthroughStep, type TDescriptionDirection, type TPopoverPosition, WalkthroughOverlay, readElement, resetWalkthrough, useWalkthrough };
package/dist/index.js CHANGED
@@ -68,6 +68,36 @@ var easeOutCubic = (t) => {
68
68
  var lerp = (a, b, t) => {
69
69
  return a + (b - a) * t;
70
70
  };
71
+ var resolveElId = (id) => typeof id === "string" && id.startsWith("#") ? id.slice(1) : id;
72
+ var readElement = (elementId, { signal } = {}) => {
73
+ return new Promise((resolve) => {
74
+ if (signal == null ? void 0 : signal.aborted) {
75
+ resolve(null);
76
+ return;
77
+ }
78
+ const id = resolveElId(elementId);
79
+ const el = document.getElementById(id);
80
+ if (el) {
81
+ resolve(el);
82
+ return;
83
+ }
84
+ const observer = new MutationObserver(() => {
85
+ const found = document.getElementById(id);
86
+ if (found) {
87
+ observer.disconnect();
88
+ resolve(found);
89
+ }
90
+ });
91
+ observer.observe(document.body, { childList: true, subtree: true });
92
+ if (signal) {
93
+ const onAbort = () => {
94
+ observer.disconnect();
95
+ resolve(null);
96
+ };
97
+ signal.addEventListener("abort", onAbort, { once: true });
98
+ }
99
+ });
100
+ };
71
101
  var STYLE_ID = "wt-keyframes";
72
102
  var injectKeyframes = () => {
73
103
  if (typeof document === "undefined") return;
@@ -166,7 +196,6 @@ var StepCounter = react.forwardRef(({ style, children, ...props }, ref) => /* @_
166
196
  ...style
167
197
  }, ...props, children }));
168
198
  var ButtonGroup = react.forwardRef(({ style, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, style: { display: "flex", gap: 6, ...style }, ...props, children }));
169
- var resolveElId = (id) => typeof id === "string" && id.startsWith("#") ? id.slice(1) : id;
170
199
  var _overlayInstanceCounter = 0;
171
200
  var _activeOverlayId = null;
172
201
  var useWalkthrough = ({
@@ -562,16 +591,40 @@ var WalkthroughOverlay = ({
562
591
  const [popoverHidden, setPopoverHidden] = react.useState(false);
563
592
  const displayStepRef = react.useRef(null);
564
593
  const displayPosRef = react.useRef(null);
594
+ const delayDoneForRef = react.useRef(null);
595
+ const [isDelaying, setIsDelaying] = react.useState(false);
596
+ const currentTourName = (_a = activeTour == null ? void 0 : activeTour.name) != null ? _a : null;
597
+ react.useEffect(() => {
598
+ var _a2;
599
+ if (!activeTour) {
600
+ delayDoneForRef.current = null;
601
+ setIsDelaying(false);
602
+ return;
603
+ }
604
+ if (delayDoneForRef.current === activeTour.name) return;
605
+ const ms = (_a2 = activeTour.delay) != null ? _a2 : 0;
606
+ if (ms <= 0) {
607
+ delayDoneForRef.current = activeTour.name;
608
+ return;
609
+ }
610
+ setIsDelaying(true);
611
+ const timer = setTimeout(() => {
612
+ delayDoneForRef.current = activeTour.name;
613
+ setIsDelaying(false);
614
+ }, ms);
615
+ return () => clearTimeout(timer);
616
+ }, [currentTourName, activeTour]);
565
617
  const [validSteps, setValidSteps] = react.useState([]);
566
618
  const waitingForElsRef = react.useRef(false);
567
619
  react.useEffect(() => {
568
- var _a2, _b2;
569
- if (!activeTour) {
620
+ var _a2, _b2, _c2;
621
+ if (!activeTour || isDelaying) {
570
622
  setValidSteps([]);
571
623
  waitingForElsRef.current = false;
572
624
  return;
573
625
  }
574
626
  waitingForElsRef.current = true;
627
+ const abortController = new AbortController();
575
628
  const compute = () => activeTour.steps.map((s, i) => ({ ...s, _originalIdx: i })).filter((s) => document.getElementById(resolveElId(s.el)));
576
629
  const found = compute();
577
630
  if (found.length > 0) {
@@ -588,63 +641,42 @@ var WalkthroughOverlay = ({
588
641
  waitingForElsRef.current = false;
589
642
  return;
590
643
  }
591
- const observer2 = new MutationObserver(() => {
592
- const el = document.getElementById(resolveElId(currentStepEl));
593
- if (el) {
644
+ readElement(currentStepEl, { signal: abortController.signal }).then((el) => {
645
+ if (el && !abortController.signal.aborted) {
594
646
  waitingForElsRef.current = false;
595
647
  setValidSteps(compute());
596
- observer2.disconnect();
597
648
  }
598
649
  });
599
- observer2.observe(document.body, { childList: true, subtree: true });
600
650
  return () => {
601
- observer2.disconnect();
651
+ abortController.abort();
602
652
  waitingForElsRef.current = false;
603
653
  };
604
654
  }
605
655
  setValidSteps([]);
606
- const observer = new MutationObserver(() => {
607
- const updated = compute();
608
- if (updated.length > 0) {
609
- waitingForElsRef.current = false;
610
- setValidSteps(updated);
611
- observer.disconnect();
656
+ const firstStepEl = (_c2 = activeTour.steps[0]) == null ? void 0 : _c2.el;
657
+ if (!firstStepEl) {
658
+ waitingForElsRef.current = false;
659
+ return;
660
+ }
661
+ readElement(firstStepEl, { signal: abortController.signal }).then((el) => {
662
+ if (el && !abortController.signal.aborted) {
663
+ const updated = compute();
664
+ if (updated.length > 0) {
665
+ waitingForElsRef.current = false;
666
+ setValidSteps(updated);
667
+ }
612
668
  }
613
669
  });
614
- observer.observe(document.body, { childList: true, subtree: true });
615
670
  return () => {
616
- observer.disconnect();
671
+ abortController.abort();
617
672
  waitingForElsRef.current = false;
618
673
  };
619
- }, [activeTour]);
620
- const currentOriginalIdx = (_a = activeTour == null ? void 0 : activeTour.currentStep) != null ? _a : 0;
674
+ }, [activeTour, isDelaying]);
675
+ const currentOriginalIdx = (_b = activeTour == null ? void 0 : activeTour.currentStep) != null ? _b : 0;
621
676
  const currentValidPos = validSteps.findIndex(
622
677
  (s) => s._originalIdx === currentOriginalIdx
623
678
  );
624
679
  const rawStep = currentValidPos !== -1 ? validSteps[currentValidPos] : null;
625
- const delayDoneForRef = react.useRef(null);
626
- const [isDelaying, setIsDelaying] = react.useState(false);
627
- const currentTourName = (_b = activeTour == null ? void 0 : activeTour.name) != null ? _b : null;
628
- react.useEffect(() => {
629
- var _a2;
630
- if (!activeTour) {
631
- delayDoneForRef.current = null;
632
- setIsDelaying(false);
633
- return;
634
- }
635
- if (delayDoneForRef.current === activeTour.name) return;
636
- const ms = (_a2 = activeTour.delay) != null ? _a2 : 0;
637
- if (ms <= 0) {
638
- delayDoneForRef.current = activeTour.name;
639
- return;
640
- }
641
- setIsDelaying(true);
642
- const timer = setTimeout(() => {
643
- delayDoneForRef.current = activeTour.name;
644
- setIsDelaying(false);
645
- }, ms);
646
- return () => clearTimeout(timer);
647
- }, [currentTourName, activeTour]);
648
680
  const step = isDelaying ? null : rawStep;
649
681
  const tourAnimationSpeed = (_c = activeTour == null ? void 0 : activeTour.animationSpeed) != null ? _c : 350;
650
682
  const { rect, isAnimating } = useAnimatedRect(step, tourAnimationSpeed, activeTour == null ? void 0 : activeTour.containerElement, !!activeTour, activeTour == null ? void 0 : activeTour.name);
@@ -841,12 +873,14 @@ var WalkthroughOverlay = ({
841
873
  triggerTarget.click();
842
874
  }
843
875
  }
844
- if (isLast) {
876
+ const currentOrigIdx = validSteps[currentValidPos]._originalIdx;
877
+ const hasMoreOriginalSteps = currentOrigIdx < activeTour.steps.length - 1;
878
+ const effectiveIsLast = isLast && !(hasTrigger && hasMoreOriginalSteps);
879
+ if (effectiveIsLast) {
845
880
  completeTour();
846
881
  } else {
847
882
  setPopoverHidden(true);
848
883
  const nextValidStep = validSteps[currentValidPos + 1];
849
- const currentOrigIdx = validSteps[currentValidPos]._originalIdx;
850
884
  const nextOrigIdx = hasTrigger && !nextValidStep ? currentOrigIdx + 1 : (_a2 = nextValidStep == null ? void 0 : nextValidStep._originalIdx) != null ? _a2 : currentOrigIdx + 1;
851
885
  setGlobalState((s) => ({
852
886
  ...s,
@@ -1011,6 +1045,7 @@ var WalkthroughOverlay = ({
1011
1045
  };
1012
1046
 
1013
1047
  exports.WalkthroughOverlay = WalkthroughOverlay;
1048
+ exports.readElement = readElement;
1014
1049
  exports.resetWalkthrough = resetWalkthrough;
1015
1050
  exports.useWalkthrough = useWalkthrough;
1016
1051
  //# sourceMappingURL=index.js.map