Added copy props/state/hooks/context button

This commit is contained in:
Brian Vaughn
2019-02-22 09:39:05 -08:00
parent 1edbfbf6cb
commit 5fd9cb5dfb
8 changed files with 115 additions and 8 deletions
+1 -1
View File
@@ -50,7 +50,7 @@
"chrome-launch": "^1.1.4",
"classnames": "2.2.1",
"cli-spinners": "^1.0.0",
"clipboard-js": "^0.3.3",
"clipboard-js": "^0.3.6",
"css-loader": "^1.0.1",
"error-stack-parser": "^2.0.2",
"es6-symbol": "3.0.2",
+9
View File
@@ -7,6 +7,7 @@ type Props = {|
type:
| 'back'
| 'close'
| 'copy'
| 'down'
| 'more'
| 'search'
@@ -25,6 +26,9 @@ export default function ButtonIcon({ type }: Props) {
case 'close':
pathData = PATH_CLOSE;
break;
case 'copy':
pathData = PATH_COPY;
break;
case 'down':
pathData = PATH_DOWN;
break;
@@ -74,6 +78,11 @@ const PATH_BACK = `
const PATH_CLOSE =
'M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z';
const PATH_COPY = `
M3 13h2v-2H3v2zm0 4h2v-2H3v2zm2 4v-2H3a2 2 0 0 0 2 2zM3 9h2V7H3v2zm12 12h2v-2h-2v2zm4-18H9a2 2 0 0 0-2
2v10a2 2 0 0 0 2 2h10c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 12H9V5h10v10zm-8 6h2v-2h-2v2zm-4 0h2v-2H7v2z
`;
const PATH_DOWN = 'M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z';
const PATH_MORE = `
+6
View File
@@ -7,7 +7,13 @@
padding-left: 0.75rem;
}
.HeaderRow {
display: flex;
align-items: center;
}
.Header {
flex: 1 1;
font-family: var(--font-family-sans);
}
+15 -2
View File
@@ -1,9 +1,13 @@
// @flow
import React, { useContext } from 'react';
import { copy } from 'clipboard-js';
import React, { useCallback, useContext } from 'react';
import { BridgeContext, StoreContext } from './context';
import Button from './Button';
import ButtonIcon from './ButtonIcon';
import EditableValue from './EditableValue';
import KeyValue from './KeyValue';
import { serializeHooksForCopy } from './utils';
import styles from './HooksTree.css';
import type { HooksNode, HooksTree } from 'src/backend/types';
@@ -15,12 +19,21 @@ type HooksTreeViewProps = {|
|};
export function HooksTreeView({ canEditHooks, hooks, id }: HooksTreeViewProps) {
const handleCopy = useCallback(() => copy(serializeHooksForCopy(hooks)), [
hooks,
]);
if (hooks === null) {
return null;
} else {
return (
<div className={styles.HooksTreeView}>
<div className={styles.Header}>hooks</div>
<div className={styles.HeaderRow}>
<div className={styles.Header}>hooks</div>
<Button onClick={handleCopy}>
<ButtonIcon type="copy" />
</Button>
</div>
<InnerHooksTreeView canEditHooks={canEditHooks} hooks={hooks} id={id} />
</div>
);
@@ -6,7 +6,13 @@
border-top: none;
}
.HeaderRow {
display: flex;
align-items: center;
}
.Header {
flex: 1 1;
font-family: var(--font-family-sans);
}
+17 -2
View File
@@ -1,7 +1,11 @@
// @flow
import React from 'react';
import { copy } from 'clipboard-js';
import React, { useCallback } from 'react';
import Button from './Button';
import ButtonIcon from './ButtonIcon';
import KeyValue from './KeyValue';
import { serializeDataForCopy } from './utils';
import styles from './InspectedElementTree.css';
type OverrideValueFn = (path: Array<string | number>, value: any) => void;
@@ -21,13 +25,24 @@ export default function InspectedElementTree({
}: Props) {
const isEmpty = data === null || Object.keys(data).length === 0;
const handleCopy = useCallback(() => copy(serializeDataForCopy(data)), [
data,
]);
if (isEmpty && !showWhenEmpty) {
return null;
} else {
// TODO Add click and key handlers for toggling element open/close state.
return (
<div className={styles.InspectedElementTree}>
<div className={styles.Header}>{label}</div>
<div className={styles.HeaderRow}>
<div className={styles.Header}>{label}</div>
{!isEmpty && (
<Button onClick={handleCopy}>
<ButtonIcon type="copy" />
</Button>
)}
</div>
{isEmpty && <div className={styles.Empty}>None</div>}
{!isEmpty &&
Object.keys((data: any)).map(name => (
+57
View File
@@ -3,6 +3,8 @@
import escapeStringRegExp from 'escape-string-regexp';
import { meta } from '../../hydration';
import type { HooksTree } from 'src/backend/types';
export function createRegExp(string: string): RegExp {
return new RegExp(escapeStringRegExp(string), 'i');
}
@@ -29,3 +31,58 @@ export function getMetaValueLabel(data: Object): string | null {
return null;
}
}
function sanitize(data: Object): void {
for (const key in data) {
const value = data[key];
if (value && value[meta.type]) {
data[key] = getMetaValueLabel(value);
} else if (value != null) {
if (Array.isArray(value)) {
sanitize(value);
} else if (typeof value === 'object') {
sanitize(value);
}
}
}
}
export function serializeDataForCopy(props: Object): string {
const cloned = Object.assign({}, props);
sanitize(cloned);
try {
return JSON.stringify(cloned, null, 2);
} catch (error) {
return '';
}
}
export function serializeHooksForCopy(hooks: HooksTree | null): string {
// $FlowFixMe "HooksTree is not an object"
const cloned = Object.assign([], hooks);
const queue = [...cloned];
while (queue.length > 0) {
const current = queue.pop();
// These aren't meaningful
delete current.isEditable;
delete current.index;
if (current.subHooks.length > 0) {
queue.push(...current.subHooks);
}
}
sanitize(cloned);
try {
return JSON.stringify(cloned, null, 2);
} catch (error) {
return '';
}
}
+4 -3
View File
@@ -2636,9 +2636,10 @@ cli-width@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a"
clipboard-js@^0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/clipboard-js/-/clipboard-js-0.3.3.tgz#62264c17c80ebf84f4022286f032501e890b8922"
clipboard-js@^0.3.6:
version "0.3.6"
resolved "https://registry.yarnpkg.com/clipboard-js/-/clipboard-js-0.3.6.tgz#6260add69b5318fde40b80f9d3c8c863efdaf339"
integrity sha512-hyrmvbrYCeRBHdiR3KrEz0tmrUTXXEU8HLeGW0Y0icUSwYmAsmc+d6wfE4EDb/TxZmAVJG0eTfMlulCIT+ecfw==
cliui@^2.1.0:
version "2.1.0"