@samitouri / QOS-React / commits / 0153eaedee

Left arrow selects parent in tree

Brian Vaughn committed Feb 27, 2019 at 13:49 UTC 0153eaedee768336d3e849b18c8889a13c752e1b
4 files changed +48 -4
src/devtools/store.js
+2 -2
@@ -118,7 +118,7 @@ export default class Store extends EventEmitter {
118 }
119 }
120
121 - return ((currentElement: any): Element);
121 + return ((currentElement: any): Element) || null;
122 }
123
124 getElementIDAtIndex(index: number): number | null {
@@ -141,7 +141,7 @@ export default class Store extends EventEmitter {
141 getIndexOfElementID(id: number): number | null {
142 const element = this.getElementByID(id);
143
144 - if (element === null) {
144 + if (element === null || element.parentID === 0) {
145 return null;
146 }
147
src/devtools/views/SearchInput.js
+12 -1
@@ -31,6 +31,16 @@ export default function SearchInput(props: Props) {
31 setSearchText('');
32 }, [setSearchText]);
33
34 + const handleKeyDown = useCallback(event => {
35 + if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') {
36 + // It's convenient for up/down arrow keys to change the selected element when focused on the search input.
37 + // But e.g. left/right arrow keys should move the text cursor.
38 + // For now just block everything except for up/down arrow keys.
39 + // TODO Revisit this approach.
40 + event.stopPropagation();
41 + }
42 + }, []);
43 +
44 const handleInputKeyPress = useCallback(
45 ({ key }) => {
46 if (key === 'Enter') {
@@ -62,8 +72,9 @@ export default function SearchInput(props: Props) {
72 <Icon className={styles.InputIcon} type="search" />
73 <input
74 className={styles.Input}
65 - onKeyPress={handleInputKeyPress}
75 onChange={handleTextChange}
76 + onKeyDown={handleKeyDown}
77 + onKeyPress={handleInputKeyPress}
78 placeholder="Search (text or /regex/)"
79 ref={inputRef}
80 value={searchText}
src/devtools/views/Tree.js
+14 -1
@@ -28,6 +28,7 @@ export default function Tree(props: Props) {
28 ownerStack,
29 selectedElementIndex,
30 selectNextElementInTree,
31 + selectParentElementInTree,
32 selectPreviousElementInTree,
33 } = useContext(TreeContext);
34 const listRef = useRef<FixedSizeList<any> | null>(null);
@@ -51,6 +52,14 @@ export default function Tree(props: Props) {
52 selectNextElementInTree();
53 event.preventDefault();
54 break;
55 + case 'ArrowLeft':
56 + console.log('LEFT');
57 + selectParentElementInTree();
58 + break;
59 + case 'ArrowRight':
60 + selectNextElementInTree();
61 + event.preventDefault();
62 + break;
63 case 'ArrowUp':
64 selectPreviousElementInTree();
65 event.preventDefault();
@@ -63,7 +72,11 @@ export default function Tree(props: Props) {
72 return () => {
73 window.removeEventListener('keydown', handleKeyDown);
74 };
66 - }, [selectNextElementInTree, selectPreviousElementInTree]);
75 + }, [
76 + selectNextElementInTree,
77 + selectParentElementInTree,
78 + selectPreviousElementInTree,
79 + ]);
80
81 // Let react-window know to re-render any time the underlying tree data changes.
82 // This includes the owner context, since it controls a filtered view of the tree.
src/devtools/views/TreeContext.js
+20
@@ -41,6 +41,7 @@ type Context = {|
41 selectElementAtIndex(index: number): void,
42 selectElementByID(id: number | null): void,
43 selectNextElementInTree(): void,
44 + selectParentElementInTree(): void,
45 selectPreviousElementInTree(): void,
46
47 // Search
@@ -91,6 +92,7 @@ type Action = {|
92 | 'SELECT_ELEMENT_AT_INDEX'
93 | 'SELECT_ELEMENT_BY_ID'
94 | 'SELECT_NEXT_ELEMENT_IN_TREE'
95 + | 'SELECT_PARENT_ELEMENT_IN_TREE'
96 | 'SELECT_PREVIOUS_ELEMENT_IN_TREE'
97 | 'SELECT_OWNER'
98 | 'SET_SEARCH_TEXT',
@@ -138,6 +140,17 @@ function reduceTreeState(store: Store, state: State, action: Action): State {
140 selectedElementIndex++;
141 }
142 break;
143 + case 'SELECT_PARENT_ELEMENT_IN_TREE':
144 + if (selectedElementIndex !== null) {
145 + const selectedElement = store.getElementAtIndex(
146 + ((selectedElementIndex: any): number)
147 + );
148 + if (selectedElement !== null && selectedElement.parentID !== null) {
149 + selectedElementIndex =
150 + store.getIndexOfElementID(selectedElement.parentID) || 0;
151 + }
152 + }
153 + break;
154 case 'SELECT_PREVIOUS_ELEMENT_IN_TREE':
155 if (selectedElementIndex !== null && selectedElementIndex > 0) {
156 selectedElementIndex--;
@@ -502,6 +515,7 @@ function TreeContextController({ children, viewElementSource }: Props) {
515 case 'SELECT_ELEMENT_AT_INDEX':
516 case 'SELECT_ELEMENT_BY_ID':
517 case 'SELECT_NEXT_ELEMENT_IN_TREE':
518 + case 'SELECT_PARENT_ELEMENT_IN_TREE':
519 case 'SELECT_PREVIOUS_ELEMENT_IN_TREE':
520 case 'SELECT_OWNER':
521 case 'SET_SEARCH_TEXT':
@@ -572,6 +586,10 @@ function TreeContextController({ children, viewElementSource }: Props) {
586 () => dispatch({ type: 'SELECT_NEXT_ELEMENT_IN_TREE' }),
587 [dispatch]
588 );
589 + const selectParentElementInTree = useCallback(
590 + () => dispatch({ type: 'SELECT_PARENT_ELEMENT_IN_TREE' }),
591 + [dispatch]
592 + );
593 const selectPreviousElementInTree = useCallback(
594 () => dispatch({ type: 'SELECT_PREVIOUS_ELEMENT_IN_TREE' }),
595 [dispatch]
@@ -592,6 +610,7 @@ function TreeContextController({ children, viewElementSource }: Props) {
610 selectElementByID,
611 selectElementAtIndex,
612 selectNextElementInTree,
613 + selectParentElementInTree,
614 selectPreviousElementInTree,
615
616 // Search
@@ -619,6 +638,7 @@ function TreeContextController({ children, viewElementSource }: Props) {
638 selectElementAtIndex,
639 selectElementByID,
640 selectNextElementInTree,
641 + selectParentElementInTree,
642 selectOwner,
643 selectPreviousElementInTree,
644 setSearchText,