@ionic/react-router 8.7.13-dev.11765829391.14bc580c → 8.7.13-dev.11765907916.16a61ecf
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
|
@@ -13,10 +13,13 @@ 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;
|
|
17
16
|
const { path, index } = componentProps, restProps = __rest(componentProps, ["path", "index"]);
|
|
18
|
-
// Handle index routes
|
|
17
|
+
// Handle index routes
|
|
19
18
|
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
|
|
20
23
|
if (pathname === '' || pathname === '/') {
|
|
21
24
|
return {
|
|
22
25
|
params: {},
|
|
@@ -29,25 +32,14 @@ const matchPath = ({ pathname, componentProps }) => {
|
|
|
29
32
|
},
|
|
30
33
|
};
|
|
31
34
|
}
|
|
35
|
+
// Otherwise, index routes don't match when there's additional path
|
|
32
36
|
return null;
|
|
33
37
|
}
|
|
34
|
-
|
|
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
|
-
}
|
|
38
|
+
if (!path) {
|
|
48
39
|
return null;
|
|
49
40
|
}
|
|
50
|
-
// For relative paths (don't start with '/'),
|
|
41
|
+
// For relative paths in nested routes (those that don't start with '/'),
|
|
42
|
+
// use React Router's matcher against a normalized path.
|
|
51
43
|
if (!path.startsWith('/')) {
|
|
52
44
|
const matchOptions = Object.assign({ path: `/${path}` }, restProps);
|
|
53
45
|
if ((matchOptions === null || matchOptions === void 0 ? void 0 : matchOptions.end) === undefined) {
|
|
@@ -59,6 +51,7 @@ const matchPath = ({ pathname, componentProps }) => {
|
|
|
59
51
|
// Adjust the match to remove the leading '/' we added
|
|
60
52
|
return Object.assign(Object.assign({}, match), { pathname: pathname, pathnameBase: match.pathnameBase === '/' ? '' : match.pathnameBase.slice(1), pattern: Object.assign(Object.assign({}, match.pattern), { path: path }) });
|
|
61
53
|
}
|
|
54
|
+
// No match found
|
|
62
55
|
return null;
|
|
63
56
|
}
|
|
64
57
|
// For absolute paths, use React Router's matcher directly.
|
|
@@ -78,16 +71,12 @@ const matchPath = ({ pathname, componentProps }) => {
|
|
|
78
71
|
*/
|
|
79
72
|
const derivePathnameToMatch = (fullPathname, routePath) => {
|
|
80
73
|
var _a;
|
|
81
|
-
// For absolute or empty routes, use the full pathname as-is
|
|
82
74
|
if (!routePath || routePath === '' || routePath.startsWith('/')) {
|
|
83
75
|
return fullPathname;
|
|
84
76
|
}
|
|
85
77
|
const trimmedPath = fullPathname.startsWith('/') ? fullPathname.slice(1) : fullPathname;
|
|
86
78
|
if (!trimmedPath) {
|
|
87
|
-
|
|
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;
|
|
79
|
+
return '';
|
|
91
80
|
}
|
|
92
81
|
const fullSegments = trimmedPath.split('/').filter(Boolean);
|
|
93
82
|
if (fullSegments.length === 0) {
|
|
@@ -163,36 +152,24 @@ const computeCommonPrefix = (paths) => {
|
|
|
163
152
|
return commonSegments.length > 0 ? '/' + commonSegments.join('/') : '';
|
|
164
153
|
};
|
|
165
154
|
/**
|
|
166
|
-
* Checks if a route
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Checks if a route has an embedded wildcard (e.g., "tab1/*" but not "*" or "/*").
|
|
173
|
-
*/
|
|
174
|
-
const hasEmbeddedWildcard = (routePath) => {
|
|
175
|
-
return !!routePath && routePath.includes('*') && !isSplatOnlyRoute(routePath);
|
|
176
|
-
};
|
|
177
|
-
/**
|
|
178
|
-
* Checks if a route with an embedded wildcard matches a pathname.
|
|
179
|
-
*/
|
|
180
|
-
const matchesEmbeddedWildcardRoute = (route, pathname) => {
|
|
181
|
-
const routePath = route.props.path;
|
|
182
|
-
if (!hasEmbeddedWildcard(routePath)) {
|
|
183
|
-
return false;
|
|
184
|
-
}
|
|
185
|
-
return !!matchPath({ pathname, componentProps: route.props });
|
|
186
|
-
};
|
|
187
|
-
/**
|
|
188
|
-
* Checks if a route is a specific match (not wildcard-only or index).
|
|
155
|
+
* Checks if a route is a specific match (not wildcard or index).
|
|
156
|
+
*
|
|
157
|
+
* @param route The route element to check.
|
|
158
|
+
* @param remainingPath The remaining path to match against.
|
|
159
|
+
* @returns True if the route specifically matches the remaining path.
|
|
189
160
|
*/
|
|
190
161
|
const isSpecificRouteMatch = (route, remainingPath) => {
|
|
191
162
|
const routePath = route.props.path;
|
|
192
|
-
|
|
163
|
+
const isWildcardOnly = routePath === '*' || routePath === '/*';
|
|
164
|
+
const isIndex = route.props.index;
|
|
165
|
+
// Skip wildcards and index routes
|
|
166
|
+
if (isIndex || isWildcardOnly) {
|
|
193
167
|
return false;
|
|
194
168
|
}
|
|
195
|
-
return !!matchPath({
|
|
169
|
+
return !!matchPath({
|
|
170
|
+
pathname: remainingPath,
|
|
171
|
+
componentProps: route.props,
|
|
172
|
+
});
|
|
196
173
|
};
|
|
197
174
|
/**
|
|
198
175
|
* Analyzes route children to determine their characteristics.
|
|
@@ -237,13 +214,11 @@ const computeParentPath = (options) => {
|
|
|
237
214
|
let firstSpecificMatch = undefined;
|
|
238
215
|
let firstWildcardMatch = undefined;
|
|
239
216
|
let indexMatchAtMount = undefined;
|
|
240
|
-
// Start at i = 1 (normal case: strip at least one segment for parent path)
|
|
241
217
|
for (let i = 1; i <= segments.length; i++) {
|
|
242
218
|
const parentPath = '/' + segments.slice(0, i).join('/');
|
|
243
219
|
const remainingPath = segments.slice(i).join('/');
|
|
244
|
-
// Check for specific
|
|
245
|
-
|
|
246
|
-
const hasSpecificMatch = routeChildren.some((route) => isSpecificRouteMatch(route, remainingPath) || matchesEmbeddedWildcardRoute(route, remainingPath));
|
|
220
|
+
// Check for specific (non-wildcard, non-index) route matches
|
|
221
|
+
const hasSpecificMatch = routeChildren.some((route) => isSpecificRouteMatch(route, remainingPath));
|
|
247
222
|
if (hasSpecificMatch && !firstSpecificMatch) {
|
|
248
223
|
firstSpecificMatch = parentPath;
|
|
249
224
|
// Found a specific match - this is our answer for non-index routes
|
|
@@ -290,16 +265,6 @@ const computeParentPath = (options) => {
|
|
|
290
265
|
}
|
|
291
266
|
}
|
|
292
267
|
}
|
|
293
|
-
// Fallback: check at root level (i = 0) for embedded wildcard routes.
|
|
294
|
-
// This handles outlets inside root-level splat routes where routes like
|
|
295
|
-
// "tab1/*" need to match the full pathname.
|
|
296
|
-
if (!firstSpecificMatch) {
|
|
297
|
-
const fullRemainingPath = segments.join('/');
|
|
298
|
-
const hasRootLevelMatch = routeChildren.some((route) => matchesEmbeddedWildcardRoute(route, fullRemainingPath));
|
|
299
|
-
if (hasRootLevelMatch) {
|
|
300
|
-
firstSpecificMatch = '/';
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
268
|
// Determine the best parent path:
|
|
304
269
|
// 1. Specific match (routes like tabs/*, favorites) - highest priority
|
|
305
270
|
// 2. Wildcard match (route path="*") - catches unmatched segments
|
|
@@ -775,36 +740,27 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
775
740
|
const combinedParams = Object.assign(Object.assign({}, accumulatedParentParams), ((_c = routeMatch === null || routeMatch === void 0 ? void 0 : routeMatch.params) !== null && _c !== void 0 ? _c : {}));
|
|
776
741
|
// For relative route paths, we need to compute an absolute pathnameBase
|
|
777
742
|
// by combining the parent's pathnameBase with the matched portion
|
|
743
|
+
let absolutePathnameBase = (routeMatch === null || routeMatch === void 0 ? void 0 : routeMatch.pathnameBase) || routeInfo.pathname;
|
|
778
744
|
const routePath = routeElement.props.path;
|
|
779
745
|
const isRelativePath = routePath && !routePath.startsWith('/');
|
|
780
746
|
const isIndexRoute = !!routeElement.props.index;
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
absolutePathnameBase =
|
|
799
|
-
parentPathnameBase === '/' ? `/${relativeBase}` : `${parentPathnameBase}/${relativeBase}`;
|
|
800
|
-
}
|
|
801
|
-
else if (isIndexRoute) {
|
|
802
|
-
// Index routes should use the parent's base as their base
|
|
803
|
-
absolutePathnameBase = parentPathnameBase;
|
|
804
|
-
}
|
|
805
|
-
else {
|
|
806
|
-
// Default: use the match's pathnameBase or the current pathname
|
|
807
|
-
absolutePathnameBase = (routeMatch === null || routeMatch === void 0 ? void 0 : routeMatch.pathnameBase) || routeInfo.pathname;
|
|
747
|
+
if (isRelativePath || isIndexRoute) {
|
|
748
|
+
// Get the parent's pathnameBase to build the absolute path
|
|
749
|
+
const parentPathnameBase = parentMatches.length > 0 ? parentMatches[parentMatches.length - 1].pathnameBase : '/';
|
|
750
|
+
// For relative paths, the matchPath returns a relative pathnameBase
|
|
751
|
+
// We need to make it absolute by prepending the parent's base
|
|
752
|
+
if ((routeMatch === null || routeMatch === void 0 ? void 0 : routeMatch.pathnameBase) && isRelativePath) {
|
|
753
|
+
// Strip leading slash if present in the relative match
|
|
754
|
+
const relativeBase = routeMatch.pathnameBase.startsWith('/')
|
|
755
|
+
? routeMatch.pathnameBase.slice(1)
|
|
756
|
+
: routeMatch.pathnameBase;
|
|
757
|
+
absolutePathnameBase =
|
|
758
|
+
parentPathnameBase === '/' ? `/${relativeBase}` : `${parentPathnameBase}/${relativeBase}`;
|
|
759
|
+
}
|
|
760
|
+
else if (isIndexRoute) {
|
|
761
|
+
// Index routes should use the parent's base as their base
|
|
762
|
+
absolutePathnameBase = parentPathnameBase;
|
|
763
|
+
}
|
|
808
764
|
}
|
|
809
765
|
const contextMatches = [
|
|
810
766
|
...parentMatches,
|
|
@@ -848,9 +804,7 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
848
804
|
let parentPath = undefined;
|
|
849
805
|
try {
|
|
850
806
|
// Only attempt parent path computation for non-root outlets
|
|
851
|
-
|
|
852
|
-
const isRootOutlet = outletId.startsWith('routerOutlet');
|
|
853
|
-
if (!isRootOutlet) {
|
|
807
|
+
if (outletId !== 'routerOutlet') {
|
|
854
808
|
const routeChildren = extractRouteChildren(ionRouterOutlet.props.children);
|
|
855
809
|
const { hasRelativeRoutes, hasIndexRoute, hasWildcardRoute } = analyzeRouteChildren(routeChildren);
|
|
856
810
|
if (hasRelativeRoutes || hasIndexRoute) {
|
|
@@ -1092,7 +1046,7 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
1092
1046
|
* Matches a view with no path prop (default fallback route) or index route.
|
|
1093
1047
|
*/
|
|
1094
1048
|
function matchDefaultRoute(v) {
|
|
1095
|
-
var _a
|
|
1049
|
+
var _a;
|
|
1096
1050
|
const childProps = v.routeData.childProps;
|
|
1097
1051
|
const isDefaultRoute = childProps.path === undefined || childProps.path === '';
|
|
1098
1052
|
const isIndexRoute = !!childProps.index;
|
|
@@ -1105,22 +1059,14 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
1105
1059
|
}
|
|
1106
1060
|
return false;
|
|
1107
1061
|
}
|
|
1108
|
-
// For empty path routes, only match if we're at the same level as when the view was created.
|
|
1109
|
-
// This prevents an empty path view item from being reused for different routes.
|
|
1110
1062
|
if (isDefaultRoute) {
|
|
1111
|
-
const previousPathnameBase = ((_b = (_a = v.routeData) === null || _a === void 0 ? void 0 : _a.match) === null || _b === void 0 ? void 0 : _b.pathnameBase) || '';
|
|
1112
|
-
const normalizedBase = normalizePathnameForComparison(previousPathnameBase);
|
|
1113
|
-
const normalizedPathname = normalizePathnameForComparison(pathname);
|
|
1114
|
-
if (normalizedPathname !== normalizedBase) {
|
|
1115
|
-
return false;
|
|
1116
|
-
}
|
|
1117
1063
|
match = {
|
|
1118
1064
|
params: {},
|
|
1119
1065
|
pathname,
|
|
1120
1066
|
pathnameBase: pathname === '' ? '/' : pathname,
|
|
1121
1067
|
pattern: {
|
|
1122
1068
|
path: '',
|
|
1123
|
-
caseSensitive: (
|
|
1069
|
+
caseSensitive: (_a = childProps.caseSensitive) !== null && _a !== void 0 ? _a : false,
|
|
1124
1070
|
end: true,
|
|
1125
1071
|
},
|
|
1126
1072
|
};
|
|
@@ -1245,30 +1191,24 @@ class StackManager extends React.PureComponent {
|
|
|
1245
1191
|
if (this.outletMountPath && !currentPathname.startsWith(this.outletMountPath)) {
|
|
1246
1192
|
return undefined;
|
|
1247
1193
|
}
|
|
1248
|
-
//
|
|
1249
|
-
|
|
1194
|
+
// If this is a nested outlet (has an explicit ID like "main"),
|
|
1195
|
+
// we need to figure out what part of the path was already matched
|
|
1196
|
+
if (this.id !== 'routerOutlet' && this.ionRouterOutlet) {
|
|
1250
1197
|
const routeChildren = extractRouteChildren(this.ionRouterOutlet.props.children);
|
|
1251
1198
|
const { hasRelativeRoutes, hasIndexRoute, hasWildcardRoute } = analyzeRouteChildren(routeChildren);
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
hasIndexRoute,
|
|
1264
|
-
hasWildcardRoute,
|
|
1265
|
-
});
|
|
1266
|
-
// Update the outlet mount path if it was set
|
|
1267
|
-
if (result.outletMountPath && !this.outletMountPath) {
|
|
1268
|
-
this.outletMountPath = result.outletMountPath;
|
|
1269
|
-
}
|
|
1270
|
-
return result.parentPath;
|
|
1199
|
+
const result = computeParentPath({
|
|
1200
|
+
currentPathname,
|
|
1201
|
+
outletMountPath: this.outletMountPath,
|
|
1202
|
+
routeChildren,
|
|
1203
|
+
hasRelativeRoutes,
|
|
1204
|
+
hasIndexRoute,
|
|
1205
|
+
hasWildcardRoute,
|
|
1206
|
+
});
|
|
1207
|
+
// Update the outlet mount path if it was set
|
|
1208
|
+
if (result.outletMountPath && !this.outletMountPath) {
|
|
1209
|
+
this.outletMountPath = result.outletMountPath;
|
|
1271
1210
|
}
|
|
1211
|
+
return result.parentPath;
|
|
1272
1212
|
}
|
|
1273
1213
|
return this.outletMountPath;
|
|
1274
1214
|
}
|
|
@@ -1316,39 +1256,12 @@ class StackManager extends React.PureComponent {
|
|
|
1316
1256
|
* Determines if the leaving view item should be unmounted after a transition.
|
|
1317
1257
|
*/
|
|
1318
1258
|
shouldUnmountLeavingView(routeInfo, enteringViewItem, leavingViewItem) {
|
|
1319
|
-
var _a, _b, _c, _d;
|
|
1320
1259
|
if (!leavingViewItem) {
|
|
1321
1260
|
return false;
|
|
1322
1261
|
}
|
|
1323
1262
|
if (routeInfo.routeAction === 'replace') {
|
|
1324
|
-
|
|
1325
|
-
// The key question is: are these routes in the same navigation context?
|
|
1326
|
-
const enteringRoutePath = (_b = (_a = enteringViewItem === null || enteringViewItem === void 0 ? void 0 : enteringViewItem.reactElement) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b.path;
|
|
1327
|
-
const leavingRoutePath = (_d = (_c = leavingViewItem === null || leavingViewItem === void 0 ? void 0 : leavingViewItem.reactElement) === null || _c === void 0 ? void 0 : _c.props) === null || _d === void 0 ? void 0 : _d.path;
|
|
1328
|
-
// Never unmount the root path "/" - it's the main entry point for back navigation
|
|
1329
|
-
if (leavingRoutePath === '/' || leavingRoutePath === '') {
|
|
1330
|
-
return false;
|
|
1331
|
-
}
|
|
1332
|
-
if (enteringRoutePath && leavingRoutePath) {
|
|
1333
|
-
// Get parent paths to check if routes share a common parent
|
|
1334
|
-
const getParentPath = (path) => {
|
|
1335
|
-
const normalized = path.replace(/\/\*$/, ''); // Remove trailing /*
|
|
1336
|
-
const lastSlash = normalized.lastIndexOf('/');
|
|
1337
|
-
return lastSlash > 0 ? normalized.substring(0, lastSlash) : '/';
|
|
1338
|
-
};
|
|
1339
|
-
const enteringParent = getParentPath(enteringRoutePath);
|
|
1340
|
-
const leavingParent = getParentPath(leavingRoutePath);
|
|
1341
|
-
// Unmount if:
|
|
1342
|
-
// 1. Routes are siblings (same parent, e.g., /page1 and /page2, or /foo/page1 and /foo/page2)
|
|
1343
|
-
// 2. Entering is a child of leaving (redirect, e.g., /tabs -> /tabs/tab1)
|
|
1344
|
-
const areSiblings = enteringParent === leavingParent && enteringParent !== '/';
|
|
1345
|
-
const isChildRedirect = enteringRoutePath.startsWith(leavingRoutePath) ||
|
|
1346
|
-
(leavingRoutePath.endsWith('/*') && enteringRoutePath.startsWith(leavingRoutePath.slice(0, -2)));
|
|
1347
|
-
return areSiblings || isChildRedirect;
|
|
1348
|
-
}
|
|
1349
|
-
return false;
|
|
1263
|
+
return true;
|
|
1350
1264
|
}
|
|
1351
|
-
// For non-replace actions, only unmount for back navigation (not forward push)
|
|
1352
1265
|
const isForwardPush = routeInfo.routeAction === 'push' && routeInfo.routeDirection === 'forward';
|
|
1353
1266
|
if (!isForwardPush && routeInfo.routeDirection !== 'none' && enteringViewItem !== leavingViewItem) {
|
|
1354
1267
|
return true;
|
|
@@ -1384,9 +1297,7 @@ class StackManager extends React.PureComponent {
|
|
|
1384
1297
|
*/
|
|
1385
1298
|
handleOutOfContextNestedOutlet(parentPath, leavingViewItem) {
|
|
1386
1299
|
var _a;
|
|
1387
|
-
|
|
1388
|
-
const isRootOutlet = this.id.startsWith('routerOutlet');
|
|
1389
|
-
if (isRootOutlet || parentPath !== undefined || !this.ionRouterOutlet) {
|
|
1300
|
+
if (this.id === 'routerOutlet' || parentPath !== undefined || !this.ionRouterOutlet) {
|
|
1390
1301
|
return false;
|
|
1391
1302
|
}
|
|
1392
1303
|
const routesChildren = (_a = getRoutesChildren(this.ionRouterOutlet.props.children)) !== null && _a !== void 0 ? _a : this.ionRouterOutlet.props.children;
|
|
@@ -1411,9 +1322,7 @@ class StackManager extends React.PureComponent {
|
|
|
1411
1322
|
* Returns true if the transition should be aborted.
|
|
1412
1323
|
*/
|
|
1413
1324
|
handleNoMatchingRoute(enteringRoute, enteringViewItem, leavingViewItem) {
|
|
1414
|
-
|
|
1415
|
-
const isRootOutlet = this.id.startsWith('routerOutlet');
|
|
1416
|
-
if (isRootOutlet || enteringRoute || enteringViewItem) {
|
|
1325
|
+
if (this.id === 'routerOutlet' || enteringRoute || enteringViewItem) {
|
|
1417
1326
|
return false;
|
|
1418
1327
|
}
|
|
1419
1328
|
// Hide any visible views in this outlet since it has no matching route
|
|
@@ -1429,6 +1338,8 @@ class StackManager extends React.PureComponent {
|
|
|
1429
1338
|
*/
|
|
1430
1339
|
handleReadyEnteringView(routeInfo, enteringViewItem, leavingViewItem, shouldUnmountLeavingViewItem) {
|
|
1431
1340
|
var _a, _b;
|
|
1341
|
+
// Ensure the entering view is not hidden from previous navigations
|
|
1342
|
+
showIonPageElement(enteringViewItem.ionPageElement);
|
|
1432
1343
|
// Handle same view item case (e.g., parameterized route changes)
|
|
1433
1344
|
if (enteringViewItem === leavingViewItem) {
|
|
1434
1345
|
const routePath = (_b = (_a = enteringViewItem.reactElement) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b.path;
|
|
@@ -1452,76 +1363,24 @@ class StackManager extends React.PureComponent {
|
|
|
1452
1363
|
if (!leavingViewItem && this.props.routeInfo.prevRouteLastPathname) {
|
|
1453
1364
|
leavingViewItem = this.context.findViewItemByPathname(this.props.routeInfo.prevRouteLastPathname, this.id);
|
|
1454
1365
|
}
|
|
1455
|
-
//
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
}
|
|
1463
|
-
// Check visibility state BEFORE showing the entering view.
|
|
1464
|
-
// This must be done before showIonPageElement to get accurate visibility state.
|
|
1465
|
-
const enteringWasVisible = enteringViewItem.ionPageElement && isViewVisible(enteringViewItem.ionPageElement);
|
|
1466
|
-
const leavingIsHidden = leavingViewItem !== undefined && leavingViewItem.ionPageElement && !isViewVisible(leavingViewItem.ionPageElement);
|
|
1366
|
+
// Skip transition if entering view is visible and leaving view is not
|
|
1367
|
+
if (enteringViewItem.ionPageElement &&
|
|
1368
|
+
isViewVisible(enteringViewItem.ionPageElement) &&
|
|
1369
|
+
leavingViewItem !== undefined &&
|
|
1370
|
+
leavingViewItem.ionPageElement &&
|
|
1371
|
+
!isViewVisible(leavingViewItem.ionPageElement)) {
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1467
1374
|
// Check for duplicate transition
|
|
1468
1375
|
const currentTransition = {
|
|
1469
1376
|
enteringId: enteringViewItem.id,
|
|
1470
1377
|
leavingId: leavingViewItem === null || leavingViewItem === void 0 ? void 0 : leavingViewItem.id,
|
|
1471
1378
|
};
|
|
1472
|
-
|
|
1379
|
+
if (leavingViewItem &&
|
|
1473
1380
|
this.lastTransition &&
|
|
1474
1381
|
this.lastTransition.leavingId &&
|
|
1475
1382
|
this.lastTransition.enteringId === currentTransition.enteringId &&
|
|
1476
|
-
this.lastTransition.leavingId === currentTransition.leavingId
|
|
1477
|
-
// Skip transition if entering view was ALREADY visible and leaving view is not visible.
|
|
1478
|
-
// This indicates the transition has already been performed (e.g., via swipe gesture).
|
|
1479
|
-
// IMPORTANT: Only skip if both ionPageElements are the same as when the transition was last done.
|
|
1480
|
-
// If the leaving view's ionPageElement changed (e.g., component re-rendered with different IonPage),
|
|
1481
|
-
// we should NOT skip because the DOM state is inconsistent.
|
|
1482
|
-
if (enteringWasVisible && leavingIsHidden && isDuplicateTransition) {
|
|
1483
|
-
// For swipe-to-go-back, the transition animation was handled by the gesture.
|
|
1484
|
-
// We still need to set mount=false so React unmounts the leaving view.
|
|
1485
|
-
// Only do this when skipTransition is set (indicating gesture completion).
|
|
1486
|
-
if (this.skipTransition &&
|
|
1487
|
-
shouldUnmountLeavingViewItem &&
|
|
1488
|
-
leavingViewItem &&
|
|
1489
|
-
enteringViewItem !== leavingViewItem) {
|
|
1490
|
-
leavingViewItem.mount = false;
|
|
1491
|
-
// Call transitionPage with duration 0 to trigger ionViewDidLeave lifecycle
|
|
1492
|
-
// which is needed for ViewLifeCycleManager to remove the view.
|
|
1493
|
-
this.transitionPage(routeInfo, enteringViewItem, leavingViewItem, 'back');
|
|
1494
|
-
}
|
|
1495
|
-
// Clear skipTransition since we're not calling transitionPage which normally clears it
|
|
1496
|
-
this.skipTransition = false;
|
|
1497
|
-
// Must call forceUpdate to trigger re-render after mount state change
|
|
1498
|
-
this.forceUpdate();
|
|
1499
|
-
return;
|
|
1500
|
-
}
|
|
1501
|
-
// Ensure the entering view is not hidden from previous navigations
|
|
1502
|
-
// This must happen AFTER the visibility check above
|
|
1503
|
-
showIonPageElement(enteringViewItem.ionPageElement);
|
|
1504
|
-
// Skip if this is a duplicate transition (but visibility state didn't match above)
|
|
1505
|
-
// OR if skipTransition is set (swipe gesture already handled the animation)
|
|
1506
|
-
if (isDuplicateTransition || this.skipTransition) {
|
|
1507
|
-
// For swipe-to-go-back, we still need to handle unmounting even if visibility
|
|
1508
|
-
// conditions aren't fully met (animation might still be in progress)
|
|
1509
|
-
if (this.skipTransition &&
|
|
1510
|
-
shouldUnmountLeavingViewItem &&
|
|
1511
|
-
leavingViewItem &&
|
|
1512
|
-
enteringViewItem !== leavingViewItem) {
|
|
1513
|
-
leavingViewItem.mount = false;
|
|
1514
|
-
// For swipe-to-go-back, we need to call transitionPage with duration 0 to
|
|
1515
|
-
// trigger the ionViewDidLeave lifecycle event. The ViewLifeCycleManager
|
|
1516
|
-
// uses componentCanBeDestroyed callback to remove the view, which is
|
|
1517
|
-
// only called from ionViewDidLeave. Since the gesture animation already
|
|
1518
|
-
// completed before mount=false was set, we need to re-fire the lifecycle.
|
|
1519
|
-
this.transitionPage(routeInfo, enteringViewItem, leavingViewItem, 'back');
|
|
1520
|
-
}
|
|
1521
|
-
// Clear skipTransition since we're not calling transitionPage which normally clears it
|
|
1522
|
-
this.skipTransition = false;
|
|
1523
|
-
// Must call forceUpdate to trigger re-render after mount state change
|
|
1524
|
-
this.forceUpdate();
|
|
1383
|
+
this.lastTransition.leavingId === currentTransition.leavingId) {
|
|
1525
1384
|
return;
|
|
1526
1385
|
}
|
|
1527
1386
|
this.lastTransition = currentTransition;
|
|
@@ -1533,28 +1392,14 @@ class StackManager extends React.PureComponent {
|
|
|
1533
1392
|
}
|
|
1534
1393
|
}
|
|
1535
1394
|
/**
|
|
1536
|
-
* Handles the delayed unmount of the leaving view item.
|
|
1537
|
-
* For 'replace' actions: handles container route transitions specially.
|
|
1538
|
-
* For back navigation: explicitly unmounts because the ionViewDidLeave lifecycle
|
|
1539
|
-
* fires DURING transitionPage, but mount=false is set AFTER.
|
|
1540
|
-
*
|
|
1541
|
-
* @param routeInfo Current route information
|
|
1542
|
-
* @param enteringViewItem The view being navigated to
|
|
1543
|
-
* @param leavingViewItem The view being navigated from
|
|
1395
|
+
* Handles the delayed unmount of the leaving view item after a replace action.
|
|
1544
1396
|
*/
|
|
1545
1397
|
handleLeavingViewUnmount(routeInfo, enteringViewItem, leavingViewItem) {
|
|
1546
1398
|
var _a, _b, _c, _d, _e, _f;
|
|
1547
|
-
if (!leavingViewItem.ionPageElement) {
|
|
1548
|
-
return;
|
|
1549
|
-
}
|
|
1550
|
-
// For push/pop actions, do NOT unmount - views are cached for navigation history.
|
|
1551
|
-
// Push: Forward navigation caches views for back navigation
|
|
1552
|
-
// Pop: Back navigation should not unmount the entering view's history
|
|
1553
|
-
// Only 'replace' actions should actually unmount views since they replace history.
|
|
1554
|
-
if (routeInfo.routeAction !== 'replace') {
|
|
1399
|
+
if (routeInfo.routeAction !== 'replace' || !leavingViewItem.ionPageElement) {
|
|
1555
1400
|
return;
|
|
1556
1401
|
}
|
|
1557
|
-
//
|
|
1402
|
+
// Check if we should skip removal for nested outlet redirects
|
|
1558
1403
|
const enteringRoutePath = (_b = (_a = enteringViewItem.reactElement) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b.path;
|
|
1559
1404
|
const leavingRoutePath = (_d = (_c = leavingViewItem.reactElement) === null || _c === void 0 ? void 0 : _c.props) === null || _d === void 0 ? void 0 : _d.path;
|
|
1560
1405
|
const isEnteringContainerRoute = enteringRoutePath && enteringRoutePath.endsWith('/*');
|
|
@@ -1570,8 +1415,6 @@ class StackManager extends React.PureComponent {
|
|
|
1570
1415
|
const viewToUnmount = leavingViewItem;
|
|
1571
1416
|
setTimeout(() => {
|
|
1572
1417
|
this.context.unMountViewItem(viewToUnmount);
|
|
1573
|
-
// Trigger re-render to remove the view from DOM
|
|
1574
|
-
this.forceUpdate();
|
|
1575
1418
|
}, VIEW_UNMOUNT_DELAY_MS);
|
|
1576
1419
|
}
|
|
1577
1420
|
/**
|
|
@@ -1616,8 +1459,6 @@ class StackManager extends React.PureComponent {
|
|
|
1616
1459
|
this.transitionPage(routeInfo, latestEnteringView, latestLeavingView !== null && latestLeavingView !== void 0 ? latestLeavingView : undefined);
|
|
1617
1460
|
if (shouldUnmountLeavingViewItem && latestLeavingView && latestEnteringView !== latestLeavingView) {
|
|
1618
1461
|
latestLeavingView.mount = false;
|
|
1619
|
-
// Call handleLeavingViewUnmount to ensure the view is properly removed
|
|
1620
|
-
this.handleLeavingViewUnmount(routeInfo, latestEnteringView, latestLeavingView);
|
|
1621
1462
|
}
|
|
1622
1463
|
this.forceUpdate();
|
|
1623
1464
|
}
|
|
@@ -1741,12 +1582,7 @@ class StackManager extends React.PureComponent {
|
|
|
1741
1582
|
this.context.addViewItem(enteringViewItem);
|
|
1742
1583
|
}
|
|
1743
1584
|
// Handle transition based on ion-page element availability
|
|
1744
|
-
|
|
1745
|
-
// If the view was previously unmounted (mount=false), the ViewLifeCycleManager
|
|
1746
|
-
// removes the React component from the tree, which removes the IonPage from the DOM.
|
|
1747
|
-
// The ionPageElement reference becomes stale and we need to wait for a new one.
|
|
1748
|
-
const ionPageIsInDocument = (enteringViewItem === null || enteringViewItem === void 0 ? void 0 : enteringViewItem.ionPageElement) && document.body.contains(enteringViewItem.ionPageElement);
|
|
1749
|
-
if (enteringViewItem && ionPageIsInDocument) {
|
|
1585
|
+
if (enteringViewItem && enteringViewItem.ionPageElement) {
|
|
1750
1586
|
// Clear waiting state
|
|
1751
1587
|
if (this.waitingForIonPage) {
|
|
1752
1588
|
this.waitingForIonPage = false;
|
|
@@ -1757,17 +1593,8 @@ class StackManager extends React.PureComponent {
|
|
|
1757
1593
|
}
|
|
1758
1594
|
this.handleReadyEnteringView(routeInfo, enteringViewItem, leavingViewItem, shouldUnmountLeavingViewItem);
|
|
1759
1595
|
}
|
|
1760
|
-
else if (enteringViewItem && !
|
|
1596
|
+
else if (enteringViewItem && !enteringViewItem.ionPageElement) {
|
|
1761
1597
|
// Wait for ion-page to mount
|
|
1762
|
-
// This handles both: no ionPageElement, or stale ionPageElement (not in document)
|
|
1763
|
-
// Clear stale reference if the element is no longer in the document
|
|
1764
|
-
if (enteringViewItem.ionPageElement && !document.body.contains(enteringViewItem.ionPageElement)) {
|
|
1765
|
-
enteringViewItem.ionPageElement = undefined;
|
|
1766
|
-
}
|
|
1767
|
-
// Ensure the view is marked as mounted so ViewLifeCycleManager renders the IonPage
|
|
1768
|
-
if (!enteringViewItem.mount) {
|
|
1769
|
-
enteringViewItem.mount = true;
|
|
1770
|
-
}
|
|
1771
1598
|
this.handleWaitingForIonPage(routeInfo, enteringViewItem, leavingViewItem, shouldUnmountLeavingViewItem);
|
|
1772
1599
|
return;
|
|
1773
1600
|
}
|
|
@@ -1799,19 +1626,6 @@ class StackManager extends React.PureComponent {
|
|
|
1799
1626
|
const foundView = this.context.findViewItemByRouteInfo(routeInfo, this.id);
|
|
1800
1627
|
if (foundView) {
|
|
1801
1628
|
const oldPageElement = foundView.ionPageElement;
|
|
1802
|
-
/**
|
|
1803
|
-
* FIX for issue #28878: Reject orphaned IonPage registrations.
|
|
1804
|
-
*
|
|
1805
|
-
* When a component conditionally renders different IonPages (e.g., list vs empty state)
|
|
1806
|
-
* using React keys, and state changes simultaneously with navigation, the new IonPage
|
|
1807
|
-
* tries to register for a route we're navigating away from. This creates a stale view.
|
|
1808
|
-
*
|
|
1809
|
-
* Only reject if both pageIds exist and differ, to allow nested outlet registrations.
|
|
1810
|
-
*/
|
|
1811
|
-
if (this.shouldRejectOrphanedPage(page, oldPageElement, routeInfo)) {
|
|
1812
|
-
this.hideAndRemoveOrphanedPage(page);
|
|
1813
|
-
return;
|
|
1814
|
-
}
|
|
1815
1629
|
foundView.ionPageElement = page;
|
|
1816
1630
|
foundView.ionRoute = true;
|
|
1817
1631
|
/**
|
|
@@ -1825,35 +1639,6 @@ class StackManager extends React.PureComponent {
|
|
|
1825
1639
|
}
|
|
1826
1640
|
this.handlePageTransition(routeInfo);
|
|
1827
1641
|
}
|
|
1828
|
-
/**
|
|
1829
|
-
* Determines if a new IonPage registration should be rejected as orphaned.
|
|
1830
|
-
* This happens when a component re-renders with a different IonPage while navigating away.
|
|
1831
|
-
*/
|
|
1832
|
-
shouldRejectOrphanedPage(newPage, oldPageElement, routeInfo) {
|
|
1833
|
-
if (!oldPageElement || oldPageElement === newPage) {
|
|
1834
|
-
return false;
|
|
1835
|
-
}
|
|
1836
|
-
const newPageId = newPage.getAttribute('data-pageid');
|
|
1837
|
-
const oldPageId = oldPageElement.getAttribute('data-pageid');
|
|
1838
|
-
// Only reject if both pageIds exist and are different
|
|
1839
|
-
if (!newPageId || !oldPageId || newPageId === oldPageId) {
|
|
1840
|
-
return false;
|
|
1841
|
-
}
|
|
1842
|
-
// Reject only if we're navigating away from this route
|
|
1843
|
-
return this.props.routeInfo.pathname !== routeInfo.pathname;
|
|
1844
|
-
}
|
|
1845
|
-
/**
|
|
1846
|
-
* Hides an orphaned IonPage and schedules its removal from the DOM.
|
|
1847
|
-
*/
|
|
1848
|
-
hideAndRemoveOrphanedPage(page) {
|
|
1849
|
-
page.classList.add('ion-page-hidden');
|
|
1850
|
-
page.setAttribute('aria-hidden', 'true');
|
|
1851
|
-
setTimeout(() => {
|
|
1852
|
-
if (page.parentElement) {
|
|
1853
|
-
page.remove();
|
|
1854
|
-
}
|
|
1855
|
-
}, VIEW_UNMOUNT_DELAY_MS);
|
|
1856
|
-
}
|
|
1857
1642
|
/**
|
|
1858
1643
|
* Configures the router outlet for the swipe-to-go-back gesture.
|
|
1859
1644
|
*
|
|
@@ -1869,23 +1654,11 @@ class StackManager extends React.PureComponent {
|
|
|
1869
1654
|
}
|
|
1870
1655
|
const { routeInfo } = this.props;
|
|
1871
1656
|
const swipeBackRouteInfo = this.getSwipeBackRouteInfo();
|
|
1872
|
-
|
|
1873
|
-
let enteringViewItem = this.context.findViewItemByRouteInfo(swipeBackRouteInfo, this.id, false);
|
|
1874
|
-
// If not found in current outlet, search all outlets (for cross-outlet swipe back)
|
|
1875
|
-
if (!enteringViewItem) {
|
|
1876
|
-
enteringViewItem = this.context.findViewItemByRouteInfo(swipeBackRouteInfo, undefined, false);
|
|
1877
|
-
}
|
|
1878
|
-
// Check if the ionPageElement is still in the document.
|
|
1879
|
-
// A view might have mount=false but still have its ionPageElement in the DOM
|
|
1880
|
-
// (due to timing differences in unmounting).
|
|
1881
|
-
const ionPageInDocument = Boolean((enteringViewItem === null || enteringViewItem === void 0 ? void 0 : enteringViewItem.ionPageElement) && document.body.contains(enteringViewItem.ionPageElement));
|
|
1657
|
+
const enteringViewItem = this.context.findViewItemByRouteInfo(swipeBackRouteInfo, this.id, false);
|
|
1882
1658
|
const canStartSwipe = !!enteringViewItem &&
|
|
1883
|
-
//
|
|
1884
|
-
//
|
|
1885
|
-
|
|
1886
|
-
// The second case handles views that have been marked for unmount but haven't
|
|
1887
|
-
// actually been removed from the DOM yet.
|
|
1888
|
-
(enteringViewItem.mount || ionPageInDocument) &&
|
|
1659
|
+
// The root url '/' is treated as the first view item (but is never mounted),
|
|
1660
|
+
// so we do not want to swipe back to the root url.
|
|
1661
|
+
enteringViewItem.mount &&
|
|
1889
1662
|
// When on the first page it is possible for findViewItemByRouteInfo to
|
|
1890
1663
|
// return the exact same view you are currently on.
|
|
1891
1664
|
// Make sure that we are not swiping back to the same instances of a view.
|
|
@@ -1895,18 +1668,8 @@ class StackManager extends React.PureComponent {
|
|
|
1895
1668
|
const onStart = async () => {
|
|
1896
1669
|
const { routeInfo } = this.props;
|
|
1897
1670
|
const swipeBackRouteInfo = this.getSwipeBackRouteInfo();
|
|
1898
|
-
|
|
1899
|
-
let enteringViewItem = this.context.findViewItemByRouteInfo(swipeBackRouteInfo, this.id, false);
|
|
1900
|
-
if (!enteringViewItem) {
|
|
1901
|
-
enteringViewItem = this.context.findViewItemByRouteInfo(swipeBackRouteInfo, undefined, false);
|
|
1902
|
-
}
|
|
1671
|
+
const enteringViewItem = this.context.findViewItemByRouteInfo(swipeBackRouteInfo, this.id, false);
|
|
1903
1672
|
const leavingViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id, false);
|
|
1904
|
-
// Ensure the entering view is mounted so React keeps rendering it during the gesture.
|
|
1905
|
-
// This is important when the view was previously marked for unmount but its
|
|
1906
|
-
// ionPageElement is still in the DOM.
|
|
1907
|
-
if (enteringViewItem && !enteringViewItem.mount) {
|
|
1908
|
-
enteringViewItem.mount = true;
|
|
1909
|
-
}
|
|
1910
1673
|
// When the gesture starts, kick off a transition controlled via swipe gesture
|
|
1911
1674
|
if (enteringViewItem && leavingViewItem) {
|
|
1912
1675
|
await this.transitionPage(routeInfo, enteringViewItem, leavingViewItem, 'back', true);
|
|
@@ -1923,11 +1686,7 @@ class StackManager extends React.PureComponent {
|
|
|
1923
1686
|
// Swipe gesture was aborted - re-hide the page that was going to enter
|
|
1924
1687
|
const { routeInfo } = this.props;
|
|
1925
1688
|
const swipeBackRouteInfo = this.getSwipeBackRouteInfo();
|
|
1926
|
-
|
|
1927
|
-
let enteringViewItem = this.context.findViewItemByRouteInfo(swipeBackRouteInfo, this.id, false);
|
|
1928
|
-
if (!enteringViewItem) {
|
|
1929
|
-
enteringViewItem = this.context.findViewItemByRouteInfo(swipeBackRouteInfo, undefined, false);
|
|
1930
|
-
}
|
|
1689
|
+
const enteringViewItem = this.context.findViewItemByRouteInfo(swipeBackRouteInfo, this.id, false);
|
|
1931
1690
|
const leavingViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id, false);
|
|
1932
1691
|
// Don't hide if entering and leaving are the same (parameterized route edge case)
|
|
1933
1692
|
if (enteringViewItem !== leavingViewItem && (enteringViewItem === null || enteringViewItem === void 0 ? void 0 : enteringViewItem.ionPageElement) !== undefined) {
|
|
@@ -2110,59 +1869,27 @@ function findRouteByRouteInfo(node, routeInfo, parentPath) {
|
|
|
2110
1869
|
});
|
|
2111
1870
|
// For nested routes in React Router 6, we need to extract the relative path
|
|
2112
1871
|
// that this outlet should be responsible for matching
|
|
2113
|
-
|
|
2114
|
-
let relativePathnameToMatch = routeInfo.pathname;
|
|
1872
|
+
let pathnameToMatch = routeInfo.pathname;
|
|
2115
1873
|
// Check if we have relative routes (routes that don't start with '/')
|
|
2116
1874
|
const hasRelativeRoutes = sortedRoutes.some((r) => r.props.path && !r.props.path.startsWith('/'));
|
|
2117
1875
|
const hasIndexRoute = sortedRoutes.some((r) => r.props.index);
|
|
2118
1876
|
// SIMPLIFIED: Trust React Router 6's matching more, compute relative path when parent is known
|
|
2119
1877
|
if ((hasRelativeRoutes || hasIndexRoute) && parentPath) {
|
|
2120
1878
|
const parentPrefix = parentPath.replace('/*', '');
|
|
2121
|
-
|
|
2122
|
-
const normalizedParent = stripTrailingSlash(parentPrefix.startsWith('/') ? parentPrefix : `/${parentPrefix}`);
|
|
1879
|
+
const normalizedParent = stripTrailingSlash(parentPrefix);
|
|
2123
1880
|
const normalizedPathname = stripTrailingSlash(routeInfo.pathname);
|
|
2124
1881
|
// Only compute relative path if pathname is within parent scope
|
|
2125
1882
|
if (normalizedPathname.startsWith(normalizedParent + '/') || normalizedPathname === normalizedParent) {
|
|
2126
1883
|
const pathSegments = routeInfo.pathname.split('/').filter(Boolean);
|
|
2127
1884
|
const parentSegments = normalizedParent.split('/').filter(Boolean);
|
|
2128
1885
|
const relativeSegments = pathSegments.slice(parentSegments.length);
|
|
2129
|
-
|
|
1886
|
+
pathnameToMatch = relativeSegments.join('/'); // Empty string is valid for index routes
|
|
2130
1887
|
}
|
|
2131
1888
|
}
|
|
2132
1889
|
// Find the first matching route
|
|
2133
1890
|
for (const child of sortedRoutes) {
|
|
2134
|
-
const childPath = child.props.path;
|
|
2135
|
-
const isAbsoluteRoute = childPath && childPath.startsWith('/');
|
|
2136
|
-
// Determine which pathname to match against:
|
|
2137
|
-
// - For absolute routes: use the original full pathname
|
|
2138
|
-
// - For relative routes with a parent: use the computed relative pathname
|
|
2139
|
-
// - For relative routes at root level (no parent): use the original pathname
|
|
2140
|
-
// (matchPath will handle the relative-to-absolute normalization)
|
|
2141
|
-
const pathnameToMatch = isAbsoluteRoute ? originalPathname : relativePathnameToMatch;
|
|
2142
|
-
// Determine the path portion to match:
|
|
2143
|
-
// - For absolute routes: use derivePathnameToMatch
|
|
2144
|
-
// - For relative routes at root level (no parent): use original pathname
|
|
2145
|
-
// directly since matchPath normalizes both path and pathname
|
|
2146
|
-
// - For relative routes with parent: use derivePathnameToMatch for wildcards,
|
|
2147
|
-
// or the computed relative pathname for non-wildcards
|
|
2148
|
-
let pathForMatch;
|
|
2149
|
-
if (isAbsoluteRoute) {
|
|
2150
|
-
pathForMatch = derivePathnameToMatch(pathnameToMatch, childPath);
|
|
2151
|
-
}
|
|
2152
|
-
else if (!parentPath && childPath) {
|
|
2153
|
-
// Root-level relative route: use the full pathname and let matchPath
|
|
2154
|
-
// handle the normalization (it adds '/' to both path and pathname)
|
|
2155
|
-
pathForMatch = originalPathname;
|
|
2156
|
-
}
|
|
2157
|
-
else if (childPath && childPath.includes('*')) {
|
|
2158
|
-
// Relative wildcard route with parent path: use derivePathnameToMatch
|
|
2159
|
-
pathForMatch = derivePathnameToMatch(pathnameToMatch, childPath);
|
|
2160
|
-
}
|
|
2161
|
-
else {
|
|
2162
|
-
pathForMatch = pathnameToMatch;
|
|
2163
|
-
}
|
|
2164
1891
|
const match = matchPath({
|
|
2165
|
-
pathname:
|
|
1892
|
+
pathname: pathnameToMatch,
|
|
2166
1893
|
componentProps: child.props,
|
|
2167
1894
|
});
|
|
2168
1895
|
if (match) {
|