Group app wide ui state into one object
Summary: Should be a bit easier to see what UI state we are holding at the plugin instance level Reviewed By: lblasa Differential Revision: D41498272 fbshipit-source-id: 6d88086766efd9c39f71be7e2ce32c5058494c96
This commit is contained in:
committed by
Facebook GitHub Bot
parent
7fc64adfd4
commit
6bb541a33f
@@ -40,17 +40,17 @@ export function Tree(props: {
|
||||
onSelectNode: (id: Id) => void;
|
||||
}) {
|
||||
const instance = usePlugin(plugin);
|
||||
const expandedItems = useValue(instance.treeState).expandedNodes;
|
||||
const focused = useValue(instance.focusedNode);
|
||||
const expandedItems = useValue(instance.uiState.treeState).expandedNodes;
|
||||
const focused = useValue(instance.uiState.focusedNode);
|
||||
|
||||
const items = useMemo(
|
||||
() => toComplexTree(focused || props.rootId, props.nodes),
|
||||
[focused, props.nodes, props.rootId],
|
||||
);
|
||||
const hoveredNodes = useValue(instance.hoveredNodes);
|
||||
const hoveredNodes = useValue(instance.uiState.hoveredNodes);
|
||||
const treeEnvRef = useRef<TreeEnvironmentRef>();
|
||||
|
||||
const searchTerm = useValue(instance.searchTerm);
|
||||
const searchTerm = useValue(instance.uiState.searchTerm);
|
||||
|
||||
useEffect(() => {
|
||||
//this makes the keyboard arrow controls work always, even when using the visualiser
|
||||
@@ -75,15 +75,15 @@ export function Tree(props: {
|
||||
},
|
||||
}}
|
||||
onFocusItem={(item) => {
|
||||
instance.hoveredNodes.set([item.index]);
|
||||
instance.uiState.hoveredNodes.set([item.index]);
|
||||
}}
|
||||
onExpandItem={(item) => {
|
||||
instance.treeState.update((draft) => {
|
||||
instance.uiState.treeState.update((draft) => {
|
||||
draft.expandedNodes.push(item.index);
|
||||
});
|
||||
}}
|
||||
onCollapseItem={(item) =>
|
||||
instance.treeState.update((draft) => {
|
||||
instance.uiState.treeState.update((draft) => {
|
||||
draft.expandedNodes = draft.expandedNodes.filter(
|
||||
(expandedItemIndex) => expandedItemIndex !== item.index,
|
||||
);
|
||||
@@ -109,8 +109,8 @@ export function Tree(props: {
|
||||
},
|
||||
|
||||
onMouseOver: () => {
|
||||
if (!instance.isContextMenuOpen.get()) {
|
||||
instance.hoveredNodes.set([item.index]);
|
||||
if (!instance.uiState.isContextMenuOpen.get()) {
|
||||
instance.uiState.hoveredNodes.set([item.index]);
|
||||
}
|
||||
},
|
||||
}),
|
||||
@@ -200,21 +200,21 @@ type ContextMenuProps = {node: UINode; id: Id; title: string};
|
||||
|
||||
const ContextMenu: React.FC<ContextMenuProps> = ({id, title, children}) => {
|
||||
const instance = usePlugin(plugin);
|
||||
const focusedNode = instance.focusedNode.get();
|
||||
const focusedNode = instance.uiState.focusedNode.get();
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
onVisibleChange={(visible) => {
|
||||
instance.isContextMenuOpen.set(visible);
|
||||
instance.uiState.isContextMenuOpen.set(visible);
|
||||
}}
|
||||
overlay={() => (
|
||||
<Menu>
|
||||
{focusedNode !== head(instance.hoveredNodes.get()) && (
|
||||
{focusedNode !== head(instance.uiState.hoveredNodes.get()) && (
|
||||
<UIDebuggerMenuItem
|
||||
key="focus"
|
||||
text={`Focus ${title}`}
|
||||
onClick={() => {
|
||||
instance.focusedNode.set(id);
|
||||
instance.uiState.focusedNode.set(id);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -224,7 +224,7 @@ const ContextMenu: React.FC<ContextMenuProps> = ({id, title, children}) => {
|
||||
key="remove-focus"
|
||||
text="Remove focus"
|
||||
onClick={() => {
|
||||
instance.focusedNode.set(undefined);
|
||||
instance.uiState.focusedNode.set(undefined);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -29,7 +29,7 @@ export const Visualization2D: React.FC<
|
||||
const instance = usePlugin(plugin);
|
||||
|
||||
const snapshot = useValue(instance.snapshot);
|
||||
const focusedNodeId = useValue(instance.focusedNode);
|
||||
const focusedNodeId = useValue(instance.uiState.focusedNode);
|
||||
|
||||
const focusState = useMemo(() => {
|
||||
const rootNode = toNestedNode(rootId, nodes);
|
||||
@@ -40,7 +40,7 @@ export const Visualization2D: React.FC<
|
||||
const mouseListener = throttle((ev: MouseEvent) => {
|
||||
const domRect = rootNodeRef.current?.getBoundingClientRect();
|
||||
|
||||
if (!focusState || !domRect || instance.isContextMenuOpen.get()) {
|
||||
if (!focusState || !domRect || instance.uiState.isContextMenuOpen.get()) {
|
||||
return;
|
||||
}
|
||||
const rawMouse = {x: ev.clientX, y: ev.clientY};
|
||||
@@ -63,9 +63,9 @@ export const Visualization2D: React.FC<
|
||||
|
||||
if (
|
||||
hitNodes.length > 0 &&
|
||||
!isEqual(hitNodes, instance.hoveredNodes.get())
|
||||
!isEqual(hitNodes, instance.uiState.hoveredNodes.get())
|
||||
) {
|
||||
instance.hoveredNodes.set(hitNodes);
|
||||
instance.uiState.hoveredNodes.set(hitNodes);
|
||||
}
|
||||
}, MouseThrottle);
|
||||
window.addEventListener('mousemove', mouseListener);
|
||||
@@ -73,7 +73,12 @@ export const Visualization2D: React.FC<
|
||||
return () => {
|
||||
window.removeEventListener('mousemove', mouseListener);
|
||||
};
|
||||
}, [instance.hoveredNodes, focusState, nodes, instance.isContextMenuOpen]);
|
||||
}, [
|
||||
instance.uiState.hoveredNodes,
|
||||
focusState,
|
||||
nodes,
|
||||
instance.uiState.isContextMenuOpen,
|
||||
]);
|
||||
|
||||
if (!focusState) {
|
||||
return null;
|
||||
@@ -94,8 +99,8 @@ export const Visualization2D: React.FC<
|
||||
onMouseLeave={(e) => {
|
||||
e.stopPropagation();
|
||||
//the context menu triggers this callback but we dont want to remove hover effect
|
||||
if (!instance.isContextMenuOpen.get()) {
|
||||
instance.hoveredNodes.set([]);
|
||||
if (!instance.uiState.isContextMenuOpen.get()) {
|
||||
instance.uiState.hoveredNodes.set([]);
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
@@ -169,11 +174,11 @@ function Visualization2DNode({
|
||||
setIsHovered(head(newValue) === node.id);
|
||||
}
|
||||
};
|
||||
instance.hoveredNodes.subscribe(listener);
|
||||
instance.uiState.hoveredNodes.subscribe(listener);
|
||||
return () => {
|
||||
instance.hoveredNodes.unsubscribe(listener);
|
||||
instance.uiState.hoveredNodes.unsubscribe(listener);
|
||||
};
|
||||
}, [instance.hoveredNodes, node.id]);
|
||||
}, [instance.uiState.hoveredNodes, node.id]);
|
||||
|
||||
const isSelected = selectedNode === node.id;
|
||||
|
||||
@@ -224,7 +229,7 @@ function Visualization2DNode({
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
const hoveredNodes = instance.hoveredNodes.get();
|
||||
const hoveredNodes = instance.uiState.hoveredNodes.get();
|
||||
if (hoveredNodes[0] === selectedNode) {
|
||||
onSelectNode(undefined);
|
||||
} else {
|
||||
@@ -241,15 +246,15 @@ function Visualization2DNode({
|
||||
const ContextMenu: React.FC<{nodes: Map<Id, UINode>}> = ({children}) => {
|
||||
const instance = usePlugin(plugin);
|
||||
|
||||
const focusedNodeId = useValue(instance.focusedNode);
|
||||
const hoveredNodeId = head(useValue(instance.hoveredNodes));
|
||||
const focusedNodeId = useValue(instance.uiState.focusedNode);
|
||||
const hoveredNodeId = head(useValue(instance.uiState.hoveredNodes));
|
||||
const nodes = useValue(instance.nodes);
|
||||
const hoveredNode = hoveredNodeId ? nodes.get(hoveredNodeId) : null;
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
onVisibleChange={(open) => {
|
||||
instance.isContextMenuOpen.set(open);
|
||||
instance.uiState.isContextMenuOpen.set(open);
|
||||
}}
|
||||
trigger={['contextMenu']}
|
||||
overlay={() => {
|
||||
@@ -260,7 +265,7 @@ const ContextMenu: React.FC<{nodes: Map<Id, UINode>}> = ({children}) => {
|
||||
key="focus"
|
||||
text={`Focus ${hoveredNode?.name}`}
|
||||
onClick={() => {
|
||||
instance.focusedNode.set(hoveredNode?.id);
|
||||
instance.uiState.focusedNode.set(hoveredNode?.id);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -269,7 +274,7 @@ const ContextMenu: React.FC<{nodes: Map<Id, UINode>}> = ({children}) => {
|
||||
key="remove-focus"
|
||||
text="Remove focus"
|
||||
onClick={() => {
|
||||
instance.focusedNode.set(undefined);
|
||||
instance.uiState.focusedNode.set(undefined);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -30,7 +30,7 @@ export function Component() {
|
||||
|
||||
useHotkeys('ctrl+i', () => setShowPerfStats((show) => !show));
|
||||
|
||||
const searchTerm = useValue(instance.searchTerm);
|
||||
const searchTerm = useValue(instance.uiState.searchTerm);
|
||||
const {ctrlPressed} = useKeyboardModifiers();
|
||||
|
||||
function renderSidebar(
|
||||
@@ -55,7 +55,7 @@ export function Component() {
|
||||
<Layout.Container grow pad="medium" gap="small">
|
||||
<Input
|
||||
value={searchTerm}
|
||||
onChange={(e) => instance.searchTerm.set(e.target.value)}
|
||||
onChange={(e) => instance.uiState.searchTerm.set(e.target.value)}
|
||||
/>
|
||||
<Layout.ScrollContainer>
|
||||
<Tree
|
||||
|
||||
@@ -24,7 +24,7 @@ export const UIDebuggerMenuItem: React.FC<{
|
||||
}> = ({text, onClick}) => {
|
||||
const instance = usePlugin(plugin);
|
||||
|
||||
const isMenuOpen = useValue(instance.isContextMenuOpen);
|
||||
const isMenuOpen = useValue(instance.uiState.isContextMenuOpen);
|
||||
/**
|
||||
* The menu is not a controlled component and seems to be a bit slow to close when user clicks on it.
|
||||
* React may rerender the menu before it has time to close resulting in seeing an incorrect context menu for a frame.
|
||||
@@ -37,7 +37,7 @@ export const UIDebuggerMenuItem: React.FC<{
|
||||
<Menu.Item
|
||||
onClick={() => {
|
||||
onClick();
|
||||
instance.isContextMenuOpen.set(false);
|
||||
instance.uiState.isContextMenuOpen.set(false);
|
||||
}}>
|
||||
{text}
|
||||
</Menu.Item>
|
||||
|
||||
Reference in New Issue
Block a user