@ionic/react-router 9.0.7-dev.11791381676.118a7a15 → 9.0.7-dev.11792524803.14f0e7d2
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 +45 -84
- package/dist/index.js.map +1 -1
- package/dist/types/ReactRouter/IonReactMemoryRouter.d.ts +1 -1
- package/dist/types/ReactRouter/IonRouter.d.ts +1 -2
- package/dist/types/ReactRouter/utils/pathMatching.d.ts +1 -1
- package/dist/types/ReactRouter/utils/transitionDefaults.d.ts +10 -0
- package/package.json +16 -9
- package/dist/types/ReactRouter/utils/areParamsEqual.d.ts +0 -9
package/dist/index.js
CHANGED
|
@@ -1,41 +1,12 @@
|
|
|
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
4
|
import { LIFECYCLE_WILL_LEAVE, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_DID_ENTER } from '@ionic/core/components';
|
|
5
|
-
import { MemoryRouter, useLocation as useLocation$1, useNavigationType as useNavigationType$1 } from 'react-router';
|
|
6
5
|
|
|
7
6
|
const IonRouteInner = ({ path, index, caseSensitive, element }) => {
|
|
8
7
|
return React.createElement(Route, { path: path, index: index, caseSensitive: caseSensitive, element: element });
|
|
9
8
|
};
|
|
10
9
|
|
|
11
|
-
/**
|
|
12
|
-
* Compares two route param objects by value, treating a missing object as empty.
|
|
13
|
-
*
|
|
14
|
-
* @param a The first params object.
|
|
15
|
-
* @param b The second params object.
|
|
16
|
-
* @returns True if both have the same keys with equal values.
|
|
17
|
-
*/
|
|
18
|
-
const areParamsEqual = (a, b) => {
|
|
19
|
-
const paramsA = a || {};
|
|
20
|
-
const paramsB = b || {};
|
|
21
|
-
const keysA = Object.keys(paramsA);
|
|
22
|
-
const keysB = Object.keys(paramsB);
|
|
23
|
-
if (keysA.length !== keysB.length) {
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
return keysA.every((key) => {
|
|
27
|
-
const valueA = paramsA[key];
|
|
28
|
-
const valueB = paramsB[key];
|
|
29
|
-
if (Array.isArray(valueA) && Array.isArray(valueB)) {
|
|
30
|
-
if (valueA.length !== valueB.length) {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
return valueA.every((entry, idx) => entry === valueB[idx]);
|
|
34
|
-
}
|
|
35
|
-
return valueA === valueB;
|
|
36
|
-
});
|
|
37
|
-
};
|
|
38
|
-
|
|
39
10
|
/**
|
|
40
11
|
* The matchPath function is used only for matching paths, not rendering components or elements.
|
|
41
12
|
* @see https://reactrouter.com/v6/utils/match-path
|
|
@@ -650,14 +621,16 @@ const getFallbackParamsFromViewItems = (allViewItems, currentOutletId, currentPa
|
|
|
650
621
|
return params;
|
|
651
622
|
};
|
|
652
623
|
/**
|
|
653
|
-
* 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>`.
|
|
654
627
|
*/
|
|
655
|
-
const buildContextMatches = (parentMatches, combinedParams,
|
|
628
|
+
const buildContextMatches = (parentMatches, combinedParams, absolutePathnameBase, viewItem, routeElement, componentElement) => {
|
|
656
629
|
return [
|
|
657
630
|
...parentMatches,
|
|
658
631
|
{
|
|
659
632
|
params: combinedParams,
|
|
660
|
-
pathname:
|
|
633
|
+
pathname: absolutePathnameBase,
|
|
661
634
|
pathnameBase: absolutePathnameBase,
|
|
662
635
|
route: {
|
|
663
636
|
id: viewItem.id,
|
|
@@ -722,42 +695,6 @@ const resolveIndexRouteMatch = (viewItem, pathname, parentPath) => {
|
|
|
722
695
|
const normalizedBase = normalizePathnameForComparison(previousMatch.pathnameBase || previousMatch.pathname || '');
|
|
723
696
|
return normalizedPathname === normalizedBase ? previousMatch : null;
|
|
724
697
|
};
|
|
725
|
-
const shallowEqual = (a, b) => {
|
|
726
|
-
const aRecord = a;
|
|
727
|
-
const bRecord = b;
|
|
728
|
-
const aKeys = Object.keys(aRecord);
|
|
729
|
-
return aKeys.length === Object.keys(bRecord).length && aKeys.every((key) => aRecord[key] === bRecord[key]);
|
|
730
|
-
};
|
|
731
|
-
const isSameMatch = (a, b) => a === b ||
|
|
732
|
-
(a.pathname === b.pathname &&
|
|
733
|
-
a.pathnameBase === b.pathnameBase &&
|
|
734
|
-
areParamsEqual(a.params, b.params) &&
|
|
735
|
-
(a.route === b.route || shallowEqual(a.route, b.route)));
|
|
736
|
-
/**
|
|
737
|
-
* The outlet rebuilds a view's RouteContext on every render, and it renders
|
|
738
|
-
* several times per navigation, so this compares by content to tell whether
|
|
739
|
-
* the view's route state actually changed.
|
|
740
|
-
*/
|
|
741
|
-
const isSameRouteContext = (a, b) => {
|
|
742
|
-
const { matches: aMatches, ...aRest } = a;
|
|
743
|
-
const { matches: bMatches, ...bRest } = b;
|
|
744
|
-
return (shallowEqual(aRest, bRest) &&
|
|
745
|
-
aMatches.length === bMatches.length &&
|
|
746
|
-
aMatches.every((match, i) => isSameMatch(match, bMatches[i])));
|
|
747
|
-
};
|
|
748
|
-
/**
|
|
749
|
-
* Provides a view's RouteContext, reusing the previous value while its content
|
|
750
|
-
* is unchanged or while `hold` is set (the view is not the one being shown), so
|
|
751
|
-
* RouteContext-only readers like useParams skip re-rendering. Kept in component
|
|
752
|
-
* state since two outlets with the same id share view items.
|
|
753
|
-
*/
|
|
754
|
-
const ViewRouteContextProvider = ({ value, hold, children }) => {
|
|
755
|
-
const [heldValue, setHeldValue] = React.useState(value);
|
|
756
|
-
if (!hold && heldValue !== value && !isSameRouteContext(heldValue, value)) {
|
|
757
|
-
setHeldValue(value);
|
|
758
|
-
}
|
|
759
|
-
return React.createElement(UNSAFE_RouteContext.Provider, { value: heldValue }, children);
|
|
760
|
-
};
|
|
761
698
|
class ReactRouterViewStack extends ViewStacks {
|
|
762
699
|
/**
|
|
763
700
|
* Stores the computed parent path for each outlet.
|
|
@@ -958,8 +895,6 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
958
895
|
viewItem.mount = true;
|
|
959
896
|
viewItem.routeData.match = match;
|
|
960
897
|
}
|
|
961
|
-
// Set when a more specific sibling owns the pathname, so this view is hidden even though it matches.
|
|
962
|
-
let hiddenBySpecificMatch = false;
|
|
963
898
|
// Deactivate wildcard (catch-all) and empty-path (default) routes when a more-specific route matches.
|
|
964
899
|
// This prevents "Not found" or fallback pages from showing alongside valid routes.
|
|
965
900
|
if (routePath === '*' || routePath === '/*' || routePath === '') {
|
|
@@ -1016,7 +951,6 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
1016
951
|
}
|
|
1017
952
|
}
|
|
1018
953
|
if (hasSpecificMatch && !isSwipeRevealed(viewItem)) {
|
|
1019
|
-
hiddenBySpecificMatch = true;
|
|
1020
954
|
// A splat can be the outlet's container page rather than a "not found" fallback.
|
|
1021
955
|
// Pushed over it is the page underneath, so unmounting it destroys its state and
|
|
1022
956
|
// leaves nothing for back to reveal. Hiding it below covers that. A view with no
|
|
@@ -1039,11 +973,6 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
1039
973
|
viewItem.routeData.match = match;
|
|
1040
974
|
}
|
|
1041
975
|
const routeMatch = shouldSkipForDifferentParam ? viewItem.routeData?.match : match || viewItem.routeData?.match;
|
|
1042
|
-
// Hold the RouteContext while the view isn't the one shown: a sibling owns the pathname, it's
|
|
1043
|
-
// parked on another param instance, or it doesn't match. A pathless default only strictly
|
|
1044
|
-
// matches at "/", so a missing match there doesn't mean it's hidden.
|
|
1045
|
-
const isPathlessDefault = !routePath && !viewItem.routeData?.childProps?.index;
|
|
1046
|
-
const holdRouteContext = hiddenBySpecificMatch || !!shouldSkipForDifferentParam || (!match && !isPathlessDefault);
|
|
1047
976
|
return (React.createElement(UNSAFE_RouteContext.Consumer, { key: `view-context-${viewItem.id}` }, (parentContext) => {
|
|
1048
977
|
const parentMatches = (parentContext?.matches ?? []);
|
|
1049
978
|
// Accumulate params from parent matches, with fallback to other outlets
|
|
@@ -1054,12 +983,12 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
1054
983
|
const combinedParams = { ...accumulatedParentParams, ...(routeMatch?.params ?? {}) };
|
|
1055
984
|
const parentPathnameBase = parentMatches.length > 0 ? parentMatches[parentMatches.length - 1].pathnameBase : '/';
|
|
1056
985
|
const absolutePathnameBase = computeAbsolutePathnameBase(routeElement, routeMatch, parentPathnameBase, routeInfo.pathname);
|
|
1057
|
-
const contextMatches = buildContextMatches(parentMatches, combinedParams,
|
|
986
|
+
const contextMatches = buildContextMatches(parentMatches, combinedParams, absolutePathnameBase, viewItem, routeElement, componentElement);
|
|
1058
987
|
const routeContextValue = parentContext
|
|
1059
988
|
? { ...parentContext, matches: contextMatches }
|
|
1060
989
|
: { outlet: null, matches: contextMatches, isDataRoute: false };
|
|
1061
990
|
return (React.createElement(ViewLifeCycleManager, { key: `view-${viewItem.id}`, mount: viewItem.mount, removeView: () => this.remove(viewItem) },
|
|
1062
|
-
React.createElement(
|
|
991
|
+
React.createElement(UNSAFE_RouteContext.Provider, { value: routeContextValue }, componentElement)));
|
|
1063
992
|
}));
|
|
1064
993
|
};
|
|
1065
994
|
/**
|
|
@@ -3178,6 +3107,26 @@ const checkIsMultiStepBack = (prevInfo, destinationPathname, history) => {
|
|
|
3178
3107
|
}
|
|
3179
3108
|
return false;
|
|
3180
3109
|
};
|
|
3110
|
+
const areParamsEqual = (a, b) => {
|
|
3111
|
+
const paramsA = a || {};
|
|
3112
|
+
const paramsB = b || {};
|
|
3113
|
+
const keysA = Object.keys(paramsA);
|
|
3114
|
+
const keysB = Object.keys(paramsB);
|
|
3115
|
+
if (keysA.length !== keysB.length) {
|
|
3116
|
+
return false;
|
|
3117
|
+
}
|
|
3118
|
+
return keysA.every((key) => {
|
|
3119
|
+
const valueA = paramsA[key];
|
|
3120
|
+
const valueB = paramsB[key];
|
|
3121
|
+
if (Array.isArray(valueA) && Array.isArray(valueB)) {
|
|
3122
|
+
if (valueA.length !== valueB.length) {
|
|
3123
|
+
return false;
|
|
3124
|
+
}
|
|
3125
|
+
return valueA.every((entry, idx) => entry === valueB[idx]);
|
|
3126
|
+
}
|
|
3127
|
+
return valueA === valueB;
|
|
3128
|
+
});
|
|
3129
|
+
};
|
|
3181
3130
|
const IonRouter = ({ children, registerHistoryListener }) => {
|
|
3182
3131
|
const location = useLocation();
|
|
3183
3132
|
const navigate = useNavigate();
|
|
@@ -3760,6 +3709,18 @@ const IonRouter = ({ children, registerHistoryListener }) => {
|
|
|
3760
3709
|
};
|
|
3761
3710
|
IonRouter.displayName = 'IonRouter';
|
|
3762
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
|
+
|
|
3763
3724
|
/**
|
|
3764
3725
|
* `IonReactRouter` facilitates the integration of Ionic's specific
|
|
3765
3726
|
* navigation and UI management with the standard React Router mechanisms,
|
|
@@ -3804,7 +3765,7 @@ const RouterContent$2 = ({ children }) => {
|
|
|
3804
3765
|
return React.createElement(IonRouter, { registerHistoryListener: registerHistoryListener }, children);
|
|
3805
3766
|
};
|
|
3806
3767
|
const IonReactRouter = ({ children, ...browserRouterProps }) => {
|
|
3807
|
-
return (React.createElement(BrowserRouter, { ...browserRouterProps },
|
|
3768
|
+
return (React.createElement(BrowserRouter, { ...withTransitionDefaults(browserRouterProps) },
|
|
3808
3769
|
React.createElement(RouterContent$2, null, children)));
|
|
3809
3770
|
};
|
|
3810
3771
|
|
|
@@ -3814,8 +3775,8 @@ const IonReactRouter = ({ children, ...browserRouterProps }) => {
|
|
|
3814
3775
|
* isn't available or desirable.
|
|
3815
3776
|
*/
|
|
3816
3777
|
const RouterContent$1 = ({ children }) => {
|
|
3817
|
-
const location = useLocation
|
|
3818
|
-
const navigationType = useNavigationType
|
|
3778
|
+
const location = useLocation();
|
|
3779
|
+
const navigationType = useNavigationType();
|
|
3819
3780
|
const historyListenHandler = useRef();
|
|
3820
3781
|
const registerHistoryListener = useCallback((cb) => {
|
|
3821
3782
|
historyListenHandler.current = cb;
|
|
@@ -3843,7 +3804,7 @@ const RouterContent$1 = ({ children }) => {
|
|
|
3843
3804
|
return React.createElement(IonRouter, { registerHistoryListener: registerHistoryListener }, children);
|
|
3844
3805
|
};
|
|
3845
3806
|
const IonReactMemoryRouter = ({ children, ...routerProps }) => {
|
|
3846
|
-
return (React.createElement(MemoryRouter, { ...routerProps },
|
|
3807
|
+
return (React.createElement(MemoryRouter, { ...withTransitionDefaults(routerProps) },
|
|
3847
3808
|
React.createElement(RouterContent$1, null, children)));
|
|
3848
3809
|
};
|
|
3849
3810
|
|
|
@@ -3881,7 +3842,7 @@ const RouterContent = ({ children }) => {
|
|
|
3881
3842
|
return React.createElement(IonRouter, { registerHistoryListener: registerHistoryListener }, children);
|
|
3882
3843
|
};
|
|
3883
3844
|
const IonReactHashRouter = ({ children, ...routerProps }) => {
|
|
3884
|
-
return (React.createElement(HashRouter, { ...routerProps },
|
|
3845
|
+
return (React.createElement(HashRouter, { ...withTransitionDefaults(routerProps) },
|
|
3885
3846
|
React.createElement(RouterContent, null, children)));
|
|
3886
3847
|
};
|
|
3887
3848
|
|