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:
committed by
Facebook GitHub Bot
parent
fb469faa1d
commit
fb503a0a2f
@@ -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';
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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'),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user