import { Children , ReactElement , ReactNode , Ref , RefAttributes , useMemo } from "react" ; import { Content , Header } from "../../placeholders" ; import { isNil , mergeProps , resolveChildren } from "../../shared" ; export interface PanelType { disabled ? : boolean ; elementType ? : ReactElement [ "type" ] ; index ? : number ; key : string ; panelId : string ; props ? : Record < string , any > ; ref ? : Ref < any > ; tabId : string ; } export interface TabType { disabled ? : boolean ; elementType ? : ReactElement [ "type" ] ; index ? : number ; key : string ; panelId : string ; props ? : Record < string , any > ; ref ? : Ref < any > ; tabId : string ; } export class TabsBuilder { private rootId ; constructor ( rootId ) { this . rootId = rootId ; } build ( children ) { const tabs = [ ] ; const panels = [ ] ; let index = 0 ; Children . toArray ( children ) . filter ( x => x ) . forEach ( ( element , position ) => { const key = ! isNil ( element . key ) ? element . key . toString ( ) . replace ( "." , "" ) . replace ( "$" , "" ) : position . toString ( ) ; const [ header , content ] = Children . toArray ( resolveChildren ( element . props . children ) ) as [ ReactElement & RefAttributes < any > , ReactElement & RefAttributes < any > ] ; if ( isNil ( header ) || isNil ( content ) ) { throw new Error ( "A tabs item must have an <Header> and a <Content>." ) ; } const tabId = this . makeId ( header , "tab" , key ) ; const panelId = this . makeId ( content , "panel" , key ) ; tabs . push ( { elementType : header . type !== Header ? header . type : undefined , index : index ++ , key , panelId , props : mergeProps ( header . props , element . props ) , ref : header . ref , tabId } ) ; index ++ ; panels . push ( { elementType : content . type !== Content ? content . type : undefined , index : index ++ , key , panelId , props : content . props , ref : content . ref , tabId } ) ; } ) ; return [ tabs , panels ] ; } private makeId ( { props : { id } } , type , key ) { return id ?? `${ this . rootId }-${ type }-${ key }` ; } } export function useTabsItems ( children , rootId ) { const builder = useMemo ( ( ) => new TabsBuilder ( rootId ) , [ rootId ] ) ; return useMemo ( ( ) => builder . build ( children ) , [ builder , children ] ) ; }