diff --git a/contributors.yml b/contributors.yml index aa0469f113..a590747a59 100644 --- a/contributors.yml +++ b/contributors.yml @@ -1,4 +1,5 @@ - Ajayff4 +- akx - awreese - bhbs - brockross diff --git a/packages/react-router-dom/index.tsx b/packages/react-router-dom/index.tsx index 40cbe72d2f..cb363353f0 100644 --- a/packages/react-router-dom/index.tsx +++ b/packages/react-router-dom/index.tsx @@ -26,7 +26,7 @@ import { useRoutes, useOutletContext } from "react-router"; -import type { To } from "react-router"; +import type { To, Path } from "react-router"; function warning(cond: boolean, message: string): void { if (!cond) { @@ -311,21 +311,7 @@ export const NavLink = React.forwardRef( }, ref ) { - let location = useLocation(); - let path = useResolvedPath(to); - - let locationPathname = location.pathname; - let toPathname = path.pathname; - if (!caseSensitive) { - locationPathname = locationPathname.toLowerCase(); - toPathname = toPathname.toLowerCase(); - } - - let isActive = - locationPathname === toPathname || - (!end && - locationPathname.startsWith(toPathname) && - locationPathname.charAt(toPathname.length) === "/"); + let isActive = useIsPathActive(to, caseSensitive, end); let ariaCurrent = isActive ? ariaCurrentProp : undefined; @@ -411,6 +397,20 @@ export function useLinkClickHandler( ); } +/** + * Returns true if the given location seems currently active. + * `caseSensitive` and `end` work the same as with ``. + */ +export function useIsPathActive( + to: To, + caseSensitive: boolean = false, + end: boolean = false +): boolean { + let location = useLocation(); + let path = useResolvedPath(to); + return isPathActive(location, path, caseSensitive, end); +} + /** * A convenient wrapper for reading and writing search parameters via the * URLSearchParams interface. @@ -504,3 +504,28 @@ export function createSearchParams( }, [] as ParamKeyValuePair[]) ); } + +/** + * Given a location and a path, returns true if the path is active in the location. + * `caseSensitive` and `end` work the same as with ``. + */ +export function isPathActive( + location: Path, + path: Path, + caseSensitive: boolean = false, + end: boolean = false +) { + let locationPathname = location.pathname; + let toPathname = path.pathname; + if (!caseSensitive) { + locationPathname = locationPathname.toLowerCase(); + toPathname = toPathname.toLowerCase(); + } + + return ( + locationPathname === toPathname || + (!end && + locationPathname.startsWith(toPathname) && + locationPathname.charAt(toPathname.length) === "/") + ); +}