UNPKG

@jbrowse/core

Version:

JBrowse 2 core libraries used by plugins

234 lines (233 loc) 11.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MenuItemEndDecoration = MenuItemEndDecoration; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const ArrowRight_1 = __importDefault(require("@mui/icons-material/ArrowRight")); const CheckBox_1 = __importDefault(require("@mui/icons-material/CheckBox")); const CheckBoxOutlineBlank_1 = __importDefault(require("@mui/icons-material/CheckBoxOutlineBlank")); const RadioButtonChecked_1 = __importDefault(require("@mui/icons-material/RadioButtonChecked")); const RadioButtonUnchecked_1 = __importDefault(require("@mui/icons-material/RadioButtonUnchecked")); const material_1 = require("@mui/material"); const mui_1 = require("tss-react/mui"); const util_1 = require("../util"); const useStyles = (0, mui_1.makeStyles)()({ paper: { position: 'fixed', overflowY: 'auto', overflowX: 'hidden', minWidth: 16, minHeight: 16, maxWidth: 'calc(100% - 32px)', maxHeight: 'calc(100% - 32px)', top: 0, left: 0, outline: 0, }, menuItemEndDecoration: { padding: 0, margin: 0, height: 16, }, }); function MenuItemEndDecoration(props) { const { classes } = useStyles(); const { type } = props; let checked; let disabled; if ('checked' in props) { ; ({ checked, disabled } = props); } let icon; switch (type) { case 'subMenu': { icon = (0, jsx_runtime_1.jsx)(ArrowRight_1.default, { color: "action" }); break; } case 'checkbox': { if (checked) { const color = disabled ? 'inherit' : undefined; icon = (0, jsx_runtime_1.jsx)(CheckBox_1.default, { color: color }); } else { icon = (0, jsx_runtime_1.jsx)(CheckBoxOutlineBlank_1.default, { color: "action" }); } break; } case 'radio': { if (checked) { const color = disabled ? 'inherit' : undefined; icon = (0, jsx_runtime_1.jsx)(RadioButtonChecked_1.default, { color: color }); } else { icon = (0, jsx_runtime_1.jsx)(RadioButtonUnchecked_1.default, { color: "action" }); } break; } } return (0, jsx_runtime_1.jsx)("div", { className: classes.menuItemEndDecoration, children: icon }); } function checkIfValid(m) { return m.type !== 'divider' && m.type !== 'subHeader' && !m.disabled; } function findNextValidIdx(menuItems, currentIdx) { const idx = menuItems.slice(currentIdx + 1).findIndex(checkIfValid); if (idx === -1) { return idx; } return currentIdx + 1 + idx; } function findPreviousValidIdx(menuItems, currentIdx) { return (0, util_1.findLastIndex)(menuItems.slice(0, currentIdx), checkIfValid); } const MenuPage = (0, react_1.forwardRef)(function MenuPage2(props, ref) { const [subMenuAnchorEl, setSubMenuAnchorEl] = (0, react_1.useState)(); const [openSubMenuIdx, setOpenSubMenuIdx] = (0, react_1.useState)(); const [isSubMenuOpen, setIsSubMenuOpen] = (0, react_1.useState)(false); const [selectedMenuItemIdx, setSelectedMenuItemIdx] = (0, react_1.useState)(); const [position, setPosition] = (0, react_1.useState)(); const paperRef = (0, react_1.useRef)(null); const { classes } = useStyles(); const { menuItems, onMenuItemClick, open, onClose, anchorEl, top = false, } = props; (0, react_1.useEffect)(() => { if (!open) { setSubMenuAnchorEl(undefined); setOpenSubMenuIdx(undefined); } }, [open]); (0, react_1.useEffect)(() => { const shouldSubMenuBeOpen = open && Boolean(subMenuAnchorEl); let timer; if (shouldSubMenuBeOpen && !isSubMenuOpen) { timer = setTimeout(() => { setIsSubMenuOpen(true); }, 300); } else if (!shouldSubMenuBeOpen && isSubMenuOpen) { timer = setTimeout(() => { setIsSubMenuOpen(false); }, 300); } return () => { clearTimeout(timer); }; }, [isSubMenuOpen, open, subMenuAnchorEl]); (0, react_1.useEffect)(() => { if (anchorEl) { const rect = anchorEl.getBoundingClientRect(); if (position) { if (rect.top !== position.top || rect.left + rect.width !== position.left) { setPosition({ top: rect.top, left: rect.left + rect.width }); } } else { setPosition({ top: rect.top, left: rect.left + rect.width }); } } else if (!position) { setPosition({}); } }, [position, anchorEl]); const hasIcon = menuItems.some(menuItem => 'icon' in menuItem && menuItem.icon); const menuItemStyle = {}; function handleClick(callback) { return (event) => { onMenuItemClick(event, callback); }; } const ListContents = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(material_1.MenuList, { autoFocusItem: open && !isSubMenuOpen, dense: true, children: menuItems .sort((a, b) => (b.priority || 0) - (a.priority || 0)) .map((menuItem, idx) => { if (menuItem.type === 'divider') { return ((0, jsx_runtime_1.jsx)(material_1.Divider, { component: "li" }, `divider-${JSON.stringify(menuItem)}-${idx}`)); } if (menuItem.type === 'subHeader') { return ((0, jsx_runtime_1.jsx)(material_1.ListSubheader, { children: menuItem.label }, `subHeader-${menuItem.label}-${idx}`)); } let icon = null; let endDecoration = null; if (menuItem.icon) { const Icon = menuItem.icon; icon = ((0, jsx_runtime_1.jsx)(material_1.ListItemIcon, { children: (0, jsx_runtime_1.jsx)(Icon, {}) })); } if ('subMenu' in menuItem) { endDecoration = (0, jsx_runtime_1.jsx)(MenuItemEndDecoration, { type: "subMenu" }); } else if (menuItem.type === 'checkbox' || menuItem.type === 'radio') { endDecoration = ((0, jsx_runtime_1.jsx)(MenuItemEndDecoration, { type: menuItem.type, checked: menuItem.checked, disabled: menuItem.disabled })); } const onClick = 'onClick' in menuItem ? handleClick(menuItem.onClick) : undefined; return ((0, jsx_runtime_1.jsxs)(material_1.MenuItem, { style: menuItemStyle, selected: idx === selectedMenuItemIdx, onClick: onClick, onMouseMove: e => { if (e.currentTarget !== document.activeElement) { e.currentTarget.focus(); setSelectedMenuItemIdx(idx); } if ('subMenu' in menuItem) { if (openSubMenuIdx !== idx) { setSubMenuAnchorEl(e.currentTarget); setOpenSubMenuIdx(idx); } } else { setSubMenuAnchorEl(undefined); setOpenSubMenuIdx(undefined); } }, onKeyDown: e => { switch (e.key) { case 'ArrowLeft': case 'Escape': { onClose === null || onClose === void 0 ? void 0 : onClose(e, 'escapeKeyDown'); break; } case 'ArrowUp': { setSelectedMenuItemIdx(findPreviousValidIdx(menuItems, idx)); break; } case 'ArrowDown': { const a = findNextValidIdx(menuItems, idx); setSelectedMenuItemIdx(a); break; } default: { if ('subMenu' in menuItem && (e.key === 'ArrowRight' || e.key === 'Enter')) { setSubMenuAnchorEl(e.currentTarget); setOpenSubMenuIdx(idx); setIsSubMenuOpen(true); } } } }, disabled: Boolean(menuItem.disabled), children: [icon, (0, jsx_runtime_1.jsx)(material_1.ListItemText, { primary: menuItem.label, secondary: menuItem.subLabel, inset: hasIcon && !menuItem.icon }), endDecoration] }, menuItem.id || String(menuItem.label))); }) }), menuItems.map((menuItem, idx) => { let subMenu = null; if ('subMenu' in menuItem) { subMenu = ((0, jsx_runtime_1.jsx)(MenuPage, { anchorEl: subMenuAnchorEl, open: isSubMenuOpen && openSubMenuIdx === idx, onClose: () => { setIsSubMenuOpen(false); setSubMenuAnchorEl(undefined); }, onMenuItemClick: onMenuItemClick, menuItems: menuItem.subMenu }, menuItem.id || String(menuItem.label))); } return subMenu; })] })); return top ? (ListContents) : ((0, jsx_runtime_1.jsx)(material_1.Grow, { in: open, style: { transformOrigin: '0 0 0' }, ref: ref, children: (0, jsx_runtime_1.jsx)(material_1.Paper, { elevation: 8, ref: paperRef, className: classes.paper, style: { ...position }, children: ListContents }) })); }); function Menu(props) { const { open, onClose, menuItems, onMenuItemClick, ...other } = props; return ((0, jsx_runtime_1.jsx)(material_1.Popover, { open: open, onClose: onClose, anchorOrigin: { vertical: 'bottom', horizontal: 'right', ...other.anchorOrigin, }, transformOrigin: { vertical: 'top', horizontal: 'left', ...other.transformOrigin, }, ...other, children: (0, jsx_runtime_1.jsx)(MenuPage, { open: open, onClose: onClose, menuItems: menuItems, onMenuItemClick: onMenuItemClick, top: true }) })); } exports.default = Menu;