From bb3b1cecef4f164babf7961bae657399097a452b Mon Sep 17 00:00:00 2001 From: Lorenzo Blasa Date: Tue, 25 Oct 2022 03:09:00 -0700 Subject: [PATCH] Simple antd types for each inspectable type Summary: Replace draft inspectors with read-only components. This is a first step into having a richer UI. At the moment, these are read-only components but will likely be extended in the future as to allow editing of values. Reviewed By: LukeDefeo Differential Revision: D40345016 fbshipit-source-id: a6aef5861474b4aa8353c00ef257ab17b4cff00e --- .../descriptors/ActivityDescriptor.kt | 6 - .../descriptors/DrawableDescriptor.kt | 2 +- .../FragmentFrameworkDescriptor.kt | 21 +- .../uidebugger/descriptors/ViewDescriptor.kt | 95 +++---- desktop/flipper-plugin/src/ui/theme.tsx | 1 + .../public/ui-debugger/components/main.tsx | 2 +- .../components/sidebar/Inspector.tsx | 5 +- .../sidebar/inspector/AttributesInspector.tsx | 237 ++++++++++++++---- .../sidebar/inspector/BoundsInspector.tsx | 225 +++++++++++++++++ .../sidebar/inspector/ColorInspector.tsx | 70 ++++++ .../inspector/Coordinate3DInspector.tsx | 68 +++++ .../sidebar/inspector/CoordinateInspector.tsx | 57 +++++ .../inspector/DefaultInspectorContainer.tsx | 35 +++ .../sidebar/inspector/IdentityInspector.tsx | 19 +- .../sidebar/inspector/LayoutInspector.tsx | 19 -- .../sidebar/inspector/SizeInspector.tsx | 57 +++++ .../sidebar/inspector/SpaceBoxInspector.tsx | 202 +++++++++++++++ .../sidebar/utilities/displayableName.tsx | 6 + .../plugins/public/ui-debugger/package.json | 15 +- desktop/plugins/public/ui-debugger/types.tsx | 54 +++- desktop/plugins/public/yarn.lock | 59 ++++- 21 files changed, 1106 insertions(+), 149 deletions(-) create mode 100644 desktop/plugins/public/ui-debugger/components/sidebar/inspector/BoundsInspector.tsx create mode 100644 desktop/plugins/public/ui-debugger/components/sidebar/inspector/ColorInspector.tsx create mode 100644 desktop/plugins/public/ui-debugger/components/sidebar/inspector/Coordinate3DInspector.tsx create mode 100644 desktop/plugins/public/ui-debugger/components/sidebar/inspector/CoordinateInspector.tsx create mode 100644 desktop/plugins/public/ui-debugger/components/sidebar/inspector/DefaultInspectorContainer.tsx delete mode 100644 desktop/plugins/public/ui-debugger/components/sidebar/inspector/LayoutInspector.tsx create mode 100644 desktop/plugins/public/ui-debugger/components/sidebar/inspector/SizeInspector.tsx create mode 100644 desktop/plugins/public/ui-debugger/components/sidebar/inspector/SpaceBoxInspector.tsx diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/ActivityDescriptor.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/ActivityDescriptor.kt index 81c745b65..51c5ee847 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/ActivityDescriptor.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/ActivityDescriptor.kt @@ -9,7 +9,6 @@ package com.facebook.flipper.plugins.uidebugger.descriptors import android.app.Activity import com.facebook.flipper.plugins.uidebugger.core.FragmentTracker -import com.facebook.flipper.plugins.uidebugger.model.InspectableObject object ActivityDescriptor : ChainedDescriptor() { @@ -27,9 +26,4 @@ object ActivityDescriptor : ChainedDescriptor() { return children } - - override fun onGetData( - node: Activity, - attributeSections: MutableMap - ) {} } diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/DrawableDescriptor.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/DrawableDescriptor.kt index 6d920482a..62668c2a2 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/DrawableDescriptor.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/DrawableDescriptor.kt @@ -26,7 +26,7 @@ object DrawableDescriptor : ChainedDescriptor() { props["alpha"] = InspectableValue.Number(node.alpha, true) val bounds = node.bounds - props["bounds"] = InspectableValue.SpaceBox(SpaceBox.fromRect(bounds)) + props["bounds"] = InspectableValue.Bounds(Bounds.fromRect(bounds)) attributeSections["Drawable"] = InspectableObject(props.toMap()) } diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/FragmentFrameworkDescriptor.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/FragmentFrameworkDescriptor.kt index e8beb0a42..6df1d55fa 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/FragmentFrameworkDescriptor.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/FragmentFrameworkDescriptor.kt @@ -7,7 +7,6 @@ package com.facebook.flipper.plugins.uidebugger.descriptors -import android.os.Build import android.os.Bundle import com.facebook.flipper.plugins.uidebugger.model.Inspectable import com.facebook.flipper.plugins.uidebugger.model.InspectableObject @@ -26,19 +25,17 @@ object FragmentFrameworkDescriptor : ChainedDescriptor() { node: android.app.Fragment, attributeSections: MutableMap ) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - val args: Bundle = node.arguments + val args: Bundle = node.arguments - val props = mutableMapOf() - for (key in args.keySet()) { - when (val value = args[key]) { - is Number -> props[key] = InspectableValue.Number(value) - is Boolean -> props[key] = InspectableValue.Boolean(value) - is String -> props[key] = InspectableValue.Text(value) - } + val props = mutableMapOf() + for (key in args.keySet()) { + when (val value = args[key]) { + is Number -> props[key] = InspectableValue.Number(value) + is Boolean -> props[key] = InspectableValue.Boolean(value) + is String -> props[key] = InspectableValue.Text(value) } - - attributeSections["Fragment"] = InspectableObject(props.toMap()) } + + attributeSections["Fragment"] = InspectableObject(props.toMap()) } } diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/ViewDescriptor.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/ViewDescriptor.kt index 2342a1cfa..0a8567644 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/ViewDescriptor.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/ViewDescriptor.kt @@ -48,60 +48,44 @@ object ViewDescriptor : ChainedDescriptor() { ) { val props = mutableMapOf() - props["size"] = InspectableValue.Size(Size(node.width, node.height), mutable = true) - props["alpha"] = InspectableValue.Number(node.alpha, mutable = true) - props["visibility"] = VisibilityMapping.toInspectable(node.visibility, mutable = false) - - fromDrawable(node.background)?.let { background -> props["background"] = background } - - node.tag - ?.let { InspectableValue.fromAny(it, mutable = false) } - ?.let { tag -> props.put("tag", tag) } - - props["keyedTags"] = InspectableObject(getViewTags(node)) - props["layoutParams"] = getLayoutParams(node) - props["state"] = - InspectableObject( - mapOf( - "enabled" to InspectableValue.Boolean(node.isEnabled, mutable = false), - "activated" to InspectableValue.Boolean(node.isActivated, mutable = false), - "focused" to InspectableValue.Boolean(node.isFocused, mutable = false), - "selected" to InspectableValue.Boolean(node.isSelected, mutable = false))) - - props["bounds"] = - InspectableValue.SpaceBox(SpaceBox(node.top, node.right, node.bottom, node.left)) - props["padding"] = - InspectableValue.SpaceBox( - SpaceBox(node.paddingTop, node.paddingRight, node.paddingBottom, node.paddingLeft)) - props["rotation"] = - InspectableValue.Coordinate3D(Coordinate3D(node.rotationX, node.rotationY, node.rotation)) - props["scale"] = InspectableValue.Coordinate(Coordinate(node.scaleX, node.scaleY)) - props["pivot"] = InspectableValue.Coordinate(Coordinate(node.pivotX, node.pivotY)) val positionOnScreen = IntArray(2) node.getLocationOnScreen(positionOnScreen) - props["globalPosition"] = - InspectableValue.Coordinate(Coordinate(positionOnScreen[0], positionOnScreen[1])) - val localVisible = Rect() node.getLocalVisibleRect(localVisible) - props["localVisible"] = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { + props["position"] = InspectableValue.Coordinate3D(Coordinate3D(node.x, node.y, node.z)) + } else { + props["position"] = InspectableValue.Coordinate(Coordinate(node.x, node.y)) + } + + props["globalPosition"] = + InspectableValue.Coordinate(Coordinate(positionOnScreen[0], positionOnScreen[1])) + + props["size"] = InspectableValue.Size(Size(node.width, node.height), mutable = true) + + props["bounds"] = InspectableValue.Bounds(Bounds(node.left, node.top, node.right, node.bottom)) + props["padding"] = + InspectableValue.SpaceBox( + SpaceBox(node.paddingTop, node.paddingRight, node.paddingBottom, node.paddingLeft)) + + props["localVisibleRect"] = InspectableObject( mapOf( "position" to InspectableValue.Coordinate(Coordinate(localVisible.left, node.top)), "size" to InspectableValue.Size(Size(node.width, node.height))), ) + props["rotation"] = + InspectableValue.Coordinate3D(Coordinate3D(node.rotationX, node.rotationY, node.rotation)) + props["scale"] = InspectableValue.Coordinate(Coordinate(node.scaleX, node.scaleY)) + props["pivot"] = InspectableValue.Coordinate(Coordinate(node.pivotX, node.pivotY)) + + props["layoutParams"] = getLayoutParams(node) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { props["layoutDirection"] = LayoutDirectionMapping.toInspectable(node.layoutDirection, false) - props["textDirection"] = TextDirectionMapping.toInspectable(node.textDirection, false) - props["textAlignment"] = TextAlignmentMapping.toInspectable(node.textAlignment, false) - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - props["elevation"] = InspectableValue.Number(node.elevation) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { @@ -113,16 +97,40 @@ object ViewDescriptor : ChainedDescriptor() { InspectableValue.Coordinate(Coordinate(node.translationX, node.translationY)) } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { - props["position"] = InspectableValue.Coordinate3D(Coordinate3D(node.x, node.y, node.z)) - } else { - props["position"] = InspectableValue.Coordinate(Coordinate(node.x, node.y)) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + props["elevation"] = InspectableValue.Number(node.elevation) } + props["visibility"] = VisibilityMapping.toInspectable(node.visibility, mutable = false) + + fromDrawable(node.background)?.let { background -> props["background"] = background } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { fromDrawable(node.foreground)?.let { foreground -> props["foreground"] = foreground } } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + props["alpha"] = InspectableValue.Number(node.alpha, mutable = true) + } + + props["state"] = + InspectableObject( + mapOf( + "enabled" to InspectableValue.Boolean(node.isEnabled, mutable = false), + "activated" to InspectableValue.Boolean(node.isActivated, mutable = false), + "focused" to InspectableValue.Boolean(node.isFocused, mutable = false), + "selected" to InspectableValue.Boolean(node.isSelected, mutable = false))) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + props["textDirection"] = TextDirectionMapping.toInspectable(node.textDirection, false) + props["textAlignment"] = TextAlignmentMapping.toInspectable(node.textAlignment, false) + } + + node.tag + ?.let { InspectableValue.fromAny(it, mutable = false) } + ?.let { tag -> props.put("tag", tag) } + + props["keyedTags"] = InspectableObject(getViewTags(node)) + attributeSections["View"] = InspectableObject(props.toMap()) } @@ -297,6 +305,7 @@ object ViewDescriptor : ChainedDescriptor() { object : EnumMapping( mapOf( + "NONE" to -1, "NO_GRAVITY" to Gravity.NO_GRAVITY, "LEFT" to Gravity.LEFT, "TOP" to Gravity.TOP, diff --git a/desktop/flipper-plugin/src/ui/theme.tsx b/desktop/flipper-plugin/src/ui/theme.tsx index 2bde12e6d..4bde7757e 100644 --- a/desktop/flipper-plugin/src/ui/theme.tsx +++ b/desktop/flipper-plugin/src/ui/theme.tsx @@ -50,6 +50,7 @@ export const theme = { large: '16px', default: '14px', small: '12px', + smaller: '10px', } as const, monospace: { fontFamily: 'SF Mono,Monaco,Andale Mono,monospace', diff --git a/desktop/plugins/public/ui-debugger/components/main.tsx b/desktop/plugins/public/ui-debugger/components/main.tsx index 6c87cdd10..265363fea 100644 --- a/desktop/plugins/public/ui-debugger/components/main.tsx +++ b/desktop/plugins/public/ui-debugger/components/main.tsx @@ -37,7 +37,7 @@ export function Component() { return; } return ( - + ); diff --git a/desktop/plugins/public/ui-debugger/components/sidebar/Inspector.tsx b/desktop/plugins/public/ui-debugger/components/sidebar/Inspector.tsx index 03c505011..b7bdbbac5 100644 --- a/desktop/plugins/public/ui-debugger/components/sidebar/Inspector.tsx +++ b/desktop/plugins/public/ui-debugger/components/sidebar/Inspector.tsx @@ -15,7 +15,6 @@ import {UINode} from '../../types'; import {IdentityInspector} from './inspector/IdentityInspector'; import {AttributesInspector} from './inspector/AttributesInspector'; import {DocumentationInspector} from './inspector/DocumentationInspector'; -import {LayoutInspector} from './inspector/LayoutInspector'; type Props = { node: UINode; @@ -39,7 +38,7 @@ export const Inspector: React.FC = ({node}) => { }> - + = ({node}) => { }> - + = ({ - name, - value, -}) => { - return ( -
- {name}: {value} -
- ); -}; +const ObjectContainer = styled.div({ + borderLeftWidth: 5, + borderLeftColor: 'lightgray', + borderLeftStyle: 'solid', +}); -const NumberAttributeInspector: React.FC<{name: string; value: number}> = ({ - name, - value, -}) => { - return ( -
- {name}: {value} -
- ); +const CenterContainer = styled.div({ + margin: 'auto', +}); +type NamedAttributeInspectorProps = { + name: string; }; - -const ColorAttributeInspector: React.FC<{name: string; value: Color}> = ({ +const NamedAttributeInspector: React.FC = ({ name, - value, + children, }) => { return ( -
- {name}: {JSON.stringify(value)} -
+ + + {name} + + + {children} + + ); }; const ObjectAttributeInspector: React.FC<{ name: string; value: Record; -}> = ({name, value}) => { + level: number; +}> = ({name, value, level}) => { return ( -
- {name}: {JSON.stringify(value)} +
+ {name} + {Object.keys(value).map(function (key, _) { + return ( + + {create(key, value[key], level + 2)} + + ); + })}
); }; -function create(key: string, inspectable: Inspectable) { +function create(key: string, inspectable: Inspectable, level: number = 2) { switch (inspectable.type) { + case 'boolean': + return ( + + + + ); + case 'enum': + return ( + + {inspectable.value.value} + + ); case 'text': - return ; + return ( + + {inspectable.value} + + ); case 'number': - return ; + return ( + + {inspectable.value} + + ); case 'color': - return ; + return ( + + + + ); + case 'size': + return ( + + + + ); + case 'bounds': + return ( + + + + ); + case 'coordinate': + return ( + + + + ); + case 'coordinate3d': + return ( + + + + ); + case 'space': + return ( + + + + ); case 'object': - return ; + return ( + + ); default: - return; + return ( + + {JSON.stringify(inspectable)} + + ); } } -function createSection(name: string, inspectable: InspectableObject) { +/** + * Filter out those inspectables that affect sizing, positioning, and + * overall layout of elements. + */ +const layoutFilter = new Set([ + 'size', + 'padding', + 'margin', + 'bounds', + 'position', + 'globalPosition', + 'localVisibleRect', + 'rotation', + 'scale', + 'pivot', + 'layoutParams', + 'layoutDirection', + 'translation', + 'elevation', +]); +function createSection( + mode: InspectorMode, + name: string, + inspectable: InspectableObject, +) { + const fields = Object.keys(inspectable.fields).filter( + (key) => + (mode === 'attributes' && !layoutFilter.has(key)) || + (mode === 'layout' && layoutFilter.has(key)), + ); + if (!fields || fields.length === 0) { + return; + } return ( - {' '} - {Object.keys(inspectable.fields).map(function (key, _) { + {fields.map(function (key, _) { return create(key, inspectable.fields[key]); })} ); } -export const AttributesInspector: React.FC = ({node}) => { - // TODO: add raw panel to inspect data as received. +type InspectorMode = 'layout' | 'attributes'; +type Props = { + node: UINode; + mode: InspectorMode; + rawDisplayEnabled?: boolean; +}; +export const AttributesInspector: React.FC = ({ + node, + mode, + rawDisplayEnabled = false, +}) => { return ( <> {Object.keys(node.attributes).map(function (key, _) { - return createSection(key, node.attributes[key] as InspectableObject); + return createSection( + mode, + key, + node.attributes[key] as InspectableObject, + ); })} + {rawDisplayEnabled ?? ( + + + + )} ); }; diff --git a/desktop/plugins/public/ui-debugger/components/sidebar/inspector/BoundsInspector.tsx b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/BoundsInspector.tsx new file mode 100644 index 000000000..ca4f177d9 --- /dev/null +++ b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/BoundsInspector.tsx @@ -0,0 +1,225 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import React from 'react'; +import {Bounds} from '../../../types'; + +type Props = { + size?: number; + strokeColor?: string; + outerBoxColor?: string; + innerBoxColor?: string; + multiplier?: number; + margin?: number; + separator?: number; + value: Bounds; +}; + +const BoundsInspector: React.FC = ({ + size = 180, + strokeColor = '#4A5967', + outerBoxColor = '#F2F3F7', + innerBoxColor = '#CCD1D9', + multiplier = 0.4, + margin = 4, + separator = 10, + value, +}) => { + const scale = + Math.min(size / (value.width + value.x), size / (value.height + value.y)) * + multiplier; + + const width = value.width * scale; + const height = value.height * scale; + + const origin = size / 2; + const originX = origin - width / 2; + const originY = origin - height / 2; + + const midX = originX + width / 2; + const midY = originY + height / 2; + + const lineStyle = {stroke: strokeColor, strokeWidth: '2'}; + + return ( + + {' '} + {/** outer-box */} + {' '} + {/** bounded-box */} + {/** left */} + {/** top */} + {' '} + {/** left-bottom */} + {' '} + {/** right-top */} + {' '} + {/** right-bottom */} + + {value.x} + + {/** x */} + + {/** left */} + + {/** bezel */} + + {/** bezel */} + + {value.width} + + {/** width */} + + {/** bottom */} + + {/** bezel */} + + {/** bezel */} + + {value.y} + + {/** y */} + + {/** top */} + + {/** bezel */} + + {/** bezel */} + + {value.height} + + {/** height */} + + {/** right */} + + {/** bezel */} + + {/** bezel */} + + ); +}; + +export default BoundsInspector; diff --git a/desktop/plugins/public/ui-debugger/components/sidebar/inspector/ColorInspector.tsx b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/ColorInspector.tsx new file mode 100644 index 000000000..62c5d1b17 --- /dev/null +++ b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/ColorInspector.tsx @@ -0,0 +1,70 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import React from 'react'; +import {Popover} from 'antd'; +import {Color} from '../../../types'; +import {SketchPicker, RGBColor, ColorResult} from 'react-color'; +import {styled} from 'flipper-plugin'; + +type State = { + color: RGBColor; +}; + +const OuterColorButton = styled.div({ + padding: '5px', + backgroundColor: '#fff', + borderRadius: '5px', + boxShadow: '0 0 0 1px rgba(0,0,0,.1)', + display: 'inline-block', + cursor: 'pointer', +}); + +const InnerColorButton = styled.div({ + width: '36px', + height: '14px', + borderRadius: '2px', +}); + +class ColorInspector extends React.Component<{color: Color}> { + state: State = { + color: this.props.color ?? { + r: 255, + g: 255, + b: 255, + a: 1, + }, + }; + + handleChange = (_color: ColorResult) => { + // No color changes to be applied at this stage. + // this.setState({color: color.rgb}); + }; + + render() { + return ( + + } + trigger="click"> + + + + + ); + } +} + +export default ColorInspector; diff --git a/desktop/plugins/public/ui-debugger/components/sidebar/inspector/Coordinate3DInspector.tsx b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/Coordinate3DInspector.tsx new file mode 100644 index 000000000..e53d460a3 --- /dev/null +++ b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/Coordinate3DInspector.tsx @@ -0,0 +1,68 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import React from 'react'; +import {Coordinate3D} from '../../../types'; +import {Col, Row} from 'antd'; +import {theme} from 'flipper-plugin'; + +type Props = { + value: Coordinate3D; +}; + +const Coordinate3DInspector: React.FC = ({value}) => { + return ( + <> + + + x + + + y + + + z + + + + + {value.x} + + + {value.y} + + + {value.z} + + + + ); +}; + +export default Coordinate3DInspector; diff --git a/desktop/plugins/public/ui-debugger/components/sidebar/inspector/CoordinateInspector.tsx b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/CoordinateInspector.tsx new file mode 100644 index 000000000..3b69faf9f --- /dev/null +++ b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/CoordinateInspector.tsx @@ -0,0 +1,57 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import React from 'react'; +import {Coordinate} from '../../../types'; +import {Col, Row} from 'antd'; +import {theme} from 'flipper-plugin'; + +type Props = { + value: Coordinate; +}; + +const CoordinateInspector: React.FC = ({value}) => { + return ( + <> + + + x + + + y + + + + + {value.x} + + + {value.y} + + + + ); +}; + +export default CoordinateInspector; diff --git a/desktop/plugins/public/ui-debugger/components/sidebar/inspector/DefaultInspectorContainer.tsx b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/DefaultInspectorContainer.tsx new file mode 100644 index 000000000..53c2fc13a --- /dev/null +++ b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/DefaultInspectorContainer.tsx @@ -0,0 +1,35 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import React from 'react'; +import {Col, Row} from 'antd'; +import {styled, theme} from 'flipper-plugin'; + +type Props = { + name: string; +}; + +export const DefaultInputContainer = styled.div({ + margin: 'auto', + padding: '2px', + minWidth: '50px', + backgroundColor: theme.backgroundDefault, + borderRadius: '5px', + boxShadow: '0 0 0 1px rgba(0,0,0,.2)', + display: 'inline-block', +}); + +export const DefaultInspectorContainer: React.FC = (props) => { + return ( + + {props.name} + {props.children} + + ); +}; diff --git a/desktop/plugins/public/ui-debugger/components/sidebar/inspector/IdentityInspector.tsx b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/IdentityInspector.tsx index e09b5633b..91a8ea4b9 100644 --- a/desktop/plugins/public/ui-debugger/components/sidebar/inspector/IdentityInspector.tsx +++ b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/IdentityInspector.tsx @@ -10,26 +10,31 @@ import React from 'react'; import {Col, Row} from 'antd'; import {UINode} from '../../../types'; +import {styled} from 'flipper-plugin'; type Props = { node: UINode; }; +const IdentityContainer = styled.div({ + marginTop: '10px', +}); + export const IdentityInspector: React.FC = ({node}) => { return ( - <> - - + + +
Name:
- {node.name} + {node.name}
- +
Id:
- {node.id} + {node.id}
- +
); }; diff --git a/desktop/plugins/public/ui-debugger/components/sidebar/inspector/LayoutInspector.tsx b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/LayoutInspector.tsx deleted file mode 100644 index 0044bf9ae..000000000 --- a/desktop/plugins/public/ui-debugger/components/sidebar/inspector/LayoutInspector.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import React from 'react'; -import {UINode} from '../../../types'; - -type Props = { - node: UINode; -}; - -export const LayoutInspector: React.FC = () => { - return

Origin and size

; -}; diff --git a/desktop/plugins/public/ui-debugger/components/sidebar/inspector/SizeInspector.tsx b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/SizeInspector.tsx new file mode 100644 index 000000000..7fb09036b --- /dev/null +++ b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/SizeInspector.tsx @@ -0,0 +1,57 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import React from 'react'; +import {Size} from '../../../types'; +import {Col, Row} from 'antd'; +import {theme} from 'flipper-plugin'; + +type Props = { + value: Size; +}; + +const SizeInspector: React.FC = ({value}) => { + return ( + <> + + + width + + + height + + + + + {value.width} + + + {value.height} + + + + ); +}; + +export default SizeInspector; diff --git a/desktop/plugins/public/ui-debugger/components/sidebar/inspector/SpaceBoxInspector.tsx b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/SpaceBoxInspector.tsx new file mode 100644 index 000000000..177e66def --- /dev/null +++ b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/SpaceBoxInspector.tsx @@ -0,0 +1,202 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import React from 'react'; +import {SpaceBox} from '../../../types'; + +type Props = { + size?: number; + strokeColor?: string; + outerBoxColor?: string; + innerBoxColor?: string; + margin?: number; + separator?: number; + value: SpaceBox; +}; + +const SpaceBoxInspector: React.FC = ({ + size = 180, + strokeColor = '#4A5967', + outerBoxColor = '#F2F3F7', + innerBoxColor = '#CCD1D9', + margin = 10, + separator = 4, + value, +}) => { + const half = size / 2; + const quarter = size / 4; + const radius = 2; + + const lineStyle = {stroke: strokeColor, strokeWidth: '2'}; + return ( + + {' '} + {/** outer-box */} + {' '} + {/** inner-box */} + + {/** left */} + + {/** top */} + + {/** bottom */} + + {/** right */} + {/** left-inner */} + + {/** straight-line */} + + {/** left-separator */} + + {/** right-separator */} + {/** right-inner */} + + {/** straight-line */} + + {/** left-separator */} + + {/** right-separator */} + {/** top-inner */} + + {/** straight-line */} + + {/** left-separator */} + + {/** right-separator */} + {/** bottom-inner */} + + {/** straight-line */} + + {/** left-separator */} + + {/** right-separator */} + + {value.top} + + {/** top */} + + {value.bottom} + + {/** bottom */} + + {value.left} + + {/** left */} + + {value.right} + + {/** right */} + + ); +}; + +export default SpaceBoxInspector; diff --git a/desktop/plugins/public/ui-debugger/components/sidebar/utilities/displayableName.tsx b/desktop/plugins/public/ui-debugger/components/sidebar/utilities/displayableName.tsx index b8be4ef6d..5204dab90 100644 --- a/desktop/plugins/public/ui-debugger/components/sidebar/utilities/displayableName.tsx +++ b/desktop/plugins/public/ui-debugger/components/sidebar/utilities/displayableName.tsx @@ -7,6 +7,12 @@ * @format */ +/** + * Utility function that generates a more human-readable name + * for an attribute in lowerCamelCase format. + * @param attribute Attribute name in the form of lowerCamelCase + * @returns Displayable name for the provided attribute. + */ export function displayableName(attribute: string): string { if (attribute.length > 0) { const displayable = attribute[0].toUpperCase() + attribute.substring(1); diff --git a/desktop/plugins/public/ui-debugger/package.json b/desktop/plugins/public/ui-debugger/package.json index 9ef7a9052..fef2532ac 100644 --- a/desktop/plugins/public/ui-debugger/package.json +++ b/desktop/plugins/public/ui-debugger/package.json @@ -13,20 +13,21 @@ "flipper-plugin" ], "dependencies": { - "react-hotkeys-hook" : "^3.4.7" + "react-color": "^2.19.3", + "react-hotkeys-hook": "^3.4.7" }, "bugs": { "url": "https://github.com/facebook/flipper/issues" }, "peerDependencies": { - "flipper-plugin": "*", - "antd": "*", - "react": "*", - "react-dom": "*", - "@emotion/styled": "*", "@ant-design/icons": "*", + "@emotion/styled": "*", + "@types/node": "*", "@types/react": "*", "@types/react-dom": "*", - "@types/node": "*" + "antd": "*", + "flipper-plugin": "*", + "react": "*", + "react-dom": "*" } } diff --git a/desktop/plugins/public/ui-debugger/types.tsx b/desktop/plugins/public/ui-debugger/types.tsx index 4e8bca042..7d538d99a 100644 --- a/desktop/plugins/public/ui-debugger/types.tsx +++ b/desktop/plugins/public/ui-debugger/types.tsx @@ -51,6 +51,29 @@ export type Bounds = { height: number; }; +export type Size = { + width: number; + height: number; +}; + +export type SpaceBox = { + top: number; + right: number; + bottom: number; + left: number; +}; + +export type Coordinate = { + x: number; + y: number; +}; + +export type Coordinate3D = { + x: number; + y: number; + z: number; +}; + export type Color = { r: number; g: number; @@ -69,7 +92,12 @@ export type Inspectable = | InspectableNumber | InspectableColor | InspectableBoolean - | InspectableEnum; + | InspectableEnum + | InspectableCoordinate + | InspectableCoordinate3D + | InspectableSize + | InspectableBounds + | InspectableSpaceBox; export type InspectableText = { type: 'text'; @@ -107,6 +135,30 @@ export type InspectableBounds = { mutable: boolean; }; +export type InspectableSize = { + type: 'size'; + value: Size; + mutable: boolean; +}; + +export type InspectableCoordinate = { + type: 'coordinate'; + value: Coordinate; + mutable: boolean; +}; + +export type InspectableCoordinate3D = { + type: 'coordinate3d'; + value: Coordinate3D; + mutable: boolean; +}; + +export type InspectableSpaceBox = { + type: 'space'; + value: SpaceBox; + mutable: boolean; +}; + export type InspectableObject = { type: 'object'; fields: Record; diff --git a/desktop/plugins/public/yarn.lock b/desktop/plugins/public/yarn.lock index 06b9cd61d..573cd4398 100644 --- a/desktop/plugins/public/yarn.lock +++ b/desktop/plugins/public/yarn.lock @@ -45,6 +45,11 @@ dependencies: regenerator-runtime "^0.13.4" +"@icons/material@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8" + integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw== + "@jest/types@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" @@ -1297,6 +1302,11 @@ klaw-sync@^6.0.0: dependencies: graceful-fs "^4.1.11" +lodash-es@^4.17.15: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" @@ -1312,16 +1322,16 @@ lodash.throttle@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= +lodash@^4.0.1, lodash@^4.17.15, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + lodash@^4.16.0, lodash@^4.17.19: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== -lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - long@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" @@ -1358,6 +1368,11 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +material-colors@^1.2.1: + version "1.2.6" + resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46" + integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg== + micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -1572,6 +1587,15 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= +prop-types@^15.5.10: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" @@ -1607,6 +1631,19 @@ raf@^3.1.0, raf@^3.4.0: dependencies: performance-now "^2.1.0" +react-color@^2.19.3: + version "2.19.3" + resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.19.3.tgz#ec6c6b4568312a3c6a18420ab0472e146aa5683d" + integrity sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA== + dependencies: + "@icons/material" "^0.2.4" + lodash "^4.17.15" + lodash-es "^4.17.15" + material-colors "^1.2.1" + prop-types "^15.5.10" + reactcss "^1.2.0" + tinycolor2 "^1.4.1" + react-devtools-core@^4.26.1: version "4.26.1" resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.26.1.tgz#2893fea58089be64c5356d5bd0eebda8d1bbf317" @@ -1724,6 +1761,13 @@ react-vis@^1.11.7: prop-types "^15.5.8" react-motion "^0.5.2" +reactcss@^1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd" + integrity sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A== + dependencies: + lodash "^4.0.1" + recharts-scale@^0.4.4: version "0.4.5" resolved "https://registry.yarnpkg.com/recharts-scale/-/recharts-scale-0.4.5.tgz#0969271f14e732e642fcc5bd4ab270d6e87dd1d9" @@ -1993,6 +2037,11 @@ symbol-observable@^1.2.0: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== +tinycolor2@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803" + integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"