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 {OptionsContext} from '../context';
    
  13. import Button from '../Button';
    
  14. import ButtonIcon from '../ButtonIcon';
    
  15. import KeyValue from './KeyValue';
    
  16. import NewKeyValue from './NewKeyValue';
    
  17. import {alphaSortEntries, serializeDataForCopy} from '../utils';
    
  18. import Store from '../../store';
    
  19. import styles from './InspectedElementSharedStyles.css';
    
  20. import {ElementTypeClass} from 'react-devtools-shared/src/frontend/types';
    
  21. 
    
  22. import type {InspectedElement} from 'react-devtools-shared/src/frontend/types';
    
  23. import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
    
  24. import type {Element} from 'react-devtools-shared/src/frontend/types';
    
  25. 
    
  26. type Props = {
    
  27.   bridge: FrontendBridge,
    
  28.   element: Element,
    
  29.   inspectedElement: InspectedElement,
    
  30.   store: Store,
    
  31. };
    
  32. 
    
  33. export default function InspectedElementPropsTree({
    
  34.   bridge,
    
  35.   element,
    
  36.   inspectedElement,
    
  37.   store,
    
  38. }: Props): React.Node {
    
  39.   const {readOnly} = React.useContext(OptionsContext);
    
  40. 
    
  41.   const {
    
  42.     canEditFunctionProps,
    
  43.     canEditFunctionPropsDeletePaths,
    
  44.     canEditFunctionPropsRenamePaths,
    
  45.     props,
    
  46.     type,
    
  47.   } = inspectedElement;
    
  48. 
    
  49.   const canDeletePaths =
    
  50.     type === ElementTypeClass || canEditFunctionPropsDeletePaths;
    
  51.   const canEditValues =
    
  52.     !readOnly && (type === ElementTypeClass || canEditFunctionProps);
    
  53.   const canRenamePaths =
    
  54.     type === ElementTypeClass || canEditFunctionPropsRenamePaths;
    
  55. 
    
  56.   const entries = props != null ? Object.entries(props) : null;
    
  57.   if (entries !== null) {
    
  58.     entries.sort(alphaSortEntries);
    
  59.   }
    
  60. 
    
  61.   const isEmpty = entries === null || entries.length === 0;
    
  62. 
    
  63.   const handleCopy = () => copy(serializeDataForCopy(((props: any): Object)));
    
  64. 
    
  65.   return (
    
  66.     <div
    
  67.       className={styles.InspectedElementTree}
    
  68.       data-testname="InspectedElementPropsTree">
    
  69.       <div className={styles.HeaderRow}>
    
  70.         <div className={styles.Header}>props</div>
    
  71.         {!isEmpty && (
    
  72.           <Button onClick={handleCopy} title="Copy to clipboard">
    
  73.             <ButtonIcon type="copy" />
    
  74.           </Button>
    
  75.         )}
    
  76.       </div>
    
  77.       {!isEmpty &&
    
  78.         (entries: any).map(([name, value]) => (
    
  79.           <KeyValue
    
  80.             key={name}
    
  81.             alphaSort={true}
    
  82.             bridge={bridge}
    
  83.             canDeletePaths={canDeletePaths}
    
  84.             canEditValues={canEditValues}
    
  85.             canRenamePaths={canRenamePaths}
    
  86.             depth={1}
    
  87.             element={element}
    
  88.             hidden={false}
    
  89.             inspectedElement={inspectedElement}
    
  90.             name={name}
    
  91.             path={[name]}
    
  92.             pathRoot="props"
    
  93.             store={store}
    
  94.             value={value}
    
  95.           />
    
  96.         ))}
    
  97.       {canEditValues && (
    
  98.         <NewKeyValue
    
  99.           bridge={bridge}
    
  100.           depth={0}
    
  101.           hidden={false}
    
  102.           inspectedElement={inspectedElement}
    
  103.           path={[]}
    
  104.           store={store}
    
  105.           type="props"
    
  106.         />
    
  107.       )}
    
  108.     </div>
    
  109.   );
    
  110. }