@@ -3,14 +3,17 @@ import {
33 Dispatch ,
44 FC ,
55 MutableRefObject ,
6+ ReactNode ,
67 SetStateAction ,
78 useCallback ,
89 useLayoutEffect ,
10+ useMemo ,
911 useRef ,
1012 useState ,
1113} from 'react'
1214
13- import { ActiveTabTipIcon } from '../svgs'
15+ import { useClickOutside } from '../hooks'
16+ import { ActiveTabTipIcon , IconOutline } from '../svgs'
1417
1518import { TabsNavItem } from './tabs-nav-item.model'
1619import styles from './TabsNavbar.module.scss'
@@ -28,6 +31,12 @@ const TabsNavbar: FC<TabsNavbarProps> = (props: TabsNavbarProps) => {
2831 const tabRefs : MutableRefObject < Array < HTMLElement > > = useRef ( [ ] as Array < HTMLElement > )
2932 const [ tabOpened , setTabOpened ] : [ string | undefined , Dispatch < SetStateAction < string | undefined > > ] = useState < string | undefined > ( props . defaultActive )
3033 const [ offset , setOffset ] : [ number , Dispatch < SetStateAction < number > > ] = useState < number > ( 0 )
34+ const [ menuIsVisible , setMenuIsVisible ] : [ boolean , Dispatch < SetStateAction < boolean > > ] = useState ( false )
35+ const triggerRef : MutableRefObject < any > = useRef ( undefined )
36+
37+ const activeTab : TabsNavItem = useMemo ( ( ) => (
38+ props . tabs . find ( tab => tab . id === tabOpened ) as TabsNavItem
39+ ) , [ tabOpened , props . tabs ] )
3140
3241 const updateOffset : ( tabId : string ) => void = useCallback ( ( tabId : string ) => {
3342
@@ -37,8 +46,8 @@ const TabsNavbar: FC<TabsNavbarProps> = (props: TabsNavbarProps) => {
3746 return
3847 }
3948
40- const activeTab : HTMLElement = tabRefs . current [ index ]
41- setOffset ( activeTab . offsetLeft + activeTab . offsetWidth / 2 )
49+ const activatedTab : HTMLElement = tabRefs . current [ index ]
50+ setOffset ( activatedTab . offsetLeft + activatedTab . offsetWidth / 2 )
4251 } , [
4352 props . tabs ,
4453 ] )
@@ -70,27 +79,54 @@ const TabsNavbar: FC<TabsNavbarProps> = (props: TabsNavbarProps) => {
7079 updateOffset ,
7180 ] )
7281
82+ const renderTabItem : ( tab : TabsNavItem , activeTabId ?: string , ref ?: ( el : HTMLDivElement ) => void ) => ReactNode = (
83+ tab : TabsNavItem ,
84+ activeTabId ?: string ,
85+ ref ?: ( el : HTMLDivElement ) => void
86+ ) => (
87+ < div
88+ ref = { ref }
89+ className = { classNames ( styles [ 'tab-item' ] , activeTabId === tab . id && 'active' ) }
90+ key = { tab . id }
91+ onClick = { ( ) => handleActivateTab ( tab . id ) }
92+ >
93+ < span className = { styles [ 'tab-label' ] } >
94+ { tab . title }
95+ </ span >
96+ { tab . badges ?. map ( ( badge , id ) => (
97+ < span className = { classNames ( styles [ 'tab-badge' ] , badge . type ) } key = { id } >
98+ { badge . count }
99+ </ span >
100+ ) ) }
101+ </ div >
102+ )
103+
104+ useClickOutside ( triggerRef . current , ( ) => setMenuIsVisible ( false ) )
105+
73106 return (
74107 < div className = { styles [ 'tabs-wrapper' ] } >
75- { props . tabs . map ( ( tab , i ) => (
76- < div
77- ref = { el => tabRefs . current [ i ] = el as HTMLElement }
78- className = { classNames ( styles [ 'tab-item' ] , tabOpened === tab . id && 'active' ) }
79- key = { tab . id }
80- onClick = { ( ) => handleActivateTab ( tab . id ) }
81- >
82- < span className = { styles [ 'tab-label' ] } >
83- { tab . title }
84- </ span >
85- { tab . badges ?. map ( ( badge , id ) => (
86- < span className = { classNames ( styles [ 'tab-badge' ] , badge . type ) } key = { id } >
87- { badge . count }
88- </ span >
89- ) ) }
90- </ div >
91- ) ) }
92108 < div
93- className = { styles [ 'active-icon' ] }
109+ className = {
110+ classNames (
111+ styles [ 'menu-trigger' ] ,
112+ 'desktop-hide' ,
113+ menuIsVisible && styles [ 'menu-is-visible' ]
114+ )
115+ }
116+ onClick = { ( ) => setMenuIsVisible ( ( menuWasVisible : boolean ) => ! menuWasVisible ) }
117+ ref = { triggerRef }
118+ >
119+ { renderTabItem ( activeTab ) }
120+ < IconOutline . ChevronDownIcon />
121+ </ div >
122+
123+ < div className = { classNames ( styles [ 'menu-wrapper' ] ) } >
124+ { props . tabs . map ( ( tab , i ) => (
125+ renderTabItem ( tab , tabOpened , el => { tabRefs . current [ i ] = el as HTMLElement } )
126+ ) ) }
127+ </ div >
128+ < div
129+ className = { classNames ( styles [ 'active-icon' ] , 'mobile-hide' ) }
94130 style = { { left : `${ offset } px` } }
95131 >
96132 < ActiveTabTipIcon />
0 commit comments