|
@@ -1,31 +1,92 @@
|
|
|
import "./Tooltip.scss";
|
|
|
|
|
|
-import React from "react";
|
|
|
+import React, { useEffect } from "react";
|
|
|
+
|
|
|
+const getTooltipDiv = () => {
|
|
|
+ const existingDiv = document.querySelector<HTMLDivElement>(
|
|
|
+ ".excalidraw-tooltip",
|
|
|
+ );
|
|
|
+ if (existingDiv) {
|
|
|
+ return existingDiv;
|
|
|
+ }
|
|
|
+ const div = document.createElement("div");
|
|
|
+ document.body.appendChild(div);
|
|
|
+ div.classList.add("excalidraw-tooltip");
|
|
|
+ return div;
|
|
|
+};
|
|
|
+
|
|
|
+const updateTooltip = (
|
|
|
+ item: HTMLDivElement,
|
|
|
+ tooltip: HTMLDivElement,
|
|
|
+ label: string,
|
|
|
+ long: boolean,
|
|
|
+) => {
|
|
|
+ tooltip.classList.add("excalidraw-tooltip--visible");
|
|
|
+ tooltip.style.minWidth = long ? "50ch" : "10ch";
|
|
|
+ tooltip.style.maxWidth = long ? "50ch" : "15ch";
|
|
|
+
|
|
|
+ tooltip.textContent = label;
|
|
|
+
|
|
|
+ const {
|
|
|
+ x: itemX,
|
|
|
+ bottom: itemBottom,
|
|
|
+ top: itemTop,
|
|
|
+ width: itemWidth,
|
|
|
+ } = item.getBoundingClientRect();
|
|
|
+
|
|
|
+ const {
|
|
|
+ width: labelWidth,
|
|
|
+ height: labelHeight,
|
|
|
+ } = tooltip.getBoundingClientRect();
|
|
|
+
|
|
|
+ const viewportWidth = window.innerWidth;
|
|
|
+ const viewportHeight = window.innerHeight;
|
|
|
+
|
|
|
+ const margin = 5;
|
|
|
+
|
|
|
+ const left = itemX + itemWidth / 2 - labelWidth / 2;
|
|
|
+ const offsetLeft =
|
|
|
+ left + labelWidth >= viewportWidth ? left + labelWidth - viewportWidth : 0;
|
|
|
+
|
|
|
+ const top = itemBottom + margin;
|
|
|
+ const offsetTop =
|
|
|
+ top + labelHeight >= viewportHeight
|
|
|
+ ? itemBottom - itemTop + labelHeight + margin * 2
|
|
|
+ : 0;
|
|
|
+
|
|
|
+ Object.assign(tooltip.style, {
|
|
|
+ top: `${top - offsetTop}px`,
|
|
|
+ left: `${left - offsetLeft}px`,
|
|
|
+ });
|
|
|
+};
|
|
|
|
|
|
type TooltipProps = {
|
|
|
children: React.ReactNode;
|
|
|
label: string;
|
|
|
- position?: "above" | "below";
|
|
|
long?: boolean;
|
|
|
};
|
|
|
|
|
|
-export const Tooltip = ({
|
|
|
- children,
|
|
|
- label,
|
|
|
- position = "below",
|
|
|
- long = false,
|
|
|
-}: TooltipProps) => (
|
|
|
- <div className="Tooltip">
|
|
|
- <span
|
|
|
- className={
|
|
|
- position === "above"
|
|
|
- ? "Tooltip__label Tooltip__label--above"
|
|
|
- : "Tooltip__label Tooltip__label--below"
|
|
|
+export const Tooltip = ({ children, label, long = false }: TooltipProps) => {
|
|
|
+ useEffect(() => {
|
|
|
+ return () =>
|
|
|
+ getTooltipDiv().classList.remove("excalidraw-tooltip--visible");
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div
|
|
|
+ onPointerEnter={(event) =>
|
|
|
+ updateTooltip(
|
|
|
+ event.currentTarget as HTMLDivElement,
|
|
|
+ getTooltipDiv(),
|
|
|
+ label,
|
|
|
+ long,
|
|
|
+ )
|
|
|
+ }
|
|
|
+ onPointerLeave={() =>
|
|
|
+ getTooltipDiv().classList.remove("excalidraw-tooltip--visible")
|
|
|
}
|
|
|
- style={{ width: long ? "50ch" : "10ch" }}
|
|
|
>
|
|
|
- {label}
|
|
|
- </span>
|
|
|
- {children}
|
|
|
- </div>
|
|
|
-);
|
|
|
+ {children}
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+};
|