import { createDisposables , isNil , useMergedRefs , useRefState , useResizeObserver } from "../../shared" ; import { useCallback , useEffect , useLayoutEffect , useRef , useState } from "react" ; import { TabType } from "./useTabsItems" ; export interface UseCollapsibleTabsOptions { gap ? : number ; isDisabled ? : boolean ; popoverTriggerWidth ? : number ; } const MinVisibleItems = 1 ; export function useCollapsibleTabs ( tabs , selectedKey , { gap , isDisabled , popoverTriggerWidth } = { } ) { const [ limit , setLimit ] = useState ( Infinity ) ; const [ visibleTabs , setVisibleTabs ] = useState ( tabs ) ; const [ collapsedTabs , setCollapsedTabs ] = useState < TabType [ ] > ( [ ] ) ; const [ isInitialResizeRef , setIsInitialResize ] = useRefState ( true ) ; const containerRef = useRef < HTMLElement > ( ) ; const computeLimit = useCallback ( ( ) => { const containerElement = containerRef . current ; if ( isNil ( containerElement ) ) { return ; } const availableWidth = containerElement . offsetWidth - popoverTriggerWidth ; const tabElements = containerElement . querySelectorAll < HTMLElement > ( "[data-o-ui-type=\"hidden-tab\"]" ) ; let i = 0 ; let currentWidth = 0 ; while ( i < tabElements . length ) { const element = tabElements [ i ] ; if ( element ) { currentWidth += element . offsetWidth + gap ; if ( currentWidth > availableWidth ) { break ; } } i ++ ; } setLimit ( Math . max ( MinVisibleItems , i ) ) ; } , [ gap , popoverTriggerWidth ] ) ; useLayoutEffect ( ( ) => { const newVisibleTabs = tabs . slice ( 0 , limit ) ; let newCollapsedTabs = tabs . slice ( limit ) ; const selectedTab = newCollapsedTabs . find ( x => x . key === selectedKey ) ; if ( ! isNil ( selectedTab ) ) { const lastVisibleTab = newVisibleTabs . pop ( ) ; newCollapsedTabs = newCollapsedTabs . filter ( x => x . key !== selectedKey ) ; newCollapsedTabs . unshift ( lastVisibleTab ) ; newVisibleTabs . push ( selectedTab ) ; } setVisibleTabs ( newVisibleTabs ) ; setCollapsedTabs ( newCollapsedTabs ) ; } , [ tabs , limit , selectedKey ] ) ; useEffect ( ( ) => { const disposables = createDisposables ( ) ; if ( ! isDisabled ) { disposables . nextFrame ( ( ) => { computeLimit ( ) ; } ) ; } return ( ) => { disposables . dispose ( ) ; } ; } , [ isDisabled , selectedKey , computeLimit ] ) ; const handleObserverResize = useCallback ( ( ) => { if ( isInitialResizeRef . current ) { setIsInitialResize ( false ) ; } else { computeLimit ( ) ; } } , [ computeLimit , isInitialResizeRef , setIsInitialResize ] ) ; const resizeRef = useResizeObserver ( handleObserverResize , { isDisabled : isDisabled || tabs ?. length < 2 } ) ; return { collapsedTabs , collapsibleTabsRef : useMergedRefs ( containerRef , resizeRef ) , hiddenTabs : [ ... visibleTabs , ... collapsedTabs ] , visibleTabs } ; }