File size: 1,473 Bytes
f909d7c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
import React from "react";
import { useDebouncedValue } from "@mantine/hooks";
import { searchQuery, cleanupHighlight, highlightMatchedNodes } from "src/lib/utils/graph/search";
import useGraph from "src/store/useGraph";
export const useFocusNode = () => {
const viewPort = useGraph(state => state.viewPort);
const [selectedNode, setSelectedNode] = React.useState(0);
const [nodeCount, setNodeCount] = React.useState(0);
const [value, setValue] = React.useState("");
const [debouncedValue] = useDebouncedValue(value, 600);
const skip = () => setSelectedNode(current => (current + 1) % nodeCount);
React.useEffect(() => {
if (!value) {
cleanupHighlight();
setSelectedNode(0);
setNodeCount(0);
return;
}
if (!viewPort || !debouncedValue) return;
const matchedNodes: NodeListOf<Element> = searchQuery(`span[data-key*='${debouncedValue}' i]`);
const matchedNode: Element | null = matchedNodes[selectedNode] || null;
cleanupHighlight();
if (matchedNode && matchedNode.parentElement) {
highlightMatchedNodes(matchedNodes, selectedNode);
setNodeCount(matchedNodes.length);
viewPort?.camera.centerFitElementIntoView(matchedNode.parentElement, {
elementExtraMarginForZoom: 400,
});
} else {
setSelectedNode(0);
setNodeCount(0);
}
}, [selectedNode, debouncedValue, value, viewPort]);
return [value, setValue, skip, nodeCount, selectedNode] as const;
};
|