Selected search result auto-opens collapsed nodes when necessary.
Also fixed an unrelated bug about when we reset search index when text changes.
Brian Vaughn committed
Apr 9, 2019 at 18:11 UTC
4c522c4c3845aac5442fd5f12957da6167b609b4
1 file changed
+45
-5
src/devtools/views/Components/TreeContext.js
+45
-5
@@ -24,6 +24,7 @@ import React, {
24
useEffect,
25
useMemo,
26
useReducer,
27
+ useRef,
28
} from 'react';
29
import { createRegExp } from '../utils';
30
import { BridgeContext, StoreContext } from '../context';
@@ -198,7 +199,7 @@ function reduceSearchState(store: Store, state: State, action: Action): State {
199
selectedElementIndex,
200
} = state;
201
201
- const prevSearchIndex = searchIndex;
202
+ let prevSearchIndex = searchIndex;
203
const prevSearchText = searchText;
204
const numPrevSearchResults = searchResults.length;
205
@@ -306,10 +307,25 @@ function reduceSearchState(store: Store, state: State, action: Action): State {
307
if (prevSearchIndex === null) {
308
searchIndex = 0;
309
} else {
309
- searchIndex = Math.min(
310
- ((prevSearchIndex: any): number),
311
- searchResults.length - 1
312
- );
310
+ // Changes in search index or typing should override the selected element.
311
+ // The one exception is when a search is broadened (e.g. "Cat" -> "Ca").
312
+ // In this case, it's probably desirable to maintain a stable selection.
313
+ // Replacements of text( e.g. "cat" -> "dog") likely require an index change.
314
+ const didRelaxSearchText =
315
+ prevSearchText.length > searchText.length &&
316
+ prevSearchText.startsWith(searchText);
317
+ if (didRelaxSearchText) {
318
+ searchIndex = prevSearchIndex;
319
+ } else {
320
+ searchIndex = Math.min(
321
+ ((prevSearchIndex: any): number),
322
+ searchResults.length - 1
323
+ );
324
+
325
+ // Force selected element ID to be re-evaluated below, even if the search index didn't change,
326
+ // because new search text means the same index may now point to a new element.
327
+ prevSearchIndex = null;
328
+ }
329
}
330
}
331
}
@@ -686,6 +702,30 @@ function TreeContextController({ children, viewElementSource }: Props) {
702
return () => bridge.removeListener('selectFiber', handleSelectFiber);
703
}, [bridge, dispatch]);
704
705
+ // If a newly-selected search result is inside of a collapsed subtree, auto expand it.
706
+ // We also need to handle when the search text changed (selecting a new element) without changing the index.
707
+ const prevSearchIndex = useRef<number | null>(null);
708
+ const prevSearchText = useRef<string>('');
709
+ useEffect(() => {
710
+ if (
711
+ state.searchIndex !== prevSearchIndex.current ||
712
+ state.searchText !== prevSearchText.current
713
+ ) {
714
+ prevSearchIndex.current = state.searchIndex;
715
+ prevSearchText.current = state.searchText;
716
+
717
+ if (state.searchIndex !== null && state.selectedElementID !== null) {
718
+ let element = store.getElementByID(state.selectedElementID);
719
+ while (element !== null && element.parentID > 0) {
720
+ element = ((store.getElementByID(element.parentID): any): Element);
721
+ if (element.isCollapsed) {
722
+ store.toggleIsCollapsed(element.id, false);
723
+ }
724
+ }
725
+ }
726
+ }
727
+ }, [state.searchIndex, state.searchText, state.selectedElementID, store]);
728
+
729
// Mutations to the underlying tree may impact this context (e.g. search results, selection state).
730
useEffect(() => {
731
const handleStoreMutated = ([