@ionic/react-router 9.0.6-dev.11790280751.1fc334cc → 9.0.6-nightly.20260925
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.js
CHANGED
|
@@ -499,41 +499,6 @@ const compareRouteSpecificity = (a, b) => {
|
|
|
499
499
|
}
|
|
500
500
|
return 0;
|
|
501
501
|
};
|
|
502
|
-
/**
|
|
503
|
-
* True when a route matches more pathnames than its own path, so a splat, an index route,
|
|
504
|
-
* or a route with an empty or absent path. A lookup can return one of these for a pathname
|
|
505
|
-
* a more specific sibling owns, so callers must confirm ownership against React Router's
|
|
506
|
-
* ranking before reusing the view item.
|
|
507
|
-
*
|
|
508
|
-
* This is deliberately wider than the catch-all checks in ReactRouterViewStack, which each
|
|
509
|
-
* gate on a narrower shape for a different reason. Don't unify them with this helper.
|
|
510
|
-
*/
|
|
511
|
-
const isOverMatchingRoute = (route) => {
|
|
512
|
-
const { path, index } = route;
|
|
513
|
-
return !path || path.includes('*') || !!index;
|
|
514
|
-
};
|
|
515
|
-
/** True when the navigation pushed a new page forward on top of the current one. */
|
|
516
|
-
const isForwardPush = (routeInfo) => routeInfo.routeAction === 'push' && routeInfo.routeDirection === 'forward';
|
|
517
|
-
const swipeRevealed = new WeakSet();
|
|
518
|
-
/**
|
|
519
|
-
* Marks the page a swipe-back gesture has revealed. For the length of the drag that page
|
|
520
|
-
* is on screen while a more specific sibling still matches the current pathname, and the
|
|
521
|
-
* deactivation scan in `renderViewItem` would otherwise re-hide it on the next render and
|
|
522
|
-
* leave the user dragging a blank page.
|
|
523
|
-
*/
|
|
524
|
-
const markSwipeRevealed = (viewItem) => {
|
|
525
|
-
if (viewItem) {
|
|
526
|
-
swipeRevealed.add(viewItem);
|
|
527
|
-
}
|
|
528
|
-
};
|
|
529
|
-
/** Drops the mark once the gesture ends, so the view is hidden normally again. */
|
|
530
|
-
const clearSwipeRevealed = (viewItem) => {
|
|
531
|
-
if (viewItem) {
|
|
532
|
-
swipeRevealed.delete(viewItem);
|
|
533
|
-
}
|
|
534
|
-
};
|
|
535
|
-
/** True while a swipe-back gesture is showing this view. */
|
|
536
|
-
const isSwipeRevealed = (viewItem) => swipeRevealed.has(viewItem);
|
|
537
502
|
/**
|
|
538
503
|
* Sorts view items by route specificity (most specific first).
|
|
539
504
|
*
|
|
@@ -895,7 +860,7 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
895
860
|
}
|
|
896
861
|
// Deactivate wildcard (catch-all) and empty-path (default) routes when a more-specific route matches.
|
|
897
862
|
// This prevents "Not found" or fallback pages from showing alongside valid routes.
|
|
898
|
-
if (routePath === '*' || routePath === '
|
|
863
|
+
if (routePath === '*' || routePath === '') {
|
|
899
864
|
// Check if any other view in this outlet has a match for the current route
|
|
900
865
|
const outletViews = this.getViewItemsForOutlet(viewItem.outletId);
|
|
901
866
|
// When parent path context is available, compute the relative pathname once
|
|
@@ -948,15 +913,8 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
948
913
|
}
|
|
949
914
|
}
|
|
950
915
|
}
|
|
951
|
-
if (hasSpecificMatch
|
|
952
|
-
|
|
953
|
-
// Pushed over it is the page underneath, so unmounting it destroys its state and
|
|
954
|
-
// leaves nothing for back to reveal. Hiding it below covers that. A view with no
|
|
955
|
-
// ion-page was never a page in the stack and has nothing to hide, so it still
|
|
956
|
-
// unmounts.
|
|
957
|
-
if (!isForwardPush(routeInfo) || !viewItem.ionPageElement) {
|
|
958
|
-
viewItem.mount = false;
|
|
959
|
-
}
|
|
916
|
+
if (hasSpecificMatch) {
|
|
917
|
+
viewItem.mount = false;
|
|
960
918
|
if (viewItem.ionPageElement) {
|
|
961
919
|
viewItem.ionPageElement.classList.add('ion-page-hidden');
|
|
962
920
|
viewItem.ionPageElement.setAttribute('aria-hidden', 'true');
|
|
@@ -1026,11 +984,8 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
1026
984
|
parentPath = result.parentPath;
|
|
1027
985
|
// Persist the mount path for subsequent calls, mirroring StackManager.outletMountPath.
|
|
1028
986
|
// Unlike outletParentPaths (cleared when parentPath is undefined), the mount path is
|
|
1029
|
-
// intentionally sticky
|
|
1030
|
-
|
|
1031
|
-
// would scope it to whatever route was active. parentPathnameBase is undefined
|
|
1032
|
-
// exactly when the outlet has no parent matches.
|
|
1033
|
-
if (parentPathnameBase && result.outletMountPath && !this.outletMountPaths.has(outletId)) {
|
|
987
|
+
// intentionally sticky — it anchors the outlet's scope and is only removed in clear().
|
|
988
|
+
if (result.outletMountPath && !this.outletMountPaths.has(outletId)) {
|
|
1034
989
|
this.outletMountPaths.set(outletId, result.outletMountPath);
|
|
1035
990
|
}
|
|
1036
991
|
}
|
|
@@ -1480,8 +1435,6 @@ class StackManager extends React.PureComponent {
|
|
|
1480
1435
|
routerOutletElement;
|
|
1481
1436
|
prevProps;
|
|
1482
1437
|
skipTransition;
|
|
1483
|
-
/** The view item the in-flight swipe gesture revealed, so the same one gets cleared. */
|
|
1484
|
-
swipeRevealedViewItem;
|
|
1485
1438
|
stackContextValue = {
|
|
1486
1439
|
registerIonPage: this.registerIonPage.bind(this),
|
|
1487
1440
|
isInOutlet: () => true,
|
|
@@ -1573,9 +1526,7 @@ class StackManager extends React.PureComponent {
|
|
|
1573
1526
|
hasIndexRoute,
|
|
1574
1527
|
hasWildcardRoute,
|
|
1575
1528
|
});
|
|
1576
|
-
|
|
1577
|
-
// it to whatever route was active and make every other pathname look out of scope.
|
|
1578
|
-
if (!this.isRootOutlet && result.outletMountPath && !this.outletMountPath) {
|
|
1529
|
+
if (result.outletMountPath && !this.outletMountPath) {
|
|
1579
1530
|
this.outletMountPath = result.outletMountPath;
|
|
1580
1531
|
}
|
|
1581
1532
|
return result.parentPath;
|
|
@@ -1630,16 +1581,12 @@ class StackManager extends React.PureComponent {
|
|
|
1630
1581
|
return true;
|
|
1631
1582
|
}
|
|
1632
1583
|
// For non-replace actions, only unmount for back navigation
|
|
1633
|
-
|
|
1584
|
+
const isForwardPush = routeInfo.routeAction === 'push' && routeInfo.routeDirection === 'forward';
|
|
1585
|
+
if (!isForwardPush && routeInfo.routeDirection !== 'none' && enteringViewItem !== leavingViewItem) {
|
|
1634
1586
|
return true;
|
|
1635
1587
|
}
|
|
1636
1588
|
return false;
|
|
1637
1589
|
}
|
|
1638
|
-
/** Clears the reveal flag from the view item the gesture marked. */
|
|
1639
|
-
clearSwipeRevealedView() {
|
|
1640
|
-
clearSwipeRevealed(this.swipeRevealedViewItem);
|
|
1641
|
-
this.swipeRevealedViewItem = undefined;
|
|
1642
|
-
}
|
|
1643
1590
|
/**
|
|
1644
1591
|
* Handles out-of-scope outlet. Returns true if transition should be aborted.
|
|
1645
1592
|
*/
|
|
@@ -1809,9 +1756,7 @@ class StackManager extends React.PureComponent {
|
|
|
1809
1756
|
const containerBase = routePath.replace(/\/\*$/, '');
|
|
1810
1757
|
const currentInContainer = routeInfo.pathname.startsWith(containerBase + '/') || routeInfo.pathname === containerBase;
|
|
1811
1758
|
const previousInContainer = routeInfo.lastPathname.startsWith(containerBase + '/') || routeInfo.lastPathname === containerBase;
|
|
1812
|
-
|
|
1813
|
-
// pathname and the shortcut would otherwise skip every navigation in this outlet.
|
|
1814
|
-
if (containerBase !== '' && currentInContainer && previousInContainer) {
|
|
1759
|
+
if (currentInContainer && previousInContainer) {
|
|
1815
1760
|
const updatedMatch = matchComponent(enteringViewItem.reactElement, routeInfo.pathname, true, this.outletMountPath);
|
|
1816
1761
|
if (updatedMatch) {
|
|
1817
1762
|
enteringViewItem.routeData.match = updatedMatch;
|
|
@@ -2273,7 +2218,6 @@ class StackManager extends React.PureComponent {
|
|
|
2273
2218
|
}
|
|
2274
2219
|
this.waitingForIonPage = false;
|
|
2275
2220
|
this.preservedViewItems.clear();
|
|
2276
|
-
this.clearSwipeRevealedView();
|
|
2277
2221
|
// Hide all views in this outlet before clearing.
|
|
2278
2222
|
// This is critical for nested outlets - when the parent component unmounts,
|
|
2279
2223
|
// the nested outlet's componentDidUpdate won't be called, so we must hide
|
|
@@ -2305,32 +2249,13 @@ class StackManager extends React.PureComponent {
|
|
|
2305
2249
|
this.pendingPageTransition = true;
|
|
2306
2250
|
return;
|
|
2307
2251
|
}
|
|
2308
|
-
// A completed swipe keeps its reveal flag past goBack() so the deactivation scan does
|
|
2309
|
-
// not re-hide the page between the gesture ending and the URL settling. Clear it at
|
|
2310
|
-
// the start of the transition for the new pathname.
|
|
2311
|
-
this.clearSwipeRevealedView();
|
|
2312
2252
|
// Find entering and leaving view items
|
|
2313
2253
|
const viewItems = this.findViewItems(routeInfo);
|
|
2314
2254
|
let enteringViewItem = viewItems.enteringViewItem;
|
|
2315
2255
|
let leavingViewItem = viewItems.leavingViewItem;
|
|
2256
|
+
let shouldUnmountLeavingViewItem = this.shouldUnmountLeavingView(routeInfo, enteringViewItem, leavingViewItem);
|
|
2316
2257
|
// Get parent path for nested outlets
|
|
2317
2258
|
const parentPath = this.getParentPath();
|
|
2318
|
-
// Find the matching route element. This is React Router's own ranking of the outlet's
|
|
2319
|
-
// routes, so it decides which route owns the pathname.
|
|
2320
|
-
const enteringRoute = findRouteByRouteInfo(this.ionRouterOutlet?.props.children, routeInfo, parentPath);
|
|
2321
|
-
// The lookup above only matches view items that already exist, so a sibling route with
|
|
2322
|
-
// no view item yet never wins there and an over-matching route (splat, index, empty
|
|
2323
|
-
// path) comes back for pathnames it does not own. Drop it rather than reusing it,
|
|
2324
|
-
// because overwriting its reactElement below would swap its page for the winning
|
|
2325
|
-
// route's and unmount it. This has to resolve before shouldUnmountLeavingView and
|
|
2326
|
-
// handleRootNavigation, which both branch on the entering view item.
|
|
2327
|
-
if (enteringViewItem &&
|
|
2328
|
-
enteringRoute &&
|
|
2329
|
-
isOverMatchingRoute(enteringViewItem.routeData?.childProps ?? {}) &&
|
|
2330
|
-
enteringRoute.props.path !== enteringViewItem.routeData?.childProps?.path) {
|
|
2331
|
-
enteringViewItem = undefined;
|
|
2332
|
-
}
|
|
2333
|
-
let shouldUnmountLeavingViewItem = this.shouldUnmountLeavingView(routeInfo, enteringViewItem, leavingViewItem);
|
|
2334
2259
|
// Handle out-of-scope outlet (route outside mount path)
|
|
2335
2260
|
if (this.handleOutOfScopeOutlet(routeInfo)) {
|
|
2336
2261
|
return;
|
|
@@ -2350,6 +2275,8 @@ class StackManager extends React.PureComponent {
|
|
|
2350
2275
|
if (this.handleOutOfContextNestedOutlet(parentPath, leavingViewItem)) {
|
|
2351
2276
|
return;
|
|
2352
2277
|
}
|
|
2278
|
+
// Find the matching route element
|
|
2279
|
+
const enteringRoute = findRouteByRouteInfo(this.ionRouterOutlet?.props.children, routeInfo, parentPath);
|
|
2353
2280
|
// Handle nested outlet with no matching route
|
|
2354
2281
|
if (this.handleNoMatchingRoute(enteringRoute, enteringViewItem, leavingViewItem)) {
|
|
2355
2282
|
return;
|
|
@@ -2570,9 +2497,6 @@ class StackManager extends React.PureComponent {
|
|
|
2570
2497
|
return canStartSwipe;
|
|
2571
2498
|
};
|
|
2572
2499
|
const onStart = async () => {
|
|
2573
|
-
// Core only calls onEnd when a progress animation exists, so with animations off a
|
|
2574
|
-
// previous gesture can leave its mark behind. Drop any stale one before marking.
|
|
2575
|
-
this.clearSwipeRevealedView();
|
|
2576
2500
|
const { routeInfo } = this.props;
|
|
2577
2501
|
const swipeBackRouteInfo = this.getSwipeBackRouteInfo();
|
|
2578
2502
|
const enteringViewItem = this.findEnteringViewForSwipe(swipeBackRouteInfo);
|
|
@@ -2599,11 +2523,6 @@ class StackManager extends React.PureComponent {
|
|
|
2599
2523
|
revealIonPageForSwipeBack(enteringViewItem?.ionPageElement);
|
|
2600
2524
|
// When the gesture starts, kick off a transition controlled via swipe gesture
|
|
2601
2525
|
if (enteringViewItem && leavingViewItem) {
|
|
2602
|
-
// Without a leaving view there is no progress animation, and core only calls
|
|
2603
|
-
// swipeHandler.onEnd when one exists, so nothing would clear the mark until the
|
|
2604
|
-
// next transition.
|
|
2605
|
-
markSwipeRevealed(enteringViewItem);
|
|
2606
|
-
this.swipeRevealedViewItem = enteringViewItem;
|
|
2607
2526
|
await this.transitionPage(routeInfo, enteringViewItem, leavingViewItem, 'back', true);
|
|
2608
2527
|
}
|
|
2609
2528
|
debug('SwipeBackOnStart:exit', () => ({
|
|
@@ -2628,7 +2547,6 @@ class StackManager extends React.PureComponent {
|
|
|
2628
2547
|
const swipeBackRouteInfo = this.getSwipeBackRouteInfo();
|
|
2629
2548
|
const enteringViewItem = this.findEnteringViewForSwipe(swipeBackRouteInfo);
|
|
2630
2549
|
const leavingViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id, false);
|
|
2631
|
-
this.clearSwipeRevealedView();
|
|
2632
2550
|
// Don't hide if entering and leaving are the same (parameterized route edge case)
|
|
2633
2551
|
if (enteringViewItem !== leavingViewItem && enteringViewItem?.ionPageElement !== undefined) {
|
|
2634
2552
|
hideIonPageElement(enteringViewItem.ionPageElement);
|