Keyboard controls moved selected and hovered node together
Summary: Following feedback when using keyboard controls its a little bit awkward to have to move with arrows and then select with enter. Now when using keyboard controls you are manipulating the selected state. Enter still selects / unselects but its not really needed anymore When using the mouse the hover state is still there Changelog: [UIDebugger] Using keyboard arrow control changes the selected and hovered state together for faster / easier navigation Reviewed By: lblasa Differential Revision: D47212492 fbshipit-source-id: 996196880d623885b4d4b7d1a70954201f809d28
This commit is contained in:
committed by
Facebook GitHub Bot
parent
f3f5018f71
commit
36447d550a
@@ -122,6 +122,7 @@ export function Tree2({nodes, rootId}: {nodes: Map<Id, UINode>; rootId: Id}) {
|
|||||||
selectedNode,
|
selectedNode,
|
||||||
hoveredNode,
|
hoveredNode,
|
||||||
instance.uiActions.onSelectNode,
|
instance.uiActions.onSelectNode,
|
||||||
|
instance.uiActions.onHoverNode,
|
||||||
instance.uiActions.onExpandNode,
|
instance.uiActions.onExpandNode,
|
||||||
instance.uiActions.onCollapseNode,
|
instance.uiActions.onCollapseNode,
|
||||||
isUsingKBToScrollUtill,
|
isUsingKBToScrollUtill,
|
||||||
@@ -163,7 +164,11 @@ export function Tree2({nodes, rootId}: {nodes: Map<Id, UINode>; rootId: Id}) {
|
|||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (selectedNode) {
|
if (selectedNode) {
|
||||||
const idx = treeNodes.findIndex((node) => node.id === selectedNode);
|
const idx = treeNodes.findIndex((node) => node.id === selectedNode);
|
||||||
if (idx !== -1) {
|
|
||||||
|
const kbIsNoLongerReservingScroll =
|
||||||
|
new Date().getTime() > (isUsingKBToScrollUtill.current ?? 0);
|
||||||
|
|
||||||
|
if (idx !== -1 && kbIsNoLongerReservingScroll) {
|
||||||
parentRef.current!!.scrollLeft =
|
parentRef.current!!.scrollLeft =
|
||||||
Math.max(0, treeNodes[idx].depth - 10) * renderDepthOffset;
|
Math.max(0, treeNodes[idx].depth - 10) * renderDepthOffset;
|
||||||
|
|
||||||
@@ -680,6 +685,7 @@ function useKeyboardShortcuts(
|
|||||||
selectedNode: Id | undefined,
|
selectedNode: Id | undefined,
|
||||||
hoveredNodeId: Id | undefined,
|
hoveredNodeId: Id | undefined,
|
||||||
onSelectNode: (id?: Id) => void,
|
onSelectNode: (id?: Id) => void,
|
||||||
|
onHoverNode: (id?: Id) => void,
|
||||||
onExpandNode: (id: Id) => void,
|
onExpandNode: (id: Id) => void,
|
||||||
onCollapseNode: (id: Id) => void,
|
onCollapseNode: (id: Id) => void,
|
||||||
isUsingKBToScrollUntill: React.MutableRefObject<number>,
|
isUsingKBToScrollUntill: React.MutableRefObject<number>,
|
||||||
@@ -692,7 +698,6 @@ function useKeyboardShortcuts(
|
|||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'Enter': {
|
case 'Enter': {
|
||||||
if (hoveredNodeId != null) {
|
if (hoveredNodeId != null) {
|
||||||
extendKBControlLease(isUsingKBToScrollUntill);
|
|
||||||
onSelectNode(hoveredNodeId);
|
onSelectNode(hoveredNodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,11 +708,14 @@ function useKeyboardShortcuts(
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (hoveredNode) {
|
if (hoveredNode) {
|
||||||
if (hoveredNode.isExpanded) {
|
if (hoveredNode.isExpanded) {
|
||||||
moveHoveredNodeUpOrDown(
|
moveSelectedNodeUpOrDown(
|
||||||
'ArrowDown',
|
'ArrowDown',
|
||||||
treeNodes,
|
treeNodes,
|
||||||
rowVirtualizer,
|
rowVirtualizer,
|
||||||
instance.uiState.hoveredNodes,
|
hoveredNodeId,
|
||||||
|
selectedNode,
|
||||||
|
onSelectNode,
|
||||||
|
onHoverNode,
|
||||||
isUsingKBToScrollUntill,
|
isUsingKBToScrollUntill,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -724,11 +732,12 @@ function useKeyboardShortcuts(
|
|||||||
const parentIdx = treeNodes.findIndex(
|
const parentIdx = treeNodes.findIndex(
|
||||||
(treeNode) => treeNode.id === hoveredNode.parent,
|
(treeNode) => treeNode.id === hoveredNode.parent,
|
||||||
);
|
);
|
||||||
moveHoveredNodeViaKeyBoard(
|
moveSelectedNodeViaKeyBoard(
|
||||||
parentIdx,
|
parentIdx,
|
||||||
treeNodes,
|
treeNodes,
|
||||||
rowVirtualizer,
|
rowVirtualizer,
|
||||||
instance.uiState.hoveredNodes,
|
onSelectNode,
|
||||||
|
onHoverNode,
|
||||||
isUsingKBToScrollUntill,
|
isUsingKBToScrollUntill,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -740,11 +749,14 @@ function useKeyboardShortcuts(
|
|||||||
case 'ArrowDown':
|
case 'ArrowDown':
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
moveHoveredNodeUpOrDown(
|
moveSelectedNodeUpOrDown(
|
||||||
event.key,
|
event.key,
|
||||||
treeNodes,
|
treeNodes,
|
||||||
rowVirtualizer,
|
rowVirtualizer,
|
||||||
instance.uiState.hoveredNodes,
|
hoveredNodeId,
|
||||||
|
selectedNode,
|
||||||
|
onSelectNode,
|
||||||
|
onHoverNode,
|
||||||
isUsingKBToScrollUntill,
|
isUsingKBToScrollUntill,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -765,47 +777,54 @@ function useKeyboardShortcuts(
|
|||||||
instance.uiState.hoveredNodes,
|
instance.uiState.hoveredNodes,
|
||||||
hoveredNodeId,
|
hoveredNodeId,
|
||||||
rowVirtualizer,
|
rowVirtualizer,
|
||||||
|
onHoverNode,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UpOrDown = 'ArrowDown' | 'ArrowUp';
|
export type UpOrDown = 'ArrowDown' | 'ArrowUp';
|
||||||
|
|
||||||
function moveHoveredNodeUpOrDown(
|
function moveSelectedNodeUpOrDown(
|
||||||
direction: UpOrDown,
|
direction: UpOrDown,
|
||||||
treeNodes: TreeNode[],
|
treeNodes: TreeNode[],
|
||||||
rowVirtualizer: Virtualizer<HTMLDivElement, Element>,
|
rowVirtualizer: Virtualizer<HTMLDivElement, Element>,
|
||||||
hoveredNodes: Atom<Id[]>,
|
hoveredNode: Id | undefined,
|
||||||
|
selectedNode: Id | undefined,
|
||||||
|
onSelectNode: (id?: Id) => void,
|
||||||
|
onHoverNode: (id?: Id) => void,
|
||||||
isUsingKBToScrollUntill: React.MutableRefObject<MillisSinceEpoch>,
|
isUsingKBToScrollUntill: React.MutableRefObject<MillisSinceEpoch>,
|
||||||
) {
|
) {
|
||||||
const curIdx = treeNodes.findIndex(
|
const nodeToUse = selectedNode != null ? selectedNode : hoveredNode;
|
||||||
(item) => item.id === head(hoveredNodes.get()),
|
const curIdx = treeNodes.findIndex((item) => item.id === nodeToUse);
|
||||||
);
|
|
||||||
if (curIdx != -1) {
|
if (curIdx != -1) {
|
||||||
const increment = direction === 'ArrowDown' ? 1 : -1;
|
const increment = direction === 'ArrowDown' ? 1 : -1;
|
||||||
const newIdx = curIdx + increment;
|
const newIdx = curIdx + increment;
|
||||||
|
|
||||||
moveHoveredNodeViaKeyBoard(
|
moveSelectedNodeViaKeyBoard(
|
||||||
newIdx,
|
newIdx,
|
||||||
treeNodes,
|
treeNodes,
|
||||||
rowVirtualizer,
|
rowVirtualizer,
|
||||||
hoveredNodes,
|
onSelectNode,
|
||||||
|
onHoverNode,
|
||||||
isUsingKBToScrollUntill,
|
isUsingKBToScrollUntill,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveHoveredNodeViaKeyBoard(
|
function moveSelectedNodeViaKeyBoard(
|
||||||
newIdx: number,
|
newIdx: number,
|
||||||
treeNodes: TreeNode[],
|
treeNodes: TreeNode[],
|
||||||
rowVirtualizer: Virtualizer<HTMLDivElement, Element>,
|
rowVirtualizer: Virtualizer<HTMLDivElement, Element>,
|
||||||
hoveredNodes: Atom<Id[]>,
|
onSelectNode: (id?: Id) => void,
|
||||||
|
onHoverNode: (id?: Id) => void,
|
||||||
isUsingKBToScrollUntil: React.MutableRefObject<number>,
|
isUsingKBToScrollUntil: React.MutableRefObject<number>,
|
||||||
) {
|
) {
|
||||||
if (newIdx >= 0 && newIdx < treeNodes.length) {
|
if (newIdx >= 0 && newIdx < treeNodes.length) {
|
||||||
const newNode = treeNodes[newIdx];
|
const newNode = treeNodes[newIdx];
|
||||||
hoveredNodes.set([newNode.id]);
|
|
||||||
|
|
||||||
extendKBControlLease(isUsingKBToScrollUntil);
|
extendKBControlLease(isUsingKBToScrollUntil);
|
||||||
|
onSelectNode(newNode.id);
|
||||||
|
onHoverNode(newNode.id);
|
||||||
|
|
||||||
rowVirtualizer.scrollToIndex(newIdx, {align: 'auto'});
|
rowVirtualizer.scrollToIndex(newIdx, {align: 'auto'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ export function plugin(client: PluginClient<Events>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UIActions = {
|
type UIActions = {
|
||||||
onHoverNode: (node: Id) => void;
|
onHoverNode: (node?: Id) => void;
|
||||||
onFocusNode: (focused?: Id) => void;
|
onFocusNode: (focused?: Id) => void;
|
||||||
onContextMenuOpen: (open: boolean) => void;
|
onContextMenuOpen: (open: boolean) => void;
|
||||||
onSelectNode: (node?: Id) => void;
|
onSelectNode: (node?: Id) => void;
|
||||||
@@ -418,8 +418,12 @@ function uiActions(uiState: UIState, nodes: Atom<Map<Id, UINode>>): UIActions {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onHoverNode = (node: Id) => {
|
const onHoverNode = (node?: Id) => {
|
||||||
|
if (node != null) {
|
||||||
uiState.hoveredNodes.set([node]);
|
uiState.hoveredNodes.set([node]);
|
||||||
|
} else {
|
||||||
|
uiState.hoveredNodes.set([]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onContextMenuOpen = (open: boolean) => {
|
const onContextMenuOpen = (open: boolean) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user