1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow
    
  8.  */
    
  9. 
    
  10. import type {Element} from 'react-devtools-shared/src/frontend/types';
    
  11. 
    
  12. import * as React from 'react';
    
  13. import {useContext, useMemo} from 'react';
    
  14. import {TreeStateContext} from './TreeContext';
    
  15. import {SettingsContext} from '../Settings/SettingsContext';
    
  16. import TreeFocusedContext from './TreeFocusedContext';
    
  17. import {StoreContext} from '../context';
    
  18. import {useSubscription} from '../hooks';
    
  19. 
    
  20. import styles from './SelectedTreeHighlight.css';
    
  21. 
    
  22. type Data = {
    
  23.   startIndex: number,
    
  24.   stopIndex: number,
    
  25. };
    
  26. 
    
  27. export default function SelectedTreeHighlight(_: {}): React.Node {
    
  28.   const {lineHeight} = useContext(SettingsContext);
    
  29.   const store = useContext(StoreContext);
    
  30.   const treeFocused = useContext(TreeFocusedContext);
    
  31.   const {ownerID, selectedElementID} = useContext(TreeStateContext);
    
  32. 
    
  33.   const subscription = useMemo(
    
  34.     () => ({
    
  35.       getCurrentValue: () => {
    
  36.         if (
    
  37.           selectedElementID === null ||
    
  38.           store.isInsideCollapsedSubTree(selectedElementID)
    
  39.         ) {
    
  40.           return null;
    
  41.         }
    
  42. 
    
  43.         const element = store.getElementByID(selectedElementID);
    
  44.         if (
    
  45.           element === null ||
    
  46.           element.isCollapsed ||
    
  47.           element.children.length === 0
    
  48.         ) {
    
  49.           return null;
    
  50.         }
    
  51. 
    
  52.         const startIndex = store.getIndexOfElementID(element.children[0]);
    
  53.         if (startIndex === null) {
    
  54.           return null;
    
  55.         }
    
  56. 
    
  57.         let stopIndex = null;
    
  58.         let current: null | Element = element;
    
  59.         while (current !== null) {
    
  60.           if (current.isCollapsed || current.children.length === 0) {
    
  61.             // We've found the last/deepest descendant.
    
  62.             stopIndex = store.getIndexOfElementID(current.id);
    
  63.             current = null;
    
  64.           } else {
    
  65.             const lastChildID = current.children[current.children.length - 1];
    
  66.             current = store.getElementByID(lastChildID);
    
  67.           }
    
  68.         }
    
  69. 
    
  70.         if (stopIndex === null) {
    
  71.           return null;
    
  72.         }
    
  73. 
    
  74.         return {
    
  75.           startIndex,
    
  76.           stopIndex,
    
  77.         };
    
  78.       },
    
  79.       subscribe: (callback: Function) => {
    
  80.         store.addListener('mutated', callback);
    
  81.         return () => {
    
  82.           store.removeListener('mutated', callback);
    
  83.         };
    
  84.       },
    
  85.     }),
    
  86.     [selectedElementID, store],
    
  87.   );
    
  88.   const data = useSubscription<Data | null>(subscription);
    
  89. 
    
  90.   if (ownerID !== null) {
    
  91.     return null;
    
  92.   }
    
  93. 
    
  94.   if (data === null) {
    
  95.     return null;
    
  96.   }
    
  97. 
    
  98.   const {startIndex, stopIndex} = data;
    
  99. 
    
  100.   return (
    
  101.     <div
    
  102.       className={treeFocused ? styles.Active : styles.Inactive}
    
  103.       style={{
    
  104.         position: 'absolute',
    
  105.         top: `${startIndex * lineHeight}px`,
    
  106.         height: `${(stopIndex + 1 - startIndex) * lineHeight}px`,
    
  107.       }}
    
  108.     />
    
  109.   );
    
  110. }