From fd5af1e2fa2eaef082384395a6d965541f4edfbd Mon Sep 17 00:00:00 2001 From: chark1es Date: Fri, 21 Feb 2025 01:38:23 -0800 Subject: [PATCH] improve visibility for tooltips --- .../Officer_EventRequestForm/InfoCard.tsx | 10 +- .../Officer_EventRequestForm/Tooltip.tsx | 95 +++++++++++++++++-- 2 files changed, 92 insertions(+), 13 deletions(-) diff --git a/src/components/dashboard/Officer_EventRequestForm/InfoCard.tsx b/src/components/dashboard/Officer_EventRequestForm/InfoCard.tsx index 3545486..9179c83 100644 --- a/src/components/dashboard/Officer_EventRequestForm/InfoCard.tsx +++ b/src/components/dashboard/Officer_EventRequestForm/InfoCard.tsx @@ -51,10 +51,10 @@ export const InfoCard: React.FC = ({ className={`alert ${typeStyles[type]} shadow-sm ${className}`} > {icon || defaultIcons[type]} -
-

{title}

+
+

{title}

= ({ - + {item} ))} diff --git a/src/components/dashboard/Officer_EventRequestForm/Tooltip.tsx b/src/components/dashboard/Officer_EventRequestForm/Tooltip.tsx index 5c9a983..efec622 100644 --- a/src/components/dashboard/Officer_EventRequestForm/Tooltip.tsx +++ b/src/components/dashboard/Officer_EventRequestForm/Tooltip.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Icon } from '@iconify/react'; @@ -12,6 +12,9 @@ interface TooltipProps { maxWidth?: string; } +// Define a small safety margin (in pixels) to keep tooltip from touching viewport edges +const VIEWPORT_MARGIN = 8; + const positionStyles = { top: 'bottom-full left-1/2 -translate-x-1/2 mb-2', bottom: 'top-full left-1/2 -translate-x-1/2 mt-2', @@ -35,10 +38,81 @@ export const Tooltip: React.FC = ({ icon = 'mdi:information', maxWidth = '350px' }) => { - const [isVisible, setIsVisible] = React.useState(false); + const [isVisible, setIsVisible] = useState(false); + const [currentPosition, setCurrentPosition] = useState(position); + const [offset, setOffset] = useState({ x: 0, y: 0 }); + const tooltipRef = useRef(null); + const containerRef = useRef(null); + + useEffect(() => { + if (!isVisible || !tooltipRef.current || !containerRef.current) return; + + const updatePosition = () => { + const tooltip = tooltipRef.current!; + const container = containerRef.current!; + const tooltipRect = tooltip.getBoundingClientRect(); + const containerRect = container.getBoundingClientRect(); + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + + // Calculate overflow amounts + const overflowRight = Math.max(0, tooltipRect.right - (viewportWidth - VIEWPORT_MARGIN)); + const overflowLeft = Math.max(0, VIEWPORT_MARGIN - tooltipRect.left); + const overflowTop = Math.max(0, VIEWPORT_MARGIN - tooltipRect.top); + const overflowBottom = Math.max(0, tooltipRect.bottom - (viewportHeight - VIEWPORT_MARGIN)); + + // Initialize offset adjustments + let xOffset = 0; + let yOffset = 0; + + // Determine best position and calculate offsets + let newPosition = position; + + if (position === 'left' || position === 'right') { + if (position === 'left' && overflowLeft > 0) { + newPosition = 'right'; + } else if (position === 'right' && overflowRight > 0) { + newPosition = 'left'; + } + + // Adjust vertical position if needed + if (overflowTop > 0) { + yOffset = overflowTop; + } else if (overflowBottom > 0) { + yOffset = -overflowBottom; + } + } else { + if (position === 'top' && overflowTop > 0) { + newPosition = 'bottom'; + } else if (position === 'bottom' && overflowBottom > 0) { + newPosition = 'top'; + } + + // Adjust horizontal position if needed + if (overflowRight > 0) { + xOffset = -overflowRight; + } else if (overflowLeft > 0) { + xOffset = overflowLeft; + } + } + + setCurrentPosition(newPosition); + setOffset({ x: xOffset, y: yOffset }); + }; + + updatePosition(); + window.addEventListener('resize', updatePosition); + window.addEventListener('scroll', updatePosition); + + return () => { + window.removeEventListener('resize', updatePosition); + window.removeEventListener('scroll', updatePosition); + }; + }, [isVisible, position]); return (
setIsVisible(true)} onMouseLeave={() => setIsVisible(false)} @@ -49,6 +123,7 @@ export const Tooltip: React.FC = ({ {isVisible && ( = ({ duration: 0.15, ease: 'easeOut' }} - style={{ maxWidth }} + style={{ + maxWidth, + width: 'min(90vw, 350px)', + transform: `translate(${offset.x}px, ${offset.y}px)` + }} className={`absolute z-50 p-3 bg-base-200/95 border border-base-300 rounded-lg shadow-lg backdrop-blur-sm - ${positionStyles[position]}`} + ${positionStyles[currentPosition]}`} > -
+
-
-

{title}

-

{description}

+
+

{title}

+

{description}