@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.
@@ -1209,9 +1209,26 @@ var CapRouterOutlet = class extends HTMLElement {
1209
1209
  skipNextHistoryBackTransition = false;
1210
1210
  swipeBackDepth = 0;
1211
1211
  lastNavigationHref = null;
1212
+ lastNavigationPosition = null;
1213
+ pendingHistoryDirection = null;
1214
+ navigationHrefs = [];
1212
1215
  swipeGestureEdgeWidth = 50;
1213
1216
  swipeGestureThreshold = 10;
1214
1217
  swipeGestureMinimumVelocity = 0.2;
1218
+ handleHistoryPopState = () => {
1219
+ const currentPosition = this.getCurrentNavigationPosition();
1220
+ if (currentPosition !== null && this.lastNavigationPosition !== null) {
1221
+ if (currentPosition < this.lastNavigationPosition) {
1222
+ this.pendingHistoryDirection = "back";
1223
+ return;
1224
+ }
1225
+ if (currentPosition > this.lastNavigationPosition) {
1226
+ this.pendingHistoryDirection = "forward";
1227
+ return;
1228
+ }
1229
+ }
1230
+ this.pendingHistoryDirection = "back";
1231
+ };
1215
1232
  static get observedAttributes() {
1216
1233
  return ["platform", "duration", "keep-in-dom", "max-cached", "swipe-gesture"];
1217
1234
  }
@@ -1231,6 +1248,8 @@ var CapRouterOutlet = class extends HTMLElement {
1231
1248
  this.style.height = "100%";
1232
1249
  this.style.overflow = "hidden";
1233
1250
  this.lastNavigationHref = this.getCurrentNavigationHref();
1251
+ this.lastNavigationPosition = this.getCurrentNavigationPosition();
1252
+ this.ownerDocument.defaultView?.addEventListener("popstate", this.handleHistoryPopState);
1234
1253
  this.observer = new MutationObserver((mutations) => {
1235
1254
  this.handleMutations(mutations);
1236
1255
  });
@@ -1246,10 +1265,14 @@ var CapRouterOutlet = class extends HTMLElement {
1246
1265
  }
1247
1266
  disconnectedCallback() {
1248
1267
  this.observer?.disconnect();
1268
+ this.ownerDocument.defaultView?.removeEventListener("popstate", this.handleHistoryPopState);
1249
1269
  this.removeSwipeGestureListeners();
1250
1270
  this.controller.clear();
1251
1271
  this.swipeBackDepth = 0;
1252
1272
  this.lastNavigationHref = null;
1273
+ this.lastNavigationPosition = null;
1274
+ this.pendingHistoryDirection = null;
1275
+ this.navigationHrefs = [];
1253
1276
  }
1254
1277
  attributeChangedCallback(name, _oldValue, newValue) {
1255
1278
  switch (name) {
@@ -1330,13 +1353,16 @@ var CapRouterOutlet = class extends HTMLElement {
1330
1353
  this.controller.pageStack.push(state);
1331
1354
  this.swipeBackDepth = 0;
1332
1355
  this.lastNavigationHref = this.getCurrentNavigationHref();
1356
+ this.lastNavigationPosition = this.getCurrentNavigationPosition();
1357
+ this.navigationHrefs = [this.lastNavigationHref];
1333
1358
  }
1334
1359
  /**
1335
1360
  * Handle a new page being added
1336
1361
  */
1337
1362
  async handleNewPage(page) {
1338
1363
  const outletDirection = this.dataset.direction;
1339
- const direction = page.dataset.direction || outletDirection || "forward";
1364
+ const explicitDirection = page.dataset.direction || outletDirection;
1365
+ const direction = this.resolveNavigationDirection(explicitDirection);
1340
1366
  if (outletDirection) {
1341
1367
  delete this.dataset.direction;
1342
1368
  }
@@ -1451,7 +1477,7 @@ var CapRouterOutlet = class extends HTMLElement {
1451
1477
  * Check if we can go back
1452
1478
  */
1453
1479
  get canGoBack() {
1454
- return this.controller.stack.length > 1 && this.swipeBackDepth > 0;
1480
+ return this.getSwipeBackDestination() !== null;
1455
1481
  }
1456
1482
  /**
1457
1483
  * Get whether edge swipe-back gesture is enabled.
@@ -1543,30 +1569,132 @@ var CapRouterOutlet = class extends HTMLElement {
1543
1569
  getCurrentNavigationHref() {
1544
1570
  return this.ownerDocument.defaultView?.location.href ?? null;
1545
1571
  }
1572
+ getCurrentNavigationPosition() {
1573
+ const win = this.ownerDocument.defaultView;
1574
+ if (!win) {
1575
+ return null;
1576
+ }
1577
+ const navigationIndex = win.navigation?.currentEntry?.index;
1578
+ if (typeof navigationIndex === "number" && Number.isFinite(navigationIndex)) {
1579
+ return navigationIndex;
1580
+ }
1581
+ const state = win.history.state;
1582
+ for (const key of ["idx", "position", "index"]) {
1583
+ const value = state?.[key];
1584
+ if (typeof value === "number" && Number.isFinite(value)) {
1585
+ return value;
1586
+ }
1587
+ }
1588
+ return null;
1589
+ }
1590
+ resolveNavigationDirection(explicitDirection) {
1591
+ if (explicitDirection) {
1592
+ this.pendingHistoryDirection = null;
1593
+ return explicitDirection;
1594
+ }
1595
+ const currentHref = this.getCurrentNavigationHref();
1596
+ const existingHrefIndex = this.findNavigationHrefIndex(currentHref, this.navigationHrefs.length - 2);
1597
+ if (existingHrefIndex !== -1) {
1598
+ this.pendingHistoryDirection = null;
1599
+ return "back";
1600
+ }
1601
+ if (currentHref !== null && currentHref === this.lastNavigationHref) {
1602
+ this.pendingHistoryDirection = null;
1603
+ return "none";
1604
+ }
1605
+ if (this.pendingHistoryDirection) {
1606
+ const direction = this.pendingHistoryDirection;
1607
+ this.pendingHistoryDirection = null;
1608
+ return direction;
1609
+ }
1610
+ const currentPosition = this.getCurrentNavigationPosition();
1611
+ if (currentPosition !== null && this.lastNavigationPosition !== null) {
1612
+ if (currentPosition < this.lastNavigationPosition) {
1613
+ return "back";
1614
+ }
1615
+ if (currentPosition === this.lastNavigationPosition) {
1616
+ return "none";
1617
+ }
1618
+ }
1619
+ return "forward";
1620
+ }
1546
1621
  recordCompletedNavigation(direction, options) {
1547
1622
  const currentHref = this.getCurrentNavigationHref();
1623
+ const currentPosition = this.getCurrentNavigationPosition();
1548
1624
  if (!options.hadPageBefore || direction === "root") {
1549
- this.swipeBackDepth = 0;
1550
- this.lastNavigationHref = currentHref;
1625
+ this.resetNavigationDepth(currentHref, currentPosition);
1551
1626
  return;
1552
1627
  }
1553
1628
  if (direction === "back") {
1554
- this.swipeBackDepth = Math.max(0, this.swipeBackDepth - 1);
1629
+ this.recordBackNavigation(currentHref);
1630
+ this.lastNavigationPosition = currentPosition;
1631
+ return;
1632
+ }
1633
+ if (direction === "none") {
1634
+ if (this.navigationHrefs.length === 0) {
1635
+ this.navigationHrefs = [currentHref];
1636
+ } else {
1637
+ this.navigationHrefs[this.navigationHrefs.length - 1] = currentHref;
1638
+ }
1639
+ this.syncSwipeBackDepth();
1555
1640
  this.lastNavigationHref = currentHref;
1641
+ this.lastNavigationPosition = currentPosition;
1556
1642
  return;
1557
1643
  }
1558
- if (direction === "forward" || direction === "none") {
1644
+ if (direction === "forward") {
1559
1645
  const hrefChanged = currentHref === null || this.lastNavigationHref === null || currentHref !== this.lastNavigationHref;
1560
1646
  if (options.forceForward || hrefChanged) {
1561
- this.swipeBackDepth += 1;
1647
+ this.navigationHrefs.push(currentHref);
1648
+ } else if (this.navigationHrefs.length === 0) {
1649
+ this.navigationHrefs = [currentHref];
1562
1650
  }
1651
+ this.syncSwipeBackDepth();
1563
1652
  this.lastNavigationHref = currentHref;
1653
+ this.lastNavigationPosition = currentPosition;
1564
1654
  return;
1565
1655
  }
1566
1656
  this.lastNavigationHref = currentHref;
1657
+ this.lastNavigationPosition = currentPosition;
1658
+ }
1659
+ resetNavigationDepth(currentHref, currentPosition) {
1660
+ this.navigationHrefs = [currentHref];
1661
+ this.swipeBackDepth = 0;
1662
+ this.lastNavigationHref = currentHref;
1663
+ this.lastNavigationPosition = currentPosition;
1664
+ }
1665
+ recordBackNavigation(currentHref) {
1666
+ const existingHrefIndex = this.findNavigationHrefIndex(currentHref, this.navigationHrefs.length - 2);
1667
+ if (existingHrefIndex !== -1) {
1668
+ this.navigationHrefs = this.navigationHrefs.slice(0, existingHrefIndex + 1);
1669
+ } else if (this.navigationHrefs.length > 1) {
1670
+ this.navigationHrefs.pop();
1671
+ this.navigationHrefs[this.navigationHrefs.length - 1] = currentHref;
1672
+ } else {
1673
+ this.navigationHrefs = [currentHref];
1674
+ }
1675
+ this.syncSwipeBackDepth();
1676
+ this.lastNavigationHref = currentHref;
1677
+ }
1678
+ findNavigationHrefIndex(href, fromIndex) {
1679
+ for (let index = Math.min(fromIndex, this.navigationHrefs.length - 1); index >= 0; index -= 1) {
1680
+ if (this.navigationHrefs[index] === href) {
1681
+ return index;
1682
+ }
1683
+ }
1684
+ return -1;
1685
+ }
1686
+ syncSwipeBackDepth() {
1687
+ this.swipeBackDepth = Math.max(0, this.navigationHrefs.length - 1);
1688
+ }
1689
+ getSwipeBackDestination() {
1690
+ const stack = this.controller.stack;
1691
+ if (this.swipeBackDepth <= 0 || stack.length <= 1) {
1692
+ return null;
1693
+ }
1694
+ return stack[stack.length - 2] ?? null;
1567
1695
  }
1568
1696
  canStartSwipeGesture(event) {
1569
- if (!this.isSwipeGestureEnabled() || this.controller.animating || this.pendingPage || !this.canGoBack) {
1697
+ if (!this.isSwipeGestureEnabled() || this.controller.animating || this.pendingPage || !this.getSwipeBackDestination()) {
1570
1698
  return false;
1571
1699
  }
1572
1700
  if (!event.isPrimary || event.pointerType === "mouse" && event.button !== 0) {
@@ -1653,6 +1781,10 @@ var CapRouterOutlet = class extends HTMLElement {
1653
1781
  return;
1654
1782
  }
1655
1783
  if (!pointer.dragging && deltaX > this.swipeGestureThreshold && absX > absY) {
1784
+ if (!this.getSwipeBackDestination()) {
1785
+ this.cancelSwipeGesturePointer(event.pointerId);
1786
+ return;
1787
+ }
1656
1788
  pointer.dragging = true;
1657
1789
  pointer.transitionStarted = this.controller.beginInteractiveBack({ direction: "back" });
1658
1790
  if (!pointer.transitionStarted) {
@@ -1661,6 +1793,10 @@ var CapRouterOutlet = class extends HTMLElement {
1661
1793
  }
1662
1794
  }
1663
1795
  if (pointer.dragging && pointer.transitionStarted) {
1796
+ if (!this.getSwipeBackDestination()) {
1797
+ this.cancelSwipeGesture(event.pointerId);
1798
+ return;
1799
+ }
1664
1800
  if (event.cancelable) event.preventDefault();
1665
1801
  const width = Math.max(this.getBoundingClientRect().width, 1);
1666
1802
  this.controller.stepInteractiveBack(deltaX / width);
@@ -1712,9 +1848,10 @@ var CapRouterOutlet = class extends HTMLElement {
1712
1848
  }
1713
1849
  }
1714
1850
  async finishSwipeGestureBack(shouldComplete, releaseDuration) {
1715
- const shouldUseHistory = shouldComplete && typeof window !== "undefined" && window.history.length > 1;
1716
- await this.controller.endInteractiveBack(shouldComplete, releaseDuration, !shouldUseHistory);
1717
- if (!shouldComplete) {
1851
+ const canComplete = shouldComplete && this.getSwipeBackDestination() !== null;
1852
+ const shouldUseHistory = canComplete && typeof window !== "undefined" && window.history.length > 1;
1853
+ await this.controller.endInteractiveBack(canComplete, canComplete ? releaseDuration : 0, !shouldUseHistory);
1854
+ if (!canComplete) {
1718
1855
  return;
1719
1856
  }
1720
1857
  if (shouldUseHistory) {