import React from "react"; import { useConfig } from "src/hocs/config"; import { searchQuery, cleanupHighlight, highlightMatchedNodes, } from "src/utils/search"; export const useFocusNode = () => { const [selectedNode, setSelectedNode] = React.useState(0); const [content, setContent] = React.useState({ value: "", debounced: "", }); const { settings } = useConfig(); const skip = () => setSelectedNode((current) => current + 1); React.useEffect(() => { const debouncer = setTimeout(() => { setContent((val) => ({ ...val, debounced: content.value })); }, 1500); return () => clearTimeout(debouncer); }, [content.value]); React.useEffect(() => { if (!settings.zoomPanPinch) return; const zoomPanPinch = settings.zoomPanPinch.instance.wrapperComponent; const matchedNodes: NodeListOf = searchQuery( `span[data-key*='${content.debounced}' i]` ); const matchedNode: Element | null = matchedNodes[selectedNode] || null; cleanupHighlight(); if (zoomPanPinch && matchedNode && matchedNode.parentElement) { const newScale = 1; const x = Number(matchedNode.getAttribute("data-x")); const y = Number(matchedNode.getAttribute("data-y")); const newPositionX = (zoomPanPinch.offsetLeft - x) * newScale + zoomPanPinch.clientWidth / 2 - matchedNode.getBoundingClientRect().width / 2; const newPositionY = (zoomPanPinch.offsetLeft - y) * newScale + zoomPanPinch.clientHeight / 2 - matchedNode.getBoundingClientRect().height / 2; highlightMatchedNodes(matchedNodes, selectedNode); settings.zoomPanPinch?.setTransform(newPositionX, newPositionY, newScale); } else { setSelectedNode(0); } return () => { if (!content.value) setSelectedNode(0); }; }, [content.debounced, settings.zoomPanPinch, selectedNode, setSelectedNode]); return [content, setContent, skip] as const; };