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 = {
|
export type UIState = {
|
||||||
viewMode: Atom<ViewMode>;
|
viewMode: Atom<ViewMode>;
|
||||||
|
wireFrameMode: Atom<WireFrameMode>;
|
||||||
isConnected: Atom<boolean>;
|
isConnected: Atom<boolean>;
|
||||||
isPaused: Atom<boolean>;
|
isPaused: Atom<boolean>;
|
||||||
streamState: Atom<StreamState>;
|
streamState: Atom<StreamState>;
|
||||||
@@ -47,6 +48,8 @@ type TransformToReadOnly<T> = {
|
|||||||
[P in keyof T]: T[P] extends Atom<infer U> ? _ReadOnlyAtom<U> : T[P];
|
[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 ReadOnlyUIState = TransformToReadOnly<UIState>;
|
||||||
|
|
||||||
export type StreamFlowState = {paused: boolean};
|
export type StreamFlowState = {paused: boolean};
|
||||||
@@ -91,6 +94,7 @@ export type UIActions = {
|
|||||||
) => void;
|
) => void;
|
||||||
onPlayPauseToggled: () => void;
|
onPlayPauseToggled: () => void;
|
||||||
onSearchTermUpdated: (searchTerm: string) => void;
|
onSearchTermUpdated: (searchTerm: string) => void;
|
||||||
|
onSetWireFrameMode: (WireFrameMode: WireFrameMode) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SelectionSource = 'visualiser' | 'tree' | 'keyboard';
|
export type SelectionSource = 'visualiser' | 'tree' | 'keyboard';
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import React, {useEffect, useMemo, useRef, useState} from 'react';
|
import React, {useEffect, useMemo, useRef, useState} from 'react';
|
||||||
import {Bounds, Coordinate, Id, ClientNode} from '../../ClientTypes';
|
import {Bounds, Coordinate, Id, ClientNode} from '../../ClientTypes';
|
||||||
import {NestedNode, OnSelectNode} from '../../DesktopTypes';
|
import {NestedNode, OnSelectNode, WireFrameMode} from '../../DesktopTypes';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
produce,
|
produce,
|
||||||
@@ -42,6 +42,7 @@ export const Visualization2D: React.FC<
|
|||||||
const selectedNodeId = useValue(instance.uiState.selectedNode);
|
const selectedNodeId = useValue(instance.uiState.selectedNode);
|
||||||
const hoveredNodes = useValue(instance.uiState.hoveredNodes);
|
const hoveredNodes = useValue(instance.uiState.hoveredNodes);
|
||||||
const hoveredNodeId = head(hoveredNodes);
|
const hoveredNodeId = head(hoveredNodes);
|
||||||
|
const wireFrameMode = useValue(instance.uiState.wireFrameMode);
|
||||||
|
|
||||||
const [targetMode, setTargetMode] = useState<TargetModeState>({
|
const [targetMode, setTargetMode] = useState<TargetModeState>({
|
||||||
state: 'disabled',
|
state: 'disabled',
|
||||||
@@ -141,6 +142,8 @@ export const Visualization2D: React.FC<
|
|||||||
return (
|
return (
|
||||||
<Layout.Container>
|
<Layout.Container>
|
||||||
<VisualiserControls
|
<VisualiserControls
|
||||||
|
onSetWireFrameMode={instance.uiActions.onSetWireFrameMode}
|
||||||
|
wireFrameMode={wireFrameMode}
|
||||||
focusedNode={focusedNodeId}
|
focusedNode={focusedNodeId}
|
||||||
selectedNode={selectedNodeId?.id}
|
selectedNode={selectedNodeId?.id}
|
||||||
setTargetMode={setTargetMode}
|
setTargetMode={setTargetMode}
|
||||||
@@ -226,6 +229,9 @@ export const Visualization2D: React.FC<
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<MemoedVisualizationNode2D
|
<MemoedVisualizationNode2D
|
||||||
|
wireframeMode={wireFrameMode}
|
||||||
|
isSelectedOrChildOrSelected={false}
|
||||||
|
selectedNode={selectedNodeId?.id}
|
||||||
node={focusState.focusedRoot}
|
node={focusState.focusedRoot}
|
||||||
onSelectNode={onSelectNode}
|
onSelectNode={onSelectNode}
|
||||||
/>
|
/>
|
||||||
@@ -238,19 +244,30 @@ export const Visualization2D: React.FC<
|
|||||||
const MemoedVisualizationNode2D = React.memo(
|
const MemoedVisualizationNode2D = React.memo(
|
||||||
Visualization2DNode,
|
Visualization2DNode,
|
||||||
(prev, next) => {
|
(prev, next) => {
|
||||||
return prev.node === next.node;
|
return (
|
||||||
|
prev.node === next.node &&
|
||||||
|
prev.selectedNode === next.selectedNode &&
|
||||||
|
prev.wireframeMode === next.wireframeMode
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
function Visualization2DNode({
|
function Visualization2DNode({
|
||||||
|
wireframeMode,
|
||||||
|
isSelectedOrChildOrSelected,
|
||||||
|
selectedNode,
|
||||||
node,
|
node,
|
||||||
onSelectNode,
|
onSelectNode,
|
||||||
}: {
|
}: {
|
||||||
|
wireframeMode: WireFrameMode;
|
||||||
|
isSelectedOrChildOrSelected: boolean;
|
||||||
|
selectedNode?: Id;
|
||||||
node: NestedNode;
|
node: NestedNode;
|
||||||
onSelectNode: OnSelectNode;
|
onSelectNode: OnSelectNode;
|
||||||
}) {
|
}) {
|
||||||
const instance = usePlugin(plugin);
|
const instance = usePlugin(plugin);
|
||||||
|
|
||||||
|
const isSelected = node.id === selectedNode;
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
let nestedChildren: NestedNode[];
|
let nestedChildren: NestedNode[];
|
||||||
|
|
||||||
@@ -268,6 +285,9 @@ function Visualization2DNode({
|
|||||||
|
|
||||||
const children = nestedChildren.map((child) => (
|
const children = nestedChildren.map((child) => (
|
||||||
<MemoedVisualizationNode2D
|
<MemoedVisualizationNode2D
|
||||||
|
wireframeMode={wireframeMode}
|
||||||
|
selectedNode={selectedNode}
|
||||||
|
isSelectedOrChildOrSelected={isSelected || isSelectedOrChildOrSelected}
|
||||||
key={child.id}
|
key={child.id}
|
||||||
node={child}
|
node={child}
|
||||||
onSelectNode={onSelectNode}
|
onSelectNode={onSelectNode}
|
||||||
@@ -278,6 +298,11 @@ function Visualization2DNode({
|
|||||||
node.id,
|
node.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const showBorder =
|
||||||
|
wireframeMode === 'All' ||
|
||||||
|
(wireframeMode === 'SelectedAndChildren' && isSelectedOrChildOrSelected) ||
|
||||||
|
(wireframeMode === 'SelectedOnly' && isSelected);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
role="button"
|
role="button"
|
||||||
@@ -293,7 +318,7 @@ function Visualization2DNode({
|
|||||||
opacity: isHighlighted ? 0.3 : 1,
|
opacity: isHighlighted ? 0.3 : 1,
|
||||||
backgroundColor: isHighlighted ? 'red' : 'transparent',
|
backgroundColor: isHighlighted ? 'red' : 'transparent',
|
||||||
}}>
|
}}>
|
||||||
<NodeBorder />
|
{showBorder && <NodeBorder />}
|
||||||
|
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* @format
|
* @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 {Layout, produce, theme, usePlugin} from 'flipper-plugin';
|
||||||
import {Id} from '../../ClientTypes';
|
import {Id} from '../../ClientTypes';
|
||||||
import {plugin} from '../../index';
|
import {plugin} from '../../index';
|
||||||
@@ -16,10 +16,11 @@ import {
|
|||||||
AimOutlined,
|
AimOutlined,
|
||||||
FullscreenExitOutlined,
|
FullscreenExitOutlined,
|
||||||
FullscreenOutlined,
|
FullscreenOutlined,
|
||||||
|
PicCenterOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {tracker} from '../../utils/tracker';
|
import {tracker} from '../../utils/tracker';
|
||||||
import {debounce} from 'lodash';
|
import {debounce} from 'lodash';
|
||||||
|
import {WireFrameMode} from '../../DesktopTypes';
|
||||||
export type TargetModeState =
|
export type TargetModeState =
|
||||||
| {
|
| {
|
||||||
state: 'selected';
|
state: 'selected';
|
||||||
@@ -38,7 +39,11 @@ export function VisualiserControls({
|
|||||||
setTargetMode,
|
setTargetMode,
|
||||||
selectedNode,
|
selectedNode,
|
||||||
focusedNode,
|
focusedNode,
|
||||||
|
wireFrameMode,
|
||||||
|
onSetWireFrameMode,
|
||||||
}: {
|
}: {
|
||||||
|
wireFrameMode: WireFrameMode;
|
||||||
|
onSetWireFrameMode: (mode: WireFrameMode) => void;
|
||||||
selectedNode?: Id;
|
selectedNode?: Id;
|
||||||
focusedNode?: Id;
|
focusedNode?: Id;
|
||||||
setTargetMode: (targetMode: TargetModeState) => void;
|
setTargetMode: (targetMode: TargetModeState) => void;
|
||||||
@@ -54,7 +59,7 @@ export function VisualiserControls({
|
|||||||
: 'Remove focus';
|
: 'Remove focus';
|
||||||
|
|
||||||
const targetToolTip =
|
const targetToolTip =
|
||||||
targetMode.state === 'disabled' ? 'TargetMode' : 'Exit target mode';
|
targetMode.state === 'disabled' ? 'Target Mode' : 'Exit target mode';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout.Right style={{padding: theme.space.medium}} gap="medium" center>
|
<Layout.Right style={{padding: theme.space.medium}} gap="medium" center>
|
||||||
@@ -81,13 +86,43 @@ export function VisualiserControls({
|
|||||||
targetMode.targetedNodes[value],
|
targetMode.targetedNodes[value],
|
||||||
'visualiser',
|
'visualiser',
|
||||||
);
|
);
|
||||||
|
|
||||||
debouncedReportTargetAdjusted();
|
debouncedReportTargetAdjusted();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Layout.Container>
|
</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}>
|
<Tooltip title={targetToolTip}>
|
||||||
<Button
|
<Button
|
||||||
shape="circle"
|
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(() => {
|
const debouncedReportTargetAdjusted = debounce(() => {
|
||||||
tracker.track('target-mode-adjusted', {});
|
tracker.track('target-mode-adjusted', {});
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
StreamState,
|
StreamState,
|
||||||
ReadOnlyUIState,
|
ReadOnlyUIState,
|
||||||
LiveClientState,
|
LiveClientState,
|
||||||
|
WireFrameMode,
|
||||||
} from './DesktopTypes';
|
} from './DesktopTypes';
|
||||||
import {getStreamInterceptor} from './fb-stubs/StreamInterceptor';
|
import {getStreamInterceptor} from './fb-stubs/StreamInterceptor';
|
||||||
import {prefetchSourceFileLocation} from './components/fb-stubs/IDEContextMenu';
|
import {prefetchSourceFileLocation} from './components/fb-stubs/IDEContextMenu';
|
||||||
@@ -365,5 +366,6 @@ function createUIState(): UIState {
|
|||||||
searchTerm: createState<string>(''),
|
searchTerm: createState<string>(''),
|
||||||
focusedNode: createState<Id | undefined>(undefined),
|
focusedNode: createState<Id | undefined>(undefined),
|
||||||
expandedNodes: createState<Set<Id>>(new Set()),
|
expandedNodes: createState<Set<Id>>(new Set()),
|
||||||
|
wireFrameMode: createState<WireFrameMode>('All'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export function checkFocusedNodeStillActive(
|
|||||||
nodes: Map<Id, ClientNode>,
|
nodes: Map<Id, ClientNode>,
|
||||||
) {
|
) {
|
||||||
const focusedNodeId = uiState.focusedNode.get();
|
const focusedNodeId = uiState.focusedNode.get();
|
||||||
const focusedNode = focusedNodeId && nodes.get(focusedNodeId);
|
const focusedNode = focusedNodeId != null && nodes.get(focusedNodeId);
|
||||||
if (!focusedNode || !isFocusedNodeAncestryAllActive(focusedNode, nodes)) {
|
if (!focusedNode || !isFocusedNodeAncestryAllActive(focusedNode, nodes)) {
|
||||||
uiState.focusedNode.set(undefined);
|
uiState.focusedNode.set(undefined);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
UIActions,
|
UIActions,
|
||||||
UIState,
|
UIState,
|
||||||
ViewMode,
|
ViewMode,
|
||||||
|
WireFrameMode,
|
||||||
} from '../DesktopTypes';
|
} from '../DesktopTypes';
|
||||||
import {tracker} from '../utils/tracker';
|
import {tracker} from '../utils/tracker';
|
||||||
import {
|
import {
|
||||||
@@ -108,6 +109,10 @@ export function uiActions(
|
|||||||
uiState.viewMode.set(viewMode);
|
uiState.viewMode.set(viewMode);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onSetWireFrameMode = (wireFrameMode: WireFrameMode) => {
|
||||||
|
uiState.wireFrameMode.set(wireFrameMode);
|
||||||
|
};
|
||||||
|
|
||||||
const onSetFrameworkEventMonitored = (
|
const onSetFrameworkEventMonitored = (
|
||||||
eventType: FrameworkEventType,
|
eventType: FrameworkEventType,
|
||||||
monitored: boolean,
|
monitored: boolean,
|
||||||
@@ -158,5 +163,6 @@ export function uiActions(
|
|||||||
onSetFrameworkEventMonitored,
|
onSetFrameworkEventMonitored,
|
||||||
onPlayPauseToggled,
|
onPlayPauseToggled,
|
||||||
onSearchTermUpdated,
|
onSearchTermUpdated,
|
||||||
|
onSetWireFrameMode,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user