@ionic/react-router 8.7.12-dev.11765377112.16762e5b → 8.7.12-dev.11765390930.11e7051a
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 +131 -68
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -13,13 +13,10 @@ const IonRouteInner = ({ path, element }) => {
|
|
|
13
13
|
* @see https://reactrouter.com/v6/utils/match-path
|
|
14
14
|
*/
|
|
15
15
|
const matchPath = ({ pathname, componentProps }) => {
|
|
16
|
+
var _a, _b;
|
|
16
17
|
const { path, index } = componentProps, restProps = __rest(componentProps, ["path", "index"]);
|
|
17
|
-
// Handle index routes
|
|
18
|
+
// Handle index routes - they match when pathname is empty or just "/"
|
|
18
19
|
if (index && !path) {
|
|
19
|
-
// Index routes match when there's no additional path after the parent route
|
|
20
|
-
// For example, in a nested outlet at /routing/*, the index route matches
|
|
21
|
-
// when the relative path is empty (i.e., we're exactly at /routing)
|
|
22
|
-
// If pathname is empty or just "/", it should match the index route
|
|
23
20
|
if (pathname === '' || pathname === '/') {
|
|
24
21
|
return {
|
|
25
22
|
params: {},
|
|
@@ -32,14 +29,25 @@ const matchPath = ({ pathname, componentProps }) => {
|
|
|
32
29
|
},
|
|
33
30
|
};
|
|
34
31
|
}
|
|
35
|
-
// Otherwise, index routes don't match when there's additional path
|
|
36
32
|
return null;
|
|
37
33
|
}
|
|
38
|
-
|
|
34
|
+
// Handle empty path routes - they match when pathname is also empty or just "/"
|
|
35
|
+
if (path === '' || path === undefined) {
|
|
36
|
+
if (pathname === '' || pathname === '/') {
|
|
37
|
+
return {
|
|
38
|
+
params: {},
|
|
39
|
+
pathname: pathname,
|
|
40
|
+
pathnameBase: pathname || '/',
|
|
41
|
+
pattern: {
|
|
42
|
+
path: '',
|
|
43
|
+
caseSensitive: (_a = restProps.caseSensitive) !== null && _a !== void 0 ? _a : false,
|
|
44
|
+
end: (_b = restProps.end) !== null && _b !== void 0 ? _b : true,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
39
48
|
return null;
|
|
40
49
|
}
|
|
41
|
-
// For relative paths
|
|
42
|
-
// use React Router's matcher against a normalized path.
|
|
50
|
+
// For relative paths (don't start with '/'), normalize both path and pathname for matching
|
|
43
51
|
if (!path.startsWith('/')) {
|
|
44
52
|
const matchOptions = Object.assign({ path: `/${path}` }, restProps);
|
|
45
53
|
if ((matchOptions === null || matchOptions === void 0 ? void 0 : matchOptions.end) === undefined) {
|
|
@@ -51,7 +59,6 @@ const matchPath = ({ pathname, componentProps }) => {
|
|
|
51
59
|
// Adjust the match to remove the leading '/' we added
|
|
52
60
|
return Object.assign(Object.assign({}, match), { pathname: pathname, pathnameBase: match.pathnameBase === '/' ? '' : match.pathnameBase.slice(1), pattern: Object.assign(Object.assign({}, match.pattern), { path: path }) });
|
|
53
61
|
}
|
|
54
|
-
// No match found
|
|
55
62
|
return null;
|
|
56
63
|
}
|
|
57
64
|
// For absolute paths, use React Router's matcher directly.
|
|
@@ -71,12 +78,16 @@ const matchPath = ({ pathname, componentProps }) => {
|
|
|
71
78
|
*/
|
|
72
79
|
const derivePathnameToMatch = (fullPathname, routePath) => {
|
|
73
80
|
var _a;
|
|
81
|
+
// For absolute or empty routes, use the full pathname as-is
|
|
74
82
|
if (!routePath || routePath === '' || routePath.startsWith('/')) {
|
|
75
83
|
return fullPathname;
|
|
76
84
|
}
|
|
77
85
|
const trimmedPath = fullPathname.startsWith('/') ? fullPathname.slice(1) : fullPathname;
|
|
78
86
|
if (!trimmedPath) {
|
|
79
|
-
|
|
87
|
+
// For root-level relative routes (pathname is "/" and routePath is relative),
|
|
88
|
+
// return the full pathname so matchPath can normalize both.
|
|
89
|
+
// This allows routes like <Route path="foo/*" .../> at root level to work correctly.
|
|
90
|
+
return fullPathname;
|
|
80
91
|
}
|
|
81
92
|
const fullSegments = trimmedPath.split('/').filter(Boolean);
|
|
82
93
|
if (fullSegments.length === 0) {
|
|
@@ -740,27 +751,36 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
740
751
|
const combinedParams = Object.assign(Object.assign({}, accumulatedParentParams), ((_c = routeMatch === null || routeMatch === void 0 ? void 0 : routeMatch.params) !== null && _c !== void 0 ? _c : {}));
|
|
741
752
|
// For relative route paths, we need to compute an absolute pathnameBase
|
|
742
753
|
// by combining the parent's pathnameBase with the matched portion
|
|
743
|
-
let absolutePathnameBase = (routeMatch === null || routeMatch === void 0 ? void 0 : routeMatch.pathnameBase) || routeInfo.pathname;
|
|
744
754
|
const routePath = routeElement.props.path;
|
|
745
755
|
const isRelativePath = routePath && !routePath.startsWith('/');
|
|
746
756
|
const isIndexRoute = !!routeElement.props.index;
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
757
|
+
const isSplatOnlyRoute = routePath === '*' || routePath === '/*';
|
|
758
|
+
// Get parent's pathnameBase for relative path resolution
|
|
759
|
+
const parentPathnameBase = parentMatches.length > 0 ? parentMatches[parentMatches.length - 1].pathnameBase : '/';
|
|
760
|
+
// Start with the match's pathnameBase, falling back to routeInfo.pathname
|
|
761
|
+
// BUT: splat-only routes should use parent's base (v7_relativeSplatPath behavior)
|
|
762
|
+
let absolutePathnameBase;
|
|
763
|
+
if (isSplatOnlyRoute) {
|
|
764
|
+
// Splat routes should NOT contribute their matched portion to pathnameBase
|
|
765
|
+
// This aligns with React Router v7's v7_relativeSplatPath behavior
|
|
766
|
+
// Without this, relative links inside splat routes get double path segments
|
|
767
|
+
absolutePathnameBase = parentPathnameBase;
|
|
768
|
+
}
|
|
769
|
+
else if (isRelativePath && (routeMatch === null || routeMatch === void 0 ? void 0 : routeMatch.pathnameBase)) {
|
|
770
|
+
// For relative paths with a pathnameBase, combine with parent
|
|
771
|
+
const relativeBase = routeMatch.pathnameBase.startsWith('/')
|
|
772
|
+
? routeMatch.pathnameBase.slice(1)
|
|
773
|
+
: routeMatch.pathnameBase;
|
|
774
|
+
absolutePathnameBase =
|
|
775
|
+
parentPathnameBase === '/' ? `/${relativeBase}` : `${parentPathnameBase}/${relativeBase}`;
|
|
776
|
+
}
|
|
777
|
+
else if (isIndexRoute) {
|
|
778
|
+
// Index routes should use the parent's base as their base
|
|
779
|
+
absolutePathnameBase = parentPathnameBase;
|
|
780
|
+
}
|
|
781
|
+
else {
|
|
782
|
+
// Default: use the match's pathnameBase or the current pathname
|
|
783
|
+
absolutePathnameBase = (routeMatch === null || routeMatch === void 0 ? void 0 : routeMatch.pathnameBase) || routeInfo.pathname;
|
|
764
784
|
}
|
|
765
785
|
const contextMatches = [
|
|
766
786
|
...parentMatches,
|
|
@@ -804,7 +824,9 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
804
824
|
let parentPath = undefined;
|
|
805
825
|
try {
|
|
806
826
|
// Only attempt parent path computation for non-root outlets
|
|
807
|
-
|
|
827
|
+
// Root outlets have IDs like 'routerOutlet' or 'routerOutlet-2'
|
|
828
|
+
const isRootOutlet = outletId.startsWith('routerOutlet');
|
|
829
|
+
if (!isRootOutlet) {
|
|
808
830
|
const routeChildren = extractRouteChildren(ionRouterOutlet.props.children);
|
|
809
831
|
const { hasRelativeRoutes, hasIndexRoute, hasWildcardRoute } = analyzeRouteChildren(routeChildren);
|
|
810
832
|
if (hasRelativeRoutes || hasIndexRoute) {
|
|
@@ -1046,7 +1068,7 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
1046
1068
|
* Matches a view with no path prop (default fallback route) or index route.
|
|
1047
1069
|
*/
|
|
1048
1070
|
function matchDefaultRoute(v) {
|
|
1049
|
-
var _a;
|
|
1071
|
+
var _a, _b, _c;
|
|
1050
1072
|
const childProps = v.routeData.childProps;
|
|
1051
1073
|
const isDefaultRoute = childProps.path === undefined || childProps.path === '';
|
|
1052
1074
|
const isIndexRoute = !!childProps.index;
|
|
@@ -1059,14 +1081,22 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
1059
1081
|
}
|
|
1060
1082
|
return false;
|
|
1061
1083
|
}
|
|
1084
|
+
// For empty path routes, only match if we're at the same level as when the view was created.
|
|
1085
|
+
// This prevents an empty path view item from being reused for different routes.
|
|
1062
1086
|
if (isDefaultRoute) {
|
|
1087
|
+
const previousPathnameBase = ((_b = (_a = v.routeData) === null || _a === void 0 ? void 0 : _a.match) === null || _b === void 0 ? void 0 : _b.pathnameBase) || '';
|
|
1088
|
+
const normalizedBase = normalizePathnameForComparison(previousPathnameBase);
|
|
1089
|
+
const normalizedPathname = normalizePathnameForComparison(pathname);
|
|
1090
|
+
if (normalizedPathname !== normalizedBase) {
|
|
1091
|
+
return false;
|
|
1092
|
+
}
|
|
1063
1093
|
match = {
|
|
1064
1094
|
params: {},
|
|
1065
1095
|
pathname,
|
|
1066
1096
|
pathnameBase: pathname === '' ? '/' : pathname,
|
|
1067
1097
|
pattern: {
|
|
1068
1098
|
path: '',
|
|
1069
|
-
caseSensitive: (
|
|
1099
|
+
caseSensitive: (_c = childProps.caseSensitive) !== null && _c !== void 0 ? _c : false,
|
|
1070
1100
|
end: true,
|
|
1071
1101
|
},
|
|
1072
1102
|
};
|
|
@@ -1191,24 +1221,30 @@ class StackManager extends React.PureComponent {
|
|
|
1191
1221
|
if (this.outletMountPath && !currentPathname.startsWith(this.outletMountPath)) {
|
|
1192
1222
|
return undefined;
|
|
1193
1223
|
}
|
|
1194
|
-
//
|
|
1195
|
-
|
|
1196
|
-
if (this.id !== 'routerOutlet' && this.ionRouterOutlet) {
|
|
1224
|
+
// Check if this outlet has route children to analyze
|
|
1225
|
+
if (this.ionRouterOutlet) {
|
|
1197
1226
|
const routeChildren = extractRouteChildren(this.ionRouterOutlet.props.children);
|
|
1198
1227
|
const { hasRelativeRoutes, hasIndexRoute, hasWildcardRoute } = analyzeRouteChildren(routeChildren);
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1228
|
+
// Root outlets have IDs like 'routerOutlet' or 'routerOutlet-2'
|
|
1229
|
+
// But even outlets with auto-generated IDs may need parent path computation
|
|
1230
|
+
// if they have relative routes (indicating they're nested outlets)
|
|
1231
|
+
const isRootOutlet = this.id.startsWith('routerOutlet');
|
|
1232
|
+
const needsParentPath = !isRootOutlet || hasRelativeRoutes || hasIndexRoute;
|
|
1233
|
+
if (needsParentPath) {
|
|
1234
|
+
const result = computeParentPath({
|
|
1235
|
+
currentPathname,
|
|
1236
|
+
outletMountPath: this.outletMountPath,
|
|
1237
|
+
routeChildren,
|
|
1238
|
+
hasRelativeRoutes,
|
|
1239
|
+
hasIndexRoute,
|
|
1240
|
+
hasWildcardRoute,
|
|
1241
|
+
});
|
|
1242
|
+
// Update the outlet mount path if it was set
|
|
1243
|
+
if (result.outletMountPath && !this.outletMountPath) {
|
|
1244
|
+
this.outletMountPath = result.outletMountPath;
|
|
1245
|
+
}
|
|
1246
|
+
return result.parentPath;
|
|
1210
1247
|
}
|
|
1211
|
-
return result.parentPath;
|
|
1212
1248
|
}
|
|
1213
1249
|
return this.outletMountPath;
|
|
1214
1250
|
}
|
|
@@ -1297,7 +1333,9 @@ class StackManager extends React.PureComponent {
|
|
|
1297
1333
|
*/
|
|
1298
1334
|
handleOutOfContextNestedOutlet(parentPath, leavingViewItem) {
|
|
1299
1335
|
var _a;
|
|
1300
|
-
|
|
1336
|
+
// Root outlets have IDs like 'routerOutlet' or 'routerOutlet-2'
|
|
1337
|
+
const isRootOutlet = this.id.startsWith('routerOutlet');
|
|
1338
|
+
if (isRootOutlet || parentPath !== undefined || !this.ionRouterOutlet) {
|
|
1301
1339
|
return false;
|
|
1302
1340
|
}
|
|
1303
1341
|
const routesChildren = (_a = getRoutesChildren(this.ionRouterOutlet.props.children)) !== null && _a !== void 0 ? _a : this.ionRouterOutlet.props.children;
|
|
@@ -1322,7 +1360,9 @@ class StackManager extends React.PureComponent {
|
|
|
1322
1360
|
* Returns true if the transition should be aborted.
|
|
1323
1361
|
*/
|
|
1324
1362
|
handleNoMatchingRoute(enteringRoute, enteringViewItem, leavingViewItem) {
|
|
1325
|
-
|
|
1363
|
+
// Root outlets have IDs like 'routerOutlet' or 'routerOutlet-2'
|
|
1364
|
+
const isRootOutlet = this.id.startsWith('routerOutlet');
|
|
1365
|
+
if (isRootOutlet || enteringRoute || enteringViewItem) {
|
|
1326
1366
|
return false;
|
|
1327
1367
|
}
|
|
1328
1368
|
// Hide any visible views in this outlet since it has no matching route
|
|
@@ -1869,27 +1909,59 @@ function findRouteByRouteInfo(node, routeInfo, parentPath) {
|
|
|
1869
1909
|
});
|
|
1870
1910
|
// For nested routes in React Router 6, we need to extract the relative path
|
|
1871
1911
|
// that this outlet should be responsible for matching
|
|
1872
|
-
|
|
1912
|
+
const originalPathname = routeInfo.pathname;
|
|
1913
|
+
let relativePathnameToMatch = routeInfo.pathname;
|
|
1873
1914
|
// Check if we have relative routes (routes that don't start with '/')
|
|
1874
1915
|
const hasRelativeRoutes = sortedRoutes.some((r) => r.props.path && !r.props.path.startsWith('/'));
|
|
1875
1916
|
const hasIndexRoute = sortedRoutes.some((r) => r.props.index);
|
|
1876
1917
|
// SIMPLIFIED: Trust React Router 6's matching more, compute relative path when parent is known
|
|
1877
1918
|
if ((hasRelativeRoutes || hasIndexRoute) && parentPath) {
|
|
1878
1919
|
const parentPrefix = parentPath.replace('/*', '');
|
|
1879
|
-
|
|
1920
|
+
// Normalize both paths to start with '/' for consistent comparison
|
|
1921
|
+
const normalizedParent = stripTrailingSlash(parentPrefix.startsWith('/') ? parentPrefix : `/${parentPrefix}`);
|
|
1880
1922
|
const normalizedPathname = stripTrailingSlash(routeInfo.pathname);
|
|
1881
1923
|
// Only compute relative path if pathname is within parent scope
|
|
1882
1924
|
if (normalizedPathname.startsWith(normalizedParent + '/') || normalizedPathname === normalizedParent) {
|
|
1883
1925
|
const pathSegments = routeInfo.pathname.split('/').filter(Boolean);
|
|
1884
1926
|
const parentSegments = normalizedParent.split('/').filter(Boolean);
|
|
1885
1927
|
const relativeSegments = pathSegments.slice(parentSegments.length);
|
|
1886
|
-
|
|
1928
|
+
relativePathnameToMatch = relativeSegments.join('/'); // Empty string is valid for index routes
|
|
1887
1929
|
}
|
|
1888
1930
|
}
|
|
1889
1931
|
// Find the first matching route
|
|
1890
1932
|
for (const child of sortedRoutes) {
|
|
1933
|
+
const childPath = child.props.path;
|
|
1934
|
+
const isAbsoluteRoute = childPath && childPath.startsWith('/');
|
|
1935
|
+
// Determine which pathname to match against:
|
|
1936
|
+
// - For absolute routes: use the original full pathname
|
|
1937
|
+
// - For relative routes with a parent: use the computed relative pathname
|
|
1938
|
+
// - For relative routes at root level (no parent): use the original pathname
|
|
1939
|
+
// (matchPath will handle the relative-to-absolute normalization)
|
|
1940
|
+
const pathnameToMatch = isAbsoluteRoute ? originalPathname : relativePathnameToMatch;
|
|
1941
|
+
// Determine the path portion to match:
|
|
1942
|
+
// - For absolute routes: use derivePathnameToMatch
|
|
1943
|
+
// - For relative routes at root level (no parent): use original pathname
|
|
1944
|
+
// directly since matchPath normalizes both path and pathname
|
|
1945
|
+
// - For relative routes with parent: use derivePathnameToMatch for wildcards,
|
|
1946
|
+
// or the computed relative pathname for non-wildcards
|
|
1947
|
+
let pathForMatch;
|
|
1948
|
+
if (isAbsoluteRoute) {
|
|
1949
|
+
pathForMatch = derivePathnameToMatch(pathnameToMatch, childPath);
|
|
1950
|
+
}
|
|
1951
|
+
else if (!parentPath && childPath) {
|
|
1952
|
+
// Root-level relative route: use the full pathname and let matchPath
|
|
1953
|
+
// handle the normalization (it adds '/' to both path and pathname)
|
|
1954
|
+
pathForMatch = originalPathname;
|
|
1955
|
+
}
|
|
1956
|
+
else if (childPath && childPath.includes('*')) {
|
|
1957
|
+
// Relative wildcard route with parent path: use derivePathnameToMatch
|
|
1958
|
+
pathForMatch = derivePathnameToMatch(pathnameToMatch, childPath);
|
|
1959
|
+
}
|
|
1960
|
+
else {
|
|
1961
|
+
pathForMatch = pathnameToMatch;
|
|
1962
|
+
}
|
|
1891
1963
|
const match = matchPath({
|
|
1892
|
-
pathname:
|
|
1964
|
+
pathname: pathForMatch,
|
|
1893
1965
|
componentProps: child.props,
|
|
1894
1966
|
});
|
|
1895
1967
|
if (match) {
|
|
@@ -2147,16 +2219,10 @@ const IonRouter = ({ children, registerHistoryListener }) => {
|
|
|
2147
2219
|
* tab and use its `pushedByRoute`.
|
|
2148
2220
|
*/
|
|
2149
2221
|
const lastRoute = locationHistory.current.getCurrentRouteInfoForTab(routeInfo.tab);
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
if (routeInfo.routeDirection === 'none') {
|
|
2155
|
-
routeInfo.pushedByRoute = lastRoute === null || lastRoute === void 0 ? void 0 : lastRoute.pushedByRoute;
|
|
2156
|
-
}
|
|
2157
|
-
else {
|
|
2158
|
-
routeInfo.pushedByRoute = (_e = lastRoute === null || lastRoute === void 0 ? void 0 : lastRoute.pushedByRoute) !== null && _e !== void 0 ? _e : leavingLocationInfo.pathname;
|
|
2159
|
-
}
|
|
2222
|
+
// This helps maintain correct back stack behavior within tabs.
|
|
2223
|
+
// If this is the first time entering this tab from a different context,
|
|
2224
|
+
// use the leaving route's pathname as the pushedByRoute to maintain the back stack.
|
|
2225
|
+
routeInfo.pushedByRoute = (_e = lastRoute === null || lastRoute === void 0 ? void 0 : lastRoute.pushedByRoute) !== null && _e !== void 0 ? _e : leavingLocationInfo.pathname;
|
|
2160
2226
|
// Triggered by `history.replace()` or a `<Redirect />` component, etc.
|
|
2161
2227
|
}
|
|
2162
2228
|
else if (routeInfo.routeAction === 'replace') {
|
|
@@ -2323,14 +2389,11 @@ const IonRouter = ({ children, registerHistoryListener }) => {
|
|
|
2323
2389
|
handleNavigate(defaultHref, 'pop', 'back', routeAnimation);
|
|
2324
2390
|
}
|
|
2325
2391
|
/**
|
|
2326
|
-
* No `pushedByRoute`
|
|
2327
|
-
*
|
|
2392
|
+
* No `pushedByRoute`
|
|
2393
|
+
* e.g., initial page load
|
|
2328
2394
|
*/
|
|
2329
2395
|
}
|
|
2330
2396
|
else {
|
|
2331
|
-
if (routeInfo && routeInfo.tab) {
|
|
2332
|
-
return;
|
|
2333
|
-
}
|
|
2334
2397
|
handleNavigate(defaultHref, 'pop', 'back', routeAnimation);
|
|
2335
2398
|
}
|
|
2336
2399
|
};
|