UNPKG

mui-nested-menu

Version:

Infinitely deep nested menu items for MUI 5.

367 lines (307 loc) 14.5 kB
import {jsxs as $dw2me$jsxs, jsx as $dw2me$jsx} from "react/jsx-runtime"; import $dw2me$muimaterialMenu from "@mui/material/Menu"; import {forwardRef as $dw2me$forwardRef, useRef as $dw2me$useRef, useState as $dw2me$useState, useImperativeHandle as $dw2me$useImperativeHandle} from "react"; import $dw2me$muimaterialMenuItem from "@mui/material/MenuItem"; import {styled as $dw2me$styled} from "@mui/material/styles"; import $dw2me$muimaterialTypography from "@mui/material/Typography"; import $dw2me$muisystemBox from "@mui/system/Box"; import $dw2me$muimaterialSvgIcon from "@mui/material/SvgIcon"; import $dw2me$muimaterialButton from "@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$export(e, n, v, s) { Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true}); } var $4a0ad0bf42c271a8$exports = {}; var $ad513b13aee61650$exports = {}; $parcel$export($ad513b13aee61650$exports, "ContextMenu", () => $ad513b13aee61650$export$8dc6765e8be191c7); var $80b2acfbe3fcf9bd$exports = {}; $parcel$export($80b2acfbe3fcf9bd$exports, "nestedMenuItemsFromObject", () => $80b2acfbe3fcf9bd$export$fa07f0a23a9d3fdc); var $72864715d956ea8e$exports = {}; $parcel$export($72864715d956ea8e$exports, "IconMenuItem", () => $72864715d956ea8e$export$29aa74ef483b19fe); const $72864715d956ea8e$var$StyledMenuItem = (0, $dw2me$styled)((0, $dw2me$muimaterialMenuItem))({ display: 'flex', justifyContent: 'space-between', paddingLeft: '4px', paddingRight: '4px' }); const $72864715d956ea8e$var$StyledTypography = (0, $dw2me$styled)((0, $dw2me$muimaterialTypography))({ paddingLeft: '8px', paddingRight: '8px', textAlign: 'left' }); const $72864715d956ea8e$var$FlexBox = (0, $dw2me$styled)((0, $dw2me$muisystemBox))({ display: 'flex' }); const $72864715d956ea8e$export$29aa74ef483b19fe = /*#__PURE__*/ (0, $dw2me$forwardRef)(function IconMenuItem({ MenuItemProps: MenuItemProps, className: className, label: label, leftIcon: leftIcon, renderLabel: renderLabel, rightIcon: rightIcon, ...props }, ref) { return /*#__PURE__*/ (0, $dw2me$jsxs)($72864715d956ea8e$var$StyledMenuItem, { ...MenuItemProps, ref: ref, className: className, ...props, children: [ /*#__PURE__*/ (0, $dw2me$jsxs)($72864715d956ea8e$var$FlexBox, { children: [ leftIcon, renderLabel ? renderLabel() : /*#__PURE__*/ (0, $dw2me$jsx)($72864715d956ea8e$var$StyledTypography, { children: label }) ] }), rightIcon ] }); }); var $fbbfd8893e0b22a2$exports = {}; $parcel$export($fbbfd8893e0b22a2$exports, "NestedMenuItem", () => $fbbfd8893e0b22a2$export$a49133e888f99d9b); const $c842cdd09bc7bdb3$export$6172d85aadfc9b96 = (props)=>{ return /*#__PURE__*/ (0, $dw2me$jsx)((0, $dw2me$muimaterialSvgIcon), { ...props, children: /*#__PURE__*/ (0, $dw2me$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 $fbbfd8893e0b22a2$export$a49133e888f99d9b = /*#__PURE__*/ (0, $dw2me$forwardRef)(function NestedMenuItem(props, ref) { const { parentMenuOpen: parentMenuOpen, label: label, renderLabel: renderLabel, rightIcon: rightIcon = /*#__PURE__*/ (0, $dw2me$jsx)((0, $c842cdd09bc7bdb3$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, $dw2me$useRef)(null); (0, $dw2me$useImperativeHandle)(ref, ()=>menuItemRef.current); // eslint-disable-line @typescript-eslint/no-non-null-assertion const containerRef = (0, $dw2me$useRef)(null); (0, $dw2me$useImperativeHandle)(containerRefProp, ()=>containerRef.current); const menuContainerRef = (0, $dw2me$useRef)(null); const timeoutRef = (0, $dw2me$useRef)(null); const [isSubMenuOpen, setIsSubMenuOpen] = (0, $dw2me$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, $dw2me$jsxs)("div", { ...ContainerProps, ref: containerRef, onFocus: handleFocus, tabIndex: tabIndex, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onKeyDown: handleKeyDown, children: [ /*#__PURE__*/ (0, $dw2me$jsx)((0, $72864715d956ea8e$export$29aa74ef483b19fe), { MenuItemProps: MenuItemProps, className: className, ref: menuItemRef, leftIcon: leftIcon, rightIcon: rightIcon, label: label, renderLabel: renderLabel }), /*#__PURE__*/ (0, $dw2me$jsx)((0, $dw2me$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, $dw2me$jsx)("div", { ref: menuContainerRef, style: { pointerEvents: 'auto' }, children: children }) }) ] }); }); $fbbfd8893e0b22a2$export$a49133e888f99d9b.displayName = 'NestedMenuItem'; function $80b2acfbe3fcf9bd$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, $dw2me$jsx)((0, $fbbfd8893e0b22a2$export$a49133e888f99d9b), { leftIcon: leftIcon, rightIcon: rightIcon, label: label, parentMenuOpen: isOpen, sx: sx, delay: delay, disabled: disabled, children: $80b2acfbe3fcf9bd$export$fa07f0a23a9d3fdc({ handleClose: handleClose, isOpen: isOpen, menuItemsData: items }) }, label); else // No children elements, return MenuItem return /*#__PURE__*/ (0, $dw2me$jsx)((0, $72864715d956ea8e$export$29aa74ef483b19fe), { leftIcon: leftIcon, rightIcon: rightIcon, label: label, onClick: (event)=>{ handleClose(); callback && callback(event, item); }, sx: sx, disabled: disabled }, label); }); } const $ad513b13aee61650$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, $dw2me$forwardRef)(function ContextMenu({ children: children, menuItems: menuItems, menuItemsData: menuItemsData }, ref) { const wrapperRef = ref ?? (0, $dw2me$useRef)(null); const [menuPosition, setMenuPosition] = (0, $dw2me$useState)(null); const [mouseDownPosition, setMouseDownPosition] = (0, $dw2me$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, $80b2acfbe3fcf9bd$export$fa07f0a23a9d3fdc)({ handleClose: handleItemClick, isOpen: !!menuPosition, menuItemsData: menuItemsData })); return /*#__PURE__*/ (0, $dw2me$jsxs)("div", { ref: wrapperRef, onContextMenu: (e)=>e.preventDefault(), onMouseDown: handleMouseDown, onMouseUp: handleMouseUp, children: [ menuPosition && /*#__PURE__*/ (0, $dw2me$jsx)((0, $dw2me$muimaterialMenu), { onContextMenu: (e)=>e.preventDefault(), open: !!menuPosition, onClose: ()=>setMenuPosition(null), anchorReference: "anchorPosition", anchorPosition: menuPosition, children: menuContents }), children ] }); }); var $0967ca77ae60d41a$exports = {}; $parcel$export($0967ca77ae60d41a$exports, "NestedDropdown", () => $0967ca77ae60d41a$export$84d8e229d5f1c7fc); const $4a9ea60dc2f34ae6$export$4e3778eb35f54199 = (props)=>{ return /*#__PURE__*/ (0, $dw2me$jsx)((0, $dw2me$muimaterialSvgIcon), { ...props, children: /*#__PURE__*/ (0, $dw2me$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 $0967ca77ae60d41a$export$84d8e229d5f1c7fc = /*#__PURE__*/ (0, $dw2me$forwardRef)(function NestedDropdown(props, ref) { const [anchorEl, setAnchorEl] = (0, $dw2me$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, $80b2acfbe3fcf9bd$export$fa07f0a23a9d3fdc)({ handleClose: handleClose, isOpen: open, menuItemsData: data?.items ?? [] }); return /*#__PURE__*/ (0, $dw2me$jsxs)("div", { ref: ref, ...rest, children: [ /*#__PURE__*/ (0, $dw2me$jsx)((0, $dw2me$muimaterialButton), { onClick: handleClick, endIcon: /*#__PURE__*/ (0, $dw2me$jsx)((0, $4a9ea60dc2f34ae6$export$4e3778eb35f54199), {}), ...ButtonProps, children: data?.label ?? 'Menu' }), /*#__PURE__*/ (0, $dw2me$jsx)((0, $dw2me$muimaterialMenu), { anchorEl: anchorEl, open: open, onClose: handleClose, ...MenuProps, children: menuItems }) ] }); }); $parcel$exportWildcard($4a0ad0bf42c271a8$exports, $ad513b13aee61650$exports); $parcel$exportWildcard($4a0ad0bf42c271a8$exports, $72864715d956ea8e$exports); $parcel$exportWildcard($4a0ad0bf42c271a8$exports, $0967ca77ae60d41a$exports); $parcel$exportWildcard($4a0ad0bf42c271a8$exports, $fbbfd8893e0b22a2$exports); $parcel$exportWildcard($4a0ad0bf42c271a8$exports, $80b2acfbe3fcf9bd$exports); var $f84fb5b0231b4d1f$exports = {}; export {$ad513b13aee61650$export$8dc6765e8be191c7 as ContextMenu, $72864715d956ea8e$export$29aa74ef483b19fe as IconMenuItem, $0967ca77ae60d41a$export$84d8e229d5f1c7fc as NestedDropdown, $fbbfd8893e0b22a2$export$a49133e888f99d9b as NestedMenuItem, $80b2acfbe3fcf9bd$export$fa07f0a23a9d3fdc as nestedMenuItemsFromObject};