Skip to content

Commit 5bcd020

Browse files
committed
Close the mobile menu before navigation
1 parent 0b4abd5 commit 5bcd020

3 files changed

Lines changed: 36 additions & 7 deletions

File tree

src/components/Layout/Sidebar/SidebarLink.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ interface SidebarLinkProps {
2626
icon?: React.ReactNode;
2727
isExpanded?: boolean;
2828
hideArrow?: boolean;
29+
onNavigate?: () => void;
2930
}
3031

3132
export function SidebarLink({
@@ -36,6 +37,7 @@ export function SidebarLink({
3637
level,
3738
isExpanded,
3839
hideArrow,
40+
onNavigate,
3941
}: SidebarLinkProps) {
4042
const ref = useRef<HTMLAnchorElement>(null);
4143

@@ -59,6 +61,7 @@ export function SidebarLink({
5961
ref={ref}
6062
title={title}
6163
target={target}
64+
onNavigate={onNavigate}
6265
passHref
6366
aria-current={selected ? 'page' : undefined}
6467
className={cn(

src/components/Layout/Sidebar/SidebarRouteTree.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ interface SidebarRouteTreeProps {
2323
breadcrumbs: RouteItem[];
2424
routeTree: RouteItem;
2525
level?: number;
26+
onNavigate?: () => void;
2627
}
2728

2829
function CollapseWrapper({
@@ -81,6 +82,7 @@ export function SidebarRouteTree({
8182
breadcrumbs,
8283
routeTree,
8384
level = 0,
85+
onNavigate,
8486
}: SidebarRouteTreeProps) {
8587
const slug = (usePathname() || '/').split(/[\?\#]/)[0];
8688
const currentRoutes = routeTree.routes as RouteItem[];
@@ -109,6 +111,7 @@ export function SidebarRouteTree({
109111
isForceExpanded={isForceExpanded}
110112
routeTree={{title, routes}}
111113
breadcrumbs={[]}
114+
onNavigate={onNavigate}
112115
/>
113116
);
114117
} else if (routes) {
@@ -128,13 +131,15 @@ export function SidebarRouteTree({
128131
version={version}
129132
isExpanded={isExpanded}
130133
hideArrow={isForceExpanded}
134+
onNavigate={onNavigate}
131135
/>
132136
<CollapseWrapper duration={250} isExpanded={isExpanded}>
133137
<SidebarRouteTree
134138
isForceExpanded={isForceExpanded}
135139
routeTree={{title, routes}}
136140
breadcrumbs={breadcrumbs}
137141
level={level + 1}
142+
onNavigate={onNavigate}
138143
/>
139144
</CollapseWrapper>
140145
</li>
@@ -149,6 +154,7 @@ export function SidebarRouteTree({
149154
level={level}
150155
title={title}
151156
version={version}
157+
onNavigate={onNavigate}
152158
/>
153159
</li>
154160
);

src/components/Layout/TopNav/TopNav.tsx

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
useRef,
1717
useCallback,
1818
useEffect,
19+
useLayoutEffect,
1920
startTransition,
2021
Suspense,
2122
} from 'react';
@@ -117,7 +118,9 @@ function Link({
117118
href,
118119
children,
119120
...props
120-
}: React.AnchorHTMLAttributes<HTMLAnchorElement>) {
121+
}: React.AnchorHTMLAttributes<HTMLAnchorElement> & {
122+
onNavigate?: () => void;
123+
}) {
121124
return (
122125
<NextLink
123126
href={`${href}`}
@@ -128,11 +131,12 @@ function Link({
128131
);
129132
}
130133

131-
function NavItem({url, isActive, children}: any) {
134+
function NavItem({url, isActive, children, onNavigate}: any) {
132135
return (
133136
<div className="flex flex-auto sm:flex-1">
134137
<Link
135138
href={url}
139+
onNavigate={onNavigate}
136140
className={cn(
137141
'active:scale-95 transition-transform w-full text-center outline-link py-1.5 px-1.5 xs:px-3 sm:px-4 rounded-full capitalize whitespace-nowrap',
138142
!isActive && 'hover:bg-primary/5 hover:dark:bg-primary-dark/5',
@@ -169,14 +173,21 @@ export default function TopNav({
169173
const [showSearch, setShowSearch] = useState(false);
170174
const [isScrolled, setIsScrolled] = useState(false);
171175
const scrollParentRef = useRef<HTMLDivElement>(null);
176+
const closeMenu = useCallback(() => setOpenMenuPath(null), []);
172177
// Deriving from the path hides the menu as soon as a navigation commits.
173178
// Forget the path afterwards, so going Back doesn't reopen the menu.
174179
if (openMenuPath !== null && openMenuPath !== asPath) {
175-
setOpenMenuPath(null);
180+
closeMenu();
176181
}
177182
const isMenuOpen = openMenuPath === asPath;
178183
const {breadcrumbs} = getRouteMeta(asPath, routeTree);
179184

185+
// The mobile menu is transient UI. Reset it when Activity hides this route
186+
// so going Back does not restore the menu in its open state.
187+
useLayoutEffect(() => {
188+
return () => setOpenMenuPath(null);
189+
}, []);
190+
180191
// HACK. Fix up the data structures instead.
181192
if ((routeTree as any).routes.length === 1) {
182193
routeTree = (routeTree as any).routes[0];
@@ -417,20 +428,28 @@ export default function TopNav({
417428
{/* No fallback UI so need to be careful not to suspend directly inside. */}
418429
<Suspense fallback={null}>
419430
<div className="ps-3 xs:ps-5 xs:gap-0.5 xs:text-base overflow-x-auto flex flex-row lg:hidden text-base font-bold text-secondary dark:text-secondary-dark">
420-
<NavItem isActive={section === 'learn'} url="/learn">
431+
<NavItem
432+
isActive={section === 'learn'}
433+
url="/learn"
434+
onNavigate={closeMenu}>
421435
Learn
422436
</NavItem>
423437
<NavItem
424438
isActive={section === 'reference'}
425-
url="/reference/react">
439+
url="/reference/react"
440+
onNavigate={closeMenu}>
426441
Reference
427442
</NavItem>
428443
<NavItem
429444
isActive={section === 'community'}
430-
url="/community">
445+
url="/community"
446+
onNavigate={closeMenu}>
431447
Community
432448
</NavItem>
433-
<NavItem isActive={section === 'blog'} url="/blog">
449+
<NavItem
450+
isActive={section === 'blog'}
451+
url="/blog"
452+
onNavigate={closeMenu}>
434453
Blog
435454
</NavItem>
436455
</div>
@@ -445,6 +464,7 @@ export default function TopNav({
445464
routeTree={routeTree}
446465
breadcrumbs={breadcrumbs}
447466
isForceExpanded={isMenuOpen}
467+
onNavigate={closeMenu}
448468
/>
449469
</Suspense>
450470
<div className="h-16" />

0 commit comments

Comments
 (0)