Better fix on mobile tooltips

This commit is contained in:
Nathan Schneider
2025-11-29 17:10:02 -05:00
parent af52f32330
commit bcc6727917

View File

@@ -1,4 +1,6 @@
<script lang="ts">
import { tick } from 'svelte';
export let text: string;
let showTooltip = false;
@@ -8,12 +10,13 @@
let wrapperElement: HTMLSpanElement;
let tooltipPosition = { align: 'center', vertical: 'top' };
function handleTouchStart() {
async function handleTouchStart() {
isLongPress = false;
touchTimer = window.setTimeout(() => {
touchTimer = window.setTimeout(async () => {
showTooltip = true;
isLongPress = true;
updateTooltipPosition();
await tick();
await updateTooltipPosition();
}, 500); // Show after 500ms press
}
@@ -27,13 +30,14 @@
}
}
function handleClick() {
async function handleClick() {
// Toggle tooltip on click/tap
if (!isLongPress) {
showTooltip = !showTooltip;
// Auto-hide after 3 seconds
if (showTooltip) {
updateTooltipPosition();
await tick();
await updateTooltipPosition();
setTimeout(() => {
showTooltip = false;
}, 3000);
@@ -42,34 +46,48 @@
isLongPress = false;
}
function handleMouseEnter() {
async function handleMouseEnter() {
showTooltip = true;
// Use requestAnimationFrame to ensure DOM is updated before positioning
requestAnimationFrame(() => updateTooltipPosition());
await tick();
await updateTooltipPosition();
}
function handleMouseLeave() {
showTooltip = false;
}
function updateTooltipPosition() {
async function updateTooltipPosition() {
// Wait for next frame to ensure rendering is complete
await new Promise(resolve => requestAnimationFrame(resolve));
if (!tooltipElement || !wrapperElement) return;
const tooltipRect = tooltipElement.getBoundingClientRect();
const wrapperRect = wrapperElement.getBoundingClientRect();
const tooltipRect = tooltipElement.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const padding = 10; // Minimum padding from screen edge
const padding = 10;
// Check horizontal overflow
// Calculate tooltip width and position
const tooltipWidth = tooltipRect.width;
const wrapperCenterX = wrapperRect.left + wrapperRect.width / 2;
// Determine horizontal alignment
let align = 'center';
if (tooltipRect.left < padding) {
// Check if center alignment would overflow
const centerLeft = wrapperCenterX - tooltipWidth / 2;
const centerRight = wrapperCenterX + tooltipWidth / 2;
if (centerLeft < padding) {
// Would overflow left, align to left edge of wrapper
align = 'left';
} else if (tooltipRect.right > viewportWidth - padding) {
} else if (centerRight > viewportWidth - padding) {
// Would overflow right, align to right edge of wrapper
align = 'right';
}
// Check vertical overflow (if tooltip would go above viewport)
// Check vertical overflow
let vertical = 'top';
if (tooltipRect.top < padding) {
vertical = 'bottom';
@@ -128,11 +146,13 @@
padding: 0.5rem;
z-index: 1000;
width: max-content;
max-width: 300px;
max-width: min(300px, calc(100vw - 20px));
font-size: 0.85rem;
line-height: 1.4;
text-align: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
word-wrap: break-word;
white-space: normal;
}
/* Horizontal alignment variants */
@@ -143,6 +163,7 @@
.tooltip-text.align-left {
left: 0;
right: auto;
transform: none;
}
@@ -218,7 +239,6 @@
@media (max-width: 768px) {
.tooltip-text {
max-width: calc(100vw - 20px);
font-size: 0.8rem;
}
}