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 {copy} from 'clipboard-js';
    
  11. import * as React from 'react';
    
  12. import Button from '../Button';
    
  13. import ButtonIcon from '../ButtonIcon';
    
  14. import KeyValue from './KeyValue';
    
  15. import {alphaSortEntries, serializeDataForCopy} from '../utils';
    
  16. import Store from '../../store';
    
  17. import styles from './InspectedElementSharedStyles.css';
    
  18. import {
    
  19.   ElementTypeClass,
    
  20.   ElementTypeFunction,
    
  21. } from 'react-devtools-shared/src/frontend/types';
    
  22. 
    
  23. import type {InspectedElement} from 'react-devtools-shared/src/frontend/types';
    
  24. import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
    
  25. import type {Element} from 'react-devtools-shared/src/frontend/types';
    
  26. 
    
  27. type Props = {
    
  28.   bridge: FrontendBridge,
    
  29.   element: Element,
    
  30.   inspectedElement: InspectedElement,
    
  31.   store: Store,
    
  32. };
    
  33. 
    
  34. export default function InspectedElementContextTree({
    
  35.   bridge,
    
  36.   element,
    
  37.   inspectedElement,
    
  38.   store,
    
  39. }: Props): React.Node {
    
  40.   const {hasLegacyContext, context, type} = inspectedElement;
    
  41. 
    
  42.   const isReadOnly = type !== ElementTypeClass && type !== ElementTypeFunction;
    
  43. 
    
  44.   const entries = context != null ? Object.entries(context) : null;
    
  45.   if (entries !== null) {
    
  46.     entries.sort(alphaSortEntries);
    
  47.   }
    
  48. 
    
  49.   const isEmpty = entries === null || entries.length === 0;
    
  50. 
    
  51.   const handleCopy = () => copy(serializeDataForCopy(((context: any): Object)));
    
  52. 
    
  53.   // We add an object with a "value" key as a wrapper around Context data
    
  54.   // so that we can use the shared <KeyValue> component to display it.
    
  55.   // This wrapper object can't be renamed.
    
  56.   // $FlowFixMe[missing-local-annot]
    
  57.   const canRenamePathsAtDepth = depth => depth > 1;
    
  58. 
    
  59.   if (isEmpty) {
    
  60.     return null;
    
  61.   } else {
    
  62.     return (
    
  63.       <div className={styles.InspectedElementTree}>
    
  64.         <div className={styles.HeaderRow}>
    
  65.           <div className={styles.Header}>
    
  66.             {hasLegacyContext ? 'legacy context' : 'context'}
    
  67.           </div>
    
  68.           {!isEmpty && (
    
  69.             <Button onClick={handleCopy} title="Copy to clipboard">
    
  70.               <ButtonIcon type="copy" />
    
  71.             </Button>
    
  72.           )}
    
  73.         </div>
    
  74.         {isEmpty && <div className={styles.Empty}>None</div>}
    
  75.         {!isEmpty &&
    
  76.           (entries: any).map(([name, value]) => (
    
  77.             <KeyValue
    
  78.               key={name}
    
  79.               alphaSort={true}
    
  80.               bridge={bridge}
    
  81.               canDeletePaths={!isReadOnly}
    
  82.               canEditValues={!isReadOnly}
    
  83.               canRenamePaths={!isReadOnly}
    
  84.               canRenamePathsAtDepth={canRenamePathsAtDepth}
    
  85.               depth={1}
    
  86.               element={element}
    
  87.               hidden={false}
    
  88.               inspectedElement={inspectedElement}
    
  89.               name={name}
    
  90.               path={[name]}
    
  91.               pathRoot="context"
    
  92.               store={store}
    
  93.               type="context"
    
  94.               value={value}
    
  95.             />
    
  96.           ))}
    
  97.       </div>
    
  98.     );
    
  99.   }
    
  100. }