UNPKG

mui-nested-menu

Version:

Infinitely deep nested menu items for MUI 5.

372 lines (311 loc) 15 kB
var $hXhXL$reactjsxruntime = require("react/jsx-runtime"); var $hXhXL$muimaterialMenu = require("@mui/material/Menu"); var $hXhXL$react = require("react"); var $hXhXL$muimaterialMenuItem = require("@mui/material/MenuItem"); var $hXhXL$muimaterialstyles = require("@mui/material/styles"); var $hXhXL$muimaterialTypography = require("@mui/material/Typography"); var $hXhXL$muisystemBox = require("@mui/system/Box"); var $hXhXL$muimaterialSvgIcon = require("@mui/material/SvgIcon"); var $hXhXL$muimaterialButton = require("@mui/material/Button"); function $parcel$exportWildcard(dest, source) { Object.keys(source).forEach(function(key) { if (key === 'default' || key === '__esModule' || Object.prototype.hasOwnProperty.call(dest, key)) { return; } Object.defineProperty(dest, key, { enumerable: true, get: function get() { return source[key]; } }); }); return dest; } function $parcel$interopDefault(a) { return a && a.__esModule ? a.default : a; } function $parcel$export(e, n, v, s) { Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true}); } var $681a5bb3d531a14d$exports = {}; var $18e895906fc59095$exports = {}; $parcel$export($18e895906fc59095$exports, "ContextMenu", () => $18e895906fc59095$export$8dc6765e8be191c7); var $f6841acb38ae6244$exports = {}; $parcel$export($f6841acb38ae6244$exports, "nestedMenuItemsFromObject", () => $f6841acb38ae6244$export$fa07f0a23a9d3fdc); var $4bfc6f7ac91dd60d$exports = {}; $parcel$export($4bfc6f7ac91dd60d$exports, "IconMenuItem", () => $4bfc6f7ac91dd60d$export$29aa74ef483b19fe); const $4bfc6f7ac91dd60d$var$StyledMenuItem = (0, $hXhXL$muimaterialstyles.styled)((0, ($parcel$interopDefault($hXhXL$muimaterialMenuItem))))({ display: 'flex', justifyContent: 'space-between', paddingLeft: '4px', paddingRight: '4px' }); const $4bfc6f7ac91dd60d$var$StyledTypography = (0, $hXhXL$muimaterialstyles.styled)((0, ($parcel$interopDefault($hXhXL$muimaterialTypography))))({ paddingLeft: '8px', paddingRight: '8px', textAlign: 'left' }); const $4bfc6f7ac91dd60d$var$FlexBox = (0, $hXhXL$muimaterialstyles.styled)((0, ($parcel$interopDefault($hXhXL$muisystemBox))))({ display: 'flex' }); const $4bfc6f7ac91dd60d$export$29aa74ef483b19fe = /*#__PURE__*/ (0, $hXhXL$react.forwardRef)(function IconMenuItem({ MenuItemProps: MenuItemProps, className: className, label: label, leftIcon: leftIcon, renderLabel: renderLabel, rightIcon: rightIcon, ...props }, ref) { return /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsxs)($4bfc6f7ac91dd60d$var$StyledMenuItem, { ...MenuItemProps, ref: ref, className: className, ...props, children: [ /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsxs)($4bfc6f7ac91dd60d$var$FlexBox, { children: [ leftIcon, renderLabel ? renderLabel() : /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)($4bfc6f7ac91dd60d$var$StyledTypography, { children: label }) ] }), rightIcon ] }); }); var $f5195a18afaf3fe7$exports = {}; $parcel$export($f5195a18afaf3fe7$exports, "NestedMenuItem", () => $f5195a18afaf3fe7$export$a49133e888f99d9b); const $e308e62c69875369$export$6172d85aadfc9b96 = (props)=>{ return /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)((0, ($parcel$interopDefault($hXhXL$muimaterialSvgIcon))), { ...props, children: /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)("path", { d: "M9.29 6.71c-.39.39-.39 1.02 0 1.41L13.17 12l-3.88 3.88c-.39.39-.39 1.02 0 1.41.39.39 1.02.39 1.41 0l4.59-4.59c.39-.39.39-1.02 0-1.41L10.7 6.7c-.38-.38-1.02-.38-1.41.01z" }) }); }; const $f5195a18afaf3fe7$export$a49133e888f99d9b = /*#__PURE__*/ (0, $hXhXL$react.forwardRef)(function NestedMenuItem(props, ref) { const { parentMenuOpen: parentMenuOpen, label: label, renderLabel: renderLabel, rightIcon: rightIcon = /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)((0, $e308e62c69875369$export$6172d85aadfc9b96), {}), leftIcon: leftIcon = null, children: children, className: className, tabIndex: tabIndexProp, ContainerProps: ContainerPropsProp = {}, MenuProps: MenuProps, delay: delay = 0, ...MenuItemProps } = props; const { ref: containerRefProp, ...ContainerProps } = ContainerPropsProp; const menuItemRef = (0, $hXhXL$react.useRef)(null); (0, $hXhXL$react.useImperativeHandle)(ref, ()=>menuItemRef.current); // eslint-disable-line @typescript-eslint/no-non-null-assertion const containerRef = (0, $hXhXL$react.useRef)(null); (0, $hXhXL$react.useImperativeHandle)(containerRefProp, ()=>containerRef.current); const menuContainerRef = (0, $hXhXL$react.useRef)(null); const timeoutRef = (0, $hXhXL$react.useRef)(null); const [isSubMenuOpen, setIsSubMenuOpen] = (0, $hXhXL$react.useState)(false); const handleMouseEnter = (e)=>{ timeoutRef.current = setTimeout(()=>{ if (!props.disabled) setIsSubMenuOpen(true); if (ContainerProps.onMouseEnter) ContainerProps.onMouseEnter(e); }, delay); }; const handleMouseLeave = (e)=>{ timeoutRef.current && clearTimeout(timeoutRef.current); setIsSubMenuOpen(false); if (ContainerProps.onMouseLeave) ContainerProps.onMouseLeave(e); }; // Check if any immediate children are active const isSubmenuFocused = ()=>{ const active = containerRef.current?.ownerDocument.activeElement ?? null; if (menuContainerRef.current == null) return false; for (const child of menuContainerRef.current.children){ if (child === active) return true; } return false; }; const handleFocus = (e)=>{ if (e.target === containerRef.current && !props.disabled) setIsSubMenuOpen(true); if (ContainerProps.onFocus) ContainerProps.onFocus(e); }; const handleKeyDown = (e)=>{ if (e.key === 'Escape') return; if (isSubmenuFocused()) e.stopPropagation(); const active = containerRef.current?.ownerDocument.activeElement; if (e.key === 'ArrowLeft' && isSubmenuFocused()) containerRef.current?.focus(); if (e.key === 'ArrowRight' && e.target === containerRef.current && e.target === active) { const firstChild = menuContainerRef.current?.children[0]; firstChild?.focus(); } }; const open = isSubMenuOpen && parentMenuOpen; // Root element must have a `tabIndex` attribute for keyboard navigation let tabIndex; if (!props.disabled) tabIndex = tabIndexProp !== undefined ? tabIndexProp : -1; return /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsxs)("div", { ...ContainerProps, ref: containerRef, onFocus: handleFocus, tabIndex: tabIndex, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onKeyDown: handleKeyDown, children: [ /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)((0, $4bfc6f7ac91dd60d$export$29aa74ef483b19fe), { MenuItemProps: MenuItemProps, className: className, ref: menuItemRef, leftIcon: leftIcon, rightIcon: rightIcon, label: label, renderLabel: renderLabel }), /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)((0, ($parcel$interopDefault($hXhXL$muimaterialMenu))), { // Set pointer events to 'none' to prevent the invisible Popover div // from capturing events for clicks and hovers style: { pointerEvents: 'none' }, anchorEl: menuItemRef.current, anchorOrigin: { horizontal: 'right', vertical: 'top' }, transformOrigin: { horizontal: 'left', vertical: 'top' }, open: open, autoFocus: false, disableAutoFocus: true, disableEnforceFocus: true, onClose: ()=>{ setIsSubMenuOpen(false); }, ...MenuProps, children: /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)("div", { ref: menuContainerRef, style: { pointerEvents: 'auto' }, children: children }) }) ] }); }); $f5195a18afaf3fe7$export$a49133e888f99d9b.displayName = 'NestedMenuItem'; function $f6841acb38ae6244$export$fa07f0a23a9d3fdc({ menuItemsData: items, isOpen: isOpen, handleClose: handleClose }) { return items.map((item)=>{ const { leftIcon: leftIcon, rightIcon: rightIcon, label: label, items: items, callback: callback, sx: sx, disabled: disabled, delay: delay } = item; if (items && items.length > 0) // Recurse deeper return /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)((0, $f5195a18afaf3fe7$export$a49133e888f99d9b), { leftIcon: leftIcon, rightIcon: rightIcon, label: label, parentMenuOpen: isOpen, sx: sx, delay: delay, disabled: disabled, children: $f6841acb38ae6244$export$fa07f0a23a9d3fdc({ handleClose: handleClose, isOpen: isOpen, menuItemsData: items }) }, label); else // No children elements, return MenuItem return /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)((0, $4bfc6f7ac91dd60d$export$29aa74ef483b19fe), { leftIcon: leftIcon, rightIcon: rightIcon, label: label, onClick: (event)=>{ handleClose(); callback && callback(event, item); }, sx: sx, disabled: disabled }, label); }); } const $18e895906fc59095$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, $hXhXL$react.forwardRef)(function ContextMenu({ children: children, menuItems: menuItems, menuItemsData: menuItemsData }, ref) { const wrapperRef = ref ?? (0, $hXhXL$react.useRef)(null); const [menuPosition, setMenuPosition] = (0, $hXhXL$react.useState)(null); const [mouseDownPosition, setMouseDownPosition] = (0, $hXhXL$react.useState)(null); const handleItemClick = ()=>setMenuPosition(null); const handleMouseDown = (e)=>{ if (menuPosition !== null) setMenuPosition(null); if (e.button !== 2) return; const wrapperBounds = wrapperRef.current.getBoundingClientRect(); if (e.clientX < wrapperBounds.left || e.clientX > wrapperBounds.right || e.clientY < wrapperBounds.top || e.clientY > wrapperBounds.bottom) return; setMouseDownPosition({ left: e.clientX, top: e.clientY }); }; const handleMouseUp = (e)=>{ const top = e.clientY; const left = e.clientX; if (mouseDownPosition === null) return; if (mouseDownPosition.top === top && mouseDownPosition.left === left) setMenuPosition({ left: e.clientX, top: e.clientY }); }; const menuContents = menuItems ?? (menuItemsData && (0, $f6841acb38ae6244$export$fa07f0a23a9d3fdc)({ handleClose: handleItemClick, isOpen: !!menuPosition, menuItemsData: menuItemsData })); return /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsxs)("div", { ref: wrapperRef, onContextMenu: (e)=>e.preventDefault(), onMouseDown: handleMouseDown, onMouseUp: handleMouseUp, children: [ menuPosition && /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)((0, ($parcel$interopDefault($hXhXL$muimaterialMenu))), { onContextMenu: (e)=>e.preventDefault(), open: !!menuPosition, onClose: ()=>setMenuPosition(null), anchorReference: "anchorPosition", anchorPosition: menuPosition, children: menuContents }), children ] }); }); var $70717eed00f20fb6$exports = {}; $parcel$export($70717eed00f20fb6$exports, "NestedDropdown", () => $70717eed00f20fb6$export$84d8e229d5f1c7fc); const $83896c6160d9245a$export$4e3778eb35f54199 = (props)=>{ return /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)((0, ($parcel$interopDefault($hXhXL$muimaterialSvgIcon))), { ...props, children: /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)("path", { d: "M8.12 9.29 12 13.17l3.88-3.88c.39-.39 1.02-.39 1.41 0 .39.39.39 1.02 0 1.41l-4.59 4.59c-.39.39-1.02.39-1.41 0L6.7 10.7a.9959.9959 0 0 1 0-1.41c.39-.38 1.03-.39 1.42 0z" }) }); }; const $70717eed00f20fb6$export$84d8e229d5f1c7fc = /*#__PURE__*/ (0, $hXhXL$react.forwardRef)(function NestedDropdown(props, ref) { const [anchorEl, setAnchorEl] = (0, $hXhXL$react.useState)(null); const open = Boolean(anchorEl); const { menuItemsData: data, onClick: onClick, ButtonProps: ButtonProps, MenuProps: MenuProps, ...rest } = props; const handleClick = (e)=>{ setAnchorEl(e.currentTarget); onClick && onClick(e); }; const handleClose = ()=>setAnchorEl(null); const menuItems = (0, $f6841acb38ae6244$export$fa07f0a23a9d3fdc)({ handleClose: handleClose, isOpen: open, menuItemsData: data?.items ?? [] }); return /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsxs)("div", { ref: ref, ...rest, children: [ /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)((0, ($parcel$interopDefault($hXhXL$muimaterialButton))), { onClick: handleClick, endIcon: /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)((0, $83896c6160d9245a$export$4e3778eb35f54199), {}), ...ButtonProps, children: data?.label ?? 'Menu' }), /*#__PURE__*/ (0, $hXhXL$reactjsxruntime.jsx)((0, ($parcel$interopDefault($hXhXL$muimaterialMenu))), { anchorEl: anchorEl, open: open, onClose: handleClose, ...MenuProps, children: menuItems }) ] }); }); $parcel$exportWildcard($681a5bb3d531a14d$exports, $18e895906fc59095$exports); $parcel$exportWildcard($681a5bb3d531a14d$exports, $4bfc6f7ac91dd60d$exports); $parcel$exportWildcard($681a5bb3d531a14d$exports, $70717eed00f20fb6$exports); $parcel$exportWildcard($681a5bb3d531a14d$exports, $f5195a18afaf3fe7$exports); $parcel$exportWildcard($681a5bb3d531a14d$exports, $f6841acb38ae6244$exports); var $dbc53ae45b7d68af$exports = {}; $parcel$exportWildcard(module.exports, $681a5bb3d531a14d$exports); $parcel$exportWildcard(module.exports, $dbc53ae45b7d68af$exports);