mui-nav-menu
Version:
Navigation menu component based on material ui
176 lines (175 loc) • 6.66 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
const material_1 = require("@mui/material");
const react_1 = tslib_1.__importStar(require("react"));
const MenuContext_1 = require("./contexts/MenuContext");
const useDidMountEffect_1 = require("./hooks/useDidMountEffect");
const useMenuNodes_1 = require("./hooks/useMenuNodes");
const MenuRoot_1 = tslib_1.__importDefault(require("./MenuRoot"));
const utils_1 = require("./utils");
const NavMenu = ({ items: itemsProp, mode = "inline", inlineIndent = {
base: 12,
step: 12,
}, openIds: openIdsProp, onOpenChange: onOpenChangeProp, onItemClick, defaultOpenIds, accordion, defaultSelectedIds, children, rootClassName, collapsed, popperClassName, disableSelection, checkSelectedFn, selectedIds: selectedIdsProp, onSelectedChange: onSelectedChangeProp, placement, defaultCollapseIcon, defaultExpandIcon, defaultPopupRootIcon, defaultPopupSubIcon, TransitionComponent = material_1.Grow, disableCloseOnSelect, trigger = "hover", arrow = true, enterDelay = 100, leaveDelay = 100, elevation = 2, linkComponent, prefixCls = "NavMenu", }) => {
const restoredOpenIds = (0, react_1.useRef)();
const isClosedRef = (0, react_1.useRef)(true);
const [openIds = [], setOpenIds] = (0, material_1.useControlled)({
name: "openIds",
controlled: openIdsProp,
default: defaultOpenIds,
});
const openIdsRef = (0, react_1.useRef)([]);
const { processItem, getChildrenIds, getNode, clearNodes, getDescendantIds, } = (0, useMenuNodes_1.useMenuNodes)();
const mergedMode = (0, react_1.useMemo)(() => {
return collapsed && mode == "inline" ? "vertical" : mode;
}, [mode, collapsed]);
const handleOpenIds = (newOpenIds) => {
openIdsRef.current = [];
onOpenChangeProp && onOpenChangeProp(newOpenIds);
setOpenIds(newOpenIds);
};
const closeAll = () => {
isClosedRef.current = true;
handleOpenIds([]);
};
const onInternalOpenChange = (0, material_1.useEventCallback)((id, open, idPaths) => {
if (mergedMode == "inline" && accordion) {
if (open) {
handleOpenIds(idPaths);
}
else {
handleOpenIds(openIdsRef.current.filter((openId) => openId != id));
}
}
else {
let newOpenIds = openIdsRef.current.filter((openId) => openId != id);
if (open) {
if (idPaths.length > 1 && isClosedRef.current) {
//Prevents direct ejection from second level if everything is closed
return;
}
if (mergedMode == "inline") {
newOpenIds.push(id);
}
else {
newOpenIds = [...idPaths];
}
isClosedRef.current = false;
}
else {
//When closing, all child nodes need to be closed
if (mergedMode != "inline") {
const descendantIds = getDescendantIds(id);
newOpenIds = newOpenIds.filter((id) => !descendantIds.includes(id));
}
}
handleOpenIds(newOpenIds);
}
});
const [focusedNodeId, setFocusedNodeId] = (0, react_1.useState)();
const [selectedIds = [], setSelectedIds] = (0, material_1.useControlled)({
name: "selectedIds",
controlled: selectedIdsProp,
default: defaultSelectedIds,
});
const onSelectedChange = (newSelectedIds, closePopup) => {
if (!disableSelection) {
onSelectedChangeProp && onSelectedChangeProp(newSelectedIds);
setSelectedIds(newSelectedIds);
closePopup && setFocusedNodeId(null);
}
if (mergedMode != "inline" && closePopup && !disableCloseOnSelect) {
closeAll();
}
};
const contextValue = (0, react_1.useMemo)(() => {
return {
mode: mergedMode,
inlineIndent,
openIds,
onInternalOpenChange,
defaultOpenIds,
popperClassName,
collapsed,
selectedIds,
onSelectedChange,
checkSelectedFn,
TransitionComponent,
onItemClick,
getChildrenIds,
getNode,
focusedNodeId,
setFocusedNodeId,
elevation,
arrow,
placement,
defaultCollapseIcon,
defaultExpandIcon,
defaultPopupRootIcon,
defaultPopupSubIcon,
prefixCls,
trigger,
linkComponent,
enterDelay,
leaveDelay,
};
}, [
mergedMode,
inlineIndent,
openIds,
defaultOpenIds,
popperClassName,
collapsed,
selectedIds,
onSelectedChange,
checkSelectedFn,
TransitionComponent,
onItemClick,
focusedNodeId,
elevation,
arrow,
placement,
defaultCollapseIcon,
defaultExpandIcon,
defaultPopupRootIcon,
defaultPopupSubIcon,
prefixCls,
trigger,
linkComponent,
enterDelay,
leaveDelay,
]);
const itemNodes = (0, react_1.useMemo)(() => {
return itemsProp ? (0, utils_1.parseItemsToNodes)(itemsProp) : null;
}, [itemsProp]);
(0, useDidMountEffect_1.useDidMountEffect)(() => {
if (collapsed) {
//store openids
restoredOpenIds.current = [...openIdsRef.current];
handleOpenIds([]);
}
else {
if (restoredOpenIds.current) {
handleOpenIds(restoredOpenIds.current);
restoredOpenIds.current = null;
}
}
}, [collapsed]);
const items = (0, react_1.useMemo)(() => {
return children || itemNodes;
}, [children, itemNodes]);
(0, react_1.useEffect)(() => {
clearNodes();
react_1.default.Children.forEach(items, (child, index) => {
processItem(child, null, index);
});
}, [items]);
(0, react_1.useEffect)(() => {
openIdsRef.current = openIds;
isClosedRef.current = openIds.length == 0;
}, [openIds]);
return ((0, jsx_runtime_1.jsx)(MenuContext_1.MenuContext.Provider, { value: contextValue, children: (0, jsx_runtime_1.jsx)(MenuRoot_1.default, { className: rootClassName, children: items }) }));
};
exports.default = NavMenu;