orcs-design-system
Version:
TeamForm's Design System, aka: ORCS
137 lines (132 loc) • 4.81 kB
JavaScript
import { useEffect, useRef, useMemo, useCallback } from "react";
import { findFirstExpandedByDefault } from "../utils/itemUtils";
import { getInitialSize as getInitialSizeUtil } from "../utils/resizeUtils";
import useResponsive from "./useResponsive";
import { useSideNavStateContext } from "../context/SideNavStateProvider";
import { useState } from "react";
/**
* Custom hook to manage SideNavV2 state
* @param {Array} items - Navigation items
* @param {boolean} startExpanded - Whether the sidebar should start expanded
* @returns {Object} Object containing all state and handlers
*/
const useSideNavState = function (items) {
let startExpanded = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
const {
expandedItem,
setExpandedItem,
isExpanded,
setIsExpanded,
expandedWidth,
setExpandedWidth
} = useSideNavStateContext();
const {
isSmallScreen
} = useResponsive();
const expandedRef = useRef(null);
const navItemRefs = useRef({});
const wrapperRef = useRef(null);
const isExpandedRef = useRef(isExpanded);
const [startedExpanded, setStartedExpanded] = useState(null);
useEffect(() => {
// first render or startExpanded changed?
if (startedExpanded === null || startedExpanded !== startExpanded) {
setStartedExpanded(startExpanded);
if (startExpanded) {
setIsExpanded(true);
} else {
setIsExpanded(false);
}
}
}, [setIsExpanded, startExpanded, startedExpanded]);
const firstExpandedItemByDefault = findFirstExpandedByDefault(items);
// Initialize expanded item by default
useEffect(() => {
if (firstExpandedItemByDefault >= 0) {
setExpandedItem(firstExpandedItemByDefault);
}
}, [firstExpandedItemByDefault, setExpandedItem]);
// Set initial size when an item is expanded
useEffect(() => {
if (expandedItem !== null) {
const currentItem = items[expandedItem];
const initialSize = getInitialSizeUtil(currentItem, isSmallScreen);
setExpandedWidth(initialSize);
}
}, [expandedItem, items, setExpandedWidth, isSmallScreen]);
// Focus on expanded item when it changes
useEffect(() => {
if (expandedItem !== null && expandedRef.current) {
expandedRef.current.focus();
}
}, [expandedItem]);
// Update isExpandedRef when isExpanded changes
useEffect(() => {
isExpandedRef.current = isExpanded;
}, [isExpanded]);
const handleItemClick = useCallback(function (item) {
let forceClose = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
const {
index: itemIndex,
actionType,
onClick: onButtonClick
} = item;
if (actionType === "link" || actionType === "button") {
// For link/button items, we need to handle related expanded panels
if (actionType === "link") {
// Find related expanded panels that should be opened for this route
const relatedPanelIndex = items.findIndex(navItem => navItem.actionType === "component" && navItem.pageSpecific === true && navItem.hide !== true);
if (relatedPanelIndex >= 0) {
// If we're already on this panel, keep it open (don't toggle)
if (expandedItem !== relatedPanelIndex) {
setExpandedItem(relatedPanelIndex);
}
} else {
// No related panel, close any open panel
setExpandedItem(null);
}
} else {
// For button items, just close any open panel
setExpandedItem(null);
}
onButtonClick && onButtonClick(item);
} else {
// Component items: open the panel and keep it open (no toggle)
// Exception: if forceClose is true (from close button), close the panel
if (forceClose && expandedItem === itemIndex) {
setExpandedItem(null);
} else if (expandedItem !== itemIndex) {
setExpandedItem(itemIndex);
}
onButtonClick && onButtonClick(item);
}
}, [expandedItem, setExpandedItem, items]);
const handleBlur = useCallback(item => {
handleItemClick(item);
}, [handleItemClick]);
const handleExpandToggle = useCallback(() => {
// Simple toggle behavior
const newExpandedState = !isExpanded;
setIsExpanded(newExpandedState);
}, [isExpanded, setIsExpanded]);
const handleWidthChange = useCallback(newWidth => {
setExpandedWidth(newWidth);
}, [setExpandedWidth]);
const isExpandedOnBigScreen = useMemo(() => {
const result = isExpanded && !isSmallScreen;
return result;
}, [isExpanded, isSmallScreen]);
return {
expandedItem,
isExpanded: isExpandedOnBigScreen,
expandedWidth,
expandedRef,
navItemRefs,
wrapperRef,
handleItemClick,
handleBlur,
handleWidthChange,
handleExpandToggle
};
};
export default useSideNavState;