Add wireframe mode control

Summary:
This allows you to control how the wire frames are drawn, useful when there are lots of overalpping wireframes

Changelog: UIDebugger - Added wireframe mode control, useful when lots of overlapping wireframes

Reviewed By: aigoncharov

Differential Revision: D47949841

fbshipit-source-id: 72de7d085ca433557107ab0cc6e4399220836d9f
This commit is contained in:
Luke De Feo
2023-08-01 10:32:29 -07:00
committed by Facebook GitHub Bot
parent fb469faa1d
commit fb503a0a2f
6 changed files with 105 additions and 8 deletions

View File

@@ -26,6 +26,7 @@ export type LiveClientState = {
export type UIState = {
viewMode: Atom<ViewMode>;
wireFrameMode: Atom<WireFrameMode>;
isConnected: Atom<boolean>;
isPaused: Atom<boolean>;
streamState: Atom<StreamState>;
@@ -47,6 +48,8 @@ type TransformToReadOnly<T> = {
[P in keyof T]: T[P] extends Atom<infer U> ? _ReadOnlyAtom<U> : T[P];
};
export type WireFrameMode = 'All' | 'SelectedAndChildren' | 'SelectedOnly';
export type ReadOnlyUIState = TransformToReadOnly<UIState>;
export type StreamFlowState = {paused: boolean};
@@ -91,6 +94,7 @@ export type UIActions = {
) => void;
onPlayPauseToggled: () => void;
onSearchTermUpdated: (searchTerm: string) => void;
onSetWireFrameMode: (WireFrameMode: WireFrameMode) => void;
};
export type SelectionSource = 'visualiser' | 'tree' | 'keyboard';

View File

@@ -9,7 +9,7 @@
import React, {useEffect, useMemo, useRef, useState} from 'react';
import {Bounds, Coordinate, Id, ClientNode} from '../../ClientTypes';
import {NestedNode, OnSelectNode} from '../../DesktopTypes';
import {NestedNode, OnSelectNode, WireFrameMode} from '../../DesktopTypes';
import {
produce,
@@ -42,6 +42,7 @@ export const Visualization2D: React.FC<
const selectedNodeId = useValue(instance.uiState.selectedNode);
const hoveredNodes = useValue(instance.uiState.hoveredNodes);
const hoveredNodeId = head(hoveredNodes);
const wireFrameMode = useValue(instance.uiState.wireFrameMode);
const [targetMode, setTargetMode] = useState<TargetModeState>({
state: 'disabled',
@@ -141,6 +142,8 @@ export const Visualization2D: React.FC<
return (
<Layout.Container>
<VisualiserControls
onSetWireFrameMode={instance.uiActions.onSetWireFrameMode}
wireFrameMode={wireFrameMode}
focusedNode={focusedNodeId}
selectedNode={selectedNodeId?.id}
setTargetMode={setTargetMode}
@@ -226,6 +229,9 @@ export const Visualization2D: React.FC<
/>
)}
<MemoedVisualizationNode2D
wireframeMode={wireFrameMode}
isSelectedOrChildOrSelected={false}
selectedNode={selectedNodeId?.id}
node={focusState.focusedRoot}
onSelectNode={onSelectNode}
/>
@@ -238,19 +244,30 @@ export const Visualization2D: React.FC<
const MemoedVisualizationNode2D = React.memo(
Visualization2DNode,
(prev, next) => {
return prev.node === next.node;
return (
prev.node === next.node &&
prev.selectedNode === next.selectedNode &&
prev.wireframeMode === next.wireframeMode
);
},
);
function Visualization2DNode({
wireframeMode,
isSelectedOrChildOrSelected,
selectedNode,
node,
onSelectNode,
}: {
wireframeMode: WireFrameMode;
isSelectedOrChildOrSelected: boolean;
selectedNode?: Id;
node: NestedNode;
onSelectNode: OnSelectNode;
}) {
const instance = usePlugin(plugin);
const isSelected = node.id === selectedNode;
const ref = useRef<HTMLDivElement>(null);
let nestedChildren: NestedNode[];
@@ -268,6 +285,9 @@ function Visualization2DNode({
const children = nestedChildren.map((child) => (
<MemoedVisualizationNode2D
wireframeMode={wireframeMode}
selectedNode={selectedNode}
isSelectedOrChildOrSelected={isSelected || isSelectedOrChildOrSelected}
key={child.id}
node={child}
onSelectNode={onSelectNode}
@@ -278,6 +298,11 @@ function Visualization2DNode({
node.id,
);
const showBorder =
wireframeMode === 'All' ||
(wireframeMode === 'SelectedAndChildren' && isSelectedOrChildOrSelected) ||
(wireframeMode === 'SelectedOnly' && isSelected);
return (
<div
role="button"
@@ -293,7 +318,7 @@ function Visualization2DNode({
opacity: isHighlighted ? 0.3 : 1,
backgroundColor: isHighlighted ? 'red' : 'transparent',
}}>
<NodeBorder />
{showBorder && <NodeBorder />}
{children}
</div>

View File

@@ -7,7 +7,7 @@
* @format
*/
import {Button, Slider, Tooltip, Typography} from 'antd';
import {Button, Dropdown, Menu, Slider, Tooltip, Typography} from 'antd';
import {Layout, produce, theme, usePlugin} from 'flipper-plugin';
import {Id} from '../../ClientTypes';
import {plugin} from '../../index';
@@ -16,10 +16,11 @@ import {
AimOutlined,
FullscreenExitOutlined,
FullscreenOutlined,
PicCenterOutlined,
} from '@ant-design/icons';
import {tracker} from '../../utils/tracker';
import {debounce} from 'lodash';
import {WireFrameMode} from '../../DesktopTypes';
export type TargetModeState =
| {
state: 'selected';
@@ -38,7 +39,11 @@ export function VisualiserControls({
setTargetMode,
selectedNode,
focusedNode,
wireFrameMode,
onSetWireFrameMode,
}: {
wireFrameMode: WireFrameMode;
onSetWireFrameMode: (mode: WireFrameMode) => void;
selectedNode?: Id;
focusedNode?: Id;
setTargetMode: (targetMode: TargetModeState) => void;
@@ -81,13 +86,43 @@ export function VisualiserControls({
targetMode.targetedNodes[value],
'visualiser',
);
debouncedReportTargetAdjusted();
}}
/>
)}
</Layout.Container>
<Layout.Horizontal gap="medium">
<Layout.Horizontal gap="medium" center>
<Dropdown
overlay={
<Menu>
<SelectableDropDownItem
onSelect={onSetWireFrameMode}
text="All"
selectedValue={wireFrameMode}
value="All"
/>
<SelectableDropDownItem
onSelect={onSetWireFrameMode}
text="Selected and children"
selectedValue={wireFrameMode}
value="SelectedAndChildren"
/>
<SelectableDropDownItem
onSelect={onSetWireFrameMode}
text="Selected only"
selectedValue={wireFrameMode}
value="SelectedOnly"
/>
</Menu>
}>
<Tooltip title="Wireframe Mode">
<Button shape="circle">
<PicCenterOutlined />
</Button>
</Tooltip>
</Dropdown>
<Tooltip title={targetToolTip}>
<Button
shape="circle"
@@ -145,6 +180,31 @@ export function VisualiserControls({
);
}
function SelectableDropDownItem<T>({
value,
selectedValue,
onSelect,
text,
}: {
value: T;
selectedValue: T;
onSelect: (value: T) => void;
text: string;
}) {
return (
<Menu.Item
style={{
color:
value === selectedValue ? theme.primaryColor : theme.textColorActive,
}}
onClick={() => {
onSelect(value);
}}>
{text}
</Menu.Item>
);
}
const debouncedReportTargetAdjusted = debounce(() => {
tracker.track('target-mode-adjusted', {});
}, 500);

View File

@@ -27,6 +27,7 @@ import {
StreamState,
ReadOnlyUIState,
LiveClientState,
WireFrameMode,
} from './DesktopTypes';
import {getStreamInterceptor} from './fb-stubs/StreamInterceptor';
import {prefetchSourceFileLocation} from './components/fb-stubs/IDEContextMenu';
@@ -365,5 +366,6 @@ function createUIState(): UIState {
searchTerm: createState<string>(''),
focusedNode: createState<Id | undefined>(undefined),
expandedNodes: createState<Set<Id>>(new Set()),
wireFrameMode: createState<WireFrameMode>('All'),
};
}

View File

@@ -30,7 +30,7 @@ export function checkFocusedNodeStillActive(
nodes: Map<Id, ClientNode>,
) {
const focusedNodeId = uiState.focusedNode.get();
const focusedNode = focusedNodeId && nodes.get(focusedNodeId);
const focusedNode = focusedNodeId != null && nodes.get(focusedNodeId);
if (!focusedNode || !isFocusedNodeAncestryAllActive(focusedNode, nodes)) {
uiState.focusedNode.set(undefined);
}

View File

@@ -16,6 +16,7 @@ import {
UIActions,
UIState,
ViewMode,
WireFrameMode,
} from '../DesktopTypes';
import {tracker} from '../utils/tracker';
import {
@@ -108,6 +109,10 @@ export function uiActions(
uiState.viewMode.set(viewMode);
};
const onSetWireFrameMode = (wireFrameMode: WireFrameMode) => {
uiState.wireFrameMode.set(wireFrameMode);
};
const onSetFrameworkEventMonitored = (
eventType: FrameworkEventType,
monitored: boolean,
@@ -158,5 +163,6 @@ export function uiActions(
onSetFrameworkEventMonitored,
onPlayPauseToggled,
onSearchTermUpdated,
onSetWireFrameMode,
};
}