From d7f24976c049204fee86e7cf2d58ed4c44330754 Mon Sep 17 00:00:00 2001 From: Andrey Kamozin Date: Thu, 3 Mar 2022 10:48:04 -0500 Subject: [PATCH 1/2] fix: relative navigation from index routes --- contributors.yml | 2 + .../react-router/__tests__/navigate-test.tsx | 45 +++++++++++++++++++ packages/react-router/lib/hooks.tsx | 6 ++- packages/router/utils.ts | 7 ++- 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/contributors.yml b/contributors.yml index 527ecfea7a..f18aa9680b 100644 --- a/contributors.yml +++ b/contributors.yml @@ -64,3 +64,5 @@ - underager - vijaypushkin - vikingviolinist +- KutnerUri +- JaffParker diff --git a/packages/react-router/__tests__/navigate-test.tsx b/packages/react-router/__tests__/navigate-test.tsx index ef6ba56bc2..006daeb464 100644 --- a/packages/react-router/__tests__/navigate-test.tsx +++ b/packages/react-router/__tests__/navigate-test.tsx @@ -1,6 +1,7 @@ import * as React from "react"; import * as TestRenderer from "react-test-renderer"; import { MemoryRouter, Navigate, Routes, Route } from "react-router"; +import { Outlet } from "../lib/components"; describe("", () => { describe("with an absolute href", () => { @@ -45,5 +46,49 @@ describe("", () => { `); }); + + it("skips a level from an index route", () => { + let renderer: TestRenderer.ReactTestRenderer; + TestRenderer.act(() => { + renderer = TestRenderer.create( + + + + } /> + + About} /> + + + ); + }); + + expect(renderer.toJSON()).toMatchInlineSnapshot(` +

+ About +

+ `); + }); + + it("skips a level from a layout route", () => { + let renderer: TestRenderer.ReactTestRenderer; + TestRenderer.act(() => { + renderer = TestRenderer.create( + + + }> + } /> + + About} /> + + + ); + }); + + expect(renderer.toJSON()).toMatchInlineSnapshot(` +

+ About +

+ `); + }); }); }); diff --git a/packages/react-router/lib/hooks.tsx b/packages/react-router/lib/hooks.tsx index 1f5adfabf4..e5e9c663d6 100644 --- a/packages/react-router/lib/hooks.tsx +++ b/packages/react-router/lib/hooks.tsx @@ -158,6 +158,7 @@ export function useNavigate(): NavigateFunction { let routePathnamesJson = JSON.stringify( matches.map((match) => match.pathnameBase) ); + let isPathlessRoute = !!matches[matches.length - 1]?.route.index; let activeRef = React.useRef(false); React.useEffect(() => { @@ -182,7 +183,8 @@ export function useNavigate(): NavigateFunction { let path = resolveTo( to, JSON.parse(routePathnamesJson), - locationPathname + locationPathname, + isPathlessRoute ); if (basename !== "/") { @@ -195,7 +197,7 @@ export function useNavigate(): NavigateFunction { options ); }, - [basename, navigator, routePathnamesJson, locationPathname] + [routePathnamesJson, locationPathname, isPathlessRoute, basename, navigator] ); return navigate; diff --git a/packages/router/utils.ts b/packages/router/utils.ts index 607ebca205..cc7b570461 100644 --- a/packages/router/utils.ts +++ b/packages/router/utils.ts @@ -656,7 +656,8 @@ function resolvePathname(relativePath: string, fromPathname: string): string { export function resolveTo( toArg: To, routePathnames: string[], - locationPathname: string + locationPathname: string, + isPathlessRoute = false ): Path { let to = typeof toArg === "string" ? parsePath(toArg) : { ...toArg }; let toPathname = toArg === "" || to.pathname === "" ? "/" : to.pathname; @@ -672,7 +673,9 @@ export function resolveTo( if (toPathname == null) { from = locationPathname; } else { - let routePathnameIndex = routePathnames.length - 1; + let routePathnameIndex = isPathlessRoute + ? routePathnames.length - 2 + : routePathnames.length - 1; if (toPathname.startsWith("..")) { let toSegments = toPathname.split("/"); From 71e8b7f48bb49324e4fb6432da51eccaf47da575 Mon Sep 17 00:00:00 2001 From: Andrey Kamozin Date: Tue, 7 Jun 2022 14:16:28 -0400 Subject: [PATCH 2/2] fix: tests --- packages/react-router-dom-v5-compat/index.ts | 4 ++-- packages/react-router-dom-v5-compat/lib/components.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-router-dom-v5-compat/index.ts b/packages/react-router-dom-v5-compat/index.ts index d504b8b796..63d48118f3 100644 --- a/packages/react-router-dom-v5-compat/index.ts +++ b/packages/react-router-dom-v5-compat/index.ts @@ -69,7 +69,7 @@ export type { Pathname, Search, RoutesProps, -} from "./react-router-dom"; +} from "../react-router-dom"; export { BrowserRouter, HashRouter, @@ -108,7 +108,7 @@ export { useResolvedPath, useRoutes, useSearchParams, -} from "./react-router-dom"; +} from "../react-router-dom"; export type { StaticRouterProps } from "./lib/components"; export { CompatRouter, CompatRoute, StaticRouter } from "./lib/components"; diff --git a/packages/react-router-dom-v5-compat/lib/components.tsx b/packages/react-router-dom-v5-compat/lib/components.tsx index 59ce5c1a91..9b2461a587 100644 --- a/packages/react-router-dom-v5-compat/lib/components.tsx +++ b/packages/react-router-dom-v5-compat/lib/components.tsx @@ -9,7 +9,7 @@ import { useHistory, Route as RouteV5 } from "react-router-dom"; // We are a wrapper around react-router-dom v6, so bring it in // and bundle it because an app can't have two versions of // react-router-dom in its package.json. -import { Router, Routes, Route } from "../react-router-dom"; +import { Router, Routes, Route } from "../../react-router-dom"; // v5 isn't in TypeScript, they'll also lose the @types/react-router with this // but not worried about that for now.