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,3 +1,13 @@
|
|
|
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
|
import { createContext, useRef, useState, useLayoutEffect, createElement, useContext, useEffect, useMemo, useCallback, Children, isValidElement, Fragment } from 'react';
|
|
2
12
|
import { createMemoryHistory, Action, parsePath } from 'history';
|
|
3
13
|
|
|
@@ -28,7 +38,20 @@ function warningOnce(key, cond, message) {
|
|
|
28
38
|
alreadyWarned[key] = true;
|
|
29
39
|
warning(false, message) ;
|
|
30
40
|
}
|
|
31
|
-
}
|
|
41
|
+
} ///////////////////////////////////////////////////////////////////////////////
|
|
42
|
+
// CONTEXT
|
|
43
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A Navigator is a "location changer"; it's how you get to different locations.
|
|
47
|
+
*
|
|
48
|
+
* Every history instance conforms to the Navigator interface, but the
|
|
49
|
+
* distinction is useful primarily when it comes to the low-level <Router> API
|
|
50
|
+
* where both the location and a navigator must be provided separately in order
|
|
51
|
+
* to avoid "tearing" that may occur in a suspense-enabled app if the action
|
|
52
|
+
* and/or location were to be read directly from the history instance.
|
|
53
|
+
*/
|
|
54
|
+
|
|
32
55
|
|
|
33
56
|
const NavigationContext = /*#__PURE__*/createContext(null);
|
|
34
57
|
|
|
@@ -44,21 +67,21 @@ const LocationContext = /*#__PURE__*/createContext(null);
|
|
|
44
67
|
|
|
45
68
|
const RouteContext = /*#__PURE__*/createContext({
|
|
46
69
|
outlet: null,
|
|
47
|
-
|
|
48
|
-
pathname: "/",
|
|
49
|
-
route: null
|
|
70
|
+
matches: []
|
|
50
71
|
});
|
|
51
72
|
|
|
52
73
|
{
|
|
53
74
|
RouteContext.displayName = "Route";
|
|
54
|
-
}
|
|
75
|
+
} ///////////////////////////////////////////////////////////////////////////////
|
|
76
|
+
// COMPONENTS
|
|
77
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
78
|
+
|
|
79
|
+
|
|
55
80
|
/**
|
|
56
81
|
* A <Router> that stores all entries in memory.
|
|
57
82
|
*
|
|
58
83
|
* @see https://reactrouter.com/api/MemoryRouter
|
|
59
84
|
*/
|
|
60
|
-
|
|
61
|
-
|
|
62
85
|
function MemoryRouter({
|
|
63
86
|
basename,
|
|
64
87
|
children,
|
|
@@ -83,11 +106,12 @@ function MemoryRouter({
|
|
|
83
106
|
return /*#__PURE__*/createElement(Router, {
|
|
84
107
|
basename: basename,
|
|
85
108
|
children: children,
|
|
86
|
-
action: state.action,
|
|
87
109
|
location: state.location,
|
|
110
|
+
navigationType: state.action,
|
|
88
111
|
navigator: history
|
|
89
112
|
});
|
|
90
113
|
}
|
|
114
|
+
|
|
91
115
|
/**
|
|
92
116
|
* Changes the current location.
|
|
93
117
|
*
|
|
@@ -97,7 +121,6 @@ function MemoryRouter({
|
|
|
97
121
|
*
|
|
98
122
|
* @see https://reactrouter.com/api/Navigate
|
|
99
123
|
*/
|
|
100
|
-
|
|
101
124
|
function Navigate({
|
|
102
125
|
to,
|
|
103
126
|
replace,
|
|
@@ -116,24 +139,25 @@ function Navigate({
|
|
|
116
139
|
});
|
|
117
140
|
return null;
|
|
118
141
|
}
|
|
142
|
+
|
|
119
143
|
/**
|
|
120
144
|
* Renders the child route's element, if there is one.
|
|
121
145
|
*
|
|
122
146
|
* @see https://reactrouter.com/api/Outlet
|
|
123
147
|
*/
|
|
124
|
-
|
|
125
148
|
function Outlet(_props) {
|
|
126
149
|
return useOutlet();
|
|
127
150
|
}
|
|
151
|
+
|
|
128
152
|
/**
|
|
129
153
|
* Declares an element that should be rendered at a certain URL path.
|
|
130
154
|
*
|
|
131
155
|
* @see https://reactrouter.com/api/Route
|
|
132
156
|
*/
|
|
133
|
-
|
|
134
157
|
function Route(_props) {
|
|
135
158
|
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>.`) ;
|
|
136
159
|
}
|
|
160
|
+
|
|
137
161
|
/**
|
|
138
162
|
* Provides location context for the rest of the app.
|
|
139
163
|
*
|
|
@@ -143,12 +167,11 @@ function Route(_props) {
|
|
|
143
167
|
*
|
|
144
168
|
* @see https://reactrouter.com/api/Router
|
|
145
169
|
*/
|
|
146
|
-
|
|
147
170
|
function Router({
|
|
148
|
-
action = Action.Pop,
|
|
149
171
|
basename: basenameProp = "/",
|
|
150
172
|
children = null,
|
|
151
173
|
location: locationProp,
|
|
174
|
+
navigationType = Action.Pop,
|
|
152
175
|
navigator,
|
|
153
176
|
static: staticProp = false
|
|
154
177
|
}) {
|
|
@@ -197,18 +220,18 @@ function Router({
|
|
|
197
220
|
}, /*#__PURE__*/createElement(LocationContext.Provider, {
|
|
198
221
|
children: children,
|
|
199
222
|
value: {
|
|
200
|
-
|
|
201
|
-
|
|
223
|
+
location,
|
|
224
|
+
navigationType
|
|
202
225
|
}
|
|
203
226
|
}));
|
|
204
227
|
}
|
|
228
|
+
|
|
205
229
|
/**
|
|
206
230
|
* A container for a nested tree of <Route> elements that renders the branch
|
|
207
231
|
* that best matches the current location.
|
|
208
232
|
*
|
|
209
233
|
* @see https://reactrouter.com/api/Routes
|
|
210
234
|
*/
|
|
211
|
-
|
|
212
235
|
function Routes({
|
|
213
236
|
children,
|
|
214
237
|
location
|
|
@@ -218,39 +241,6 @@ function Routes({
|
|
|
218
241
|
// HOOKS
|
|
219
242
|
///////////////////////////////////////////////////////////////////////////////
|
|
220
243
|
|
|
221
|
-
/**
|
|
222
|
-
* Blocks all navigation attempts. This is useful for preventing the page from
|
|
223
|
-
* changing until some condition is met, like saving form data.
|
|
224
|
-
*
|
|
225
|
-
* @see https://reactrouter.com/api/useBlocker
|
|
226
|
-
*/
|
|
227
|
-
|
|
228
|
-
function useBlocker(blocker, when = true) {
|
|
229
|
-
!useInRouterContext() ? invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
|
230
|
-
// router loaded. We can help them understand how to avoid that.
|
|
231
|
-
`useBlocker() may be used only in the context of a <Router> component.`) : void 0;
|
|
232
|
-
let {
|
|
233
|
-
navigator
|
|
234
|
-
} = useContext(NavigationContext);
|
|
235
|
-
useEffect(() => {
|
|
236
|
-
if (!when) return;
|
|
237
|
-
let unblock = navigator.block(tx => {
|
|
238
|
-
let autoUnblockingTx = { ...tx,
|
|
239
|
-
|
|
240
|
-
retry() {
|
|
241
|
-
// Automatically unblock the transition so it can play all the way
|
|
242
|
-
// through before retrying it. TODO: Figure out how to re-enable
|
|
243
|
-
// this block if the transition is cancelled for some reason.
|
|
244
|
-
unblock();
|
|
245
|
-
tx.retry();
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
};
|
|
249
|
-
blocker(autoUnblockingTx);
|
|
250
|
-
});
|
|
251
|
-
return unblock;
|
|
252
|
-
}, [navigator, blocker, when]);
|
|
253
|
-
}
|
|
254
244
|
/**
|
|
255
245
|
* Returns the full href for the given "to" value. This is useful for building
|
|
256
246
|
* custom links that are also accessible and preserve right-click behavior.
|
|
@@ -266,15 +256,24 @@ function useHref(to) {
|
|
|
266
256
|
basename,
|
|
267
257
|
navigator
|
|
268
258
|
} = useContext(NavigationContext);
|
|
269
|
-
let
|
|
259
|
+
let {
|
|
260
|
+
hash,
|
|
261
|
+
pathname,
|
|
262
|
+
search
|
|
263
|
+
} = useResolvedPath(to);
|
|
264
|
+
let joinedPathname = pathname;
|
|
270
265
|
|
|
271
266
|
if (basename !== "/") {
|
|
272
267
|
let toPathname = getToPathname(to);
|
|
273
268
|
let endsWithSlash = toPathname != null && toPathname.endsWith("/");
|
|
274
|
-
|
|
269
|
+
joinedPathname = pathname === "/" ? basename + (endsWithSlash ? "/" : "") : joinPaths([basename, pathname]);
|
|
275
270
|
}
|
|
276
271
|
|
|
277
|
-
return navigator.createHref(
|
|
272
|
+
return navigator.createHref({
|
|
273
|
+
pathname: joinedPathname,
|
|
274
|
+
search,
|
|
275
|
+
hash
|
|
276
|
+
});
|
|
278
277
|
}
|
|
279
278
|
/**
|
|
280
279
|
* Returns true if this component is a descendant of a <Router>.
|
|
@@ -302,6 +301,16 @@ function useLocation() {
|
|
|
302
301
|
`useLocation() may be used only in the context of a <Router> component.`) : void 0;
|
|
303
302
|
return useContext(LocationContext).location;
|
|
304
303
|
}
|
|
304
|
+
/**
|
|
305
|
+
* Returns the current navigation action which describes how the router came to
|
|
306
|
+
* the current location, either by a pop, push, or replace on the history stack.
|
|
307
|
+
*
|
|
308
|
+
* @see https://reactrouter.com/api/useNavigationType
|
|
309
|
+
*/
|
|
310
|
+
|
|
311
|
+
function useNavigationType() {
|
|
312
|
+
return useContext(LocationContext).navigationType;
|
|
313
|
+
}
|
|
305
314
|
/**
|
|
306
315
|
* Returns true if the URL for the given "to" value matches the current URL.
|
|
307
316
|
* This is useful for components that need to know "active" state, e.g.
|
|
@@ -316,13 +325,16 @@ function useMatch(pattern) {
|
|
|
316
325
|
`useMatch() may be used only in the context of a <Router> component.`) : void 0;
|
|
317
326
|
return matchPath(pattern, useLocation().pathname);
|
|
318
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
* The interface for the navigate() function returned from useNavigate().
|
|
330
|
+
*/
|
|
331
|
+
|
|
319
332
|
/**
|
|
320
333
|
* Returns an imperative method for changing the location. Used by <Link>s, but
|
|
321
334
|
* may also be used by other elements to change the location.
|
|
322
335
|
*
|
|
323
336
|
* @see https://reactrouter.com/api/useNavigate
|
|
324
337
|
*/
|
|
325
|
-
|
|
326
338
|
function useNavigate() {
|
|
327
339
|
!useInRouterContext() ? invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
|
328
340
|
// router loaded. We can help them understand how to avoid that.
|
|
@@ -332,11 +344,12 @@ function useNavigate() {
|
|
|
332
344
|
navigator
|
|
333
345
|
} = useContext(NavigationContext);
|
|
334
346
|
let {
|
|
335
|
-
|
|
347
|
+
matches
|
|
336
348
|
} = useContext(RouteContext);
|
|
337
349
|
let {
|
|
338
350
|
pathname: locationPathname
|
|
339
351
|
} = useLocation();
|
|
352
|
+
let routePathnamesJson = JSON.stringify(matches.map(match => match.pathnameBase));
|
|
340
353
|
let activeRef = useRef(false);
|
|
341
354
|
useEffect(() => {
|
|
342
355
|
activeRef.current = true;
|
|
@@ -350,14 +363,14 @@ function useNavigate() {
|
|
|
350
363
|
return;
|
|
351
364
|
}
|
|
352
365
|
|
|
353
|
-
let path = resolveTo(to,
|
|
366
|
+
let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname);
|
|
354
367
|
|
|
355
368
|
if (basename !== "/") {
|
|
356
369
|
path.pathname = joinPaths([basename, path.pathname]);
|
|
357
370
|
}
|
|
358
371
|
|
|
359
372
|
(!!options.replace ? navigator.replace : navigator.push)(path, options.state);
|
|
360
|
-
}, [basename, navigator,
|
|
373
|
+
}, [basename, navigator, routePathnamesJson, locationPathname]);
|
|
361
374
|
return navigate;
|
|
362
375
|
}
|
|
363
376
|
/**
|
|
@@ -378,7 +391,11 @@ function useOutlet() {
|
|
|
378
391
|
*/
|
|
379
392
|
|
|
380
393
|
function useParams() {
|
|
381
|
-
|
|
394
|
+
let {
|
|
395
|
+
matches
|
|
396
|
+
} = useContext(RouteContext);
|
|
397
|
+
let routeMatch = matches[matches.length - 1];
|
|
398
|
+
return routeMatch ? routeMatch.params : {};
|
|
382
399
|
}
|
|
383
400
|
/**
|
|
384
401
|
* Resolves the pathname of the given `to` value against the current location.
|
|
@@ -387,13 +404,14 @@ function useParams() {
|
|
|
387
404
|
*/
|
|
388
405
|
|
|
389
406
|
function useResolvedPath(to) {
|
|
407
|
+
let {
|
|
408
|
+
matches
|
|
409
|
+
} = useContext(RouteContext);
|
|
390
410
|
let {
|
|
391
411
|
pathname: locationPathname
|
|
392
412
|
} = useLocation();
|
|
393
|
-
let
|
|
394
|
-
|
|
395
|
-
} = useContext(RouteContext);
|
|
396
|
-
return useMemo(() => resolveTo(to, routePathname, locationPathname), [to, routePathname, locationPathname]);
|
|
413
|
+
let routePathnamesJson = JSON.stringify(matches.map(match => match.pathnameBase));
|
|
414
|
+
return useMemo(() => resolveTo(to, JSON.parse(routePathnamesJson), locationPathname), [to, routePathnamesJson, locationPathname]);
|
|
397
415
|
}
|
|
398
416
|
/**
|
|
399
417
|
* Returns the element of the route that matched the current location, prepared
|
|
@@ -409,10 +427,13 @@ function useRoutes(routes, locationArg) {
|
|
|
409
427
|
// router loaded. We can help them understand how to avoid that.
|
|
410
428
|
`useRoutes() may be used only in the context of a <Router> component.`) : void 0;
|
|
411
429
|
let {
|
|
412
|
-
|
|
413
|
-
pathname: parentPathname,
|
|
414
|
-
route: parentRoute
|
|
430
|
+
matches: parentMatches
|
|
415
431
|
} = useContext(RouteContext);
|
|
432
|
+
let routeMatch = parentMatches[parentMatches.length - 1];
|
|
433
|
+
let parentParams = routeMatch ? routeMatch.params : {};
|
|
434
|
+
let parentPathname = routeMatch ? routeMatch.pathname : "/";
|
|
435
|
+
let parentPathnameBase = routeMatch ? routeMatch.pathnameBase : "/";
|
|
436
|
+
let parentRoute = routeMatch && routeMatch.route;
|
|
416
437
|
|
|
417
438
|
{
|
|
418
439
|
// You won't get a warning about 2 different <Routes> under a <Route>
|
|
@@ -440,21 +461,32 @@ function useRoutes(routes, locationArg) {
|
|
|
440
461
|
}
|
|
441
462
|
|
|
442
463
|
let locationFromContext = useLocation();
|
|
443
|
-
let location
|
|
464
|
+
let location;
|
|
465
|
+
|
|
466
|
+
if (locationArg) {
|
|
467
|
+
let parsedLocationArg = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
|
|
468
|
+
!(parentPathnameBase === "/" || parsedLocationArg.pathname?.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;
|
|
469
|
+
location = parsedLocationArg;
|
|
470
|
+
} else {
|
|
471
|
+
location = locationFromContext;
|
|
472
|
+
}
|
|
473
|
+
|
|
444
474
|
let pathname = location.pathname || "/";
|
|
445
|
-
let
|
|
446
|
-
let remainingPathname = parentPathnameStart === "/" ? pathname : pathname.slice(parentPathnameStart.length);
|
|
475
|
+
let remainingPathname = parentPathnameBase === "/" ? pathname : pathname.slice(parentPathnameBase.length) || "/";
|
|
447
476
|
let matches = matchRoutes(routes, {
|
|
448
477
|
pathname: remainingPathname
|
|
449
478
|
});
|
|
450
479
|
|
|
451
480
|
{
|
|
452
481
|
warning(parentRoute || matches != null, `No routes matched location "${location.pathname}${location.search}${location.hash}" `) ;
|
|
482
|
+
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.`) ;
|
|
453
483
|
}
|
|
454
484
|
|
|
455
|
-
return
|
|
456
|
-
|
|
457
|
-
|
|
485
|
+
return _renderMatches(matches && matches.map(match => Object.assign({}, match, {
|
|
486
|
+
params: Object.assign({}, parentParams, match.params),
|
|
487
|
+
pathname: joinPaths([parentPathnameBase, match.pathname]),
|
|
488
|
+
pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : joinPaths([parentPathnameBase, match.pathnameBase])
|
|
489
|
+
})), parentMatches);
|
|
458
490
|
} ///////////////////////////////////////////////////////////////////////////////
|
|
459
491
|
// UTILS
|
|
460
492
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -483,10 +515,10 @@ function createRoutesFromChildren(children) {
|
|
|
483
515
|
}
|
|
484
516
|
|
|
485
517
|
let route = {
|
|
486
|
-
path: element.props.path,
|
|
487
518
|
caseSensitive: element.props.caseSensitive,
|
|
519
|
+
element: element.props.element,
|
|
488
520
|
index: element.props.index,
|
|
489
|
-
|
|
521
|
+
path: element.props.path
|
|
490
522
|
};
|
|
491
523
|
|
|
492
524
|
if (element.props.children) {
|
|
@@ -497,24 +529,30 @@ function createRoutesFromChildren(children) {
|
|
|
497
529
|
});
|
|
498
530
|
return routes;
|
|
499
531
|
}
|
|
532
|
+
/**
|
|
533
|
+
* The parameters that were parsed from the URL path.
|
|
534
|
+
*/
|
|
535
|
+
|
|
500
536
|
/**
|
|
501
537
|
* Returns a path with params interpolated.
|
|
502
538
|
*
|
|
503
539
|
* @see https://reactrouter.com/api/generatePath
|
|
504
540
|
*/
|
|
505
|
-
|
|
506
541
|
function generatePath(path, params = {}) {
|
|
507
542
|
return path.replace(/:(\w+)/g, (_, key) => {
|
|
508
543
|
!(params[key] != null) ? invariant(false, `Missing ":${key}" param`) : void 0;
|
|
509
544
|
return params[key];
|
|
510
545
|
}).replace(/\/*\*$/, _ => params["*"] == null ? "" : params["*"].replace(/^\/*/, "/"));
|
|
511
546
|
}
|
|
547
|
+
/**
|
|
548
|
+
* A RouteMatch contains info about how a route matched a URL.
|
|
549
|
+
*/
|
|
550
|
+
|
|
512
551
|
/**
|
|
513
552
|
* Matches the given routes to a location and returns the match data.
|
|
514
553
|
*
|
|
515
554
|
* @see https://reactrouter.com/api/matchRoutes
|
|
516
555
|
*/
|
|
517
|
-
|
|
518
556
|
function matchRoutes(routes, locationArg, basename = "/") {
|
|
519
557
|
let location = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
|
|
520
558
|
let pathname = stripBasename(location.pathname || "/", basename);
|
|
@@ -555,11 +593,17 @@ function flattenRoutes(routes, branches = [], parentsMeta = [], parentPath = "")
|
|
|
555
593
|
if (route.children && route.children.length > 0) {
|
|
556
594
|
!(route.index !== true) ? invariant(false, `Index routes must not have child routes. Please remove ` + `all child routes from route path "${path}".`) : void 0;
|
|
557
595
|
flattenRoutes(route.children, branches, routesMeta, path);
|
|
596
|
+
} // Routes without a path shouldn't ever match by themselves unless they are
|
|
597
|
+
// index routes, so don't add them to the list of possible branches.
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
if (route.path == null && !route.index) {
|
|
601
|
+
return;
|
|
558
602
|
}
|
|
559
603
|
|
|
560
604
|
branches.push({
|
|
561
605
|
path,
|
|
562
|
-
score: computeScore(path),
|
|
606
|
+
score: computeScore(path, route.index),
|
|
563
607
|
routesMeta
|
|
564
608
|
});
|
|
565
609
|
});
|
|
@@ -572,14 +616,15 @@ function rankRouteBranches(branches) {
|
|
|
572
616
|
}
|
|
573
617
|
|
|
574
618
|
const paramRe = /^:\w+$/;
|
|
575
|
-
const dynamicSegmentValue =
|
|
619
|
+
const dynamicSegmentValue = 3;
|
|
620
|
+
const indexRouteValue = 2;
|
|
576
621
|
const emptySegmentValue = 1;
|
|
577
622
|
const staticSegmentValue = 10;
|
|
578
623
|
const splatPenalty = -2;
|
|
579
624
|
|
|
580
625
|
const isSplat = s => s === "*";
|
|
581
626
|
|
|
582
|
-
function computeScore(path) {
|
|
627
|
+
function computeScore(path, index) {
|
|
583
628
|
let segments = path.split("/");
|
|
584
629
|
let initialScore = segments.length;
|
|
585
630
|
|
|
@@ -587,6 +632,10 @@ function computeScore(path) {
|
|
|
587
632
|
initialScore += splatPenalty;
|
|
588
633
|
}
|
|
589
634
|
|
|
635
|
+
if (index) {
|
|
636
|
+
initialScore += indexRouteValue;
|
|
637
|
+
}
|
|
638
|
+
|
|
590
639
|
return segments.filter(s => !isSplat(s)).reduce((score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue), initialScore);
|
|
591
640
|
}
|
|
592
641
|
|
|
@@ -601,7 +650,8 @@ function compareIndexes(a, b) {
|
|
|
601
650
|
0;
|
|
602
651
|
}
|
|
603
652
|
|
|
604
|
-
function matchRouteBranch(branch,
|
|
653
|
+
function matchRouteBranch(branch, // TODO: attach original route object inside routesMeta so we don't need this arg
|
|
654
|
+
routesArg, pathname) {
|
|
605
655
|
let routes = routesArg;
|
|
606
656
|
let {
|
|
607
657
|
routesMeta
|
|
@@ -612,27 +662,25 @@ function matchRouteBranch(branch, routesArg, pathname) {
|
|
|
612
662
|
|
|
613
663
|
for (let i = 0; i < routesMeta.length; ++i) {
|
|
614
664
|
let meta = routesMeta[i];
|
|
615
|
-
let
|
|
665
|
+
let end = i === routesMeta.length - 1;
|
|
666
|
+
let remainingPathname = matchedPathname === "/" ? pathname : pathname.slice(matchedPathname.length) || "/";
|
|
616
667
|
let match = matchPath({
|
|
617
668
|
path: meta.relativePath,
|
|
618
669
|
caseSensitive: meta.caseSensitive,
|
|
619
|
-
end
|
|
620
|
-
},
|
|
670
|
+
end
|
|
671
|
+
}, remainingPathname);
|
|
621
672
|
if (!match) return null;
|
|
622
673
|
Object.assign(matchedParams, match.params);
|
|
623
674
|
let route = routes[meta.childrenIndex];
|
|
624
675
|
matches.push({
|
|
625
676
|
params: matchedParams,
|
|
626
|
-
pathname:
|
|
677
|
+
pathname: joinPaths([matchedPathname, match.pathname]),
|
|
678
|
+
pathnameBase: joinPaths([matchedPathname, match.pathnameBase]),
|
|
627
679
|
route
|
|
628
680
|
});
|
|
629
|
-
let pathnameStart = getPathnameStart(match.pathname, match.params);
|
|
630
681
|
|
|
631
|
-
if (
|
|
632
|
-
|
|
633
|
-
// the matchedPathname. This allows child routes to match against the
|
|
634
|
-
// portion of the pathname that was matched by the *.
|
|
635
|
-
matchedPathname = joinPaths([matchedPathname, pathnameStart]);
|
|
682
|
+
if (match.pathnameBase !== "/") {
|
|
683
|
+
matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
|
|
636
684
|
}
|
|
637
685
|
|
|
638
686
|
routes = route.children;
|
|
@@ -646,26 +694,32 @@ function matchRouteBranch(branch, routesArg, pathname) {
|
|
|
646
694
|
|
|
647
695
|
|
|
648
696
|
function renderMatches(matches) {
|
|
697
|
+
return _renderMatches(matches);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
function _renderMatches(matches, parentMatches = []) {
|
|
649
701
|
if (matches == null) return null;
|
|
650
|
-
return matches.reduceRight((outlet, match) => {
|
|
702
|
+
return matches.reduceRight((outlet, match, index) => {
|
|
651
703
|
return /*#__PURE__*/createElement(RouteContext.Provider, {
|
|
652
|
-
children: match.route.element
|
|
704
|
+
children: match.route.element !== undefined ? match.route.element : /*#__PURE__*/createElement(Outlet, null),
|
|
653
705
|
value: {
|
|
654
706
|
outlet,
|
|
655
|
-
|
|
656
|
-
pathname: match.pathname,
|
|
657
|
-
route: match.route
|
|
707
|
+
matches: parentMatches.concat(matches.slice(0, index + 1))
|
|
658
708
|
}
|
|
659
709
|
});
|
|
660
710
|
}, null);
|
|
661
711
|
}
|
|
712
|
+
/**
|
|
713
|
+
* A PathPattern is used to match on some portion of a URL pathname.
|
|
714
|
+
*/
|
|
715
|
+
|
|
716
|
+
|
|
662
717
|
/**
|
|
663
718
|
* Performs pattern matching on a URL pathname and returns information about
|
|
664
719
|
* the match.
|
|
665
720
|
*
|
|
666
721
|
* @see https://reactrouter.com/api/matchPath
|
|
667
722
|
*/
|
|
668
|
-
|
|
669
723
|
function matchPath(pattern, pathname) {
|
|
670
724
|
if (typeof pattern === "string") {
|
|
671
725
|
pattern = {
|
|
@@ -679,48 +733,52 @@ function matchPath(pattern, pathname) {
|
|
|
679
733
|
let match = pathname.match(matcher);
|
|
680
734
|
if (!match) return null;
|
|
681
735
|
let matchedPathname = match[0];
|
|
682
|
-
let
|
|
736
|
+
let pathnameBase = matchedPathname.replace(/(.)\/+$/, "$1");
|
|
737
|
+
let captureGroups = match.slice(1);
|
|
683
738
|
let params = paramNames.reduce((memo, paramName, index) => {
|
|
684
|
-
|
|
739
|
+
// We need to compute the pathnameBase here using the raw splat value
|
|
740
|
+
// instead of using params["*"] later because it will be decoded then
|
|
741
|
+
if (paramName === "*") {
|
|
742
|
+
let splatValue = captureGroups[index] || "";
|
|
743
|
+
pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length).replace(/(.)\/+$/, "$1");
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
memo[paramName] = safelyDecodeURIComponent(captureGroups[index] || "", paramName);
|
|
685
747
|
return memo;
|
|
686
748
|
}, {});
|
|
687
749
|
return {
|
|
688
750
|
params,
|
|
689
751
|
pathname: matchedPathname,
|
|
752
|
+
pathnameBase,
|
|
690
753
|
pattern
|
|
691
754
|
};
|
|
692
755
|
}
|
|
693
756
|
|
|
694
757
|
function compilePath(path, caseSensitive = false, end = true) {
|
|
695
|
-
|
|
696
|
-
let
|
|
758
|
+
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(/\*$/, "/*")}".`) ;
|
|
759
|
+
let paramNames = [];
|
|
760
|
+
let regexpSource = "^" + path.replace(/\/*\*?$/, "") // Ignore trailing / and /*, we'll handle it below
|
|
697
761
|
.replace(/^\/*/, "/") // Make sure it has a leading /
|
|
698
762
|
.replace(/[\\.*+^$?{}|()[\]]/g, "\\$&") // Escape special regex chars
|
|
699
|
-
.replace(/:(\w+)/g, (_,
|
|
700
|
-
|
|
763
|
+
.replace(/:(\w+)/g, (_, paramName) => {
|
|
764
|
+
paramNames.push(paramName);
|
|
701
765
|
return "([^\\/]+)";
|
|
702
766
|
});
|
|
703
767
|
|
|
704
768
|
if (path.endsWith("*")) {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
source += "(.*)$";
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
keys.push("*");
|
|
712
|
-
} else if (end) {
|
|
713
|
-
// When matching to the end, ignore trailing slashes.
|
|
714
|
-
source += "\\/?$";
|
|
769
|
+
paramNames.push("*");
|
|
770
|
+
regexpSource += path === "*" || path === "/*" ? "(.*)$" // Already matched the initial /, just match the rest
|
|
771
|
+
: "(?:\\/(.+)|\\/*)$"; // Don't include the / in params["*"]
|
|
715
772
|
} else {
|
|
716
|
-
//
|
|
717
|
-
//
|
|
718
|
-
// and nothing more, e.g. parent
|
|
719
|
-
|
|
773
|
+
regexpSource += end ? "\\/*$" // When matching to the end, ignore trailing slashes
|
|
774
|
+
: // Otherwise, at least match a word boundary. This restricts parent
|
|
775
|
+
// routes to matching only their own words and nothing more, e.g. parent
|
|
776
|
+
// route "/home" should not match "/home2".
|
|
777
|
+
"(?:\\b|$)";
|
|
720
778
|
}
|
|
721
779
|
|
|
722
|
-
let matcher = new RegExp(
|
|
723
|
-
return [matcher,
|
|
780
|
+
let matcher = new RegExp(regexpSource, caseSensitive ? undefined : "i");
|
|
781
|
+
return [matcher, paramNames];
|
|
724
782
|
}
|
|
725
783
|
|
|
726
784
|
function safelyDecodeURIComponent(value, paramName) {
|
|
@@ -766,17 +824,48 @@ function resolvePathname(relativePath, fromPathname) {
|
|
|
766
824
|
return segments.length > 1 ? segments.join("/") : "/";
|
|
767
825
|
}
|
|
768
826
|
|
|
769
|
-
function resolveTo(
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
// `<Link to>` values` in our
|
|
773
|
-
// disambiguation between `to` values
|
|
774
|
-
// that do not. However, this is problematic for
|
|
775
|
-
// not provide a pathname. `to` can simply be a search or
|
|
776
|
-
// string, in which case we should assume that the navigation is
|
|
777
|
-
//
|
|
778
|
-
|
|
779
|
-
|
|
827
|
+
function resolveTo(toArg, routePathnames, locationPathname) {
|
|
828
|
+
let to = typeof toArg === "string" ? parsePath(toArg) : toArg;
|
|
829
|
+
let toPathname = toArg === "" || to.pathname === "" ? "/" : to.pathname; // If a pathname is explicitly provided in `to`, it should be relative to the
|
|
830
|
+
// route context. This is explained in `Note on `<Link to>` values` in our
|
|
831
|
+
// migration guide from v5 as a means of disambiguation between `to` values
|
|
832
|
+
// that begin with `/` and those that do not. However, this is problematic for
|
|
833
|
+
// `to` values that do not provide a pathname. `to` can simply be a search or
|
|
834
|
+
// hash string, in which case we should assume that the navigation is relative
|
|
835
|
+
// to the current location's pathname and *not* the route pathname.
|
|
836
|
+
|
|
837
|
+
let from;
|
|
838
|
+
|
|
839
|
+
if (toPathname == null) {
|
|
840
|
+
from = locationPathname;
|
|
841
|
+
} else {
|
|
842
|
+
let routePathnameIndex = routePathnames.length - 1;
|
|
843
|
+
|
|
844
|
+
if (toPathname.startsWith("..")) {
|
|
845
|
+
let toSegments = toPathname.split("/"); // Each leading .. segment means "go up one route" instead of "go up one
|
|
846
|
+
// URL segment". This is a key difference from how <a href> works and a
|
|
847
|
+
// major reason we call this a "to" value instead of a "href".
|
|
848
|
+
|
|
849
|
+
while (toSegments[0] === "..") {
|
|
850
|
+
toSegments.shift();
|
|
851
|
+
routePathnameIndex -= 1;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
to.pathname = toSegments.join("/");
|
|
855
|
+
} // If there are more ".." segments than parent routes, resolve relative to
|
|
856
|
+
// the root / URL.
|
|
857
|
+
|
|
858
|
+
|
|
859
|
+
from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
let path = resolvePath(to, from); // Ensure the pathname has a trailing slash if the original to value had one.
|
|
863
|
+
|
|
864
|
+
if (toPathname && toPathname !== "/" && toPathname.endsWith("/") && !path.pathname.endsWith("/")) {
|
|
865
|
+
path.pathname += "/";
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
return path;
|
|
780
869
|
}
|
|
781
870
|
|
|
782
871
|
function getToPathname(to) {
|
|
@@ -784,16 +873,6 @@ function getToPathname(to) {
|
|
|
784
873
|
return to === "" || to.pathname === "" ? "/" : typeof to === "string" ? parsePath(to).pathname : to.pathname;
|
|
785
874
|
}
|
|
786
875
|
|
|
787
|
-
function getPathnameStart(pathname, params) {
|
|
788
|
-
let splat = params["*"];
|
|
789
|
-
if (!splat) return pathname;
|
|
790
|
-
let pathnameStart = pathname.slice(0, -splat.length);
|
|
791
|
-
if (splat.startsWith("/")) return pathnameStart;
|
|
792
|
-
let index = pathnameStart.lastIndexOf("/");
|
|
793
|
-
if (index > 0) return pathnameStart.slice(0, index);
|
|
794
|
-
return "/";
|
|
795
|
-
}
|
|
796
|
-
|
|
797
876
|
function stripBasename(pathname, basename) {
|
|
798
877
|
if (basename === "/") return pathname;
|
|
799
878
|
|
|
@@ -819,5 +898,5 @@ const normalizeSearch = search => !search || search === "?" ? "" : search.starts
|
|
|
819
898
|
|
|
820
899
|
const normalizeHash = hash => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash; ///////////////////////////////////////////////////////////////////////////////
|
|
821
900
|
|
|
822
|
-
export { MemoryRouter, Navigate, Outlet, Route, Router, Routes, LocationContext as UNSAFE_LocationContext, NavigationContext as UNSAFE_NavigationContext, RouteContext as UNSAFE_RouteContext, createRoutesFromChildren, generatePath, matchPath, matchRoutes, renderMatches, resolvePath,
|
|
901
|
+
export { MemoryRouter, Navigate, Outlet, Route, Router, Routes, LocationContext as UNSAFE_LocationContext, NavigationContext as UNSAFE_NavigationContext, RouteContext as UNSAFE_RouteContext, createRoutesFromChildren, generatePath, matchPath, matchRoutes, renderMatches, resolvePath, useHref, useInRouterContext, useLocation, useMatch, useNavigate, useNavigationType, useOutlet, useParams, useResolvedPath, useRoutes };
|
|
823
902
|
//# sourceMappingURL=react-router.development.js.map
|