From 0153eaedee768336d3e849b18c8889a13c752e1b Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Wed, 27 Feb 2019 13:49:46 -0800 Subject: [PATCH] Left arrow selects parent in tree --- src/devtools/store.js | 4 ++-- src/devtools/views/SearchInput.js | 13 ++++++++++++- src/devtools/views/Tree.js | 15 ++++++++++++++- src/devtools/views/TreeContext.js | 20 ++++++++++++++++++++ 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/devtools/store.js b/src/devtools/store.js index 511812430d..988bcc92a6 100644 --- a/src/devtools/store.js +++ b/src/devtools/store.js @@ -118,7 +118,7 @@ export default class Store extends EventEmitter { } } - return ((currentElement: any): Element); + return ((currentElement: any): Element) || null; } getElementIDAtIndex(index: number): number | null { @@ -141,7 +141,7 @@ export default class Store extends EventEmitter { getIndexOfElementID(id: number): number | null { const element = this.getElementByID(id); - if (element === null) { + if (element === null || element.parentID === 0) { return null; } diff --git a/src/devtools/views/SearchInput.js b/src/devtools/views/SearchInput.js index b5bc2c5767..103858138d 100644 --- a/src/devtools/views/SearchInput.js +++ b/src/devtools/views/SearchInput.js @@ -31,6 +31,16 @@ export default function SearchInput(props: Props) { setSearchText(''); }, [setSearchText]); + const handleKeyDown = useCallback(event => { + if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') { + // It's convenient for up/down arrow keys to change the selected element when focused on the search input. + // But e.g. left/right arrow keys should move the text cursor. + // For now just block everything except for up/down arrow keys. + // TODO Revisit this approach. + event.stopPropagation(); + } + }, []); + const handleInputKeyPress = useCallback( ({ key }) => { if (key === 'Enter') { @@ -62,8 +72,9 @@ export default function SearchInput(props: Props) { | null>(null); @@ -51,6 +52,14 @@ export default function Tree(props: Props) { selectNextElementInTree(); event.preventDefault(); break; + case 'ArrowLeft': + console.log('LEFT'); + selectParentElementInTree(); + break; + case 'ArrowRight': + selectNextElementInTree(); + event.preventDefault(); + break; case 'ArrowUp': selectPreviousElementInTree(); event.preventDefault(); @@ -63,7 +72,11 @@ export default function Tree(props: Props) { return () => { window.removeEventListener('keydown', handleKeyDown); }; - }, [selectNextElementInTree, selectPreviousElementInTree]); + }, [ + selectNextElementInTree, + selectParentElementInTree, + selectPreviousElementInTree, + ]); // Let react-window know to re-render any time the underlying tree data changes. // This includes the owner context, since it controls a filtered view of the tree. diff --git a/src/devtools/views/TreeContext.js b/src/devtools/views/TreeContext.js index 66b4b1b088..715eee3cbf 100644 --- a/src/devtools/views/TreeContext.js +++ b/src/devtools/views/TreeContext.js @@ -41,6 +41,7 @@ type Context = {| selectElementAtIndex(index: number): void, selectElementByID(id: number | null): void, selectNextElementInTree(): void, + selectParentElementInTree(): void, selectPreviousElementInTree(): void, // Search @@ -91,6 +92,7 @@ type Action = {| | 'SELECT_ELEMENT_AT_INDEX' | 'SELECT_ELEMENT_BY_ID' | 'SELECT_NEXT_ELEMENT_IN_TREE' + | 'SELECT_PARENT_ELEMENT_IN_TREE' | 'SELECT_PREVIOUS_ELEMENT_IN_TREE' | 'SELECT_OWNER' | 'SET_SEARCH_TEXT', @@ -138,6 +140,17 @@ function reduceTreeState(store: Store, state: State, action: Action): State { selectedElementIndex++; } break; + case 'SELECT_PARENT_ELEMENT_IN_TREE': + if (selectedElementIndex !== null) { + const selectedElement = store.getElementAtIndex( + ((selectedElementIndex: any): number) + ); + if (selectedElement !== null && selectedElement.parentID !== null) { + selectedElementIndex = + store.getIndexOfElementID(selectedElement.parentID) || 0; + } + } + break; case 'SELECT_PREVIOUS_ELEMENT_IN_TREE': if (selectedElementIndex !== null && selectedElementIndex > 0) { selectedElementIndex--; @@ -502,6 +515,7 @@ function TreeContextController({ children, viewElementSource }: Props) { case 'SELECT_ELEMENT_AT_INDEX': case 'SELECT_ELEMENT_BY_ID': case 'SELECT_NEXT_ELEMENT_IN_TREE': + case 'SELECT_PARENT_ELEMENT_IN_TREE': case 'SELECT_PREVIOUS_ELEMENT_IN_TREE': case 'SELECT_OWNER': case 'SET_SEARCH_TEXT': @@ -572,6 +586,10 @@ function TreeContextController({ children, viewElementSource }: Props) { () => dispatch({ type: 'SELECT_NEXT_ELEMENT_IN_TREE' }), [dispatch] ); + const selectParentElementInTree = useCallback( + () => dispatch({ type: 'SELECT_PARENT_ELEMENT_IN_TREE' }), + [dispatch] + ); const selectPreviousElementInTree = useCallback( () => dispatch({ type: 'SELECT_PREVIOUS_ELEMENT_IN_TREE' }), [dispatch] @@ -592,6 +610,7 @@ function TreeContextController({ children, viewElementSource }: Props) { selectElementByID, selectElementAtIndex, selectNextElementInTree, + selectParentElementInTree, selectPreviousElementInTree, // Search @@ -619,6 +638,7 @@ function TreeContextController({ children, viewElementSource }: Props) { selectElementAtIndex, selectElementByID, selectNextElementInTree, + selectParentElementInTree, selectOwner, selectPreviousElementInTree, setSearchText,