@amplifyup/sdk 0.1.19 → 0.1.21

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/react.js CHANGED
@@ -371,6 +371,15 @@ var AmplifyUpSDK = class {
371
371
  this.componentViewObservers = [];
372
372
  this.componentViewSeen = /* @__PURE__ */ new Set();
373
373
  this.pageEngagementActive = false;
374
+ /** Path of the last page() / routeChange — avoids duplicate SPA fires. */
375
+ this.lastTrackedPath = null;
376
+ this.historyHooksInstalled = false;
377
+ this.pageEngagementState = {
378
+ reached: /* @__PURE__ */ new Set(),
379
+ visibleMs: 0,
380
+ visibleSince: null,
381
+ lastDwellSecondsSent: 0
382
+ };
374
383
  this.adapter = adapter || new AWSAdapter();
375
384
  if (typeof window !== "undefined") {
376
385
  this.isVisualEditorMode = this.detectVisualEditorMode();
@@ -543,7 +552,9 @@ var AmplifyUpSDK = class {
543
552
  this.initialPageSent = true;
544
553
  const url = window.location.pathname;
545
554
  this.page(url);
555
+ this.lastTrackedPath = url;
546
556
  this.setupPageEngagement();
557
+ this.installHistoryHooks();
547
558
  }
548
559
  }
549
560
  if (this.config?.debug && this.initialized) {
@@ -586,16 +597,18 @@ var AmplifyUpSDK = class {
586
597
  }
587
598
  /**
588
599
  * Automatic page-level Scroll Depth + Time on Page (dwell heartbeat).
600
+ * State lives on the instance so SPA route changes can reset milestones.
589
601
  */
590
602
  setupPageEngagement() {
591
603
  if (typeof window === "undefined" || typeof document === "undefined") return;
592
604
  if (this.isPreviewMode() || this.pageEngagementActive) return;
593
605
  this.pageEngagementActive = true;
594
606
  const milestones = [25, 50, 75, 100];
595
- const reached = /* @__PURE__ */ new Set();
596
- let visibleMs = 0;
597
- let visibleSince = document.visibilityState === "visible" ? Date.now() : null;
598
- let lastDwellSecondsSent = 0;
607
+ const state = this.pageEngagementState;
608
+ state.reached = /* @__PURE__ */ new Set();
609
+ state.visibleMs = 0;
610
+ state.visibleSince = document.visibilityState === "visible" ? Date.now() : null;
611
+ state.lastDwellSecondsSent = 0;
599
612
  let scrollRaf = null;
600
613
  const path = () => this.currentPath();
601
614
  const measureScrollPercent = () => {
@@ -617,8 +630,8 @@ var AmplifyUpSDK = class {
617
630
  if (this.isPreviewMode()) return;
618
631
  const pct = measureScrollPercent();
619
632
  for (const milestone of milestones) {
620
- if (pct >= milestone && !reached.has(milestone)) {
621
- reached.add(milestone);
633
+ if (pct >= milestone && !state.reached.has(milestone)) {
634
+ state.reached.add(milestone);
622
635
  this.track("Scroll Depth", {
623
636
  percentage: milestone,
624
637
  path: path()
@@ -634,28 +647,29 @@ var AmplifyUpSDK = class {
634
647
  });
635
648
  };
636
649
  const accumulateVisible = () => {
637
- if (visibleSince == null) return;
638
- visibleMs += Date.now() - visibleSince;
639
- visibleSince = Date.now();
650
+ if (state.visibleSince == null) return;
651
+ state.visibleMs += Date.now() - state.visibleSince;
652
+ state.visibleSince = Date.now();
640
653
  };
641
654
  const emitDwell = (force = false) => {
642
655
  if (this.isPreviewMode()) return;
643
656
  accumulateVisible();
644
- const seconds = Math.floor(visibleMs / 1e3);
657
+ const seconds = Math.floor(state.visibleMs / 1e3);
645
658
  if (seconds <= 0) return;
646
- if (!force && seconds <= lastDwellSecondsSent) return;
647
- lastDwellSecondsSent = seconds;
659
+ if (!force && seconds <= state.lastDwellSecondsSent) return;
660
+ state.lastDwellSecondsSent = seconds;
648
661
  this.track("Time on Page", {
649
662
  seconds,
650
- path: path()
663
+ path: this.lastTrackedPath || path()
651
664
  });
652
665
  };
666
+ this._emitPageDwell = emitDwell;
653
667
  const onVisibility = () => {
654
668
  if (document.visibilityState === "visible") {
655
- visibleSince = Date.now();
669
+ state.visibleSince = Date.now();
656
670
  } else {
657
671
  emitDwell(true);
658
- visibleSince = null;
672
+ state.visibleSince = null;
659
673
  }
660
674
  };
661
675
  const onPageHide = () => {
@@ -682,11 +696,64 @@ var AmplifyUpSDK = class {
682
696
  }
683
697
  previousCleanup?.();
684
698
  this.pageEngagementActive = false;
699
+ delete this._emitPageDwell;
685
700
  };
686
701
  if (this.config?.debug) {
687
702
  console.log("[AmplifyUp SDK] Page engagement tracking enabled");
688
703
  }
689
704
  }
705
+ resetEngagementForNewPage() {
706
+ const emit = this._emitPageDwell;
707
+ emit?.(true);
708
+ const state = this.pageEngagementState;
709
+ state.reached = /* @__PURE__ */ new Set();
710
+ state.visibleMs = 0;
711
+ state.lastDwellSecondsSent = 0;
712
+ state.visibleSince = typeof document !== "undefined" && document.visibilityState === "visible" ? Date.now() : null;
713
+ this.componentViewSeen.clear();
714
+ }
715
+ /**
716
+ * SPA / soft navigation: fire a page view and reset engagement.
717
+ * No-op when the path has not changed. Safe for React Strict Mode remounts.
718
+ */
719
+ routeChange(url, properties) {
720
+ if (this.isPreviewMode()) return;
721
+ if (!this.isInitialized()) return;
722
+ if (typeof window === "undefined") return;
723
+ const path = url || window.location.pathname || "/";
724
+ if (path === this.lastTrackedPath) return;
725
+ this.resetEngagementForNewPage();
726
+ this.page(path, properties);
727
+ this.lastTrackedPath = path;
728
+ if (!this.pageEngagementActive) {
729
+ this.setupPageEngagement();
730
+ }
731
+ if (this.config?.debug) {
732
+ console.log("[AmplifyUp SDK] Route change page view", path);
733
+ }
734
+ }
735
+ /**
736
+ * Patch history.pushState / replaceState + popstate for non-React SPAs.
737
+ * React/Next apps should also call routeChange from the provider.
738
+ */
739
+ installHistoryHooks() {
740
+ if (typeof window === "undefined" || this.historyHooksInstalled) return;
741
+ this.historyHooksInstalled = true;
742
+ const notify = () => {
743
+ queueMicrotask(() => this.routeChange(window.location.pathname));
744
+ };
745
+ const wrap = (method) => {
746
+ const original = history[method].bind(history);
747
+ history[method] = (...args) => {
748
+ const result = original(...args);
749
+ notify();
750
+ return result;
751
+ };
752
+ };
753
+ wrap("pushState");
754
+ wrap("replaceState");
755
+ window.addEventListener("popstate", notify);
756
+ }
690
757
  /**
691
758
  * Automatic Component View when component hosts enter the viewport.
692
759
  */
@@ -761,6 +828,7 @@ var AmplifyUpSDK = class {
761
828
  ...properties
762
829
  };
763
830
  this.adapter.page(pageProperties);
831
+ this.lastTrackedPath = url;
764
832
  }
765
833
  /**
766
834
  * Track an event
@@ -3005,6 +3073,7 @@ function AmplifyUpProvider({ children, config }) {
3005
3073
  return;
3006
3074
  }
3007
3075
  const sdk = getSDK();
3076
+ sdk.routeChange(actualRoute);
3008
3077
  const isPreviewContext = isComposerPreview();
3009
3078
  const page = await sdk.fetchPageConfig(actualRoute, isPreviewContext);
3010
3079
  if (!page) {