Skip to content

Commit

Permalink
[DevTools] - Highlight rendered by elements on hover. (#18479)
Browse files Browse the repository at this point in the history
* [DevTools] - Highlight rendered by elements on hover.

* Fixed formatting issue.

* DevTools - Extracted highlight logic to custom hook. Added highlight support for rendered by elements.

* Removed unnecessary padding style

* Removed unnecessary wrapper function.

Co-authored-by: Brian Vaughn <brian.david.vaughn@gmail.com>
  • Loading branch information
hristo-kanchev and bvaughn committed Apr 3, 2020
1 parent f312a3f commit 7785a52
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 32 deletions.
Expand Up @@ -82,7 +82,6 @@
.Owner {
border-radius: 0.25rem;
padding: 0.125rem 0.25rem;
cursor: pointer;
background: none;
border: none;
display: block;
Expand All @@ -107,12 +106,23 @@
}

.OwnerButton {
cursor: pointer;
width: 100%;
padding: 0;
}

.OwnerContent {
display: flex;
align-items: center;
margin-left: 0.5rem;
padding: 0;
padding-left: 1rem;
width: 100%;
border-radius: 0.25rem;
}

.OwnerContent:hover {
background-color: var(--color-background-hover);
}

.ContextMenuIcon {
margin-right: 0.5rem;
}
}
Expand Up @@ -26,6 +26,7 @@ import ViewElementSourceContext from './ViewElementSourceContext';
import NativeStyleEditor from './NativeStyleEditor';
import Toggle from '../Toggle';
import Badge from './Badge';
import {useHighlightNativeElement} from '../hooks';
import {
ComponentFilterElementType,
ElementTypeClass,
Expand Down Expand Up @@ -522,6 +523,10 @@ function OwnerView({
type,
}: OwnerViewProps) {
const dispatch = useContext(TreeDispatcherContext);
const {
highlightNativeElement,
clearHighlightNativeElement,
} = useHighlightNativeElement();

const handleClick = useCallback(
() =>
Expand All @@ -532,18 +537,26 @@ function OwnerView({
[dispatch, id],
);

const onMouseEnter = () => highlightNativeElement(id);

const onMouseLeave = clearHighlightNativeElement;

return (
<Button
key={id}
className={styles.OwnerButton}
disabled={!isInStore}
onClick={handleClick}>
<span
className={`${styles.Owner} ${isInStore ? '' : styles.NotInStore}`}
title={displayName}>
{displayName}
onClick={handleClick}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}>
<span className={styles.OwnerContent}>
<span
className={`${styles.Owner} ${isInStore ? '' : styles.NotInStore}`}
title={displayName}>
{displayName}
</span>
<Badge hocDisplayNames={hocDisplayNames} type={type} />
</span>
<Badge hocDisplayNames={hocDisplayNames} type={type} />
</Button>
);
}
Expand Down
Expand Up @@ -30,6 +30,7 @@ import SearchInput from './SearchInput';
import SettingsModalContextToggle from 'react-devtools-shared/src/devtools/views/Settings/SettingsModalContextToggle';
import SelectedTreeHighlight from './SelectedTreeHighlight';
import TreeFocusedContext from './TreeFocusedContext';
import {useHighlightNativeElement} from '../hooks';

import styles from './Tree.css';

Expand Down Expand Up @@ -61,6 +62,10 @@ export default function Tree(props: Props) {
const [isNavigatingWithKeyboard, setIsNavigatingWithKeyboard] = useState(
false,
);
const {
highlightNativeElement,
clearHighlightNativeElement,
} = useHighlightNativeElement();
const treeRef = useRef<HTMLDivElement | null>(null);
const focusTargetRef = useRef<HTMLDivElement | null>(null);

Expand Down Expand Up @@ -205,24 +210,6 @@ export default function Tree(props: Props) {
[dispatch, selectedElementID],
);

const highlightNativeElement = useCallback(
(id: number) => {
const element = store.getElementByID(id);
const rendererID = store.getRendererIDForElement(id);
if (element !== null && rendererID !== null) {
bridge.send('highlightNativeElement', {
displayName: element.displayName,
hideAfterTimeout: false,
id,
openNativeElementsPanel: false,
rendererID,
scrollIntoView: false,
});
}
},
[store, bridge],
);

// If we switch the selected element while using the keyboard,
// start highlighting it in the DOM instead of the last hovered node.
const searchRef = useRef({searchIndex, searchResults});
Expand All @@ -240,7 +227,7 @@ export default function Tree(props: Props) {
if (selectedElementID !== null) {
highlightNativeElement(selectedElementID);
} else {
bridge.send('clearNativeElementHighlight');
clearHighlightNativeElement();
}
}
}, [
Expand Down Expand Up @@ -270,9 +257,7 @@ export default function Tree(props: Props) {
setIsNavigatingWithKeyboard(false);
}, []);

const handleMouseLeave = useCallback(() => {
bridge.send('clearNativeElementHighlight');
}, [bridge]);
const handleMouseLeave = clearHighlightNativeElement;

// 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.
Expand Down
34 changes: 34 additions & 0 deletions packages/react-devtools-shared/src/devtools/views/hooks.js
Expand Up @@ -14,11 +14,13 @@ import {
useLayoutEffect,
useReducer,
useState,
useContext,
} from 'react';
import {
localStorageGetItem,
localStorageSetItem,
} from 'react-devtools-shared/src/storage';
import {StoreContext, BridgeContext} from './context';
import {sanitizeForParse, smartParse, smartStringify} from '../utils';

type ACTION_RESET = {|
Expand Down Expand Up @@ -301,3 +303,35 @@ export function useSubscription<Value>({

return state.value;
}

export function useHighlightNativeElement() {
const bridge = useContext(BridgeContext);
const store = useContext(StoreContext);

const highlightNativeElement = useCallback(
(id: number) => {
const element = store.getElementByID(id);
const rendererID = store.getRendererIDForElement(id);
if (element !== null && rendererID !== null) {
bridge.send('highlightNativeElement', {
displayName: element.displayName,
hideAfterTimeout: false,
id,
openNativeElementsPanel: false,
rendererID,
scrollIntoView: false,
});
}
},
[store, bridge],
);

const clearHighlightNativeElement = useCallback(() => {
bridge.send('clearNativeElementHighlight');
}, [bridge]);

return {
highlightNativeElement,
clearHighlightNativeElement,
};
}

0 comments on commit 7785a52

Please sign in to comment.