ar-design
Version:
AR Design is a (react | nextjs) ui library.
83 lines (82 loc) • 3.45 kB
JavaScript
"use client";
import React, { useCallback, useEffect, useRef, useState } from "react";
import ReactDOM from "react-dom";
import "../../../assets/css/components/feedback/tooltip/styles.css";
const Tooltip = ({ children, text, direction = "top" }) => {
// refs
const _arTooltip = useRef(null);
const _children = useRef(null);
// states
const [mouseEnter, setMouseEnter] = useState(false);
const [_direction, setDirection] = useState(direction);
// methods
const handlePosition = useCallback(() => {
const child = _children.current;
const tooltip = _arTooltip.current;
if (!child || !tooltip)
return;
const margin = 17.5;
const windowWidth = window.innerWidth;
const screenCenterX = windowWidth / 2;
const childRect = child.getBoundingClientRect();
const tooltipRect = tooltip.getBoundingClientRect();
const isOnRight = childRect.left > screenCenterX;
if (direction === "top" || direction === "bottom") {
if (isOnRight && tooltipRect.right > windowWidth - 10) {
direction = "left";
}
else if (!isOnRight && tooltipRect.left < 10) {
direction = "right";
}
}
let top = 0;
let left = 0;
switch (direction) {
case "top":
top = childRect.top - tooltipRect.height - margin;
left = childRect.left + childRect.width / 2 - tooltipRect.width / 2;
break;
case "right":
top = childRect.top + childRect.height / 2 - tooltipRect.height / 2;
left = childRect.right + margin;
break;
case "bottom":
top = childRect.bottom + margin;
left = childRect.left + childRect.width / 2 - tooltipRect.width / 2;
break;
case "left":
top = childRect.top + childRect.height / 2 - tooltipRect.height / 2;
left = childRect.left - tooltipRect.width - margin;
break;
}
tooltip.style.top = `${top}px`;
tooltip.style.left = `${left}px`;
setDirection(direction);
}, []);
//useEffects
useEffect(() => {
const observer = new MutationObserver(() => {
handlePosition();
});
observer.observe(document.body, {
attributes: true,
childList: true,
subtree: true,
});
return () => {
observer.disconnect();
};
}, []);
useEffect(() => {
if (mouseEnter)
setTimeout(() => handlePosition(), 0);
}, [mouseEnter]);
return (React.createElement("div", { className: "ar-tooltip-wrapper" },
React.createElement("div", { ref: _children, onMouseEnter: () => setMouseEnter(true), onMouseLeave: () => setMouseEnter(false) }, children),
mouseEnter &&
ReactDOM.createPortal(React.createElement("div", { ref: _arTooltip, className: `ar-tooltip ${_direction}` }, Array.isArray(text) ? (text.map((t) => (React.createElement("span", { className: "text" },
React.createElement("span", { className: "bullet" }, "\u2022"),
React.createElement("span", null, t))))) : (React.createElement("span", { className: "text" }, text))), document.body)));
};
Tooltip.displayName = "Tooltip";
export default Tooltip;