@ionic/react-router 9.0.6-nightly.20260930 → 9.0.7-dev.11790792026.1963eab3

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
@@ -1,7 +1,7 @@
1
1
  import React, { useRef, useState, useEffect, useCallback } from 'react';
2
- import { Route, matchPath as matchPath$1, Routes, Navigate, UNSAFE_RouteContext, matchRoutes, useLocation, useNavigate, BrowserRouter, useNavigationType, HashRouter } from 'react-router-dom';
2
+ import { Route, matchPath as matchPath$1, Routes, Navigate, UNSAFE_RouteContext, matchRoutes, useLocation, useNavigate, BrowserRouter, useNavigationType, MemoryRouter, HashRouter } from 'react-router-dom';
3
3
  import { IonRoute, ViewStacks, generateId, ViewLifeCycleManager, createDebugLogger, StackContext, RouteManagerContext, getConfig, LocationHistory, NavManager } from '@ionic/react';
4
- import { MemoryRouter, useLocation as useLocation$1, useNavigationType as useNavigationType$1 } from 'react-router';
4
+ import { LIFECYCLE_WILL_LEAVE, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_DID_ENTER } from '@ionic/core/components';
5
5
 
6
6
  const IonRouteInner = ({ path, index, caseSensitive, element }) => {
7
7
  return React.createElement(Route, { path: path, index: index, caseSensitive: caseSensitive, element: element });
@@ -621,14 +621,16 @@ const getFallbackParamsFromViewItems = (allViewItems, currentOutletId, currentPa
621
621
  return params;
622
622
  };
623
623
  /**
624
- * Builds the matches array for RouteContext.
624
+ * Builds the matches array for RouteContext. The leaf `pathname` uses the absolute base,
625
+ * because the raw match is relative for a route without a leading slash, which breaks
626
+ * relative links, and includes a splat's tail, which loops an index `<Navigate>`.
625
627
  */
626
- const buildContextMatches = (parentMatches, combinedParams, routeMatch, routeInfoPathname, absolutePathnameBase, viewItem, routeElement, componentElement) => {
628
+ const buildContextMatches = (parentMatches, combinedParams, absolutePathnameBase, viewItem, routeElement, componentElement) => {
627
629
  return [
628
630
  ...parentMatches,
629
631
  {
630
632
  params: combinedParams,
631
- pathname: routeMatch?.pathname || routeInfoPathname,
633
+ pathname: absolutePathnameBase,
632
634
  pathnameBase: absolutePathnameBase,
633
635
  route: {
634
636
  id: viewItem.id,
@@ -981,7 +983,7 @@ class ReactRouterViewStack extends ViewStacks {
981
983
  const combinedParams = { ...accumulatedParentParams, ...(routeMatch?.params ?? {}) };
982
984
  const parentPathnameBase = parentMatches.length > 0 ? parentMatches[parentMatches.length - 1].pathnameBase : '/';
983
985
  const absolutePathnameBase = computeAbsolutePathnameBase(routeElement, routeMatch, parentPathnameBase, routeInfo.pathname);
984
- const contextMatches = buildContextMatches(parentMatches, combinedParams, routeMatch, routeInfo.pathname, absolutePathnameBase, viewItem, routeElement, componentElement);
986
+ const contextMatches = buildContextMatches(parentMatches, combinedParams, absolutePathnameBase, viewItem, routeElement, componentElement);
985
987
  const routeContextValue = parentContext
986
988
  ? { ...parentContext, matches: contextMatches }
987
989
  : { outlet: null, matches: contextMatches, isDataRoute: false };
@@ -1452,6 +1454,12 @@ const revealIonPageForSwipeBack = (element) => {
1452
1454
  element.removeAttribute('aria-hidden');
1453
1455
  }
1454
1456
  };
1457
+ /** Dispatches a view lifecycle event the way core's `lifecycle()` does. */
1458
+ const dispatchLifecycleEvent = (element, eventName) => {
1459
+ if (element) {
1460
+ element.dispatchEvent(new CustomEvent(eventName, { bubbles: false, cancelable: false }));
1461
+ }
1462
+ };
1455
1463
  /**
1456
1464
  * A leaf view is "preservable" on browser-back (pop) when its React state
1457
1465
  * should survive a forward-pop round-trip. Non-parameterized leaf paths
@@ -1688,8 +1696,8 @@ class StackManager extends React.PureComponent {
1688
1696
  const allViewsInOutlet = this.context.getViewItemsForOutlet(this.id);
1689
1697
  allViewsInOutlet.forEach((viewItem) => {
1690
1698
  if (viewItem.ionPageElement && isViewVisible(viewItem.ionPageElement)) {
1691
- viewItem.ionPageElement.dispatchEvent(new CustomEvent('ionViewWillLeave', { bubbles: false, cancelable: false }));
1692
- viewItem.ionPageElement.dispatchEvent(new CustomEvent('ionViewDidLeave', { bubbles: false, cancelable: false }));
1699
+ dispatchLifecycleEvent(viewItem.ionPageElement, LIFECYCLE_WILL_LEAVE);
1700
+ dispatchLifecycleEvent(viewItem.ionPageElement, LIFECYCLE_DID_LEAVE);
1693
1701
  }
1694
1702
  });
1695
1703
  // Defer removal of view items to allow the parent outlet's leaving-page
@@ -1724,8 +1732,8 @@ class StackManager extends React.PureComponent {
1724
1732
  return;
1725
1733
  }
1726
1734
  if (viewItem.ionPageElement && isViewVisible(viewItem.ionPageElement)) {
1727
- viewItem.ionPageElement.dispatchEvent(new CustomEvent('ionViewWillLeave', { bubbles: false, cancelable: false }));
1728
- viewItem.ionPageElement.dispatchEvent(new CustomEvent('ionViewDidLeave', { bubbles: false, cancelable: false }));
1735
+ dispatchLifecycleEvent(viewItem.ionPageElement, LIFECYCLE_WILL_LEAVE);
1736
+ dispatchLifecycleEvent(viewItem.ionPageElement, LIFECYCLE_DID_LEAVE);
1729
1737
  }
1730
1738
  this.context.unMountViewItem(viewItem);
1731
1739
  });
@@ -2856,10 +2864,34 @@ class StackManager extends React.PureComponent {
2856
2864
  // Bail out if the component unmounted during waitForComponentsReady
2857
2865
  if (!this._isMounted)
2858
2866
  return;
2867
+ const isCurrent = myGeneration === this.transitionGeneration;
2868
+ // A page the newest transition is entering is not leaving after all.
2869
+ const isLeaving = isCurrent || leavingEl !== this.transitionEnteringElement;
2870
+ // Already hidden means the leave events have fired. This checks the class rather
2871
+ // than `isViewVisible` because a nested outlet marks its leaving page
2872
+ // `visibility: hidden` before we get here and still needs `ionViewDidLeave`.
2873
+ const announceLeaving = isLeaving && !leavingEl.classList.contains('ion-page-hidden');
2874
+ /**
2875
+ * Dispatch the lifecycle events, since we skipped `commit()`. Only the
2876
+ * newest transition fires the entering events, and the class swap follows
2877
+ * all four so the ordering matches core's `transition()`.
2878
+ *
2879
+ * These run after `waitForComponentsReady` because on a first mount the
2880
+ * page has not attached its listeners yet.
2881
+ */
2882
+ if (announceLeaving) {
2883
+ dispatchLifecycleEvent(leavingEl, LIFECYCLE_WILL_LEAVE);
2884
+ }
2885
+ if (isCurrent) {
2886
+ dispatchLifecycleEvent(enteringEl, LIFECYCLE_WILL_ENTER);
2887
+ dispatchLifecycleEvent(enteringEl, LIFECYCLE_DID_ENTER);
2888
+ }
2889
+ if (announceLeaving) {
2890
+ dispatchLifecycleEvent(leavingEl, LIFECYCLE_DID_LEAVE);
2891
+ }
2859
2892
  // Swap visibility synchronously - show entering, hide leaving
2860
- // Skip hiding if a newer transition already made leavingEl the entering view
2861
2893
  enteringEl.classList.remove('ion-page-invisible');
2862
- if (myGeneration === this.transitionGeneration || leavingEl !== this.transitionEnteringElement) {
2894
+ if (isLeaving) {
2863
2895
  leavingEl.classList.add('ion-page-hidden');
2864
2896
  leavingEl.setAttribute('aria-hidden', 'true');
2865
2897
  }
@@ -3677,6 +3709,18 @@ const IonRouter = ({ children, registerHistoryListener }) => {
3677
3709
  };
3678
3710
  IonRouter.displayName = 'IonRouter';
3679
3711
 
3712
+ /**
3713
+ * Defaults React Router 7's `useTransitions` to `false`, since a transition can defer the
3714
+ * commit past Ionic's page-visible signal. React Router 6 ignores the prop.
3715
+ *
3716
+ * Uses `??` instead of spreading a default first, because an explicit
3717
+ * `useTransitions={undefined}` would override it and React Router reads that as on.
3718
+ */
3719
+ const withTransitionDefaults = (props) => {
3720
+ const { useTransitions } = props;
3721
+ return { ...props, useTransitions: useTransitions ?? false };
3722
+ };
3723
+
3680
3724
  /**
3681
3725
  * `IonReactRouter` facilitates the integration of Ionic's specific
3682
3726
  * navigation and UI management with the standard React Router mechanisms,
@@ -3721,7 +3765,7 @@ const RouterContent$2 = ({ children }) => {
3721
3765
  return React.createElement(IonRouter, { registerHistoryListener: registerHistoryListener }, children);
3722
3766
  };
3723
3767
  const IonReactRouter = ({ children, ...browserRouterProps }) => {
3724
- return (React.createElement(BrowserRouter, { ...browserRouterProps },
3768
+ return (React.createElement(BrowserRouter, { ...withTransitionDefaults(browserRouterProps) },
3725
3769
  React.createElement(RouterContent$2, null, children)));
3726
3770
  };
3727
3771
 
@@ -3731,8 +3775,8 @@ const IonReactRouter = ({ children, ...browserRouterProps }) => {
3731
3775
  * isn't available or desirable.
3732
3776
  */
3733
3777
  const RouterContent$1 = ({ children }) => {
3734
- const location = useLocation$1();
3735
- const navigationType = useNavigationType$1();
3778
+ const location = useLocation();
3779
+ const navigationType = useNavigationType();
3736
3780
  const historyListenHandler = useRef();
3737
3781
  const registerHistoryListener = useCallback((cb) => {
3738
3782
  historyListenHandler.current = cb;
@@ -3760,7 +3804,7 @@ const RouterContent$1 = ({ children }) => {
3760
3804
  return React.createElement(IonRouter, { registerHistoryListener: registerHistoryListener }, children);
3761
3805
  };
3762
3806
  const IonReactMemoryRouter = ({ children, ...routerProps }) => {
3763
- return (React.createElement(MemoryRouter, { ...routerProps },
3807
+ return (React.createElement(MemoryRouter, { ...withTransitionDefaults(routerProps) },
3764
3808
  React.createElement(RouterContent$1, null, children)));
3765
3809
  };
3766
3810
 
@@ -3798,7 +3842,7 @@ const RouterContent = ({ children }) => {
3798
3842
  return React.createElement(IonRouter, { registerHistoryListener: registerHistoryListener }, children);
3799
3843
  };
3800
3844
  const IonReactHashRouter = ({ children, ...routerProps }) => {
3801
- return (React.createElement(HashRouter, { ...routerProps },
3845
+ return (React.createElement(HashRouter, { ...withTransitionDefaults(routerProps) },
3802
3846
  React.createElement(RouterContent, null, children)));
3803
3847
  };
3804
3848