123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 |
- import { h } from 'preact';
- import { createPortal } from 'preact/compat';
- import { useLayoutEffect, useRef, useState } from 'preact/hooks';
- const TIP_SPACE = 20;
- export default function Tooltip({ relativeTo, text }) {
- const [position, setPosition] = useState({ top: -9999, left: -9999 });
- const portalRoot = document.getElementById('tooltips');
- const ref = useRef();
- useLayoutEffect(() => {
- if (ref && ref.current && relativeTo && relativeTo.current) {
- const windowWidth = window.innerWidth;
- const {
- x: relativeToX,
- y: relativeToY,
- width: relativeToWidth,
- height: relativeToHeight,
- } = relativeTo.current.getBoundingClientRect();
- const { width: _tipWidth, height: _tipHeight } = ref.current.getBoundingClientRect();
- const tipWidth = _tipWidth * 1.1;
- const tipHeight = _tipHeight * 1.1;
- const left = relativeToX + Math.round(relativeToWidth / 2) + window.scrollX;
- const top = relativeToY + Math.round(relativeToHeight / 2) + window.scrollY;
- let newTop = top - TIP_SPACE - tipHeight;
- let newLeft = left - Math.round(tipWidth / 2);
- // too far right
- if (newLeft + tipWidth + TIP_SPACE > windowWidth - window.scrollX) {
- newLeft = left - tipWidth - TIP_SPACE;
- newTop = top - Math.round(tipHeight / 2);
- }
- // too far left
- else if (newLeft < TIP_SPACE + window.scrollX) {
- newLeft = left + TIP_SPACE;
- newTop = top - Math.round(tipHeight / 2);
- }
- // too close to top
- else if (newTop <= TIP_SPACE + window.scrollY) {
- newTop = top + tipHeight + TIP_SPACE;
- }
- setPosition({ left: newLeft, top: newTop });
- }
- }, [relativeTo, ref]);
- const tooltip = (
- <div
- role="tooltip"
- className={`shadow max-w-lg absolute pointer-events-none bg-gray-900 dark:bg-gray-200 bg-opacity-80 rounded px-2 py-1 transition-transform transition-opacity duration-75 transform scale-90 opacity-0 text-gray-100 dark:text-gray-900 text-sm ${
- position.top >= 0 ? 'opacity-100 scale-100' : ''
- }`}
- ref={ref}
- style={position}
- >
- {text}
- </div>
- );
- return portalRoot ? createPortal(tooltip, portalRoot) : tooltip;
- }
|