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