@@ -26,12 +26,10 @@ interface NodeEntry {
2626
2727/**
2828 * Search context for structured output tree.
29- * Separates stable values from frequently changing currentMatchIndex to avoid re-renders.
3029 */
3130interface SearchContextValue {
3231 query : string
3332 pathToMatchIndices : Map < string , number [ ] >
34- currentMatchIndexRef : React . RefObject < number >
3533}
3634
3735const SearchContext = createContext < SearchContextValue | null > ( null )
@@ -270,29 +268,26 @@ interface HighlightedTextProps {
270268 text : string
271269 matchIndices : number [ ]
272270 path : string
271+ currentMatchIndex : number
273272}
274273
275274/**
276275 * Renders text with search highlights for non-virtualized mode.
276+ * Accepts currentMatchIndex as prop to ensure re-render when it changes.
277277 */
278278const HighlightedText = memo ( function HighlightedText ( {
279279 text,
280280 matchIndices,
281281 path,
282+ currentMatchIndex,
282283} : HighlightedTextProps ) {
283284 const searchContext = useContext ( SearchContext )
284285
285286 if ( ! searchContext || matchIndices . length === 0 ) return < > { text } </ >
286287
287288 return (
288289 < >
289- { renderHighlightedSegments (
290- text ,
291- searchContext . query ,
292- matchIndices ,
293- searchContext . currentMatchIndexRef . current ,
294- path
295- ) }
290+ { renderHighlightedSegments ( text , searchContext . query , matchIndices , currentMatchIndex , path ) }
296291 </ >
297292 )
298293} )
@@ -304,6 +299,7 @@ interface StructuredNodeProps {
304299 expandedPaths : Set < string >
305300 onToggle : ( path : string ) => void
306301 wrapText : boolean
302+ currentMatchIndex : number
307303 isError ?: boolean
308304}
309305
@@ -318,6 +314,7 @@ const StructuredNode = memo(function StructuredNode({
318314 expandedPaths,
319315 onToggle,
320316 wrapText,
317+ currentMatchIndex,
321318 isError = false ,
322319} : StructuredNodeProps ) {
323320 const searchContext = useContext ( SearchContext )
@@ -381,7 +378,12 @@ const StructuredNode = memo(function StructuredNode({
381378 wrapText ? '[word-break:break-word]' : 'whitespace-nowrap'
382379 ) }
383380 >
384- < HighlightedText text = { valueText } matchIndices = { matchIndices } path = { path } />
381+ < HighlightedText
382+ text = { valueText }
383+ matchIndices = { matchIndices }
384+ path = { path }
385+ currentMatchIndex = { currentMatchIndex }
386+ />
385387 </ div >
386388 ) : isEmptyValue ? (
387389 < div className = { STYLES . emptyValue } > { Array . isArray ( value ) ? '[]' : '{}' } </ div >
@@ -395,6 +397,7 @@ const StructuredNode = memo(function StructuredNode({
395397 expandedPaths = { expandedPaths }
396398 onToggle = { onToggle }
397399 wrapText = { wrapText }
400+ currentMatchIndex = { currentMatchIndex }
398401 />
399402 ) )
400403 ) }
@@ -682,18 +685,9 @@ export const StructuredOutput = memo(function StructuredOutput({
682685 const prevDataRef = useRef ( data )
683686 const prevIsErrorRef = useRef ( isError )
684687 const internalRef = useRef < HTMLDivElement > ( null )
685- const currentMatchIndexRef = useRef ( currentMatchIndex )
686688 const listRef = useListRef ( null )
687689 const [ containerHeight , setContainerHeight ] = useState ( 400 )
688690
689- currentMatchIndexRef . current = currentMatchIndex
690-
691- // Force re-render when currentMatchIndex changes
692- const [ , forceUpdate ] = useState ( 0 )
693- useEffect ( ( ) => {
694- forceUpdate ( ( n ) => n + 1 )
695- } , [ currentMatchIndex ] )
696-
697691 const setContainerRef = useCallback (
698692 ( node : HTMLDivElement | null ) => {
699693 ; ( internalRef as React . MutableRefObject < HTMLDivElement | null > ) . current = node
@@ -782,7 +776,7 @@ export const StructuredOutput = memo(function StructuredOutput({
782776
783777 const searchContextValue = useMemo < SearchContextValue | null > ( ( ) => {
784778 if ( ! searchQuery ) return null
785- return { query : searchQuery , pathToMatchIndices, currentMatchIndexRef }
779+ return { query : searchQuery , pathToMatchIndices }
786780 } , [ searchQuery , pathToMatchIndices ] )
787781
788782 const visibleRowCount = useMemo (
@@ -890,6 +884,7 @@ export const StructuredOutput = memo(function StructuredOutput({
890884 expandedPaths = { expandedPaths }
891885 onToggle = { handleToggle }
892886 wrapText = { wrapText }
887+ currentMatchIndex = { currentMatchIndex }
893888 isError
894889 />
895890 </ div >
@@ -909,6 +904,7 @@ export const StructuredOutput = memo(function StructuredOutput({
909904 expandedPaths = { expandedPaths }
910905 onToggle = { handleToggle }
911906 wrapText = { wrapText }
907+ currentMatchIndex = { currentMatchIndex }
912908 />
913909 ) ) }
914910 </ div >
0 commit comments