useFocusNode.tsx 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import React from "react";
  2. import { useConfig } from "src/hocs/config";
  3. import {
  4. searchQuery,
  5. cleanupHighlight,
  6. highlightMatchedNodes,
  7. } from "src/utils/search";
  8. export const useFocusNode = () => {
  9. const [selectedNode, setSelectedNode] = React.useState(0);
  10. const [content, setContent] = React.useState({
  11. value: "",
  12. debounced: "",
  13. });
  14. const { settings } = useConfig();
  15. const skip = () => setSelectedNode((current) => current + 1);
  16. React.useEffect(() => {
  17. const debouncer = setTimeout(() => {
  18. setContent((val) => ({ ...val, debounced: content.value }));
  19. }, 1500);
  20. return () => clearTimeout(debouncer);
  21. }, [content.value]);
  22. React.useEffect(() => {
  23. if (!settings.zoomPanPinch) return;
  24. const zoomPanPinch = settings.zoomPanPinch.instance.wrapperComponent;
  25. const matchedNodes: NodeListOf<Element> = searchQuery(
  26. `span[data-key*='${content.debounced}' i]`
  27. );
  28. const matchedNode: Element | null = matchedNodes[selectedNode] || null;
  29. cleanupHighlight();
  30. if (zoomPanPinch && matchedNode && matchedNode.parentElement) {
  31. const newScale = 1;
  32. const x = Number(matchedNode.getAttribute("data-x"));
  33. const y = Number(matchedNode.getAttribute("data-y"));
  34. const newPositionX =
  35. (zoomPanPinch.offsetLeft - x) * newScale +
  36. zoomPanPinch.clientWidth / 2 -
  37. matchedNode.getBoundingClientRect().width / 2;
  38. const newPositionY =
  39. (zoomPanPinch.offsetLeft - y) * newScale +
  40. zoomPanPinch.clientHeight / 2 -
  41. matchedNode.getBoundingClientRect().height / 2;
  42. highlightMatchedNodes(matchedNodes, selectedNode);
  43. settings.zoomPanPinch?.setTransform(newPositionX, newPositionY, newScale);
  44. } else {
  45. setSelectedNode(0);
  46. }
  47. return () => {
  48. if (!content.value) setSelectedNode(0);
  49. };
  50. }, [content.debounced, settings.zoomPanPinch, selectedNode, setSelectedNode]);
  51. return [content, setContent, skip] as const;
  52. };