@@ -24,6 +24,7 @@ export class Find extends Module {
2424 _myFindRanges : Range [ ] = [ ] ;
2525 _myCurrentRanges : Range [ ] = [ ] ;
2626 _findArgs : FindArgs | null = null ;
27+ _cachedRegex : RegExp | null = null ;
2728 _currentMatchIndex = 0 ;
2829 _matchIndexes : { [ key : number ] : RowComponent } = { } ;
2930
@@ -55,6 +56,10 @@ export class Find extends Module {
5556 this . _cellTextCache = new WeakMap ( ) ;
5657 } ) ;
5758
59+ this . table . on ( 'tableDestroyed' , ( ) => {
60+ this . _clearFindHighlights ( ) ;
61+ } ) ;
62+
5863 this . table . on ( 'renderComplete' , ( ) => {
5964 if ( this . _findArgs ?. text ) {
6065 this . _applyHighlights ( ) ;
@@ -118,10 +123,7 @@ export class Find extends Module {
118123 const grps = tbl . getGroups ( ) . flatMap ( flattenFromGrps ) ;
119124 const flattenedRows : RowComponent [ ] = grps . length ? grps : this . _getRows ( tbl . getRows ( 'active' ) ) ;
120125
121- const findOptions = findArgs . options ;
122- let searchString = findOptions . matchCase ? findArgs . text : findArgs . text . toLowerCase ( ) ;
123- searchString = searchString . replaceAll ( / [ [ \] * + ? { } . ( ) ^ $ | \\ - ] / g, '\\$&' ) ;
124- const regex = new RegExp ( searchString , `g${ findArgs . options . matchCase ? '' : 'i' } ` ) ;
126+ const regex = this . _buildRegex ( findArgs ) ;
125127
126128 // Reset highlightIndexes on all rows (no reformat needed with CSS Highlight API)
127129 for ( const row of flattenedRows ) {
@@ -134,7 +136,7 @@ export class Find extends Module {
134136 }
135137
136138 let totalMatches = 0 ;
137- if ( searchString ) {
139+ if ( regex ) {
138140 // Avoid row.getCells() — for uninitialized off-screen rows it calls generateCells()
139141 // which creates a DOM element per cell (document.createElement). For 10k rows that
140142 // is O(rows × cols) element creation before a single search character is matched.
@@ -249,12 +251,12 @@ export class Find extends Module {
249251 return ;
250252 }
251253
252- const findOptions = this . _findArgs . options ;
253- let searchString = findOptions . matchCase
254- ? this . _findArgs . text
255- : this . _findArgs . text . toLowerCase ( ) ;
256- searchString = searchString . replaceAll ( / [ [ \] * + ? { } . ( ) ^ $ | \\ - ] / g , '\\$&' ) ;
257- const regex = new RegExp ( searchString , `g ${ findOptions . matchCase ? '' : 'i' } ` ) ;
254+ const regex = this . _cachedRegex ;
255+ if ( ! regex ) {
256+ CSS . highlights . set ( 'find-match' , Find . _findHighlight ) ;
257+ CSS . highlights . set ( 'current-find-match' , Find . _currentHighlight ) ;
258+ return ;
259+ }
258260
259261 const rows = this . _getRenderedRows ( ) ;
260262 for ( const row of rows ) {
@@ -305,10 +307,22 @@ export class Find extends Module {
305307 _clearFindHighlights ( ) {
306308 this . _clearInstanceRanges ( ) ;
307309 this . _findArgs = null ;
310+ this . _cachedRegex = null ;
308311 this . _currentMatchIndex = 0 ;
309312 this . _matchIndexes = { } ;
310313 }
311314
315+ _buildRegex ( findArgs : FindArgs ) : RegExp | null {
316+ if ( ! findArgs . text ) {
317+ this . _cachedRegex = null ;
318+ return null ;
319+ }
320+ let searchString = findArgs . options . matchCase ? findArgs . text : findArgs . text . toLowerCase ( ) ;
321+ searchString = searchString . replaceAll ( / [ [ \] * + ? { } . ( ) ^ $ | \\ - ] / g, '\\$&' ) ;
322+ this . _cachedRegex = new RegExp ( searchString , `g${ findArgs . options . matchCase ? '' : 'i' } ` ) ;
323+ return this . _cachedRegex ;
324+ }
325+
312326 _clearInstanceRanges ( ) {
313327 for ( const range of this . _myFindRanges ) {
314328 Find . _findHighlight ?. delete ( range ) ;
0 commit comments