/
kan64
/
spreadsheet-lab
Обзор
Документация
Войти
/
kan64
/
spreadsheet-lab
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
develop
client/src/components/ContextMenu.tsx
73 строки
2 KB
Anton Kravchenkov
feat(ui): Add row column menu
21 мар 2026, 15:21
21 мар 2026, 15:21
b112cb3
Код
Авторство
О чём код?
import React, { useEffect, useRef } from 'react'; import { createPortal } from 'react-dom'; export interface ContextMenuItem { label: string; action: () => void; disabled?: boolean; separator?: boolean; icon?: React.ReactNode; } interface ContextMenuProps { x: number; y: number; items: ContextMenuItem[]; onClose: () => void; } export const ContextMenu: React.FC<ContextMenuProps> = ({ x, y, items, onClose }) => { const menuRef = useRef<HTMLDivElement>(null); useEffect(() => { const handleClick = (e: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(e.target as Node)) { onClose(); } }; const handleEsc = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; document.addEventListener('mousedown', handleClick); document.addEventListener('keydown', handleEsc); return () => { document.removeEventListener('mousedown', handleClick); document.removeEventListener('keydown', handleEsc); }; }, [onClose]); // Adjust position to keep menu in viewport; only adjust when would overflow const menuHeight = items.length * 36; const adjustedX = Math.min(Math.max(0, x), window.innerWidth - 200); const adjustedY = y + menuHeight > window.innerHeight ? Math.max(0, window.innerHeight - menuHeight) : Math.max(0, y); return createPortal( <div ref={menuRef} className="context-menu" style={{ left: adjustedX, top: adjustedY }} > {items.map((item, i) => item.separator ? ( <div key={i} className="context-menu-separator" /> ) : ( <button key={i} className="context-menu-item" onClick={() => { item.action(); onClose(); }} disabled={item.disabled} > {item.icon && <span className="context-menu-item-icon">{item.icon}</span>} {item.label} </button> ) )} </div>, document.body, ); };