@@ -495,6 +495,9 @@ export function TableGrid({
495495 const pendingMatchRef = useRef < TableFindMatch | null > ( null )
496496 /** Monotonic id for the in-flight match jump; see `goToMatch`. */
497497 const goToMatchSeqRef = useRef ( 0 )
498+ /** The match the cursor is on, by identity rather than position, so a
499+ * reordered result set can re-point at the same cell. */
500+ const activeMatchRef = useRef < TableFindMatch | null > ( null )
498501 /** Term the auto-reveal has already run for, so a background refetch of the
499502 * same term doesn't re-jump the viewport. */
500503 const autoRevealedTermRef = useRef ( '' )
@@ -1266,6 +1269,7 @@ export function TableGrid({
12661269 goToMatchSeqRef . current ++
12671270 pendingMatchRef . current = null
12681271 cursorIsOnMatchRef . current = false
1272+ activeMatchRef . current = null
12691273 setIsJumping ( false )
12701274 } , [ trimmedFindQuery , findOpen ] )
12711275
@@ -1288,9 +1292,32 @@ export function TableGrid({
12881292 setRowSelection ( ( prev ) => ( prev . kind === 'none' ? prev : ROW_SELECTION_NONE ) )
12891293 setSelectionFocus ( null )
12901294 cursorIsOnMatchRef . current = true
1295+ activeMatchRef . current = match
12911296 setSelectionAnchor ( { rowIndex, colIndex } )
12921297 } , [ rows , displayColumns , pendingMatchTick ] )
12931298
1299+ /**
1300+ * Re-point the cursor at the match it is actually on after the set changes.
1301+ *
1302+ * The cursor is stored as an index, but the list underneath it is mutable: a
1303+ * row insert or delete elsewhere in the table reorders matches for the SAME
1304+ * term, and index 1 can silently become a different cell. Stepping from it
1305+ * would then revisit the cell the user is on, or skip its neighbour. Matching
1306+ * on (rowId, column) — the match's identity — keeps the cursor attached to the
1307+ * cell rather than the position.
1308+ *
1309+ * When the active match is gone entirely there is nothing to re-point at;
1310+ * `stepBaseIndex` clamps the now-possibly-out-of-range index instead.
1311+ */
1312+ useEffect ( ( ) => {
1313+ const active = activeMatchRef . current
1314+ if ( ! active || findMatches . length === 0 ) return
1315+ const index = findMatches . findIndex (
1316+ ( m ) => m . rowId === active . rowId && m . column === active . column
1317+ )
1318+ if ( index !== - 1 && index !== currentMatchIndexRef . current ) setCurrentMatchIndex ( index )
1319+ } , [ findMatches ] )
1320+
12941321 /**
12951322 * A new TERM resets to its first match and reveals it.
12961323 *
@@ -1327,6 +1354,7 @@ export function TableGrid({
13271354 autoRevealedTermRef . current = submittedQuery
13281355 setCurrentMatchIndex ( 0 )
13291356 cursorIsOnMatchRef . current = false
1357+ activeMatchRef . current = null
13301358 const first = findMatches [ 0 ]
13311359 if ( ! first ) return
13321360 if ( ! rowsRef . current . some ( ( r ) => r . id === first . rowId ) ) return
@@ -1389,6 +1417,7 @@ export function TableGrid({
13891417 goToMatchSeqRef . current ++
13901418 autoRevealedTermRef . current = ''
13911419 cursorIsOnMatchRef . current = false
1420+ activeMatchRef . current = null
13921421 setIsJumping ( false )
13931422 scrollRef . current ?. focus ( { preventScroll : true } )
13941423 } , [ ] )
0 commit comments