@@ -70,82 +70,100 @@ export function getNodeState(
7070 } ;
7171}
7272
73- export function reducer ( state : NavigationTreeState = { } , action : NavigationTreeAction ) {
74- switch ( action . type ) {
75- case NavigationTreeActionType . ToggleCollapsed :
76- return {
77- ...state ,
78- [ action . payload . path ] : {
79- ...state [ action . payload . path ] ,
80- collapsed : ! state [ action . payload . path ] . collapsed ,
81- } ,
82- } ;
83- case NavigationTreeActionType . StartLoading :
84- return {
85- ...state ,
86- [ action . payload . path ] : {
87- ...state [ action . payload . path ] ,
88- loading : true ,
89- loaded : false ,
90- error : false ,
91- children : [ ] ,
92- } ,
93- } ;
94- case NavigationTreeActionType . FinishLoading : {
95- const newState : NavigationTreeState = {
96- ...state ,
97- [ action . payload . path ] : {
98- ...state [ action . payload . path ] ,
99- loading : false ,
100- loaded : Boolean ( action . payload . data ) ,
101- error : false ,
102- } ,
103- } ;
104-
105- if ( action . payload . data ) {
106- newState [ action . payload . path ] . children = action . payload . data . map (
107- ( { name} : { name : string } ) => name ,
108- ) ;
109-
110- for ( const item of action . payload . data ) {
111- const path = `${ action . payload . path } /${ item . name } ` ;
112-
113- // expand the tree according to the active path
114- // prioritize the existing state to expand the tree only on first load
115- const { activePath = '' } = action . payload ;
116- const collapsed = state [ path ] ?. collapsed ?? ! activePath . startsWith ( `${ path } /` ) ;
117-
118- newState [ path ] = getNodeState ( {
119- ...item ,
120- collapsed,
121- path,
122- } ) ;
73+ interface NavigationTreeReducerOptions {
74+ collapseChildlessNodes ?: boolean ;
75+ }
76+
77+ export function createNavigationTreeReducer ( options : NavigationTreeReducerOptions ) {
78+ return function reducer ( state : NavigationTreeState = { } , action : NavigationTreeAction ) {
79+ switch ( action . type ) {
80+ case NavigationTreeActionType . ToggleCollapsed :
81+ return {
82+ ...state ,
83+ [ action . payload . path ] : {
84+ ...state [ action . payload . path ] ,
85+ collapsed : ! state [ action . payload . path ] . collapsed ,
86+ } ,
87+ } ;
88+ case NavigationTreeActionType . StartLoading :
89+ return {
90+ ...state ,
91+ [ action . payload . path ] : {
92+ ...state [ action . payload . path ] ,
93+ loading : true ,
94+ loaded : false ,
95+ error : false ,
96+ children : [ ] ,
97+ } ,
98+ } ;
99+ case NavigationTreeActionType . FinishLoading : {
100+ const newState : NavigationTreeState = {
101+ ...state ,
102+ [ action . payload . path ] : {
103+ ...state [ action . payload . path ] ,
104+ loading : false ,
105+ loaded : Boolean ( action . payload . data ) ,
106+ error : false ,
107+ } ,
108+ } ;
109+
110+ if ( action . payload . data ) {
111+ newState [ action . payload . path ] . children = action . payload . data . map (
112+ ( { name} : { name : string } ) => name ,
113+ ) ;
114+
115+ for ( const item of action . payload . data ) {
116+ const path = `${ action . payload . path } /${ item . name } ` ;
117+
118+ // expand the tree according to the active path
119+ // prioritize the existing state to expand the tree only on first load
120+ const { activePath = '' } = action . payload ;
121+ const collapsed =
122+ state [ path ] ?. collapsed ?? ! activePath . startsWith ( `${ path } /` ) ;
123+
124+ newState [ path ] = getNodeState ( {
125+ ...item ,
126+ collapsed,
127+ path,
128+ } ) ;
129+ }
130+ }
131+
132+ if (
133+ ( ! action . payload . data || action . payload . data . length === 0 ) &&
134+ options . collapseChildlessNodes
135+ ) {
136+ newState [ action . payload . path ] = {
137+ ...newState [ action . payload . path ] ,
138+ expandable : false ,
139+ collapsed : true ,
140+ } ;
123141 }
124- }
125142
126- return newState ;
143+ return newState ;
144+ }
145+ case NavigationTreeActionType . ErrorLoading :
146+ return {
147+ ...state ,
148+ [ action . payload . path ] : {
149+ ...state [ action . payload . path ] ,
150+ loading : false ,
151+ loaded : false ,
152+ error : true ,
153+ } ,
154+ } ;
155+ case NavigationTreeActionType . ResetNode :
156+ return {
157+ ...state ,
158+ [ action . payload . path ] : {
159+ ...state [ action . payload . path ] ,
160+ ...getDefaultNodeState ( ) ,
161+ } ,
162+ } ;
163+ default :
164+ return state ;
127165 }
128- case NavigationTreeActionType . ErrorLoading :
129- return {
130- ...state ,
131- [ action . payload . path ] : {
132- ...state [ action . payload . path ] ,
133- loading : false ,
134- loaded : false ,
135- error : true ,
136- } ,
137- } ;
138- case NavigationTreeActionType . ResetNode :
139- return {
140- ...state ,
141- [ action . payload . path ] : {
142- ...state [ action . payload . path ] ,
143- ...getDefaultNodeState ( ) ,
144- } ,
145- } ;
146- default :
147- return state ;
148- }
166+ } ;
149167}
150168
151169export function selectTreeAsList ( state : NavigationTreeState , rootPath : string ) {
0 commit comments