main
js 93 lines 2.72 KB
Raw
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 {ElementTypeHostComponent} from 'react-devtools-shared/src/frontend/types';
13 import Button from '../Button';
14 import ButtonIcon from '../ButtonIcon';
15 import KeyValue from './KeyValue';
16 import {alphaSortEntries, serializeDataForCopy} from '../utils';
17 import Store from '../../store';
18 import styles from './InspectedElementSharedStyles.css';
19 import {withPermissionsCheck} from 'react-devtools-shared/src/frontend/utils/withPermissionsCheck';
20
21 import type {InspectedElement} from 'react-devtools-shared/src/frontend/types';
22 import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
23 import type {Element} from 'react-devtools-shared/src/frontend/types';
24
25 type Props = {
26 bridge: FrontendBridge,
27 element: Element,
28 inspectedElement: InspectedElement,
29 store: Store,
30 };
31
32 export default function InspectedElementStateTree({
33 bridge,
34 element,
35 inspectedElement,
36 store,
37 }: Props): React.Node {
38 const {state, type} = inspectedElement;
39 if (state == null) {
40 return null;
41 }
42
43 // HostSingleton and HostHoistable may have state that we don't want to expose to users
44 const isHostComponent = type === ElementTypeHostComponent;
45 const entries = Object.entries(state);
46 const isEmpty = entries.length === 0;
47 if (isEmpty || isHostComponent) {
48 return null;
49 }
50
51 entries.sort(alphaSortEntries);
52 const handleCopy = withPermissionsCheck(
53 {permissions: ['clipboardWrite']},
54 () => copy(serializeDataForCopy(state)),
55 );
56
57 return (
58 <div>
59 <div className={styles.HeaderRow}>
60 <div className={styles.Header}>state</div>
61 {/* $FlowFixMe[constant-condition] */}
62 {!isEmpty && (
63 <Button onClick={handleCopy} title="Copy to clipboard">
64 <ButtonIcon type="copy" />
65 </Button>
66 )}
67 </div>
68 {/* $FlowFixMe[constant-condition] */}
69 {isEmpty && <div className={styles.Empty}>None</div>}
70 {/* $FlowFixMe[constant-condition] */}
71 {!isEmpty &&
72 (entries as any).map(([name, value]) => (
73 <KeyValue
74 key={name}
75 alphaSort={true}
76 bridge={bridge}
77 canDeletePaths={true}
78 canEditValues={true}
79 canRenamePaths={true}
80 depth={1}
81 element={element}
82 hidden={false}
83 inspectedElement={inspectedElement}
84 name={name}
85 path={[name]}
86 pathRoot="state"
87 store={store}
88 value={value}
89 />
90 ))}
91 </div>
92 );
93 }