UNPKG

@jbrowse/core

Version:

JBrowse 2 core libraries used by plugins

57 lines (56 loc) 5.03 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { useState } from 'react'; import ChevronRight from '@mui/icons-material/ChevronRight'; import { Divider, ListItemIcon, ListItemText, ListSubheader, Menu, MenuItem, } from '@mui/material'; import CascadingMenuHelpIconButton from "./CascadingMenuHelpIconButton.js"; import HoverMenu from "./HoverMenu.js"; import { MenuItemEndDecoration } from "./MenuItems.js"; function labelToTestId(label) { if (typeof label === 'string') { return label.toLowerCase().replace(/\s+/g, '_'); } return undefined; } function CascadingSubmenu({ title, Icon, inset, menuItems, onMenuItemClick, closeAfterItemClick, onCloseRoot, isOpen, onOpen, onClose, }) { const [anchorEl, setAnchorEl] = useState(null); const testId = labelToTestId(title); return (_jsxs(_Fragment, { children: [_jsxs(MenuItem, { ref: setAnchorEl, "data-testid": testId ? `cascading-submenu-${testId}` : undefined, onMouseOver: onOpen, onFocus: onOpen, onClick: onOpen, children: [Icon ? (_jsx(ListItemIcon, { children: _jsx(Icon, {}) })) : null, _jsx(ListItemText, { primary: title, inset: inset }), _jsx(ChevronRight, {})] }), _jsx(HoverMenu, { open: isOpen, anchorEl: anchorEl, onClose: onClose, anchorOrigin: { vertical: 'top', horizontal: 'right' }, transformOrigin: { vertical: 'top', horizontal: 'left' }, children: _jsx(CascadingMenuList, { closeAfterItemClick: closeAfterItemClick, onMenuItemClick: onMenuItemClick, menuItems: menuItems, onCloseRoot: onCloseRoot }) })] })); } function CascadingMenuList({ onMenuItemClick, closeAfterItemClick, menuItems, onCloseRoot, }) { const [openSubmenuIdx, setOpenSubmenuIdx] = useState(); const closeSubmenu = () => { setOpenSubmenuIdx(undefined); }; const hasIcon = menuItems.some(m => 'icon' in m && m.icon); const hasCheckboxOrRadioWithHelp = menuItems.some(m => (m.type === 'checkbox' || m.type === 'radio') && 'helpText' in m && m.helpText); const sortedItems = menuItems.toSorted((a, b) => (b.priority || 0) - (a.priority || 0)); return (_jsx(_Fragment, { children: sortedItems.map((item, idx) => { if ('subMenu' in item) { return (_jsx(CascadingSubmenu, { title: item.label, Icon: item.icon, inset: hasIcon && !item.icon, onMenuItemClick: onMenuItemClick, menuItems: item.subMenu, closeAfterItemClick: closeAfterItemClick, onCloseRoot: onCloseRoot, isOpen: openSubmenuIdx === idx, onOpen: () => { setOpenSubmenuIdx(idx); }, onClose: closeSubmenu }, `subMenu-${item.label}-${idx}`)); } if (item.type === 'divider') { return _jsx(Divider, { component: "li" }, `divider-${idx}`); } if (item.type === 'subHeader') { return (_jsx(ListSubheader, { children: item.label }, `subHeader-${item.label}-${idx}`)); } const actionItem = item; const helpText = actionItem.helpText; const isCheckOrRadio = actionItem.type === 'checkbox' || actionItem.type === 'radio'; const itemTestId = labelToTestId(actionItem.label); return (_jsxs(MenuItem, { "data-testid": itemTestId ? `cascading-menuitem-${itemTestId}` : undefined, disabled: Boolean(actionItem.disabled), onClick: event => { if (closeAfterItemClick) { onCloseRoot(); } onMenuItemClick(event, actionItem.onClick); }, onMouseOver: closeSubmenu, children: [actionItem.icon ? (_jsx(ListItemIcon, { children: _jsx(actionItem.icon, {}) })) : null, _jsx(ListItemText, { primary: actionItem.label, secondary: actionItem.subLabel, inset: hasIcon && !actionItem.icon }), _jsx("div", { style: { flexGrow: 1, minWidth: 10 } }), isCheckOrRadio ? (_jsx(MenuItemEndDecoration, { type: actionItem.type, checked: actionItem.checked, disabled: actionItem.disabled })) : null, helpText ? (_jsx(CascadingMenuHelpIconButton, { helpText: helpText, label: actionItem.label })) : isCheckOrRadio && hasCheckboxOrRadioWithHelp ? (_jsx("div", { style: { marginLeft: 4, padding: 4, width: 28, height: 28 } })) : null] }, `${actionItem.label}-${idx}`)); }) })); } export default function CascadingMenu({ onMenuItemClick, closeAfterItemClick = true, menuItems, open, onClose, anchorEl, anchorOrigin, transformOrigin, anchorReference, anchorPosition, slotProps, marginThreshold, style, }) { const items = Array.isArray(menuItems) ? menuItems : menuItems(); return (_jsx(Menu, { anchorEl: anchorEl, open: open, onClose: onClose, anchorOrigin: anchorOrigin, transformOrigin: transformOrigin, anchorReference: anchorReference, anchorPosition: anchorPosition, slotProps: slotProps, marginThreshold: marginThreshold ?? undefined, style: style, children: _jsx(CascadingMenuList, { menuItems: items, closeAfterItemClick: closeAfterItemClick, onMenuItemClick: onMenuItemClick, onCloseRoot: onClose }) })); }