@capgo/capacitor-transitions 8.0.1 → 8.0.2

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.
@@ -1243,9 +1243,26 @@ var CapRouterOutlet = class extends HTMLElement {
1243
1243
  skipNextHistoryBackTransition = false;
1244
1244
  swipeBackDepth = 0;
1245
1245
  lastNavigationHref = null;
1246
+ lastNavigationPosition = null;
1247
+ pendingHistoryDirection = null;
1248
+ navigationHrefs = [];
1246
1249
  swipeGestureEdgeWidth = 50;
1247
1250
  swipeGestureThreshold = 10;
1248
1251
  swipeGestureMinimumVelocity = 0.2;
1252
+ handleHistoryPopState = () => {
1253
+ const currentPosition = this.getCurrentNavigationPosition();
1254
+ if (currentPosition !== null && this.lastNavigationPosition !== null) {
1255
+ if (currentPosition < this.lastNavigationPosition) {
1256
+ this.pendingHistoryDirection = "back";
1257
+ return;
1258
+ }
1259
+ if (currentPosition > this.lastNavigationPosition) {
1260
+ this.pendingHistoryDirection = "forward";
1261
+ return;
1262
+ }
1263
+ }
1264
+ this.pendingHistoryDirection = "back";
1265
+ };
1249
1266
  static get observedAttributes() {
1250
1267
  return ["platform", "duration", "keep-in-dom", "max-cached", "swipe-gesture"];
1251
1268
  }
@@ -1265,6 +1282,8 @@ var CapRouterOutlet = class extends HTMLElement {
1265
1282
  this.style.height = "100%";
1266
1283
  this.style.overflow = "hidden";
1267
1284
  this.lastNavigationHref = this.getCurrentNavigationHref();
1285
+ this.lastNavigationPosition = this.getCurrentNavigationPosition();
1286
+ this.ownerDocument.defaultView?.addEventListener("popstate", this.handleHistoryPopState);
1268
1287
  this.observer = new MutationObserver((mutations) => {
1269
1288
  this.handleMutations(mutations);
1270
1289
  });
@@ -1280,10 +1299,14 @@ var CapRouterOutlet = class extends HTMLElement {
1280
1299
  }
1281
1300
  disconnectedCallback() {
1282
1301
  this.observer?.disconnect();
1302
+ this.ownerDocument.defaultView?.removeEventListener("popstate", this.handleHistoryPopState);
1283
1303
  this.removeSwipeGestureListeners();
1284
1304
  this.controller.clear();
1285
1305
  this.swipeBackDepth = 0;
1286
1306
  this.lastNavigationHref = null;
1307
+ this.lastNavigationPosition = null;
1308
+ this.pendingHistoryDirection = null;
1309
+ this.navigationHrefs = [];
1287
1310
  }
1288
1311
  attributeChangedCallback(name, _oldValue, newValue) {
1289
1312
  switch (name) {
@@ -1364,13 +1387,16 @@ var CapRouterOutlet = class extends HTMLElement {
1364
1387
  this.controller.pageStack.push(state);
1365
1388
  this.swipeBackDepth = 0;
1366
1389
  this.lastNavigationHref = this.getCurrentNavigationHref();
1390
+ this.lastNavigationPosition = this.getCurrentNavigationPosition();
1391
+ this.navigationHrefs = [this.lastNavigationHref];
1367
1392
  }
1368
1393
  /**
1369
1394
  * Handle a new page being added
1370
1395
  */
1371
1396
  async handleNewPage(page2) {
1372
1397
  const outletDirection = this.dataset.direction;
1373
- const direction = page2.dataset.direction || outletDirection || "forward";
1398
+ const explicitDirection = page2.dataset.direction || outletDirection;
1399
+ const direction = this.resolveNavigationDirection(explicitDirection);
1374
1400
  if (outletDirection) {
1375
1401
  delete this.dataset.direction;
1376
1402
  }
@@ -1485,7 +1511,7 @@ var CapRouterOutlet = class extends HTMLElement {
1485
1511
  * Check if we can go back
1486
1512
  */
1487
1513
  get canGoBack() {
1488
- return this.controller.stack.length > 1 && this.swipeBackDepth > 0;
1514
+ return this.getSwipeBackDestination() !== null;
1489
1515
  }
1490
1516
  /**
1491
1517
  * Get whether edge swipe-back gesture is enabled.
@@ -1577,30 +1603,132 @@ var CapRouterOutlet = class extends HTMLElement {
1577
1603
  getCurrentNavigationHref() {
1578
1604
  return this.ownerDocument.defaultView?.location.href ?? null;
1579
1605
  }
1606
+ getCurrentNavigationPosition() {
1607
+ const win = this.ownerDocument.defaultView;
1608
+ if (!win) {
1609
+ return null;
1610
+ }
1611
+ const navigationIndex = win.navigation?.currentEntry?.index;
1612
+ if (typeof navigationIndex === "number" && Number.isFinite(navigationIndex)) {
1613
+ return navigationIndex;
1614
+ }
1615
+ const state = win.history.state;
1616
+ for (const key of ["idx", "position", "index"]) {
1617
+ const value = state?.[key];
1618
+ if (typeof value === "number" && Number.isFinite(value)) {
1619
+ return value;
1620
+ }
1621
+ }
1622
+ return null;
1623
+ }
1624
+ resolveNavigationDirection(explicitDirection) {
1625
+ if (explicitDirection) {
1626
+ this.pendingHistoryDirection = null;
1627
+ return explicitDirection;
1628
+ }
1629
+ const currentHref = this.getCurrentNavigationHref();
1630
+ const existingHrefIndex = this.findNavigationHrefIndex(currentHref, this.navigationHrefs.length - 2);
1631
+ if (existingHrefIndex !== -1) {
1632
+ this.pendingHistoryDirection = null;
1633
+ return "back";
1634
+ }
1635
+ if (currentHref !== null && currentHref === this.lastNavigationHref) {
1636
+ this.pendingHistoryDirection = null;
1637
+ return "none";
1638
+ }
1639
+ if (this.pendingHistoryDirection) {
1640
+ const direction = this.pendingHistoryDirection;
1641
+ this.pendingHistoryDirection = null;
1642
+ return direction;
1643
+ }
1644
+ const currentPosition = this.getCurrentNavigationPosition();
1645
+ if (currentPosition !== null && this.lastNavigationPosition !== null) {
1646
+ if (currentPosition < this.lastNavigationPosition) {
1647
+ return "back";
1648
+ }
1649
+ if (currentPosition === this.lastNavigationPosition) {
1650
+ return "none";
1651
+ }
1652
+ }
1653
+ return "forward";
1654
+ }
1580
1655
  recordCompletedNavigation(direction, options) {
1581
1656
  const currentHref = this.getCurrentNavigationHref();
1657
+ const currentPosition = this.getCurrentNavigationPosition();
1582
1658
  if (!options.hadPageBefore || direction === "root") {
1583
- this.swipeBackDepth = 0;
1584
- this.lastNavigationHref = currentHref;
1659
+ this.resetNavigationDepth(currentHref, currentPosition);
1585
1660
  return;
1586
1661
  }
1587
1662
  if (direction === "back") {
1588
- this.swipeBackDepth = Math.max(0, this.swipeBackDepth - 1);
1663
+ this.recordBackNavigation(currentHref);
1664
+ this.lastNavigationPosition = currentPosition;
1665
+ return;
1666
+ }
1667
+ if (direction === "none") {
1668
+ if (this.navigationHrefs.length === 0) {
1669
+ this.navigationHrefs = [currentHref];
1670
+ } else {
1671
+ this.navigationHrefs[this.navigationHrefs.length - 1] = currentHref;
1672
+ }
1673
+ this.syncSwipeBackDepth();
1589
1674
  this.lastNavigationHref = currentHref;
1675
+ this.lastNavigationPosition = currentPosition;
1590
1676
  return;
1591
1677
  }
1592
- if (direction === "forward" || direction === "none") {
1678
+ if (direction === "forward") {
1593
1679
  const hrefChanged = currentHref === null || this.lastNavigationHref === null || currentHref !== this.lastNavigationHref;
1594
1680
  if (options.forceForward || hrefChanged) {
1595
- this.swipeBackDepth += 1;
1681
+ this.navigationHrefs.push(currentHref);
1682
+ } else if (this.navigationHrefs.length === 0) {
1683
+ this.navigationHrefs = [currentHref];
1596
1684
  }
1685
+ this.syncSwipeBackDepth();
1597
1686
  this.lastNavigationHref = currentHref;
1687
+ this.lastNavigationPosition = currentPosition;
1598
1688
  return;
1599
1689
  }
1600
1690
  this.lastNavigationHref = currentHref;
1691
+ this.lastNavigationPosition = currentPosition;
1692
+ }
1693
+ resetNavigationDepth(currentHref, currentPosition) {
1694
+ this.navigationHrefs = [currentHref];
1695
+ this.swipeBackDepth = 0;
1696
+ this.lastNavigationHref = currentHref;
1697
+ this.lastNavigationPosition = currentPosition;
1698
+ }
1699
+ recordBackNavigation(currentHref) {
1700
+ const existingHrefIndex = this.findNavigationHrefIndex(currentHref, this.navigationHrefs.length - 2);
1701
+ if (existingHrefIndex !== -1) {
1702
+ this.navigationHrefs = this.navigationHrefs.slice(0, existingHrefIndex + 1);
1703
+ } else if (this.navigationHrefs.length > 1) {
1704
+ this.navigationHrefs.pop();
1705
+ this.navigationHrefs[this.navigationHrefs.length - 1] = currentHref;
1706
+ } else {
1707
+ this.navigationHrefs = [currentHref];
1708
+ }
1709
+ this.syncSwipeBackDepth();
1710
+ this.lastNavigationHref = currentHref;
1711
+ }
1712
+ findNavigationHrefIndex(href, fromIndex) {
1713
+ for (let index = Math.min(fromIndex, this.navigationHrefs.length - 1); index >= 0; index -= 1) {
1714
+ if (this.navigationHrefs[index] === href) {
1715
+ return index;
1716
+ }
1717
+ }
1718
+ return -1;
1719
+ }
1720
+ syncSwipeBackDepth() {
1721
+ this.swipeBackDepth = Math.max(0, this.navigationHrefs.length - 1);
1722
+ }
1723
+ getSwipeBackDestination() {
1724
+ const stack = this.controller.stack;
1725
+ if (this.swipeBackDepth <= 0 || stack.length <= 1) {
1726
+ return null;
1727
+ }
1728
+ return stack[stack.length - 2] ?? null;
1601
1729
  }
1602
1730
  canStartSwipeGesture(event) {
1603
- if (!this.isSwipeGestureEnabled() || this.controller.animating || this.pendingPage || !this.canGoBack) {
1731
+ if (!this.isSwipeGestureEnabled() || this.controller.animating || this.pendingPage || !this.getSwipeBackDestination()) {
1604
1732
  return false;
1605
1733
  }
1606
1734
  if (!event.isPrimary || event.pointerType === "mouse" && event.button !== 0) {
@@ -1687,6 +1815,10 @@ var CapRouterOutlet = class extends HTMLElement {
1687
1815
  return;
1688
1816
  }
1689
1817
  if (!pointer.dragging && deltaX > this.swipeGestureThreshold && absX > absY) {
1818
+ if (!this.getSwipeBackDestination()) {
1819
+ this.cancelSwipeGesturePointer(event.pointerId);
1820
+ return;
1821
+ }
1690
1822
  pointer.dragging = true;
1691
1823
  pointer.transitionStarted = this.controller.beginInteractiveBack({ direction: "back" });
1692
1824
  if (!pointer.transitionStarted) {
@@ -1695,6 +1827,10 @@ var CapRouterOutlet = class extends HTMLElement {
1695
1827
  }
1696
1828
  }
1697
1829
  if (pointer.dragging && pointer.transitionStarted) {
1830
+ if (!this.getSwipeBackDestination()) {
1831
+ this.cancelSwipeGesture(event.pointerId);
1832
+ return;
1833
+ }
1698
1834
  if (event.cancelable) event.preventDefault();
1699
1835
  const width = Math.max(this.getBoundingClientRect().width, 1);
1700
1836
  this.controller.stepInteractiveBack(deltaX / width);
@@ -1746,9 +1882,10 @@ var CapRouterOutlet = class extends HTMLElement {
1746
1882
  }
1747
1883
  }
1748
1884
  async finishSwipeGestureBack(shouldComplete, releaseDuration) {
1749
- const shouldUseHistory = shouldComplete && typeof window !== "undefined" && window.history.length > 1;
1750
- await this.controller.endInteractiveBack(shouldComplete, releaseDuration, !shouldUseHistory);
1751
- if (!shouldComplete) {
1885
+ const canComplete = shouldComplete && this.getSwipeBackDestination() !== null;
1886
+ const shouldUseHistory = canComplete && typeof window !== "undefined" && window.history.length > 1;
1887
+ await this.controller.endInteractiveBack(canComplete, canComplete ? releaseDuration : 0, !shouldUseHistory);
1888
+ if (!canComplete) {
1752
1889
  return;
1753
1890
  }
1754
1891
  if (shouldUseHistory) {