Skip to content

Commit a06bb3f

Browse files
committed
Fix nav menu dismissal on navigation
1 parent 9f529c5 commit a06bb3f

2 files changed

Lines changed: 86 additions & 13 deletions

File tree

src/components/Navbar.tsx

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -437,11 +437,36 @@ export function Navbar({ children }: { children: React.ReactNode }) {
437437
}, [])
438438

439439
const [mobileMenuOpen, setMobileMenuOpen] = React.useState(false)
440+
const [dismissedDesktopMenuKey, setDismissedDesktopMenuKey] =
441+
React.useState<NavMenuKey | null>(null)
440442
const [canLoadAuthControls, setCanLoadAuthControls] = React.useState(false)
441443

442444
React.useEffect(() => {
443445
setMobileMenuOpen(false)
444-
}, [location.pathname, location.hash])
446+
}, [location.href])
447+
448+
const blurActiveNavigationElement = React.useCallback(() => {
449+
if (typeof document === 'undefined') {
450+
return
451+
}
452+
453+
const activeElement = document.activeElement
454+
455+
if (
456+
activeElement instanceof HTMLElement &&
457+
containerRef.current?.contains(activeElement)
458+
) {
459+
activeElement.blur()
460+
}
461+
}, [])
462+
463+
const dismissDesktopMenu = React.useCallback(
464+
(key: NavMenuKey) => {
465+
setDismissedDesktopMenuKey(key)
466+
blurActiveNavigationElement()
467+
},
468+
[blurActiveNavigationElement],
469+
)
445470

446471
React.useEffect(() => {
447472
if (typeof window === 'undefined') {
@@ -549,7 +574,17 @@ export function Navbar({ children }: { children: React.ReactNode }) {
549574
)}
550575
>
551576
{NAV_GROUPS.map((group) => (
552-
<DesktopNavTrigger key={group.key} group={group} />
577+
<DesktopNavTrigger
578+
key={group.key}
579+
group={group}
580+
dismissed={dismissedDesktopMenuKey === group.key}
581+
onDismiss={() => dismissDesktopMenu(group.key)}
582+
onResetDismissed={() => {
583+
setDismissedDesktopMenuKey((dismissedKey) =>
584+
dismissedKey === group.key ? null : dismissedKey,
585+
)
586+
}}
587+
/>
553588
))}
554589
</nav>
555590
</div>
@@ -663,20 +698,37 @@ export function Navbar({ children }: { children: React.ReactNode }) {
663698
)
664699
}
665700

666-
function DesktopNavTrigger({ group }: { group: NavMenuGroup }) {
701+
function DesktopNavTrigger({
702+
group,
703+
dismissed,
704+
onDismiss,
705+
onResetDismissed,
706+
}: {
707+
group: NavMenuGroup
708+
dismissed: boolean
709+
onDismiss: () => void
710+
onResetDismissed: () => void
711+
}) {
667712
const triggerClassName = twMerge(
668713
'ts-mega-trigger inline-flex items-center gap-1.5 rounded-md px-3 py-2 text-[13px] font-medium',
669714
'text-gray-700 transition-colors hover:bg-gray-500/10 hover:text-gray-950',
670715
'dark:text-gray-300 dark:hover:text-white',
671716
)
672717

673718
return (
674-
<div className="ts-mega-trigger-wrap" data-menu-key={group.key}>
719+
<div
720+
className="ts-mega-trigger-wrap"
721+
data-menu-key={group.key}
722+
data-menu-dismissed={dismissed ? 'true' : undefined}
723+
onPointerLeave={onResetDismissed}
724+
onFocusCapture={onResetDismissed}
725+
>
675726
{group.to ? (
676727
<Link
677728
to={group.to}
678729
data-menu-key={group.key}
679730
className={triggerClassName}
731+
onClick={onDismiss}
680732
preload="intent"
681733
>
682734
<span>{group.label}</span>
@@ -693,12 +745,18 @@ function DesktopNavTrigger({ group }: { group: NavMenuGroup }) {
693745
<span>{group.label}</span>
694746
</button>
695747
)}
696-
<DesktopNavDropdown group={group} />
748+
<DesktopNavDropdown group={group} onNavigate={onDismiss} />
697749
</div>
698750
)
699751
}
700752

701-
function DesktopNavDropdown({ group }: { group: NavMenuGroup }) {
753+
function DesktopNavDropdown({
754+
group,
755+
onNavigate,
756+
}: {
757+
group: NavMenuGroup
758+
onNavigate: () => void
759+
}) {
702760
return (
703761
<div className="ts-mega-dropdown">
704762
<div
@@ -710,7 +768,7 @@ function DesktopNavDropdown({ group }: { group: NavMenuGroup }) {
710768
>
711769
<MegaMenuContent
712770
group={group}
713-
onNavigate={() => undefined}
771+
onNavigate={onNavigate}
714772
variant="desktop"
715773
/>
716774
</div>

src/styles/app.css

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,10 @@ button {
177177
visibility 0s linear 160ms;
178178
}
179179

180-
.ts-mega-trigger-wrap:hover > .ts-mega-dropdown,
181-
.ts-mega-trigger-wrap:focus-within > .ts-mega-dropdown {
180+
.ts-mega-trigger-wrap:not([data-menu-dismissed='true']):hover
181+
> .ts-mega-dropdown,
182+
.ts-mega-trigger-wrap:not([data-menu-dismissed='true']):focus-within
183+
> .ts-mega-dropdown {
182184
opacity: 1;
183185
visibility: visible;
184186
pointer-events: auto;
@@ -250,15 +252,28 @@ button {
250252
}
251253

252254
@media (min-width: 960px) {
253-
body:has(.ts-mega-trigger-wrap:hover > .ts-mega-dropdown)
255+
body:has(
256+
.ts-mega-trigger-wrap:not([data-menu-dismissed='true']):hover
257+
> .ts-mega-dropdown
258+
)
254259
[data-site-menu-tint],
255-
body:has(.ts-mega-trigger-wrap:focus-within > .ts-mega-dropdown)
260+
body:has(
261+
.ts-mega-trigger-wrap:not([data-menu-dismissed='true']):focus-within
262+
> .ts-mega-dropdown
263+
)
256264
[data-site-menu-tint] {
257265
opacity: 1;
258266
}
259267

260-
body:has(.ts-mega-trigger-wrap:hover > .ts-mega-dropdown) [data-site-content],
261-
body:has(.ts-mega-trigger-wrap:focus-within > .ts-mega-dropdown)
268+
body:has(
269+
.ts-mega-trigger-wrap:not([data-menu-dismissed='true']):hover
270+
> .ts-mega-dropdown
271+
)
272+
[data-site-content],
273+
body:has(
274+
.ts-mega-trigger-wrap:not([data-menu-dismissed='true']):focus-within
275+
> .ts-mega-dropdown
276+
)
262277
[data-site-content] {
263278
filter: blur(4px);
264279
}

0 commit comments

Comments
 (0)