@@ -534,28 +534,59 @@ export function DocsLayout({
534534 d . status === 'active' && d . name !== 'Nozzle.io' && d . id !== 'fireship' ,
535535 )
536536
537- const menuItems = menuConfig . map ( ( group , i ) => {
538- const WrapperComp = group . collapsible ? 'details' : 'div'
539- const LabelComp = group . collapsible ? 'summary' : 'div'
537+ const groupInitialOpenState = React . useMemo ( ( ) => {
538+ return menuConfig . reduce < Record < string , boolean > > ( ( acc , group , index ) => {
539+ const isChildActive = group . children . some ( ( child ) => child . to === _splat )
540+ const key = `${ index } :${ String ( group . label ) } `
540541
541- const isChildActive = group . children . some ( ( d ) => d . to === _splat )
542- const configGroupOpenState =
543- typeof group . defaultCollapsed !== 'undefined'
544- ? ! group . defaultCollapsed // defaultCollapsed is true means the group is closed
545- : undefined
546- const isOpen = isChildActive ? true : ( configGroupOpenState ?? false )
542+ acc [ key ] = isChildActive
543+ ? true
544+ : typeof group . defaultCollapsed !== 'undefined'
545+ ? ! group . defaultCollapsed
546+ : false
547547
548- const detailsProps = group . collapsible ? { open : isOpen } : { }
548+ return acc
549+ } , { } )
550+ } , [ menuConfig , _splat ] )
549551
550- return (
551- < WrapperComp
552- key = { `group-${ i } ` }
553- className = "[&>summary]:before:mr-1 [&>summary]:marker:text-[0.8em] [&>summary]:marker:leading-4 relative select-none"
554- { ...detailsProps }
555- >
556- < LabelComp className = "text-[.8em] font-bold leading-4 px-2 ts-sidebar-label" >
557- { group ?. label }
558- </ LabelComp >
552+ const [ openGroups , setOpenGroups ] = React . useState ( groupInitialOpenState )
553+
554+ React . useEffect ( ( ) => {
555+ setOpenGroups ( ( prev ) => {
556+ let hasChanged = false
557+ const next = { ...prev }
558+
559+ Object . entries ( groupInitialOpenState ) . forEach ( ( [ key , isOpen ] ) => {
560+ if ( ! ( key in next ) ) {
561+ next [ key ] = isOpen
562+ hasChanged = true
563+ return
564+ }
565+
566+ if ( isOpen && ! next [ key ] ) {
567+ next [ key ] = true
568+ hasChanged = true
569+ }
570+ } )
571+
572+ return hasChanged ? next : prev
573+ } )
574+ } , [ groupInitialOpenState ] )
575+
576+ const menuItems = menuConfig . map ( ( group , i ) => {
577+ const groupKey = `${ i } :${ String ( group . label ) } `
578+
579+ const groupContent = (
580+ < >
581+ { group . collapsible ? (
582+ < summary className = "text-[.8em] font-bold leading-4 px-2 ts-sidebar-label" >
583+ { group . label }
584+ </ summary >
585+ ) : (
586+ < div className = "text-[.8em] font-bold leading-4 px-2 ts-sidebar-label" >
587+ { group . label }
588+ </ div >
589+ ) }
559590 < div className = "h-2" />
560591 < ul className = "text-[.85em] leading-snug list-none" >
561592 { group ?. children ?. map ( ( child , i ) => {
@@ -580,6 +611,7 @@ export function DocsLayout({
580611 onClick = { ( ) => {
581612 detailsRef . current . removeAttribute ( 'open' )
582613 } }
614+ preload = { false }
583615 activeOptions = { {
584616 exact : true ,
585617 includeHash : false ,
@@ -614,7 +646,32 @@ export function DocsLayout({
614646 )
615647 } ) }
616648 </ ul >
617- </ WrapperComp >
649+ </ >
650+ )
651+
652+ return group . collapsible ? (
653+ < details
654+ key = { `group-${ i } ` }
655+ className = "[&>summary]:before:mr-1 [&>summary]:marker:text-[0.8em] [&>summary]:marker:leading-4 relative select-none"
656+ open = { openGroups [ groupKey ] ?? false }
657+ onToggle = { ( event ) => {
658+ const nextOpen = event . currentTarget . open
659+ setOpenGroups ( ( prev ) =>
660+ prev [ groupKey ] === nextOpen
661+ ? prev
662+ : { ...prev , [ groupKey ] : nextOpen } ,
663+ )
664+ } }
665+ >
666+ { groupContent }
667+ </ details >
668+ ) : (
669+ < div
670+ key = { `group-${ i } ` }
671+ className = "[&>summary]:before:mr-1 [&>summary]:marker:text-[0.8em] [&>summary]:marker:leading-4 relative select-none"
672+ >
673+ { groupContent }
674+ </ div >
618675 )
619676 } )
620677
0 commit comments