@@ -258,7 +258,7 @@ export function Router({
258258 children = null ,
259259 location : locationProp ,
260260 navigationType = NavigationType . Pop ,
261- navigator,
261+ navigator : navigatorProp ,
262262 static : staticProp = false
263263} : RouterProps ) : React . ReactElement | null {
264264 invariant (
@@ -267,6 +267,7 @@ export function Router({
267267 ` You should never have more than one in your app.`
268268 ) ;
269269
270+ let navigator = useNavigator ( navigatorProp , basenameProp ) ;
270271 let basename = normalizePathname ( basenameProp ) ;
271272 let navigationContext = React . useMemo (
272273 ( ) => ( { basename, navigator, static : staticProp } ) ,
@@ -277,13 +278,7 @@ export function Router({
277278 locationProp = parsePath ( locationProp ) ;
278279 }
279280
280- let {
281- pathname = "/" ,
282- search = "" ,
283- hash = "" ,
284- state = null ,
285- key = "default"
286- } = locationProp ;
281+ let { pathname, search, hash, state, key } = parseLocation ( locationProp ) ;
287282
288283 let location = React . useMemo ( ( ) => {
289284 let trailingPathname = stripBasename ( pathname , basename ) ;
@@ -450,6 +445,62 @@ type ParamParseKey<Segment extends string> =
450445 ? ParamParseSegment < Segment >
451446 : string ;
452447
448+ /**
449+ * Returns a complete Location with an absolute pathname
450+ */
451+ export function parseLocation ( {
452+ pathname = "/" ,
453+ ...rest
454+ } : Partial < Location > ) : Location {
455+ const defaultLocation = {
456+ pathname : "/" ,
457+ search : "" ,
458+ hash : "" ,
459+ state : null ,
460+ key : "default"
461+ } ;
462+ return {
463+ ...defaultLocation ,
464+ ...rest ,
465+ pathname : normalizePathnameStart ( pathname )
466+ } ;
467+ }
468+
469+ /**
470+ * Returns a modified navigator to allow relative pathnames
471+ */
472+ export function useNavigator (
473+ navigator : Navigator ,
474+ basename : string
475+ ) : Navigator {
476+ if ( basename !== "" ) {
477+ return navigator ;
478+ }
479+
480+ const makeRelative = ( path : Path ) : Path => {
481+ return {
482+ ...path ,
483+ pathname : path . pathname . replace ( / ^ \/ / , "" )
484+ } ;
485+ } ;
486+ const push = ( to : To , state ?: any ) : void => {
487+ navigator . push ( makeRelative ( resolvePath ( to ) ) , state ) ;
488+ } ;
489+ const replace = ( to : To , state ?: any ) : void => {
490+ navigator . replace ( makeRelative ( resolvePath ( to ) ) , state ) ;
491+ } ;
492+ const createHref = ( to : To ) : string => {
493+ return navigator . createHref ( makeRelative ( resolvePath ( to ) ) ) ;
494+ } ;
495+
496+ return {
497+ go : navigator . go ,
498+ push,
499+ replace,
500+ createHref
501+ } ;
502+ }
503+
453504/**
454505 * Returns the current navigation action which describes how the router came to
455506 * the current location, either by a pop, push, or replace on the history stack.
@@ -599,7 +650,6 @@ export function useResolvedPath(to: To): Path {
599650 let routePathnamesJson = JSON . stringify (
600651 matches . map ( match => match . pathnameBase )
601652 ) ;
602-
603653 return React . useMemo (
604654 ( ) => resolveTo ( to , JSON . parse ( routePathnamesJson ) , locationPathname ) ,
605655 [ to , routePathnamesJson , locationPathname ]
@@ -848,10 +898,11 @@ export function matchRoutes(
848898 locationArg : Partial < Location > | string ,
849899 basename = "/"
850900) : RouteMatch [ ] | null {
851- let location =
852- typeof locationArg === "string" ? parsePath ( locationArg ) : locationArg ;
901+ let absolutePathname = parseLocation (
902+ typeof locationArg === "string" ? parsePath ( locationArg ) : locationArg
903+ ) . pathname ;
853904
854- let pathname = stripBasename ( location . pathname || "/" , basename ) ;
905+ let pathname = stripBasename ( absolutePathname , basename ) ;
855906
856907 if ( pathname == null ) {
857908 return null ;
@@ -1353,8 +1404,11 @@ function stripBasename(pathname: string, basename: string): string | null {
13531404const joinPaths = ( paths : string [ ] ) : string =>
13541405 paths . join ( "/" ) . replace ( / \/ \/ + / g, "/" ) ;
13551406
1407+ const normalizePathnameStart = ( pathname : string ) : string =>
1408+ pathname . replace ( / ^ \/ * / , "/" ) ;
1409+
13561410const normalizePathname = ( pathname : string ) : string =>
1357- pathname . replace ( / \/ + $ / , "" ) . replace ( / ^ \/ * / , "/" ) ;
1411+ normalizePathnameStart ( pathname . replace ( / \/ + $ / , "" ) ) ;
13581412
13591413const normalizeSearch = ( search : string ) : string =>
13601414 ! search || search === "?"
0 commit comments