Skip to content

Commit 136e9de

Browse files
committed
moremenu now closes when loosing focus
Mobile users rejoice
1 parent 4c67c7f commit 136e9de

File tree

1 file changed

+48
-6
lines changed

1 file changed

+48
-6
lines changed

app/ui/moremenu.tsx

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
'use client';
33

44
import type { Dispatch, SetStateAction } from 'react';
5-
import { useState } from 'react';
5+
import { useState, useEffect, useRef } from 'react';
66
import IconLink from './iconlink';
77
import SortSelect from './sort-select';
88

99
// Types matching those in Header/Page
1010
import { SortOption } from './sort-types';
11+
1112
interface ProfileLink {
1213
href: string;
1314
label: string;
@@ -24,12 +25,51 @@ interface MoreMenuProps {
2425

2526
export default function MoreMenu({ profileLinks, sort, setSort, query, setQuery }: MoreMenuProps) {
2627
const [open, setOpen] = useState(false);
28+
const menuRef = useRef<HTMLDivElement>(null);
29+
30+
// Close menu when scrolling
31+
useEffect(() => {
32+
function handleScroll() {
33+
if (open) {
34+
setOpen(false);
35+
}
36+
}
37+
38+
// Add scroll event listener
39+
window.addEventListener('scroll', handleScroll, { passive: true });
40+
41+
// Clean up
42+
return () => {
43+
window.removeEventListener('scroll', handleScroll);
44+
};
45+
}, [open]);
46+
47+
// Close menu when clicking outside
48+
useEffect(() => {
49+
function handleClickOutside(event: MouseEvent) {
50+
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
51+
setOpen(false);
52+
}
53+
}
54+
55+
if (open) {
56+
document.addEventListener('mousedown', handleClickOutside);
57+
}
58+
59+
return () => {
60+
document.removeEventListener('mousedown', handleClickOutside);
61+
};
62+
}, [open]);
2763

2864
return (
29-
<div className="relative flex-shrink-0">
65+
<div className="relative flex-shrink-0" ref={menuRef}>
3066
<button
31-
onClick={() => setOpen(!open)}
32-
aria-label="Open menu"
67+
onClick={(e) => {
68+
e.stopPropagation();
69+
setOpen(!open);
70+
}}
71+
aria-label={open ? 'Close menu' : 'Open menu'}
72+
aria-expanded={open}
3373
className="p-2 rounded-md bg-neutral-800/70 hover:bg-neutral-800 focus:outline-none focus:ring-2 focus:ring-amber-500 lg:hidden"
3474
>
3575
<svg viewBox="0 0 24 24" className="w-4 h-4 fill-neutral-300">
@@ -40,9 +80,11 @@ export default function MoreMenu({ profileLinks, sort, setSort, query, setQuery
4080
</button>
4181

4282
{open && (
43-
<div className="absolute right-0 mt-2 w-56 rounded-md bg-neutral-900 shadow-lg ring-1 ring-neutral-700/60 z-50">
83+
<div
84+
className="absolute right-0 mt-2 w-56 rounded-md bg-neutral-900 shadow-lg ring-1 ring-neutral-700/60 z-50"
85+
onClick={(e) => e.stopPropagation()}
86+
>
4487
<div className="flex flex-col p-2 gap-2 divide-y divide-neutral-700/60">
45-
4688
{/* Search Input - Shown below sm */}
4789
<div className="sm:hidden px-2 pt-1 pb-2">
4890
<input

0 commit comments

Comments
 (0)