@@ -23,6 +23,8 @@ const TreeNodeComponent = component$(
2323 expandLevel : number ;
2424 onNodeClick : QRL < ( node : TreeNode ) => void > ;
2525 renderNode ?: QRL < ( node : TreeNode ) => JSXOutput > ;
26+ animate ?: boolean ;
27+ animationDuration ?: number ;
2628 } ) => {
2729 const isExpanded = useSignal ( props . expandLevel <= props . level ) ; // Default to expanded
2830 const hasChildren = props . node . children && props . node . children . length > 0 ;
@@ -50,10 +52,28 @@ const TreeNodeComponent = component$(
5052 const isActive = props . isHover
5153 ? props . node . id === props . activeNodeId
5254 : false ;
55+ const duration = props . animationDuration ?? 200 ;
56+ const shouldShowChildren = hasChildren && ! isExpanded . value ;
57+ const renderChildren = props . node . children ?. map ( ( child ) => (
58+ < TreeNodeComponent
59+ isHover = { props . isHover }
60+ key = { child . id }
61+ node = { child }
62+ gap = { props . gap }
63+ expandLevel = { props . expandLevel }
64+ level = { props . level + 1 }
65+ activeNodeId = { props . activeNodeId }
66+ onNodeClick = { props . onNodeClick }
67+ renderNode = { props . renderNode }
68+ animate = { props . animate }
69+ animationDuration = { props . animationDuration }
70+ />
71+ ) ) ;
5372 return (
54- < div style = { { paddingLeft : ` ${ props . level * props . gap } px` } } >
73+ < div class = "w-full" >
5574 < div
56- class = { `flex cursor-pointer items-center rounded-md p-1 transition-colors duration-150
75+ style = { { paddingLeft : `${ props . level * props . gap } px` } }
76+ class = { `flex w-full cursor-pointer items-center rounded-md p-1 transition-colors duration-150
5777 ${
5878 isActive
5979 ? 'bg-primary text-white '
@@ -68,31 +88,30 @@ const TreeNodeComponent = component$(
6888 ) : (
6989 < div class = "mr-2 w-4 flex-shrink-0" > </ div >
7090 ) }
71- < span class = "text-sm" >
91+ < div class = "text-sm whitespace-nowrap cursor-pointer " >
7292 { props . renderNode ? (
7393 < > { props . renderNode ( props . node ) } </ >
7494 ) : (
7595 `<${ props . node . label || props . node . name } ${ iterateProps ( props . node . props ! || { } ) } >`
7696 ) }
77- </ span >
97+ </ div >
7898 </ div >
79- { ! isExpanded . value && hasChildren && (
80- < >
81- { props . node . children ?. map ( ( child ) => (
82- < TreeNodeComponent
83- isHover = { props . isHover }
84- key = { child . id }
85- node = { child }
86- gap = { props . gap }
87- expandLevel = { props . expandLevel }
88- level = { props . level + 1 }
89- activeNodeId = { props . activeNodeId }
90- onNodeClick = { props . onNodeClick }
91- renderNode = { props . renderNode }
92- />
93- ) ) }
94- </ >
95- ) }
99+ { hasChildren ? (
100+ props . animate ? (
101+ < div
102+ class = { `overflow-hidden transition-all ease-in-out` }
103+ style = { {
104+ maxHeight : shouldShowChildren ? '1000px' : '0px' ,
105+ opacity : shouldShowChildren ? '1' : '0' ,
106+ transition : `max-height ${ duration } ms ease-in-out, opacity ${ duration } ms ease-in-out` ,
107+ } }
108+ >
109+ { renderChildren }
110+ </ div >
111+ ) : (
112+ shouldShowChildren && < > { renderChildren } </ >
113+ )
114+ ) : null }
96115 </ div >
97116 ) ;
98117 } ,
@@ -105,6 +124,9 @@ export const Tree = component$(
105124 renderNode ?: QRL < ( node : TreeNode ) => JSXOutput > ;
106125 gap ?: number ;
107126 isHover ?: boolean ;
127+ animate ?: boolean ;
128+ animationDuration ?: number ;
129+ expandLevel ?: number ;
108130 } ) => {
109131 const ref = useSignal < HTMLElement | undefined > ( ) ;
110132 const store = props . data ;
@@ -120,15 +142,17 @@ export const Tree = component$(
120142 < div class = "h-full w-full overflow-x-auto overflow-y-auto" ref = { ref } >
121143 { store . value . map ( ( rootNode ) => (
122144 < TreeNodeComponent
123- isHover = { props . isHover ?? true }
145+ isHover = { props . isHover === false ? false : true }
124146 gap = { props . gap || 20 }
125147 key = { rootNode . id }
126148 node = { rootNode }
127149 level = { 0 }
128- expandLevel = { 2 }
150+ expandLevel = { props . expandLevel ?? 2 }
129151 activeNodeId = { activeNodeId . value }
130152 onNodeClick = { setActiveNode }
131153 renderNode = { props . renderNode }
154+ animate = { props . animate ?? true }
155+ animationDuration = { props . animationDuration }
132156 />
133157 ) ) }
134158 </ div >
0 commit comments