@@ -18,6 +18,19 @@ type ConfigItem = {
1818 screens ?: Record < string , ConfigItem > ;
1919} ;
2020
21+ const getActiveRoute = ( state : State ) : { name : string ; params ?: object } => {
22+ const route =
23+ typeof state . index === 'number'
24+ ? state . routes [ state . index ]
25+ : state . routes [ state . routes . length - 1 ] ;
26+
27+ if ( route . state ) {
28+ return getActiveRoute ( route . state ) ;
29+ }
30+
31+ return route ;
32+ } ;
33+
2134/**
2235 * Utility to serialize a navigation state object to a path string.
2336 *
@@ -69,7 +82,8 @@ export default function getPathFromState(
6982
7083 let pattern : string | undefined ;
7184
72- let currentParams : Record < string , any > = { ...route . params } ;
85+ let focusedParams : Record < string , any > | undefined ;
86+ let focusedRoute = getActiveRoute ( state ) ;
7387 let currentOptions = configs ;
7488
7589 // Keep all the route names that appeared during going deeper in config in case the pattern is resolved to undefined
@@ -85,7 +99,7 @@ export default function getPathFromState(
8599 if ( route . params ) {
86100 const stringify = currentOptions [ route . name ] ?. stringify ;
87101
88- currentParams = fromEntries (
102+ const currentParams = fromEntries (
89103 Object . entries ( route . params ) . map ( ( [ key , value ] ) => [
90104 key ,
91105 stringify ?. [ key ] ? stringify [ key ] ( value ) : String ( value ) ,
@@ -95,6 +109,26 @@ export default function getPathFromState(
95109 if ( pattern ) {
96110 Object . assign ( allParams , currentParams ) ;
97111 }
112+
113+ if ( focusedRoute === route ) {
114+ // If this is the focused route, keep the params for later use
115+ // We save it here since it's been stringified already
116+ focusedParams = { ...currentParams } ;
117+
118+ pattern
119+ ?. split ( '/' )
120+ . filter ( ( p ) => p . startsWith ( ':' ) )
121+ // eslint-disable-next-line no-loop-func
122+ . forEach ( ( p ) => {
123+ const name = getParamName ( p ) ;
124+
125+ // Remove the params present in the pattern since we'll only use the rest for query string
126+ if ( focusedParams ) {
127+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
128+ delete focusedParams [ name ] ;
129+ }
130+ } ) ;
131+ }
98132 }
99133
100134 // If there is no `screens` property or no nested state, we return pattern
@@ -128,18 +162,12 @@ export default function getPathFromState(
128162 path += pattern
129163 . split ( '/' )
130164 . map ( ( p ) => {
131- const name = p . replace ( / ^ : / , '' ) . replace ( / \? $ / , '' ) ;
165+ const name = getParamName ( p ) ;
132166
133167 // If the path has a pattern for a param, put the param in the path
134168 if ( p . startsWith ( ':' ) ) {
135169 const value = allParams [ name ] ;
136170
137- // Remove the used value from the params object since we'll use the rest for query string
138- if ( currentParams ) {
139- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
140- delete currentParams [ name ] ;
141- }
142-
143171 if ( value === undefined && p . endsWith ( '?' ) ) {
144172 // Optional params without value assigned in route.params should be ignored
145173 return '' ;
@@ -155,17 +183,21 @@ export default function getPathFromState(
155183 path += encodeURIComponent ( route . name ) ;
156184 }
157185
186+ if ( ! focusedParams ) {
187+ focusedParams = focusedRoute . params ;
188+ }
189+
158190 if ( route . state ) {
159191 path += '/' ;
160- } else if ( currentParams ) {
161- for ( let param in currentParams ) {
162- if ( currentParams [ param ] === 'undefined' ) {
192+ } else if ( focusedParams ) {
193+ for ( let param in focusedParams ) {
194+ if ( focusedParams [ param ] === 'undefined' ) {
163195 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
164- delete currentParams [ param ] ;
196+ delete focusedParams [ param ] ;
165197 }
166198 }
167199
168- const query = queryString . stringify ( currentParams ) ;
200+ const query = queryString . stringify ( focusedParams ) ;
169201
170202 if ( query ) {
171203 path += `?${ query } ` ;
@@ -189,6 +221,9 @@ const fromEntries = <K extends string, V>(entries: (readonly [K, V])[]) =>
189221 return acc ;
190222 } , { } as Record < K , V > ) ;
191223
224+ const getParamName = ( pattern : string ) =>
225+ pattern . replace ( / ^ : / , '' ) . replace ( / \? $ / , '' ) ;
226+
192227const joinPaths = ( ...paths : string [ ] ) : string =>
193228 ( [ ] as string [ ] )
194229 . concat ( ...paths . map ( ( p ) => p . split ( '/' ) ) )
0 commit comments