UNPKG

ar-design

Version:

AR Design is a (react | nextjs) ui library.

83 lines (82 loc) 3.45 kB
"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;