99 * Copyright (c) Facebook, Inc. and its affiliates.
1010 */
1111
12- import { useRef , useLayoutEffect , Fragment } from 'react' ;
12+ import { useRef , useLayoutEffect , useState , useEffect , Fragment } from 'react' ;
1313
1414import cn from 'classnames' ;
1515import { useRouter } from 'next/router' ;
@@ -78,6 +78,95 @@ function CollapseWrapper({
7878 ) ;
7979}
8080
81+ interface SidebarItemProps {
82+ item : RouteItem ;
83+ level : number ;
84+ isForceExpanded : boolean ;
85+ breadcrumbs : RouteItem [ ] ;
86+ slug : string ;
87+ pendingRoute : string | null ;
88+ }
89+
90+ function SidebarItem ( {
91+ item,
92+ level,
93+ isForceExpanded,
94+ breadcrumbs,
95+ slug,
96+ pendingRoute,
97+ } : SidebarItemProps ) {
98+ const { path, title, routes, version, heading} = item ;
99+ const selected = slug === path ;
100+ const isBreadcrumb =
101+ breadcrumbs . length > 1 && breadcrumbs [ breadcrumbs . length - 1 ] . path === path ;
102+
103+ const [ isCollapsed , setIsCollapsed ] = useState ( false ) ;
104+
105+ const shouldBeExpanded = isForceExpanded || isBreadcrumb || selected ;
106+ const isExpanded = shouldBeExpanded && ! isCollapsed ;
107+
108+ useEffect ( ( ) => {
109+ if ( ! selected ) {
110+ setIsCollapsed ( false ) ;
111+ }
112+ } , [ selected ] ) ;
113+
114+ const handleClick = ( event : React . MouseEvent < HTMLAnchorElement > ) => {
115+ if ( selected ) {
116+ event . preventDefault ( ) ;
117+ setIsCollapsed ( ( prev ) => ! prev ) ;
118+ }
119+ } ;
120+
121+ if ( ! path || heading ) {
122+ return (
123+ < SidebarRouteTree
124+ level = { level + 1 }
125+ isForceExpanded = { isForceExpanded }
126+ routeTree = { { title, routes} }
127+ breadcrumbs = { [ ] }
128+ />
129+ ) ;
130+ } else if ( routes ) {
131+ return (
132+ < li >
133+ < SidebarLink
134+ href = { path }
135+ isPending = { pendingRoute === path }
136+ selected = { selected }
137+ level = { level }
138+ title = { title }
139+ version = { version }
140+ isExpanded = { isExpanded }
141+ hideArrow = { isForceExpanded }
142+ onClick = { handleClick }
143+ />
144+ < CollapseWrapper duration = { 250 } isExpanded = { isExpanded } >
145+ < SidebarRouteTree
146+ isForceExpanded = { isForceExpanded }
147+ routeTree = { { title, routes} }
148+ breadcrumbs = { breadcrumbs }
149+ level = { level + 1 }
150+ />
151+ </ CollapseWrapper >
152+ </ li >
153+ ) ;
154+ } else {
155+ return (
156+ < li >
157+ < SidebarLink
158+ isPending = { pendingRoute === path }
159+ href = { path }
160+ selected = { selected }
161+ level = { level }
162+ title = { title }
163+ version = { version }
164+ />
165+ </ li >
166+ ) ;
167+ }
168+ }
169+
81170export function SidebarRouteTree ( {
82171 isForceExpanded,
83172 breadcrumbs,
@@ -89,102 +178,44 @@ export function SidebarRouteTree({
89178 const currentRoutes = routeTree . routes as RouteItem [ ] ;
90179 return (
91180 < ul >
92- { currentRoutes . map (
93- (
94- {
95- path,
96- title,
97- routes,
98- version,
99- heading,
100- hasSectionHeader,
101- sectionHeader,
102- } ,
103- index
104- ) => {
105- const selected = slug === path ;
106- let listItem = null ;
107- if ( ! path || heading ) {
108- // if current route item has no path and children treat it as an API sidebar heading
109- listItem = (
110- < SidebarRouteTree
111- level = { level + 1 }
112- isForceExpanded = { isForceExpanded }
113- routeTree = { { title, routes} }
114- breadcrumbs = { [ ] }
115- />
116- ) ;
117- } else if ( routes ) {
118- // if route has a path and child routes, treat it as an expandable sidebar item
119- const isBreadcrumb =
120- breadcrumbs . length > 1 &&
121- breadcrumbs [ breadcrumbs . length - 1 ] . path === path ;
122- const isExpanded = isForceExpanded || isBreadcrumb || selected ;
123- listItem = (
124- < li key = { `${ title } -${ path } -${ level } -heading` } >
125- < SidebarLink
126- key = { `${ title } -${ path } -${ level } -link` }
127- href = { path }
128- isPending = { pendingRoute === path }
129- selected = { selected }
130- level = { level }
131- title = { title }
132- version = { version }
133- isExpanded = { isExpanded }
134- hideArrow = { isForceExpanded }
135- />
136- < CollapseWrapper duration = { 250 } isExpanded = { isExpanded } >
137- < SidebarRouteTree
138- isForceExpanded = { isForceExpanded }
139- routeTree = { { title, routes} }
140- breadcrumbs = { breadcrumbs }
141- level = { level + 1 }
142- />
143- </ CollapseWrapper >
144- </ li >
145- ) ;
146- } else {
147- // if route has a path and no child routes, treat it as a sidebar link
148- listItem = (
149- < li key = { `${ title } -${ path } -${ level } -link` } >
150- < SidebarLink
151- isPending = { pendingRoute === path }
152- href = { path }
153- selected = { selected }
154- level = { level }
155- title = { title }
156- version = { version }
181+ { currentRoutes . map ( ( item , index ) => {
182+ const { path, title, hasSectionHeader, sectionHeader} = item ;
183+ if ( hasSectionHeader ) {
184+ let sectionHeaderText =
185+ sectionHeader != null
186+ ? sectionHeader . replace ( '{{version}}' , siteConfig . version )
187+ : '' ;
188+ return (
189+ < Fragment key = { `${ sectionHeaderText } -${ level } -separator` } >
190+ { index !== 0 && (
191+ < li
192+ role = "separator"
193+ className = "mt-4 mb-2 ms-5 border-b border-border dark:border-border-dark"
157194 />
158- </ li >
159- ) ;
160- }
161- if ( hasSectionHeader ) {
162- let sectionHeaderText =
163- sectionHeader != null
164- ? sectionHeader . replace ( '{{version}}' , siteConfig . version )
165- : '' ;
166- return (
167- < Fragment key = { `${ sectionHeaderText } -${ level } -separator` } >
168- { index !== 0 && (
169- < li
170- role = "separator"
171- className = "mt-4 mb-2 ms-5 border-b border-border dark:border-border-dark"
172- />
173- ) }
174- < h3
175- className = { cn (
176- 'mb-1 text-sm font-bold ms-5 text-tertiary dark:text-tertiary-dark' ,
177- index !== 0 && 'mt-2'
178- ) } >
179- { sectionHeaderText }
180- </ h3 >
181- </ Fragment >
182- ) ;
183- } else {
184- return listItem ;
185- }
195+ ) }
196+ < h3
197+ className = { cn (
198+ 'mb-1 text-sm font-bold ms-5 text-tertiary dark:text-tertiary-dark' ,
199+ index !== 0 && 'mt-2'
200+ ) } >
201+ { sectionHeaderText }
202+ </ h3 >
203+ </ Fragment >
204+ ) ;
205+ } else {
206+ return (
207+ < SidebarItem
208+ key = { `${ title } -${ path } -${ level } -item` }
209+ item = { item }
210+ level = { level }
211+ isForceExpanded = { isForceExpanded }
212+ breadcrumbs = { breadcrumbs }
213+ slug = { slug }
214+ pendingRoute = { pendingRoute }
215+ />
216+ ) ;
186217 }
187- ) }
218+ } ) }
188219 </ ul >
189220 ) ;
190221}
0 commit comments