From caf2eb973af0bad812aa0d9ae42e92f4899c6c13 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Thu, 21 Feb 2019 14:20:14 -0800 Subject: [PATCH] Split large InspectedElementTree file into separate component-files --- src/devtools/views/EditableValue.css | 25 +++ src/devtools/views/EditableValue.js | 113 ++++++++++ src/devtools/views/HooksTree.js | 3 +- src/devtools/views/InspectedElementTree.css | 26 --- src/devtools/views/InspectedElementTree.js | 224 +------------------- src/devtools/views/KeyValue.css | 22 ++ src/devtools/views/KeyValue.js | 121 +++++++++++ 7 files changed, 285 insertions(+), 249 deletions(-) create mode 100644 src/devtools/views/EditableValue.css create mode 100644 src/devtools/views/EditableValue.js create mode 100644 src/devtools/views/KeyValue.css create mode 100644 src/devtools/views/KeyValue.js diff --git a/src/devtools/views/EditableValue.css b/src/devtools/views/EditableValue.css new file mode 100644 index 0000000000..6440579882 --- /dev/null +++ b/src/devtools/views/EditableValue.css @@ -0,0 +1,25 @@ +.ValueInputLabel { + flex: 1 1 100%; +} +.ValueInputLabel:focus-within { + background-color: var(--color-button-background-focus); +} + +.ValueInput { + width: 100%; + background: none; + border: 1px solid transparent; + color: var(--color-attribute-editable-value); + border-radius: 0.125rem; + font-family: var(--font-family-monospace); + font-size: var(--font-size-monospace-normal); +} + +.ValueInput:focus { + background-color: var(--color-button-background-focus); + outline: none; +} +.ResetButton { + flex: 0 0 auto; + padding: 0 0.5rem; +} diff --git a/src/devtools/views/EditableValue.js b/src/devtools/views/EditableValue.js new file mode 100644 index 0000000000..b590419f52 --- /dev/null +++ b/src/devtools/views/EditableValue.js @@ -0,0 +1,113 @@ +// @flow + +import React, { Fragment, useCallback, useRef, useState } from 'react'; +import Button from './Button'; +import ButtonIcon from './ButtonIcon'; +import styles from './EditableValue.css'; + +type OverrideValueFn = (path: Array, value: any) => void; + +type EditableValueProps = {| + dataType: string, + overrideValueFn: OverrideValueFn, + path: Array, + value: any, +|}; + +export default function EditableValue({ + dataType, + overrideValueFn, + path, + value, +}: EditableValueProps) { + const [hasPendingChanges, setHasPendingChanges] = useState(false); + const [editableValue, setEditableValue] = useState(value); + const inputRef = useRef(null); + + if (hasPendingChanges && editableValue === value) { + setHasPendingChanges(false); + } + + const handleChange = useCallback( + ({ target }) => { + if (dataType === 'boolean') { + setEditableValue(target.checked); + overrideValueFn(path, target.checked); + } else if (dataType === 'number') { + setEditableValue(parseFloat(target.value)); + } else { + setEditableValue(target.value); + } + setHasPendingChanges(true); + }, + [dataType, overrideValueFn, path] + ); + + const handleReset = useCallback(() => { + setEditableValue(value); + setHasPendingChanges(false); + + if (inputRef.current !== null) { + inputRef.current.focus(); + } + }, [value]); + + const handleKeyDown = useCallback( + event => { + // Prevent keydown events from e.g. change selected element in the tree + event.stopPropagation(); + + const { key } = event; + + if (key === 'Enter') { + overrideValueFn(path, editableValue); + + // Don't reset the pending change flag here. + // The inspected fiber won't be updated until after the next "inspectElement" message. + // We'll reset that flag during a subsequent render. + } else if (key === 'Escape') { + setEditableValue(value); + setHasPendingChanges(false); + } + }, + [path, editableValue, overrideValueFn, value] + ); + + // Render different input types based on the dataType + let type = 'text'; + if (dataType === 'boolean') { + type = 'checkbox'; + } else if (dataType === 'number') { + type = 'number'; + } + + let inputValue = value == null ? '' : value; + if (hasPendingChanges) { + inputValue = editableValue == null ? '' : editableValue; + } + + return ( + + + {hasPendingChanges && dataType !== 'boolean' && ( + + )} + + ); +} diff --git a/src/devtools/views/HooksTree.js b/src/devtools/views/HooksTree.js index 9c6eb0a9fc..4c9434b55d 100644 --- a/src/devtools/views/HooksTree.js +++ b/src/devtools/views/HooksTree.js @@ -2,7 +2,8 @@ import React, { useContext } from 'react'; import { BridgeContext, StoreContext } from './context'; -import { EditableValue, KeyValue } from './InspectedElementTree'; +import EditableValue from './EditableValue'; +import KeyValue from './KeyValue'; import styles from './HooksTree.css'; import type { HooksNode, HooksTree } from 'src/backend/types'; diff --git a/src/devtools/views/InspectedElementTree.css b/src/devtools/views/InspectedElementTree.css index 653213c857..4996d36e4e 100644 --- a/src/devtools/views/InspectedElementTree.css +++ b/src/devtools/views/InspectedElementTree.css @@ -28,27 +28,6 @@ color: var(--color-attribute-value); } -.ValueInputLabel { - flex: 1 1 100%; -} -.ValueInputLabel:focus-within { - background-color: var(--color-button-background-focus); -} - -.ValueInput { - width: 100%; - background: none; - border: 1px solid transparent; - color: var(--color-attribute-editable-value); - border-radius: 0.125rem; - font-family: var(--font-family-monospace); - font-size: var(--font-size-monospace-normal); -} -.ValueInput:focus { - background-color: var(--color-button-background-focus); - outline: none; -} - .None { color: var(--color-dimmer); font-style: italic; @@ -59,8 +38,3 @@ font-style: italic; padding-left: 0.75rem; } - -.ResetButton { - flex: 0 0 auto; - padding: 0 0.5rem; -} diff --git a/src/devtools/views/InspectedElementTree.js b/src/devtools/views/InspectedElementTree.js index afeb8f0b18..012d78875b 100644 --- a/src/devtools/views/InspectedElementTree.js +++ b/src/devtools/views/InspectedElementTree.js @@ -1,10 +1,7 @@ // @flow -import React, { Fragment, useCallback, useRef, useState } from 'react'; -import Button from './Button'; -import ButtonIcon from './ButtonIcon'; -import { getMetaValueLabel } from './utils'; -import { meta } from '../../hydration'; +import React from 'react'; +import KeyValue from './KeyValue'; import styles from './InspectedElementTree.css'; type OverrideValueFn = (path: Array, value: any) => void; @@ -47,220 +44,3 @@ export default function InspectedElementTree({ ); } } - -type KeyValueProps = {| - depth: number, - name: string, - nameClassName?: string, - overrideValueFn?: ?OverrideValueFn, - path?: Array, - value: any, -|}; - -export function KeyValue({ - depth, - name, - nameClassName = styles.Name, - overrideValueFn, - path = [], - value, -}: KeyValueProps) { - const dataType = typeof value; - const isSimpleType = - dataType === 'number' || - dataType === 'string' || - dataType === 'boolean' || - value == null; - - const paddingLeft = `${depth * 0.75}rem`; - - let children = null; - if (isSimpleType) { - let displayValue = value; - if (dataType === 'string') { - displayValue = `"${value}"`; - } else if (dataType === 'boolean') { - displayValue = value ? 'true' : 'false'; - } else if (value === null) { - displayValue = 'null'; - } else if (value === undefined) { - displayValue = 'undefined'; - } - - children = ( -
- {name} - {typeof overrideValueFn === 'function' ? ( - - ) : ( - {displayValue} - )} -
- ); - } else if (value.hasOwnProperty(meta.type)) { - // TODO Is this type even necessary? Can we just drop it? - children = ( -
- {name} - {getMetaValueLabel(value)} -
- ); - } else { - if (Array.isArray(value)) { - children = value.map((innerValue, index) => ( - - )); - children.unshift( -
- {name} - Array -
- ); - } else { - // $FlowFixMe "Missing type annotation for U" whatever that means - children = Object.entries(value).map(([name, value]) => ( - - )); - children.unshift( -
- {name} - Object -
- ); - } - } - - return children; -} - -type EditableValueProps = {| - dataType: string, - overrideValueFn: OverrideValueFn, - path: Array, - value: any, -|}; - -export function EditableValue({ - dataType, - overrideValueFn, - path, - value, -}: EditableValueProps) { - const [hasPendingChanges, setHasPendingChanges] = useState(false); - const [editableValue, setEditableValue] = useState(value); - const inputRef = useRef(null); - - if (hasPendingChanges && editableValue === value) { - setHasPendingChanges(false); - } - - const handleChange = useCallback( - ({ target }) => { - if (dataType === 'boolean') { - setEditableValue(target.checked); - overrideValueFn(path, target.checked); - } else if (dataType === 'number') { - setEditableValue(parseFloat(target.value)); - } else { - setEditableValue(target.value); - } - setHasPendingChanges(true); - }, - [dataType, overrideValueFn, path] - ); - - const handleReset = useCallback(() => { - setEditableValue(value); - setHasPendingChanges(false); - - if (inputRef.current !== null) { - inputRef.current.focus(); - } - }, [value]); - - const handleKeyDown = useCallback( - event => { - // Prevent keydown events from e.g. change selected element in the tree - event.stopPropagation(); - - const { key } = event; - - if (key === 'Enter') { - overrideValueFn(path, editableValue); - - // Don't reset the pending change flag here. - // The inspected fiber won't be updated until after the next "inspectElement" message. - // We'll reset that flag during a subsequent render. - } else if (key === 'Escape') { - setEditableValue(value); - setHasPendingChanges(false); - } - }, - [path, editableValue, overrideValueFn, value] - ); - - // Render different input types based on the dataType - let type = 'text'; - if (dataType === 'boolean') { - type = 'checkbox'; - } else if (dataType === 'number') { - type = 'number'; - } - - let inputValue = value == null ? '' : value; - if (hasPendingChanges) { - inputValue = editableValue == null ? '' : editableValue; - } - - return ( - - - {hasPendingChanges && dataType !== 'boolean' && ( - - )} - - ); -} diff --git a/src/devtools/views/KeyValue.css b/src/devtools/views/KeyValue.css new file mode 100644 index 0000000000..d8d94b11a2 --- /dev/null +++ b/src/devtools/views/KeyValue.css @@ -0,0 +1,22 @@ +.Item { + display: flex; +} + +.Name { + color: var(--color-attribute-name); + flex: 0 0 auto; +} +.Name:after { + content: ': '; + color: var(--color-text-color); + margin-right: 0.5rem; +} + +.Value { + color: var(--color-attribute-value); +} + +.None { + color: var(--color-dimmer); + font-style: italic; +} diff --git a/src/devtools/views/KeyValue.js b/src/devtools/views/KeyValue.js new file mode 100644 index 0000000000..f2186ea16d --- /dev/null +++ b/src/devtools/views/KeyValue.js @@ -0,0 +1,121 @@ +// @flow + +import React from 'react'; +import EditableValue from './EditableValue'; +import { getMetaValueLabel } from './utils'; +import { meta } from '../../hydration'; +import styles from './KeyValue.css'; + +type OverrideValueFn = (path: Array, value: any) => void; + +type KeyValueProps = {| + depth: number, + name: string, + nameClassName?: string, + overrideValueFn?: ?OverrideValueFn, + path?: Array, + value: any, +|}; + +export default function KeyValue({ + depth, + name, + nameClassName = styles.Name, + overrideValueFn, + path = [], + value, +}: KeyValueProps) { + const dataType = typeof value; + const isSimpleType = + dataType === 'number' || + dataType === 'string' || + dataType === 'boolean' || + value == null; + + const paddingLeft = `${depth * 0.75}rem`; + + let children = null; + if (isSimpleType) { + let displayValue = value; + if (dataType === 'string') { + displayValue = `"${value}"`; + } else if (dataType === 'boolean') { + displayValue = value ? 'true' : 'false'; + } else if (value === null) { + displayValue = 'null'; + } else if (value === undefined) { + displayValue = 'undefined'; + } + + children = ( +
+ {name} + {typeof overrideValueFn === 'function' ? ( + + ) : ( + {displayValue} + )} +
+ ); + } else if (value.hasOwnProperty(meta.type)) { + // TODO Is this type even necessary? Can we just drop it? + children = ( +
+ {name} + {getMetaValueLabel(value)} +
+ ); + } else { + if (Array.isArray(value)) { + children = value.map((innerValue, index) => ( + + )); + children.unshift( +
+ {name} + Array +
+ ); + } else { + // $FlowFixMe "Missing type annotation for U" whatever that means + children = Object.entries(value).map(([name, value]) => ( + + )); + children.unshift( +
+ {name} + Object +
+ ); + } + } + + return children; +}