@jbrowse/core
Version:
JBrowse 2 core libraries used by plugins
57 lines (56 loc) • 5.03 kB
JavaScript
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 }) }));
}