Skip to content

Commit e53c695

Browse files
committed
Fix empty path to be more specific than a catch-all.
1 parent 82fbe32 commit e53c695

3 files changed

Lines changed: 104 additions & 4 deletions

File tree

packages/ra-router-tanstack/src/tanStackRouterProvider.spec.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
PathlessLayoutRoutes,
2727
NestedResourcesPrecedence,
2828
PathlessLayoutRoutesPriority,
29+
PathlessLayoutRoutesWithEmptyRoute,
2930
} from './tanStackRouterProvider.stories';
3031
import { tanStackRouterProvider } from './tanStackRouterProvider';
3132

@@ -1506,6 +1507,22 @@ describe('tanStackRouterProvider', () => {
15061507
});
15071508
});
15081509

1510+
it('should match the empty path route as most specific within pathless layout routes', async () => {
1511+
window.location.hash = '#/posts';
1512+
1513+
render(<PathlessLayoutRoutesWithEmptyRoute />);
1514+
1515+
await waitFor(() => {
1516+
expect(screen.getByTestId('posts-page')).toBeInTheDocument();
1517+
});
1518+
1519+
fireEvent.click(screen.getByText('Home (path="")'));
1520+
1521+
await waitFor(() => {
1522+
expect(screen.getByTestId('home-page')).toBeInTheDocument();
1523+
});
1524+
});
1525+
15091526
describe('Resource Children (Route as children of Resource)', () => {
15101527
it('should navigate to child routes without matching parent edit route', async () => {
15111528
render(<NestedResourcesPrecedence />);

packages/ra-router-tanstack/src/tanStackRouterProvider.stories.tsx

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,3 +1585,86 @@ export const PathlessLayoutRoutesPriority = () => {
15851585
</RouterProviderContext.Provider>
15861586
);
15871587
};
1588+
1589+
export const PathlessLayoutRoutesWithEmptyRoute = () => {
1590+
const { RouterWrapper } = tanStackRouterProvider;
1591+
1592+
return (
1593+
<RouterProviderContext.Provider value={tanStackRouterProvider}>
1594+
<RouterWrapper>
1595+
<p style={{ marginBottom: 10 }}>
1596+
Expected: "/" renders Home Page (path=""). If you see
1597+
Catch-all Page instead, path="" is being treated as
1598+
catch-all.
1599+
</p>
1600+
<Routes>
1601+
<Route
1602+
path="*"
1603+
element={
1604+
<div data-testid="catchall-page">
1605+
Catch-all Page
1606+
</div>
1607+
}
1608+
/>
1609+
<Route
1610+
element={
1611+
<div data-testid="layout-wrapper">
1612+
<h2>Layout Wrapper</h2>
1613+
<nav>
1614+
<LinkBase
1615+
to="/posts"
1616+
style={{ marginRight: 10 }}
1617+
>
1618+
Posts
1619+
</LinkBase>
1620+
<LinkBase to="/comments">Comments</LinkBase>
1621+
</nav>
1622+
<nav>
1623+
<LinkBase
1624+
to="/"
1625+
style={{ marginRight: 10 }}
1626+
>
1627+
Home (path="")
1628+
</LinkBase>
1629+
</nav>
1630+
<div
1631+
style={{
1632+
border: '2px solid blue',
1633+
padding: 20,
1634+
marginTop: 10,
1635+
}}
1636+
>
1637+
<RouterOutlet />
1638+
</div>
1639+
</div>
1640+
}
1641+
>
1642+
<Route
1643+
path=""
1644+
element={
1645+
<div data-testid="home-page">
1646+
Home Page (path="")
1647+
</div>
1648+
}
1649+
/>
1650+
<Route
1651+
path="/posts"
1652+
element={
1653+
<div data-testid="posts-page">Posts Page</div>
1654+
}
1655+
/>
1656+
<Route
1657+
path="/comments"
1658+
element={
1659+
<div data-testid="comments-page">
1660+
Comments Page
1661+
</div>
1662+
}
1663+
/>
1664+
</Route>
1665+
</Routes>
1666+
<LocationDisplay />
1667+
</RouterWrapper>
1668+
</RouterProviderContext.Provider>
1669+
);
1670+
};

packages/ra-router-tanstack/src/tanStackRouterProvider.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,7 @@ const Routes = ({ children, location: locationProp }: RouterRoutesProps) => {
651651

652652
// Check if a route pattern has a catch-all at the end
653653
const hasCatchAll = (path: string | undefined): boolean => {
654-
return !path || path.endsWith('/*') || path === '*';
654+
return path === undefined || path.endsWith('/*') || path === '*';
655655
};
656656

657657
// Check if routeB is more specific than routeA when both match the same path
@@ -744,8 +744,8 @@ const Routes = ({ children, location: locationProp }: RouterRoutesProps) => {
744744
childMatch &&
745745
// If no best match yet, or the child route is more specific than the current best, use this one
746746
(!bestMatch ||
747-
(bestMatch.route.path &&
748-
childMatch.route.path &&
747+
(bestMatch.route.path !== undefined &&
748+
childMatch.route.path !== undefined &&
749749
isMoreSpecific(
750750
bestMatch.route.path,
751751
childMatch.route.path
@@ -782,7 +782,7 @@ const Routes = ({ children, location: locationProp }: RouterRoutesProps) => {
782782
// If no best match yet, or this route is more specific than the current best, use this one
783783
if (
784784
!bestMatch ||
785-
(bestMatch.route.path &&
785+
(bestMatch.route.path !== undefined &&
786786
isMoreSpecific(
787787
bestMatch.route.path,
788788
route.path

0 commit comments

Comments
 (0)