Tooltip.tsx 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import "./Tooltip.scss";
  2. import React, { useEffect } from "react";
  3. const getTooltipDiv = () => {
  4. const existingDiv = document.querySelector<HTMLDivElement>(
  5. ".excalidraw-tooltip",
  6. );
  7. if (existingDiv) {
  8. return existingDiv;
  9. }
  10. const div = document.createElement("div");
  11. document.body.appendChild(div);
  12. div.classList.add("excalidraw-tooltip");
  13. return div;
  14. };
  15. const updateTooltip = (
  16. item: HTMLDivElement,
  17. tooltip: HTMLDivElement,
  18. label: string,
  19. long: boolean,
  20. ) => {
  21. tooltip.classList.add("excalidraw-tooltip--visible");
  22. tooltip.style.minWidth = long ? "50ch" : "10ch";
  23. tooltip.style.maxWidth = long ? "50ch" : "15ch";
  24. tooltip.textContent = label;
  25. const {
  26. x: itemX,
  27. bottom: itemBottom,
  28. top: itemTop,
  29. width: itemWidth,
  30. } = item.getBoundingClientRect();
  31. const { width: labelWidth, height: labelHeight } =
  32. tooltip.getBoundingClientRect();
  33. const viewportWidth = window.innerWidth;
  34. const viewportHeight = window.innerHeight;
  35. const margin = 5;
  36. const left = itemX + itemWidth / 2 - labelWidth / 2;
  37. const offsetLeft =
  38. left + labelWidth >= viewportWidth ? left + labelWidth - viewportWidth : 0;
  39. const top = itemBottom + margin;
  40. const offsetTop =
  41. top + labelHeight >= viewportHeight
  42. ? itemBottom - itemTop + labelHeight + margin * 2
  43. : 0;
  44. Object.assign(tooltip.style, {
  45. top: `${top - offsetTop}px`,
  46. left: `${left - offsetLeft}px`,
  47. });
  48. };
  49. type TooltipProps = {
  50. children: React.ReactNode;
  51. label: string;
  52. long?: boolean;
  53. };
  54. export const Tooltip = ({ children, label, long = false }: TooltipProps) => {
  55. useEffect(() => {
  56. return () =>
  57. getTooltipDiv().classList.remove("excalidraw-tooltip--visible");
  58. }, []);
  59. return (
  60. <div
  61. className="excalidraw-tooltip-wrapper"
  62. onPointerEnter={(event) =>
  63. updateTooltip(
  64. event.currentTarget as HTMLDivElement,
  65. getTooltipDiv(),
  66. label,
  67. long,
  68. )
  69. }
  70. onPointerLeave={() =>
  71. getTooltipDiv().classList.remove("excalidraw-tooltip--visible")
  72. }
  73. >
  74. {children}
  75. </div>
  76. );
  77. };