@@ -49,8 +49,6 @@ function searchBar($list, setHide, onhideCb, searchFunction) {
4949
5050 function hide ( ) {
5151 actionStack . remove ( "searchbar" ) ;
52-
53- if ( ! $list . parentElement ) return ;
5452 if ( typeof onhideCb === "function" ) onhideCb ( ) ;
5553
5654 $list . content = children ;
@@ -70,6 +68,12 @@ function searchBar($list, setHide, onhideCb, searchFunction) {
7068 */
7169 async function searchNow ( ) {
7270 const val = $searchInput . value . toLowerCase ( ) ;
71+
72+ if ( ! val ) {
73+ $list . content = children ;
74+ return ;
75+ }
76+
7377 let result ;
7478
7579 if ( searchFunction ) {
@@ -89,7 +93,7 @@ function searchBar($list, setHide, onhideCb, searchFunction) {
8993 }
9094
9195 $list . textContent = "" ;
92- $list . append ( ...result ) ;
96+ $list . append ( ...buildSearchContent ( result , val ) ) ;
9397 }
9498
9599 /**
@@ -103,6 +107,87 @@ function searchBar($list, setHide, onhideCb, searchFunction) {
103107 return text . match ( val , "i" ) ;
104108 } ) ;
105109 }
110+
111+ /**
112+ * Keep grouped settings search results in section cards instead of flattening them.
113+ * @param {HTMLElement[] } result
114+ * @param {string } val
115+ * @returns {HTMLElement[] }
116+ */
117+ function buildSearchContent ( result , val ) {
118+ if ( ! val || ! result . length ) return result ;
119+
120+ const groupedSections = [ ] ;
121+ const sectionIndexByLabel = new Map ( ) ;
122+ let hasGroups = false ;
123+
124+ result . forEach ( ( $item ) => {
125+ const label = $item . dataset . searchGroup ;
126+ if ( ! label ) {
127+ groupedSections . push ( {
128+ items : [ $item ] ,
129+ type : "ungrouped" ,
130+ } ) ;
131+ return ;
132+ }
133+
134+ hasGroups = true ;
135+ const existingSectionIndex = sectionIndexByLabel . get ( label ) ;
136+ if ( existingSectionIndex !== undefined ) {
137+ groupedSections [ existingSectionIndex ] . items . push ( $item ) ;
138+ return ;
139+ }
140+
141+ sectionIndexByLabel . set ( label , groupedSections . length ) ;
142+ groupedSections . push ( {
143+ items : [ $item ] ,
144+ label,
145+ type : "group" ,
146+ } ) ;
147+ } ) ;
148+
149+ if ( ! hasGroups ) return result . map ( cloneSearchItem ) ;
150+
151+ const countLabel = `${ result . length } ${
152+ result . length === 1
153+ ? strings [ "search result label singular" ]
154+ : strings [ "search result label plural" ]
155+ } `;
156+ const content = [
157+ < div className = "settings-search-summary" > { countLabel } </ div > ,
158+ ] ;
159+
160+ groupedSections . forEach ( ( section ) => {
161+ if ( section . type === "ungrouped" ) {
162+ content . push ( ...section . items . map ( cloneSearchItem ) ) ;
163+ return ;
164+ }
165+
166+ content . push (
167+ < section className = "settings-section settings-search-section" >
168+ < div className = "settings-section-label" > { section . label } </ div >
169+ < div className = "settings-section-card" >
170+ { section . items . map ( cloneSearchItem ) }
171+ </ div >
172+ </ section > ,
173+ ) ;
174+ } ) ;
175+
176+ return content ;
177+ }
178+
179+ /**
180+ * Render search results without moving the original list items out of their groups.
181+ * @param {HTMLElement } $item
182+ * @returns {HTMLElement }
183+ */
184+ function cloneSearchItem ( $item ) {
185+ const $clone = $item . cloneNode ( true ) ;
186+ $clone . addEventListener ( "click" , ( ) => {
187+ $item . click ( ) ;
188+ } ) ;
189+ return $clone ;
190+ }
106191}
107192
108193export default searchBar ;
0 commit comments