react-router 6.0.0-beta.5 → 6.0.0
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/{LICENSE → LICENSE.md} +0 -0
- package/index.d.ts +45 -22
- package/index.js +223 -160
- package/index.js.map +1 -1
- package/main.js +10 -0
- package/package.json +8 -6
- package/react-router.development.js +217 -138
- package/react-router.development.js.map +1 -1
- package/react-router.production.min.js +11 -1
- package/react-router.production.min.js.map +1 -1
- package/umd/react-router.development.js +223 -160
- package/umd/react-router.development.js.map +1 -1
- package/umd/react-router.production.min.js +11 -1
- package/umd/react-router.production.min.js.map +1 -1
- package/umd/index.d.ts +0 -303
|
@@ -1,27 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Router v6.0.0
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Remix Software Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
1
11
|
(function (global, factory) {
|
|
2
12
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('history')) :
|
|
3
13
|
typeof define === 'function' && define.amd ? define(['exports', 'react', 'history'], factory) :
|
|
4
14
|
(global = global || self, factory(global.ReactRouter = {}, global.React, global.HistoryLibrary));
|
|
5
15
|
}(this, (function (exports, React, history) { 'use strict';
|
|
6
16
|
|
|
7
|
-
function _extends() {
|
|
8
|
-
_extends = Object.assign || function (target) {
|
|
9
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
10
|
-
var source = arguments[i];
|
|
11
|
-
|
|
12
|
-
for (var key in source) {
|
|
13
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
14
|
-
target[key] = source[key];
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return target;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
return _extends.apply(this, arguments);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
17
|
function invariant(cond, message) {
|
|
26
18
|
if (!cond) throw new Error(message);
|
|
27
19
|
}
|
|
@@ -49,7 +41,20 @@
|
|
|
49
41
|
alreadyWarned[key] = true;
|
|
50
42
|
warning(false, message) ;
|
|
51
43
|
}
|
|
52
|
-
}
|
|
44
|
+
} ///////////////////////////////////////////////////////////////////////////////
|
|
45
|
+
// CONTEXT
|
|
46
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A Navigator is a "location changer"; it's how you get to different locations.
|
|
50
|
+
*
|
|
51
|
+
* Every history instance conforms to the Navigator interface, but the
|
|
52
|
+
* distinction is useful primarily when it comes to the low-level <Router> API
|
|
53
|
+
* where both the location and a navigator must be provided separately in order
|
|
54
|
+
* to avoid "tearing" that may occur in a suspense-enabled app if the action
|
|
55
|
+
* and/or location were to be read directly from the history instance.
|
|
56
|
+
*/
|
|
57
|
+
|
|
53
58
|
|
|
54
59
|
const NavigationContext = /*#__PURE__*/React.createContext(null);
|
|
55
60
|
|
|
@@ -65,21 +70,21 @@
|
|
|
65
70
|
|
|
66
71
|
const RouteContext = /*#__PURE__*/React.createContext({
|
|
67
72
|
outlet: null,
|
|
68
|
-
|
|
69
|
-
pathname: "/",
|
|
70
|
-
route: null
|
|
73
|
+
matches: []
|
|
71
74
|
});
|
|
72
75
|
|
|
73
76
|
{
|
|
74
77
|
RouteContext.displayName = "Route";
|
|
75
|
-
}
|
|
78
|
+
} ///////////////////////////////////////////////////////////////////////////////
|
|
79
|
+
// COMPONENTS
|
|
80
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
81
|
+
|
|
82
|
+
|
|
76
83
|
/**
|
|
77
84
|
* A <Router> that stores all entries in memory.
|
|
78
85
|
*
|
|
79
86
|
* @see https://reactrouter.com/api/MemoryRouter
|
|
80
87
|
*/
|
|
81
|
-
|
|
82
|
-
|
|
83
88
|
function MemoryRouter(_ref) {
|
|
84
89
|
let {
|
|
85
90
|
basename,
|
|
@@ -105,11 +110,12 @@
|
|
|
105
110
|
return /*#__PURE__*/React.createElement(Router, {
|
|
106
111
|
basename: basename,
|
|
107
112
|
children: children,
|
|
108
|
-
action: state.action,
|
|
109
113
|
location: state.location,
|
|
114
|
+
navigationType: state.action,
|
|
110
115
|
navigator: history$1
|
|
111
116
|
});
|
|
112
117
|
}
|
|
118
|
+
|
|
113
119
|
/**
|
|
114
120
|
* Changes the current location.
|
|
115
121
|
*
|
|
@@ -119,7 +125,6 @@
|
|
|
119
125
|
*
|
|
120
126
|
* @see https://reactrouter.com/api/Navigate
|
|
121
127
|
*/
|
|
122
|
-
|
|
123
128
|
function Navigate(_ref2) {
|
|
124
129
|
let {
|
|
125
130
|
to,
|
|
@@ -139,24 +144,25 @@
|
|
|
139
144
|
});
|
|
140
145
|
return null;
|
|
141
146
|
}
|
|
147
|
+
|
|
142
148
|
/**
|
|
143
149
|
* Renders the child route's element, if there is one.
|
|
144
150
|
*
|
|
145
151
|
* @see https://reactrouter.com/api/Outlet
|
|
146
152
|
*/
|
|
147
|
-
|
|
148
153
|
function Outlet(_props) {
|
|
149
154
|
return useOutlet();
|
|
150
155
|
}
|
|
156
|
+
|
|
151
157
|
/**
|
|
152
158
|
* Declares an element that should be rendered at a certain URL path.
|
|
153
159
|
*
|
|
154
160
|
* @see https://reactrouter.com/api/Route
|
|
155
161
|
*/
|
|
156
|
-
|
|
157
162
|
function Route(_props) {
|
|
158
163
|
invariant(false, "A <Route> is only ever to be used as the child of <Routes> element, " + "never rendered directly. Please wrap your <Route> in a <Routes>.") ;
|
|
159
164
|
}
|
|
165
|
+
|
|
160
166
|
/**
|
|
161
167
|
* Provides location context for the rest of the app.
|
|
162
168
|
*
|
|
@@ -166,13 +172,12 @@
|
|
|
166
172
|
*
|
|
167
173
|
* @see https://reactrouter.com/api/Router
|
|
168
174
|
*/
|
|
169
|
-
|
|
170
175
|
function Router(_ref3) {
|
|
171
176
|
let {
|
|
172
|
-
action = history.Action.Pop,
|
|
173
177
|
basename: basenameProp = "/",
|
|
174
178
|
children = null,
|
|
175
179
|
location: locationProp,
|
|
180
|
+
navigationType = history.Action.Pop,
|
|
176
181
|
navigator,
|
|
177
182
|
static: staticProp = false
|
|
178
183
|
} = _ref3;
|
|
@@ -221,18 +226,18 @@
|
|
|
221
226
|
}, /*#__PURE__*/React.createElement(LocationContext.Provider, {
|
|
222
227
|
children: children,
|
|
223
228
|
value: {
|
|
224
|
-
|
|
225
|
-
|
|
229
|
+
location,
|
|
230
|
+
navigationType
|
|
226
231
|
}
|
|
227
232
|
}));
|
|
228
233
|
}
|
|
234
|
+
|
|
229
235
|
/**
|
|
230
236
|
* A container for a nested tree of <Route> elements that renders the branch
|
|
231
237
|
* that best matches the current location.
|
|
232
238
|
*
|
|
233
239
|
* @see https://reactrouter.com/api/Routes
|
|
234
240
|
*/
|
|
235
|
-
|
|
236
241
|
function Routes(_ref4) {
|
|
237
242
|
let {
|
|
238
243
|
children,
|
|
@@ -243,43 +248,6 @@
|
|
|
243
248
|
// HOOKS
|
|
244
249
|
///////////////////////////////////////////////////////////////////////////////
|
|
245
250
|
|
|
246
|
-
/**
|
|
247
|
-
* Blocks all navigation attempts. This is useful for preventing the page from
|
|
248
|
-
* changing until some condition is met, like saving form data.
|
|
249
|
-
*
|
|
250
|
-
* @see https://reactrouter.com/api/useBlocker
|
|
251
|
-
*/
|
|
252
|
-
|
|
253
|
-
function useBlocker(blocker, when) {
|
|
254
|
-
if (when === void 0) {
|
|
255
|
-
when = true;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
!useInRouterContext() ? invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
|
259
|
-
// router loaded. We can help them understand how to avoid that.
|
|
260
|
-
"useBlocker() may be used only in the context of a <Router> component.") : void 0;
|
|
261
|
-
let {
|
|
262
|
-
navigator
|
|
263
|
-
} = React.useContext(NavigationContext);
|
|
264
|
-
React.useEffect(() => {
|
|
265
|
-
if (!when) return;
|
|
266
|
-
let unblock = navigator.block(tx => {
|
|
267
|
-
let autoUnblockingTx = _extends({}, tx, {
|
|
268
|
-
retry() {
|
|
269
|
-
// Automatically unblock the transition so it can play all the way
|
|
270
|
-
// through before retrying it. TODO: Figure out how to re-enable
|
|
271
|
-
// this block if the transition is cancelled for some reason.
|
|
272
|
-
unblock();
|
|
273
|
-
tx.retry();
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
blocker(autoUnblockingTx);
|
|
279
|
-
});
|
|
280
|
-
return unblock;
|
|
281
|
-
}, [navigator, blocker, when]);
|
|
282
|
-
}
|
|
283
251
|
/**
|
|
284
252
|
* Returns the full href for the given "to" value. This is useful for building
|
|
285
253
|
* custom links that are also accessible and preserve right-click behavior.
|
|
@@ -295,15 +263,24 @@
|
|
|
295
263
|
basename,
|
|
296
264
|
navigator
|
|
297
265
|
} = React.useContext(NavigationContext);
|
|
298
|
-
let
|
|
266
|
+
let {
|
|
267
|
+
hash,
|
|
268
|
+
pathname,
|
|
269
|
+
search
|
|
270
|
+
} = useResolvedPath(to);
|
|
271
|
+
let joinedPathname = pathname;
|
|
299
272
|
|
|
300
273
|
if (basename !== "/") {
|
|
301
274
|
let toPathname = getToPathname(to);
|
|
302
275
|
let endsWithSlash = toPathname != null && toPathname.endsWith("/");
|
|
303
|
-
|
|
276
|
+
joinedPathname = pathname === "/" ? basename + (endsWithSlash ? "/" : "") : joinPaths([basename, pathname]);
|
|
304
277
|
}
|
|
305
278
|
|
|
306
|
-
return navigator.createHref(
|
|
279
|
+
return navigator.createHref({
|
|
280
|
+
pathname: joinedPathname,
|
|
281
|
+
search,
|
|
282
|
+
hash
|
|
283
|
+
});
|
|
307
284
|
}
|
|
308
285
|
/**
|
|
309
286
|
* Returns true if this component is a descendant of a <Router>.
|
|
@@ -331,6 +308,16 @@
|
|
|
331
308
|
"useLocation() may be used only in the context of a <Router> component.") : void 0;
|
|
332
309
|
return React.useContext(LocationContext).location;
|
|
333
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* Returns the current navigation action which describes how the router came to
|
|
313
|
+
* the current location, either by a pop, push, or replace on the history stack.
|
|
314
|
+
*
|
|
315
|
+
* @see https://reactrouter.com/api/useNavigationType
|
|
316
|
+
*/
|
|
317
|
+
|
|
318
|
+
function useNavigationType() {
|
|
319
|
+
return React.useContext(LocationContext).navigationType;
|
|
320
|
+
}
|
|
334
321
|
/**
|
|
335
322
|
* Returns true if the URL for the given "to" value matches the current URL.
|
|
336
323
|
* This is useful for components that need to know "active" state, e.g.
|
|
@@ -345,13 +332,16 @@
|
|
|
345
332
|
"useMatch() may be used only in the context of a <Router> component.") : void 0;
|
|
346
333
|
return matchPath(pattern, useLocation().pathname);
|
|
347
334
|
}
|
|
335
|
+
/**
|
|
336
|
+
* The interface for the navigate() function returned from useNavigate().
|
|
337
|
+
*/
|
|
338
|
+
|
|
348
339
|
/**
|
|
349
340
|
* Returns an imperative method for changing the location. Used by <Link>s, but
|
|
350
341
|
* may also be used by other elements to change the location.
|
|
351
342
|
*
|
|
352
343
|
* @see https://reactrouter.com/api/useNavigate
|
|
353
344
|
*/
|
|
354
|
-
|
|
355
345
|
function useNavigate() {
|
|
356
346
|
!useInRouterContext() ? invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
|
357
347
|
// router loaded. We can help them understand how to avoid that.
|
|
@@ -361,11 +351,12 @@
|
|
|
361
351
|
navigator
|
|
362
352
|
} = React.useContext(NavigationContext);
|
|
363
353
|
let {
|
|
364
|
-
|
|
354
|
+
matches
|
|
365
355
|
} = React.useContext(RouteContext);
|
|
366
356
|
let {
|
|
367
357
|
pathname: locationPathname
|
|
368
358
|
} = useLocation();
|
|
359
|
+
let routePathnamesJson = JSON.stringify(matches.map(match => match.pathnameBase));
|
|
369
360
|
let activeRef = React.useRef(false);
|
|
370
361
|
React.useEffect(() => {
|
|
371
362
|
activeRef.current = true;
|
|
@@ -383,14 +374,14 @@
|
|
|
383
374
|
return;
|
|
384
375
|
}
|
|
385
376
|
|
|
386
|
-
let path = resolveTo(to,
|
|
377
|
+
let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname);
|
|
387
378
|
|
|
388
379
|
if (basename !== "/") {
|
|
389
380
|
path.pathname = joinPaths([basename, path.pathname]);
|
|
390
381
|
}
|
|
391
382
|
|
|
392
383
|
(!!options.replace ? navigator.replace : navigator.push)(path, options.state);
|
|
393
|
-
}, [basename, navigator,
|
|
384
|
+
}, [basename, navigator, routePathnamesJson, locationPathname]);
|
|
394
385
|
return navigate;
|
|
395
386
|
}
|
|
396
387
|
/**
|
|
@@ -411,7 +402,11 @@
|
|
|
411
402
|
*/
|
|
412
403
|
|
|
413
404
|
function useParams() {
|
|
414
|
-
|
|
405
|
+
let {
|
|
406
|
+
matches
|
|
407
|
+
} = React.useContext(RouteContext);
|
|
408
|
+
let routeMatch = matches[matches.length - 1];
|
|
409
|
+
return routeMatch ? routeMatch.params : {};
|
|
415
410
|
}
|
|
416
411
|
/**
|
|
417
412
|
* Resolves the pathname of the given `to` value against the current location.
|
|
@@ -420,13 +415,14 @@
|
|
|
420
415
|
*/
|
|
421
416
|
|
|
422
417
|
function useResolvedPath(to) {
|
|
418
|
+
let {
|
|
419
|
+
matches
|
|
420
|
+
} = React.useContext(RouteContext);
|
|
423
421
|
let {
|
|
424
422
|
pathname: locationPathname
|
|
425
423
|
} = useLocation();
|
|
426
|
-
let
|
|
427
|
-
|
|
428
|
-
} = React.useContext(RouteContext);
|
|
429
|
-
return React.useMemo(() => resolveTo(to, routePathname, locationPathname), [to, routePathname, locationPathname]);
|
|
424
|
+
let routePathnamesJson = JSON.stringify(matches.map(match => match.pathnameBase));
|
|
425
|
+
return React.useMemo(() => resolveTo(to, JSON.parse(routePathnamesJson), locationPathname), [to, routePathnamesJson, locationPathname]);
|
|
430
426
|
}
|
|
431
427
|
/**
|
|
432
428
|
* Returns the element of the route that matched the current location, prepared
|
|
@@ -442,10 +438,13 @@
|
|
|
442
438
|
// router loaded. We can help them understand how to avoid that.
|
|
443
439
|
"useRoutes() may be used only in the context of a <Router> component.") : void 0;
|
|
444
440
|
let {
|
|
445
|
-
|
|
446
|
-
pathname: parentPathname,
|
|
447
|
-
route: parentRoute
|
|
441
|
+
matches: parentMatches
|
|
448
442
|
} = React.useContext(RouteContext);
|
|
443
|
+
let routeMatch = parentMatches[parentMatches.length - 1];
|
|
444
|
+
let parentParams = routeMatch ? routeMatch.params : {};
|
|
445
|
+
let parentPathname = routeMatch ? routeMatch.pathname : "/";
|
|
446
|
+
let parentPathnameBase = routeMatch ? routeMatch.pathnameBase : "/";
|
|
447
|
+
let parentRoute = routeMatch && routeMatch.route;
|
|
449
448
|
|
|
450
449
|
{
|
|
451
450
|
// You won't get a warning about 2 different <Routes> under a <Route>
|
|
@@ -473,21 +472,34 @@
|
|
|
473
472
|
}
|
|
474
473
|
|
|
475
474
|
let locationFromContext = useLocation();
|
|
476
|
-
let location
|
|
475
|
+
let location;
|
|
476
|
+
|
|
477
|
+
if (locationArg) {
|
|
478
|
+
var _parsedLocationArg$pa;
|
|
479
|
+
|
|
480
|
+
let parsedLocationArg = typeof locationArg === "string" ? history.parsePath(locationArg) : locationArg;
|
|
481
|
+
!(parentPathnameBase === "/" || ((_parsedLocationArg$pa = parsedLocationArg.pathname) == null ? void 0 : _parsedLocationArg$pa.startsWith(parentPathnameBase))) ? invariant(false, "When overriding the location using `<Routes location>` or `useRoutes(routes, location)`, " + "the location pathname must begin with the portion of the URL pathname that was " + ("matched by all parent routes. The current pathname base is \"" + parentPathnameBase + "\" ") + ("but pathname \"" + parsedLocationArg.pathname + "\" was given in the `location` prop.")) : void 0;
|
|
482
|
+
location = parsedLocationArg;
|
|
483
|
+
} else {
|
|
484
|
+
location = locationFromContext;
|
|
485
|
+
}
|
|
486
|
+
|
|
477
487
|
let pathname = location.pathname || "/";
|
|
478
|
-
let
|
|
479
|
-
let remainingPathname = parentPathnameStart === "/" ? pathname : pathname.slice(parentPathnameStart.length);
|
|
488
|
+
let remainingPathname = parentPathnameBase === "/" ? pathname : pathname.slice(parentPathnameBase.length) || "/";
|
|
480
489
|
let matches = matchRoutes(routes, {
|
|
481
490
|
pathname: remainingPathname
|
|
482
491
|
});
|
|
483
492
|
|
|
484
493
|
{
|
|
485
494
|
warning(parentRoute || matches != null, "No routes matched location \"" + location.pathname + location.search + location.hash + "\" ") ;
|
|
495
|
+
warning(matches == null || matches[matches.length - 1].route.element !== undefined, "Matched leaf route at location \"" + location.pathname + location.search + location.hash + "\" does not have an element. " + "This means it will render an <Outlet /> with a null value by default resulting in an \"empty\" page.") ;
|
|
486
496
|
}
|
|
487
497
|
|
|
488
|
-
return
|
|
489
|
-
|
|
490
|
-
|
|
498
|
+
return _renderMatches(matches && matches.map(match => Object.assign({}, match, {
|
|
499
|
+
params: Object.assign({}, parentParams, match.params),
|
|
500
|
+
pathname: joinPaths([parentPathnameBase, match.pathname]),
|
|
501
|
+
pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : joinPaths([parentPathnameBase, match.pathnameBase])
|
|
502
|
+
})), parentMatches);
|
|
491
503
|
} ///////////////////////////////////////////////////////////////////////////////
|
|
492
504
|
// UTILS
|
|
493
505
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -516,10 +528,10 @@
|
|
|
516
528
|
}
|
|
517
529
|
|
|
518
530
|
let route = {
|
|
519
|
-
path: element.props.path,
|
|
520
531
|
caseSensitive: element.props.caseSensitive,
|
|
532
|
+
element: element.props.element,
|
|
521
533
|
index: element.props.index,
|
|
522
|
-
|
|
534
|
+
path: element.props.path
|
|
523
535
|
};
|
|
524
536
|
|
|
525
537
|
if (element.props.children) {
|
|
@@ -530,12 +542,15 @@
|
|
|
530
542
|
});
|
|
531
543
|
return routes;
|
|
532
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* The parameters that were parsed from the URL path.
|
|
547
|
+
*/
|
|
548
|
+
|
|
533
549
|
/**
|
|
534
550
|
* Returns a path with params interpolated.
|
|
535
551
|
*
|
|
536
552
|
* @see https://reactrouter.com/api/generatePath
|
|
537
553
|
*/
|
|
538
|
-
|
|
539
554
|
function generatePath(path, params) {
|
|
540
555
|
if (params === void 0) {
|
|
541
556
|
params = {};
|
|
@@ -546,12 +561,15 @@
|
|
|
546
561
|
return params[key];
|
|
547
562
|
}).replace(/\/*\*$/, _ => params["*"] == null ? "" : params["*"].replace(/^\/*/, "/"));
|
|
548
563
|
}
|
|
564
|
+
/**
|
|
565
|
+
* A RouteMatch contains info about how a route matched a URL.
|
|
566
|
+
*/
|
|
567
|
+
|
|
549
568
|
/**
|
|
550
569
|
* Matches the given routes to a location and returns the match data.
|
|
551
570
|
*
|
|
552
571
|
* @see https://reactrouter.com/api/matchRoutes
|
|
553
572
|
*/
|
|
554
|
-
|
|
555
573
|
function matchRoutes(routes, locationArg, basename) {
|
|
556
574
|
if (basename === void 0) {
|
|
557
575
|
basename = "/";
|
|
@@ -608,11 +626,17 @@
|
|
|
608
626
|
if (route.children && route.children.length > 0) {
|
|
609
627
|
!(route.index !== true) ? invariant(false, "Index routes must not have child routes. Please remove " + ("all child routes from route path \"" + path + "\".")) : void 0;
|
|
610
628
|
flattenRoutes(route.children, branches, routesMeta, path);
|
|
629
|
+
} // Routes without a path shouldn't ever match by themselves unless they are
|
|
630
|
+
// index routes, so don't add them to the list of possible branches.
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
if (route.path == null && !route.index) {
|
|
634
|
+
return;
|
|
611
635
|
}
|
|
612
636
|
|
|
613
637
|
branches.push({
|
|
614
638
|
path,
|
|
615
|
-
score: computeScore(path),
|
|
639
|
+
score: computeScore(path, route.index),
|
|
616
640
|
routesMeta
|
|
617
641
|
});
|
|
618
642
|
});
|
|
@@ -625,14 +649,15 @@
|
|
|
625
649
|
}
|
|
626
650
|
|
|
627
651
|
const paramRe = /^:\w+$/;
|
|
628
|
-
const dynamicSegmentValue =
|
|
652
|
+
const dynamicSegmentValue = 3;
|
|
653
|
+
const indexRouteValue = 2;
|
|
629
654
|
const emptySegmentValue = 1;
|
|
630
655
|
const staticSegmentValue = 10;
|
|
631
656
|
const splatPenalty = -2;
|
|
632
657
|
|
|
633
658
|
const isSplat = s => s === "*";
|
|
634
659
|
|
|
635
|
-
function computeScore(path) {
|
|
660
|
+
function computeScore(path, index) {
|
|
636
661
|
let segments = path.split("/");
|
|
637
662
|
let initialScore = segments.length;
|
|
638
663
|
|
|
@@ -640,6 +665,10 @@
|
|
|
640
665
|
initialScore += splatPenalty;
|
|
641
666
|
}
|
|
642
667
|
|
|
668
|
+
if (index) {
|
|
669
|
+
initialScore += indexRouteValue;
|
|
670
|
+
}
|
|
671
|
+
|
|
643
672
|
return segments.filter(s => !isSplat(s)).reduce((score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue), initialScore);
|
|
644
673
|
}
|
|
645
674
|
|
|
@@ -654,7 +683,8 @@
|
|
|
654
683
|
0;
|
|
655
684
|
}
|
|
656
685
|
|
|
657
|
-
function matchRouteBranch(branch,
|
|
686
|
+
function matchRouteBranch(branch, // TODO: attach original route object inside routesMeta so we don't need this arg
|
|
687
|
+
routesArg, pathname) {
|
|
658
688
|
let routes = routesArg;
|
|
659
689
|
let {
|
|
660
690
|
routesMeta
|
|
@@ -665,27 +695,25 @@
|
|
|
665
695
|
|
|
666
696
|
for (let i = 0; i < routesMeta.length; ++i) {
|
|
667
697
|
let meta = routesMeta[i];
|
|
668
|
-
let
|
|
698
|
+
let end = i === routesMeta.length - 1;
|
|
699
|
+
let remainingPathname = matchedPathname === "/" ? pathname : pathname.slice(matchedPathname.length) || "/";
|
|
669
700
|
let match = matchPath({
|
|
670
701
|
path: meta.relativePath,
|
|
671
702
|
caseSensitive: meta.caseSensitive,
|
|
672
|
-
end
|
|
673
|
-
},
|
|
703
|
+
end
|
|
704
|
+
}, remainingPathname);
|
|
674
705
|
if (!match) return null;
|
|
675
706
|
Object.assign(matchedParams, match.params);
|
|
676
707
|
let route = routes[meta.childrenIndex];
|
|
677
708
|
matches.push({
|
|
678
709
|
params: matchedParams,
|
|
679
|
-
pathname:
|
|
710
|
+
pathname: joinPaths([matchedPathname, match.pathname]),
|
|
711
|
+
pathnameBase: joinPaths([matchedPathname, match.pathnameBase]),
|
|
680
712
|
route
|
|
681
713
|
});
|
|
682
|
-
let pathnameStart = getPathnameStart(match.pathname, match.params);
|
|
683
714
|
|
|
684
|
-
if (
|
|
685
|
-
|
|
686
|
-
// the matchedPathname. This allows child routes to match against the
|
|
687
|
-
// portion of the pathname that was matched by the *.
|
|
688
|
-
matchedPathname = joinPaths([matchedPathname, pathnameStart]);
|
|
715
|
+
if (match.pathnameBase !== "/") {
|
|
716
|
+
matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
|
|
689
717
|
}
|
|
690
718
|
|
|
691
719
|
routes = route.children;
|
|
@@ -699,26 +727,36 @@
|
|
|
699
727
|
|
|
700
728
|
|
|
701
729
|
function renderMatches(matches) {
|
|
730
|
+
return _renderMatches(matches);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
function _renderMatches(matches, parentMatches) {
|
|
734
|
+
if (parentMatches === void 0) {
|
|
735
|
+
parentMatches = [];
|
|
736
|
+
}
|
|
737
|
+
|
|
702
738
|
if (matches == null) return null;
|
|
703
|
-
return matches.reduceRight((outlet, match) => {
|
|
739
|
+
return matches.reduceRight((outlet, match, index) => {
|
|
704
740
|
return /*#__PURE__*/React.createElement(RouteContext.Provider, {
|
|
705
|
-
children: match.route.element
|
|
741
|
+
children: match.route.element !== undefined ? match.route.element : /*#__PURE__*/React.createElement(Outlet, null),
|
|
706
742
|
value: {
|
|
707
743
|
outlet,
|
|
708
|
-
|
|
709
|
-
pathname: match.pathname,
|
|
710
|
-
route: match.route
|
|
744
|
+
matches: parentMatches.concat(matches.slice(0, index + 1))
|
|
711
745
|
}
|
|
712
746
|
});
|
|
713
747
|
}, null);
|
|
714
748
|
}
|
|
749
|
+
/**
|
|
750
|
+
* A PathPattern is used to match on some portion of a URL pathname.
|
|
751
|
+
*/
|
|
752
|
+
|
|
753
|
+
|
|
715
754
|
/**
|
|
716
755
|
* Performs pattern matching on a URL pathname and returns information about
|
|
717
756
|
* the match.
|
|
718
757
|
*
|
|
719
758
|
* @see https://reactrouter.com/api/matchPath
|
|
720
759
|
*/
|
|
721
|
-
|
|
722
760
|
function matchPath(pattern, pathname) {
|
|
723
761
|
if (typeof pattern === "string") {
|
|
724
762
|
pattern = {
|
|
@@ -732,14 +770,23 @@
|
|
|
732
770
|
let match = pathname.match(matcher);
|
|
733
771
|
if (!match) return null;
|
|
734
772
|
let matchedPathname = match[0];
|
|
735
|
-
let
|
|
773
|
+
let pathnameBase = matchedPathname.replace(/(.)\/+$/, "$1");
|
|
774
|
+
let captureGroups = match.slice(1);
|
|
736
775
|
let params = paramNames.reduce((memo, paramName, index) => {
|
|
737
|
-
|
|
776
|
+
// We need to compute the pathnameBase here using the raw splat value
|
|
777
|
+
// instead of using params["*"] later because it will be decoded then
|
|
778
|
+
if (paramName === "*") {
|
|
779
|
+
let splatValue = captureGroups[index] || "";
|
|
780
|
+
pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length).replace(/(.)\/+$/, "$1");
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
memo[paramName] = safelyDecodeURIComponent(captureGroups[index] || "", paramName);
|
|
738
784
|
return memo;
|
|
739
785
|
}, {});
|
|
740
786
|
return {
|
|
741
787
|
params,
|
|
742
788
|
pathname: matchedPathname,
|
|
789
|
+
pathnameBase,
|
|
743
790
|
pattern
|
|
744
791
|
};
|
|
745
792
|
}
|
|
@@ -753,35 +800,30 @@
|
|
|
753
800
|
end = true;
|
|
754
801
|
}
|
|
755
802
|
|
|
756
|
-
|
|
757
|
-
let
|
|
803
|
+
warning(path === "*" || !path.endsWith("*") || path.endsWith("/*"), "Route path \"" + path + "\" will be treated as if it were " + ("\"" + path.replace(/\*$/, "/*") + "\" because the `*` character must ") + "always follow a `/` in the pattern. To get rid of this warning, " + ("please change the route path to \"" + path.replace(/\*$/, "/*") + "\".")) ;
|
|
804
|
+
let paramNames = [];
|
|
805
|
+
let regexpSource = "^" + path.replace(/\/*\*?$/, "") // Ignore trailing / and /*, we'll handle it below
|
|
758
806
|
.replace(/^\/*/, "/") // Make sure it has a leading /
|
|
759
807
|
.replace(/[\\.*+^$?{}|()[\]]/g, "\\$&") // Escape special regex chars
|
|
760
|
-
.replace(/:(\w+)/g, (_,
|
|
761
|
-
|
|
808
|
+
.replace(/:(\w+)/g, (_, paramName) => {
|
|
809
|
+
paramNames.push(paramName);
|
|
762
810
|
return "([^\\/]+)";
|
|
763
811
|
});
|
|
764
812
|
|
|
765
813
|
if (path.endsWith("*")) {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
source += "(.*)$";
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
keys.push("*");
|
|
773
|
-
} else if (end) {
|
|
774
|
-
// When matching to the end, ignore trailing slashes.
|
|
775
|
-
source += "\\/?$";
|
|
814
|
+
paramNames.push("*");
|
|
815
|
+
regexpSource += path === "*" || path === "/*" ? "(.*)$" // Already matched the initial /, just match the rest
|
|
816
|
+
: "(?:\\/(.+)|\\/*)$"; // Don't include the / in params["*"]
|
|
776
817
|
} else {
|
|
777
|
-
//
|
|
778
|
-
//
|
|
779
|
-
// and nothing more, e.g. parent
|
|
780
|
-
|
|
818
|
+
regexpSource += end ? "\\/*$" // When matching to the end, ignore trailing slashes
|
|
819
|
+
: // Otherwise, at least match a word boundary. This restricts parent
|
|
820
|
+
// routes to matching only their own words and nothing more, e.g. parent
|
|
821
|
+
// route "/home" should not match "/home2".
|
|
822
|
+
"(?:\\b|$)";
|
|
781
823
|
}
|
|
782
824
|
|
|
783
|
-
let matcher = new RegExp(
|
|
784
|
-
return [matcher,
|
|
825
|
+
let matcher = new RegExp(regexpSource, caseSensitive ? undefined : "i");
|
|
826
|
+
return [matcher, paramNames];
|
|
785
827
|
}
|
|
786
828
|
|
|
787
829
|
function safelyDecodeURIComponent(value, paramName) {
|
|
@@ -831,17 +873,48 @@
|
|
|
831
873
|
return segments.length > 1 ? segments.join("/") : "/";
|
|
832
874
|
}
|
|
833
875
|
|
|
834
|
-
function resolveTo(
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
// `<Link to>` values` in our
|
|
838
|
-
// disambiguation between `to` values
|
|
839
|
-
// that do not. However, this is problematic for
|
|
840
|
-
// not provide a pathname. `to` can simply be a search or
|
|
841
|
-
// string, in which case we should assume that the navigation is
|
|
842
|
-
//
|
|
843
|
-
|
|
844
|
-
|
|
876
|
+
function resolveTo(toArg, routePathnames, locationPathname) {
|
|
877
|
+
let to = typeof toArg === "string" ? history.parsePath(toArg) : toArg;
|
|
878
|
+
let toPathname = toArg === "" || to.pathname === "" ? "/" : to.pathname; // If a pathname is explicitly provided in `to`, it should be relative to the
|
|
879
|
+
// route context. This is explained in `Note on `<Link to>` values` in our
|
|
880
|
+
// migration guide from v5 as a means of disambiguation between `to` values
|
|
881
|
+
// that begin with `/` and those that do not. However, this is problematic for
|
|
882
|
+
// `to` values that do not provide a pathname. `to` can simply be a search or
|
|
883
|
+
// hash string, in which case we should assume that the navigation is relative
|
|
884
|
+
// to the current location's pathname and *not* the route pathname.
|
|
885
|
+
|
|
886
|
+
let from;
|
|
887
|
+
|
|
888
|
+
if (toPathname == null) {
|
|
889
|
+
from = locationPathname;
|
|
890
|
+
} else {
|
|
891
|
+
let routePathnameIndex = routePathnames.length - 1;
|
|
892
|
+
|
|
893
|
+
if (toPathname.startsWith("..")) {
|
|
894
|
+
let toSegments = toPathname.split("/"); // Each leading .. segment means "go up one route" instead of "go up one
|
|
895
|
+
// URL segment". This is a key difference from how <a href> works and a
|
|
896
|
+
// major reason we call this a "to" value instead of a "href".
|
|
897
|
+
|
|
898
|
+
while (toSegments[0] === "..") {
|
|
899
|
+
toSegments.shift();
|
|
900
|
+
routePathnameIndex -= 1;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
to.pathname = toSegments.join("/");
|
|
904
|
+
} // If there are more ".." segments than parent routes, resolve relative to
|
|
905
|
+
// the root / URL.
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
let path = resolvePath(to, from); // Ensure the pathname has a trailing slash if the original to value had one.
|
|
912
|
+
|
|
913
|
+
if (toPathname && toPathname !== "/" && toPathname.endsWith("/") && !path.pathname.endsWith("/")) {
|
|
914
|
+
path.pathname += "/";
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
return path;
|
|
845
918
|
}
|
|
846
919
|
|
|
847
920
|
function getToPathname(to) {
|
|
@@ -849,16 +922,6 @@
|
|
|
849
922
|
return to === "" || to.pathname === "" ? "/" : typeof to === "string" ? history.parsePath(to).pathname : to.pathname;
|
|
850
923
|
}
|
|
851
924
|
|
|
852
|
-
function getPathnameStart(pathname, params) {
|
|
853
|
-
let splat = params["*"];
|
|
854
|
-
if (!splat) return pathname;
|
|
855
|
-
let pathnameStart = pathname.slice(0, -splat.length);
|
|
856
|
-
if (splat.startsWith("/")) return pathnameStart;
|
|
857
|
-
let index = pathnameStart.lastIndexOf("/");
|
|
858
|
-
if (index > 0) return pathnameStart.slice(0, index);
|
|
859
|
-
return "/";
|
|
860
|
-
}
|
|
861
|
-
|
|
862
925
|
function stripBasename(pathname, basename) {
|
|
863
926
|
if (basename === "/") return pathname;
|
|
864
927
|
|
|
@@ -899,12 +962,12 @@
|
|
|
899
962
|
exports.matchRoutes = matchRoutes;
|
|
900
963
|
exports.renderMatches = renderMatches;
|
|
901
964
|
exports.resolvePath = resolvePath;
|
|
902
|
-
exports.useBlocker = useBlocker;
|
|
903
965
|
exports.useHref = useHref;
|
|
904
966
|
exports.useInRouterContext = useInRouterContext;
|
|
905
967
|
exports.useLocation = useLocation;
|
|
906
968
|
exports.useMatch = useMatch;
|
|
907
969
|
exports.useNavigate = useNavigate;
|
|
970
|
+
exports.useNavigationType = useNavigationType;
|
|
908
971
|
exports.useOutlet = useOutlet;
|
|
909
972
|
exports.useParams = useParams;
|
|
910
973
|
exports.useResolvedPath = useResolvedPath;
|