Files
memind/src/components/ChatHeaderMoreMenu.tsx
T

89 lines
2.5 KiB
TypeScript
Raw Normal View History

import { useEffect, useRef, useState } from 'react';
import { WechatAccountButton } from './WechatAccountButton';
type MenuItem = {
id: string;
label: string;
onClick: () => void;
disabled?: boolean;
danger?: boolean;
};
export function ChatHeaderMoreMenu({
items,
returnTo,
showWechat = false,
}: {
items: MenuItem[];
returnTo?: string;
showWechat?: boolean;
}) {
const [open, setOpen] = useState(false);
const wrapRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!open) return;
const handleClick = (event: MouseEvent) => {
if (wrapRef.current && !wrapRef.current.contains(event.target as Node)) {
setOpen(false);
}
};
const handleKey = (event: KeyboardEvent) => {
if (event.key === 'Escape') setOpen(false);
};
document.addEventListener('click', handleClick);
document.addEventListener('keydown', handleKey);
return () => {
document.removeEventListener('click', handleClick);
document.removeEventListener('keydown', handleKey);
};
}, [open]);
return (
<div className={`header-more-menu${open ? ' open' : ''}`} ref={wrapRef}>
<button
type="button"
className="header-icon-btn"
aria-label="更多操作"
aria-expanded={open}
aria-haspopup="menu"
onClick={() => setOpen((prev) => !prev)}
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<circle cx="12" cy="5" r="1.75" />
<circle cx="12" cy="12" r="1.75" />
<circle cx="12" cy="19" r="1.75" />
</svg>
</button>
{open && (
<div className="header-more-dropdown" role="menu" aria-label="更多操作">
{items.map((item) => (
<button
key={item.id}
type="button"
className={`header-more-item${item.danger ? ' header-more-item-danger' : ''}`}
role="menuitem"
disabled={item.disabled}
onClick={() => {
setOpen(false);
item.onClick();
}}
>
{item.label}
</button>
))}
{showWechat && (
<>
<div className="header-more-divider" role="separator" />
<div className="header-more-wechat">
<WechatAccountButton returnTo={returnTo} onBeforeAction={() => setOpen(false)} />
</div>
</>
)}
</div>
)}
</div>
);
}