@hitachivantara/uikit-react-core
Version:
UI Kit Core React components.
196 lines (195 loc) • 7.32 kB
JavaScript
import { useControlled } from "../../hooks/useControlled.js";
import { uniqueId } from "../../utils/helpers.js";
import { getParentItemById } from "../NavigationSlider/utils.js";
import { VerticalNavigationContext } from "../VerticalNavigationContext.js";
import { NavigationPopupContainer } from "../NavigationPopup/NavigationPopupContainer.js";
import { HvVerticalNavigationSlider } from "../NavigationSlider/NavigationSlider.js";
import { HvVerticalNavigationTreeView } from "../TreeView/TreeView.js";
import { HvVerticalNavigationTreeViewItem } from "../TreeView/TreeViewItem.js";
import { useClasses } from "./Navigation.styles.js";
import { useDefaultProps } from "@hitachivantara/uikit-react-utils";
import { useCallback, useContext, useEffect, useMemo, useState } from "react";
import { jsx, jsxs } from "react/jsx-runtime";
//#region src/VerticalNavigation/Navigation/Navigation.tsx
var createListHierarchy = (items, classes, mouseEnterHandler, disableTooltip = false) => items.map((item) => {
const { id: itemId, label: itemLabel, icon, data: children, selectable, disabled, href, target } = item;
const itemMouseEnterHandler = (event) => {
mouseEnterHandler?.(event, item);
};
return /* @__PURE__ */ jsx(HvVerticalNavigationTreeViewItem, {
className: classes?.listItem,
href,
target,
nodeId: itemId,
label: itemLabel,
icon,
payload: item,
selectable,
disabled,
onMouseEnter: itemMouseEnterHandler,
disableTooltip,
children: children ? createListHierarchy(children, classes, mouseEnterHandler, disableTooltip) : void 0
}, itemId);
});
var getAllParents = (items) => {
const parents = items.filter((item) => item.data != null && item.data.length > 0);
const childParents = parents.flatMap((item) => getAllParents(item.data));
return [...parents, ...childParents];
};
function pathToElement(data, targetId) {
const path = [];
if (data != null && data.length > 0) for (let i = 0; i !== data.length; ++i) {
const item = data[i];
if (item.id === targetId) {
path.push(item.id);
break;
}
const subPaths = pathToElement(item.data, targetId);
if (subPaths.length > 0) {
path.push(item.id);
path.push(...subPaths);
break;
}
}
return path;
}
var HvVerticalNavigationTree = (props) => {
const { id, className, classes: classesProp, data, mode = "navigation", collapsible = false, expanded: expandedProp, defaultExpanded, onToggle, selected: selectedProp, defaultSelected, onChange, sliderForwardButtonAriaLabel = "Navigate to submenu", ...others } = useDefaultProps("HvVerticalNavigationTree", props);
const { classes, cx } = useClasses(classesProp);
const [selected, setSelected] = useControlled(selectedProp, defaultSelected);
const [expanded, setExpanded] = useControlled(expandedProp, () => {
if (defaultExpanded === true) return getAllParents(data).map((item) => item.id);
if (defaultExpanded === false) return [];
if (defaultExpanded == null) {
if (selected != null) return pathToElement(data, selected).slice(0, -1);
return [];
}
return defaultExpanded;
});
const { isOpen, useIcons, slider, parentItem, setParentItem, withParentData, navigateToChildHandler, setParentData, setParentSelected } = useContext(VerticalNavigationContext);
const [navigationPopup, setNavigationPopup] = useState(null);
const handleChange = useCallback((event, selectedId, selectedItem) => {
if (useIcons && !isOpen && selectedItem.data) {
const currentEventTarget = event.currentTarget;
setNavigationPopup((prevState) => {
return prevState?.anchorEl === currentEventTarget ? null : {
uniqueKey: uniqueId(),
anchorEl: currentEventTarget,
fixedMode: true,
data: selectedItem.data
};
});
event.stopPropagation();
} else {
setSelected(selectedId);
setExpanded((prevState) => {
if (!isOpen) return [...prevState, ...pathToElement(data, selectedId)];
return [...prevState];
});
setNavigationPopup(null);
onChange?.(event, selectedItem);
}
}, [
onChange,
setSelected,
setExpanded,
isOpen,
useIcons,
data
]);
const treeViewItemMouseEnterHandler = useCallback((event, item) => {
const isCollapsed = useIcons && !isOpen;
if (isCollapsed && item.data && !navigationPopup?.fixedMode) {
const currentEventTarget = event.currentTarget;
setNavigationPopup?.({
uniqueKey: uniqueId(),
anchorEl: currentEventTarget,
fixedMode: false,
data: item.data
});
} else if (isCollapsed && !item.data && !navigationPopup?.fixedMode) setNavigationPopup(null);
}, [
isOpen,
useIcons,
navigationPopup
]);
const handleToggle = useCallback((event, newExpanded) => {
setExpanded(newExpanded);
onToggle?.(event, newExpanded);
}, [onToggle, setExpanded]);
const children = useMemo(() => data && createListHierarchy(data, classes, treeViewItemMouseEnterHandler, navigationPopup?.fixedMode), [
classes,
data,
navigationPopup,
treeViewItemMouseEnterHandler
]);
useEffect(() => {
if (!isOpen) setNavigationPopup?.(null);
}, [isOpen]);
useEffect(() => {
if (setParentSelected) setParentSelected(selected);
}, [
selected,
setSelected,
setParentSelected
]);
useEffect(() => {
if (setParentData) setParentData(data);
}, [data, setParentData]);
useEffect(() => {
if (withParentData && selected && setParentItem && getParentItemById(withParentData, selected)) setParentItem(getParentItemById(withParentData, selected));
}, [
withParentData,
selected,
setParentItem
]);
const navigateToTargetHandler = (event, selectedItem) => handleChange(event, selectedItem.id, selectedItem);
const handleNavigationPopupClose = () => setNavigationPopup(null);
const handleStyledNavMouseLeave = () => {
if (useIcons && !isOpen && !navigationPopup?.fixedMode) setNavigationPopup(null);
};
const handleNavigationPopupMouseLeave = () => {
if (!navigationPopup?.fixedMode) handleNavigationPopupClose();
};
const handleNavigationPopupChange = (event, selectedItem) => {
handleChange(event, selectedItem.id, selectedItem);
};
return /* @__PURE__ */ jsx("nav", {
id,
className: cx(classes.root, { [classes.collapsed]: !isOpen && !useIcons }, className),
onMouseLeave: handleStyledNavMouseLeave,
...others,
children: slider ? /* @__PURE__ */ jsx(HvVerticalNavigationSlider, {
data: parentItem.data || withParentData,
selected,
onNavigateToTarget: navigateToTargetHandler,
onNavigateToChild: navigateToChildHandler,
forwardButtonAriaLabel: sliderForwardButtonAriaLabel
}) : /* @__PURE__ */ jsxs(HvVerticalNavigationTreeView, {
className: classes.list,
selectable: true,
mode,
collapsible,
selected,
onChange: handleChange,
expanded,
onToggle: handleToggle,
children: [useIcons && !isOpen && navigationPopup && /* @__PURE__ */ jsx(NavigationPopupContainer, {
anchorEl: navigationPopup.anchorEl,
onClose: handleNavigationPopupClose,
className: classes.navigationPopup,
children: /* @__PURE__ */ jsx(HvVerticalNavigationTree, {
className: classes.popup,
collapsible: true,
defaultExpanded: true,
selected,
data: navigationPopup.data,
onChange: handleNavigationPopupChange,
onMouseLeave: handleNavigationPopupMouseLeave
})
}, navigationPopup.uniqueKey), children]
})
});
};
//#endregion
export { HvVerticalNavigationTree };