/** * TabContextMenu - 标签右键菜单 */ import { useRef, useEffect } from 'react' import { useTranslation } from 'react-i18next' interface MenuItem { label: string action: () => void danger?: boolean separator?: boolean } interface TabContextMenuProps { isOpen: boolean position: { x: number; y: number } onClose: () => void onCloseTab: () => void onCloseOthers: () => void onCloseRight: () => void onCloseLeft: () => void onCloseAll: () => void onClone?: () => void onOpenSftp?: () => void } export function TabContextMenu({ isOpen, position, onClose, onCloseTab, onCloseOthers, onCloseRight, onCloseLeft, onCloseAll, onClone, onOpenSftp, }: TabContextMenuProps) { const { t } = useTranslation('common') const menuRef = useRef(null) const onCloseRef = useRef(onClose) onCloseRef.current = onClose useEffect(() => { if (!isOpen) return const handlePointerDown = (e: PointerEvent) => { if (menuRef.current && !menuRef.current.contains(e.target as Node)) { onCloseRef.current() } } const handleKeydown = (e: KeyboardEvent) => { if (e.key === 'Escape') onCloseRef.current() } document.addEventListener('pointerdown', handlePointerDown, true) document.addEventListener('keydown', handleKeydown) return () => { document.removeEventListener('pointerdown', handlePointerDown, true) document.removeEventListener('keydown', handleKeydown) } }, [isOpen]) if (!isOpen) return null const items: MenuItem[] = [ { label: t('action.close'), action: onCloseTab }, { label: t('tab.menu.closeOthers'), action: onCloseOthers }, { label: t('tab.menu.closeRight'), action: onCloseRight }, { label: t('tab.menu.closeLeft'), action: onCloseLeft }, { label: t('tab.menu.closeAll'), action: onCloseAll, danger: true }, ] if (onClone) { items.unshift({ label: t('tab.menu.clone'), action: onClone }) } if (onOpenSftp) { items.unshift({ label: t('tab.menu.openSftp'), action: onOpenSftp }) } return (
e.stopPropagation()} > {items.map((item, index) => ( ))}
) }