import { useState, useEffect, useCallback, useRef } from 'react'; import { RouteGroup } from './sidebar'; import { useIsMobile } from '../../shared/use-mobile'; export interface UseSidebarProps { defaultExpanded?: boolean; expanded?: boolean; onExpandedChange?: (expanded: boolean) => void; navigationGroups?: RouteGroup[]; } export function useSidebar({ defaultExpanded = true, expanded: controlledExpanded, onExpandedChange, navigationGroups = [], }: UseSidebarProps = {}) { const [localExpanded, setLocalExpanded] = useState(defaultExpanded); const isControlled = controlledExpanded !== undefined; const expanded = isControlled ? controlledExpanded : localExpanded; const isMobileViewport = useIsMobile(); const [hasOverflow, setHasOverflow] = useState(false); const [visibleItems, setVisibleItems] = useState([]); const [overflowItems, setOverflowItems] = useState([]); const [openSubmenu, setOpenSubmenu] = useState(null); const [isFilterOpen, setIsFilterOpen] = useState(false); const navRef = useRef(null); const setExpanded = useCallback( (value: boolean | ((prev: boolean) => boolean)) => { const newValue = typeof value === 'function' ? value(expanded) : value; if (!isControlled) { setLocalExpanded(newValue); } onExpandedChange?.(newValue); }, [expanded, isControlled, onExpandedChange] ); const toggleExpanded = useCallback(() => { setExpanded(prev => !prev); }, [setExpanded]); // Overflow detection useEffect(() => { const checkOverflow = () => { if (!navRef.current || navigationGroups.length === 0) return; const containerHeight = navRef.current.clientHeight; let currentHeight = 0; let visibleCount = 0; // Approximate heights const itemHeight = 40; const groupHeaderHeight = 32; const padding = 32; currentHeight += padding; for (let i = 0; i < navigationGroups.length; i++) { const group = navigationGroups[i]; if (group.label) currentHeight += groupHeaderHeight; currentHeight += group.items.length * itemHeight; if (currentHeight > containerHeight) { break; } visibleCount++; } if (visibleCount < navigationGroups.length) { setHasOverflow(true); setVisibleItems(navigationGroups.slice(0, visibleCount)); setOverflowItems(navigationGroups.slice(visibleCount)); } else { setHasOverflow(false); setVisibleItems(navigationGroups); setOverflowItems([]); } }; checkOverflow(); window.addEventListener('resize', checkOverflow); return () => window.removeEventListener('resize', checkOverflow); }, [navigationGroups, expanded]); return { expanded, setExpanded, toggleExpanded, isMobileViewport, hasOverflow, visibleItems, overflowItems, openSubmenu, setOpenSubmenu, isFilterOpen, setIsFilterOpen, navRef, navigationGroups, }; }