@@ -259,6 +259,28 @@ export class StructuredYson extends React.PureComponent<Props, State> {
259259 return null ;
260260 } ;
261261
262+ navigateToMatch = (
263+ targetIndex : number ,
264+ allMatchPaths : Array < string > ,
265+ matchedRows : Array < number > ,
266+ collapsedState : CollapsedState ,
267+ ) => {
268+ // Count how many visible matches are before our target
269+ let visibleMatchCount = 0 ;
270+ for ( let i = 0 ; i < targetIndex ; i ++ ) {
271+ if ( this . findCollapsedParent ( allMatchPaths [ i ] , collapsedState ) === null ) {
272+ visibleMatchCount ++ ;
273+ }
274+ }
275+
276+ // Navigate to the visible match
277+ if ( visibleMatchCount < matchedRows . length ) {
278+ this . setState ( { matchIndex : targetIndex } ) ;
279+ this . tableRef . current ?. scrollToIndex ( matchedRows [ visibleMatchCount ] ) ;
280+ this . searchRef . current ?. focus ( ) ;
281+ }
282+ } ;
283+
262284 onNextMatch = ( _event : unknown , diff = 1 ) => {
263285 const { matchIndex, matchedRows, allMatchPaths, collapsedState} = this . state ;
264286
@@ -276,74 +298,40 @@ export class StructuredYson extends React.PureComponent<Props, State> {
276298
277299 // Expand all collapsed parents at once
278300 let effectiveCollapsedState = collapsedState ;
279- let hasCollapsedParents = false ;
280-
281- let nextSlash = 0 ;
282- while ( ( nextSlash = targetMatchPath . indexOf ( '/' , nextSlash ) ) !== - 1 ) {
283- const checkPath = targetMatchPath . slice ( 0 , nextSlash ) ;
284- if ( collapsedState [ checkPath ] ) {
285- if ( ! hasCollapsedParents ) {
286- effectiveCollapsedState = { ...collapsedState } ;
287- hasCollapsedParents = true ;
288- }
289- delete effectiveCollapsedState [ checkPath ] ;
290- }
291- nextSlash ++ ;
292- }
293- // Check the full path as well
294- if ( collapsedState [ targetMatchPath ] ) {
295- if ( ! hasCollapsedParents ) {
301+ let collapsedParent : string | null ;
302+
303+ // Keep expanding collapsed parents until target is fully visible
304+ while (
305+ ( collapsedParent = this . findCollapsedParent ( targetMatchPath , effectiveCollapsedState ) )
306+ ) {
307+ // Lazy copy on first modification
308+ if ( effectiveCollapsedState === collapsedState ) {
296309 effectiveCollapsedState = { ...collapsedState } ;
297- hasCollapsedParents = true ;
298310 }
299- delete effectiveCollapsedState [ targetMatchPath ] ;
311+ delete effectiveCollapsedState [ collapsedParent ] ;
300312 }
301313
302314 // If we expanded any parents, recalculate state and retry
303- if ( hasCollapsedParents ) {
315+ if ( collapsedState !== effectiveCollapsedState ) {
304316 this . updateState ( { collapsedState : effectiveCollapsedState } , ( ) => {
305317 // After state recalculation, find the target in the new allMatchPaths
306318 const newAllMatchPaths = this . state . allMatchPaths ;
307319 const newTargetIndex = newAllMatchPaths . indexOf ( targetMatchPath ) ;
308320 if ( newTargetIndex !== - 1 ) {
309321 // Navigate to the target using its new index
310- const newMatchedRows = this . state . matchedRows ;
311- let visibleMatchCount = 0 ;
312- for ( let i = 0 ; i < newTargetIndex ; i ++ ) {
313- if (
314- this . findCollapsedParent (
315- newAllMatchPaths [ i ] ,
316- this . state . collapsedState ,
317- ) === null
318- ) {
319- visibleMatchCount ++ ;
320- }
321- }
322- if ( visibleMatchCount < newMatchedRows . length ) {
323- this . setState ( { matchIndex : newTargetIndex } ) ;
324- this . tableRef . current ?. scrollToIndex ( newMatchedRows [ visibleMatchCount ] ) ;
325- this . searchRef . current ?. focus ( ) ;
326- }
322+ this . navigateToMatch (
323+ newTargetIndex ,
324+ newAllMatchPaths ,
325+ this . state . matchedRows ,
326+ this . state . collapsedState ,
327+ ) ;
327328 }
328329 } ) ;
329330 return ;
330331 }
331332
332333 // Target is visible - navigate to it
333- // Count how many visible matches are before our target
334- let visibleMatchCount = 0 ;
335- for ( let i = 0 ; i < nextTotalIndex ; i ++ ) {
336- if ( this . findCollapsedParent ( allMatchPaths [ i ] , effectiveCollapsedState ) === null ) {
337- visibleMatchCount ++ ;
338- }
339- }
340-
341- // Navigate to the visible match
342- if ( visibleMatchCount < matchedRows . length ) {
343- this . setState ( { matchIndex : nextTotalIndex } ) ;
344- this . tableRef . current ?. scrollToIndex ( matchedRows [ visibleMatchCount ] ) ;
345- this . searchRef . current ?. focus ( ) ;
346- }
334+ this . navigateToMatch ( nextTotalIndex , allMatchPaths , matchedRows , effectiveCollapsedState ) ;
347335 } ;
348336
349337 onPrevMatch = ( ) => {
0 commit comments