@@ -492,7 +492,7 @@ export default function SearchBar() {
492492 // Multi-select state for products
493493 const [ selectedProducts , setSelectedProducts ] = useState ( ( ) => {
494494 if ( typeof window === 'undefined' ) return [ ] ;
495- const saved = localStorage . getItem ( 'docs_product_filter' ) ;
495+ const saved = sessionStorage . getItem ( 'docs_product_filter' ) ;
496496 try {
497497 return saved ? JSON . parse ( saved ) : [ ] ;
498498 } catch {
@@ -507,10 +507,10 @@ export default function SearchBar() {
507507 selectedProductsRef . current = selectedProducts ;
508508 } , [ selectedProducts ] ) ;
509509
510- // Sync selectedProducts to localStorage and dispatch custom event for same-tab sync
510+ // Sync selectedProducts to sessionStorage and dispatch custom event for same-tab sync
511511 useEffect ( ( ) => {
512512 if ( typeof window !== 'undefined' ) {
513- localStorage . setItem ( 'docs_product_filter' , JSON . stringify ( selectedProducts ) ) ;
513+ sessionStorage . setItem ( 'docs_product_filter' , JSON . stringify ( selectedProducts ) ) ;
514514 // Dispatch custom event for same-tab synchronization
515515 window . dispatchEvent ( new CustomEvent ( 'productFilterChange' , {
516516 detail : { products : selectedProducts }
@@ -558,38 +558,44 @@ export default function SearchBar() {
558558 return ( ) => clearInterval ( interval ) ;
559559 } , [ ] ) ;
560560
561- // Helper to refresh search - preserve query and wait for user action
561+ // Helper to refresh search results with current filters.
562+ // DocSearch uses React-controlled inputs, so plain native input events don't trigger
563+ // its onChange handler. We use React's native HTMLInputElement value setter to bypass
564+ // React's change-tracking wrapper, then dispatch an input event so React processes it.
562565 const refreshSearch = useCallback ( ( ) => {
563566 const input =
564567 document . querySelector ( '.DocSearch-Input' ) ||
565568 document . querySelector ( 'input[type="search"]' ) ;
566569
567- if ( input && input . value ) {
568- searchQueryRef . current = input . value ;
570+ if ( ! input || ! input . value ) return ;
569571
570- // Try multiple approaches to trigger search
571- const query = input . value ;
572+ const query = input . value ;
573+ searchQueryRef . current = query ;
572574
573- // Approach 1: Simulate typing by adding/removing character
574- setTimeout ( ( ) => {
575- if ( input ) {
576- input . value = query + ' ' ;
577- input . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
575+ // Grab the native setter before React wraps it
576+ const nativeSetter = Object . getOwnPropertyDescriptor (
577+ window . HTMLInputElement . prototype ,
578+ ' value' ,
579+ ) . set ;
578580
579- setTimeout ( ( ) => {
580- input . value = query ;
581- input . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
582- input . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'Enter' , bubbles : true } ) ) ;
583- } , 50 ) ;
584- }
585- } , 50 ) ;
586- }
581+ // Simulate typing a trailing space and removing it.
582+ // This causes DocSearch/Autocomplete to run a new search with the updated filters.
583+ // Both events fire in the same JS task so DocSearch batches them — only the final
584+ // value (query) triggers a visible search, preventing an intermediate result flash.
585+ setTimeout ( ( ) => {
586+ nativeSetter . call ( input , query + ' ' ) ;
587+ input . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
588+
589+ nativeSetter . call ( input , query ) ;
590+ input . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
591+ } , 50 ) ;
587592 } , [ ] ) ;
588593
589594 const onChangeProducts = useCallback ( ( newProducts ) => {
595+ selectedProductsRef . current = newProducts ; // Sync ref immediately so search uses new filters
590596 setSelectedProducts ( newProducts ) ;
591- // localStorage and event dispatch handled by useEffect
592- } , [ ] ) ;
597+ refreshSearch ( ) ; // Re-run current query with updated filters
598+ } , [ refreshSearch ] ) ;
593599
594600 // This is where we will portal the filters into the modal DOM.
595601 const [ modalHeaderEl , setModalHeaderEl ] = useState ( null ) ;
0 commit comments