Fixed mobile tooltip positioning on mobile
This commit is contained in:
@@ -4,12 +4,16 @@
|
||||
let showTooltip = false;
|
||||
let touchTimer: number;
|
||||
let isLongPress = false;
|
||||
let tooltipElement: HTMLSpanElement;
|
||||
let wrapperElement: HTMLSpanElement;
|
||||
let tooltipPosition = { align: 'center', vertical: 'top' };
|
||||
|
||||
function handleTouchStart() {
|
||||
isLongPress = false;
|
||||
touchTimer = window.setTimeout(() => {
|
||||
showTooltip = true;
|
||||
isLongPress = true;
|
||||
updateTooltipPosition();
|
||||
}, 500); // Show after 500ms press
|
||||
}
|
||||
|
||||
@@ -29,6 +33,7 @@
|
||||
showTooltip = !showTooltip;
|
||||
// Auto-hide after 3 seconds
|
||||
if (showTooltip) {
|
||||
updateTooltipPosition();
|
||||
setTimeout(() => {
|
||||
showTooltip = false;
|
||||
}, 3000);
|
||||
@@ -39,14 +44,43 @@
|
||||
|
||||
function handleMouseEnter() {
|
||||
showTooltip = true;
|
||||
// Use requestAnimationFrame to ensure DOM is updated before positioning
|
||||
requestAnimationFrame(() => updateTooltipPosition());
|
||||
}
|
||||
|
||||
function handleMouseLeave() {
|
||||
showTooltip = false;
|
||||
}
|
||||
|
||||
function updateTooltipPosition() {
|
||||
if (!tooltipElement || !wrapperElement) return;
|
||||
|
||||
const tooltipRect = tooltipElement.getBoundingClientRect();
|
||||
const wrapperRect = wrapperElement.getBoundingClientRect();
|
||||
const viewportWidth = window.innerWidth;
|
||||
const viewportHeight = window.innerHeight;
|
||||
const padding = 10; // Minimum padding from screen edge
|
||||
|
||||
// Check horizontal overflow
|
||||
let align = 'center';
|
||||
if (tooltipRect.left < padding) {
|
||||
align = 'left';
|
||||
} else if (tooltipRect.right > viewportWidth - padding) {
|
||||
align = 'right';
|
||||
}
|
||||
|
||||
// Check vertical overflow (if tooltip would go above viewport)
|
||||
let vertical = 'top';
|
||||
if (tooltipRect.top < padding) {
|
||||
vertical = 'bottom';
|
||||
}
|
||||
|
||||
tooltipPosition = { align, vertical };
|
||||
}
|
||||
</script>
|
||||
|
||||
<span
|
||||
bind:this={wrapperElement}
|
||||
class="tooltip-wrapper"
|
||||
on:mouseenter={handleMouseEnter}
|
||||
on:mouseleave={handleMouseLeave}
|
||||
@@ -61,7 +95,16 @@
|
||||
>
|
||||
<slot />
|
||||
{#if showTooltip}
|
||||
<span class="tooltip-text" role="status" aria-live="polite">
|
||||
<span
|
||||
bind:this={tooltipElement}
|
||||
class="tooltip-text"
|
||||
class:align-left={tooltipPosition.align === 'left'}
|
||||
class:align-right={tooltipPosition.align === 'right'}
|
||||
class:align-center={tooltipPosition.align === 'center'}
|
||||
class:position-bottom={tooltipPosition.vertical === 'bottom'}
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
{text}
|
||||
</span>
|
||||
{/if}
|
||||
@@ -79,8 +122,6 @@
|
||||
.tooltip-text {
|
||||
position: absolute;
|
||||
bottom: 125%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background-color: var(--bg-color);
|
||||
color: var(--fg-color);
|
||||
border: 2px solid var(--border-color);
|
||||
@@ -94,13 +135,37 @@
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Horizontal alignment variants */
|
||||
.tooltip-text.align-center {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.tooltip-text.align-left {
|
||||
left: 0;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.tooltip-text.align-right {
|
||||
right: 0;
|
||||
left: auto;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
/* Vertical position variant (when tooltip would overflow top) */
|
||||
.tooltip-text.position-bottom {
|
||||
bottom: auto;
|
||||
top: 125%;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.tooltip-text {
|
||||
box-shadow: 0 2px 8px rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip-text::after {
|
||||
/* Arrow positioning for center-aligned tooltip */
|
||||
.tooltip-text.align-center::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
@@ -111,9 +176,49 @@
|
||||
border-color: var(--border-color) transparent transparent transparent;
|
||||
}
|
||||
|
||||
.tooltip-text.align-center.position-bottom::after {
|
||||
top: auto;
|
||||
bottom: 100%;
|
||||
border-color: transparent transparent var(--border-color) transparent;
|
||||
}
|
||||
|
||||
/* Arrow positioning for left-aligned tooltip */
|
||||
.tooltip-text.align-left::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 1rem;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: var(--border-color) transparent transparent transparent;
|
||||
}
|
||||
|
||||
.tooltip-text.align-left.position-bottom::after {
|
||||
top: auto;
|
||||
bottom: 100%;
|
||||
border-color: transparent transparent var(--border-color) transparent;
|
||||
}
|
||||
|
||||
/* Arrow positioning for right-aligned tooltip */
|
||||
.tooltip-text.align-right::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 1rem;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: var(--border-color) transparent transparent transparent;
|
||||
}
|
||||
|
||||
.tooltip-text.align-right.position-bottom::after {
|
||||
top: auto;
|
||||
bottom: 100%;
|
||||
border-color: transparent transparent var(--border-color) transparent;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.tooltip-text {
|
||||
max-width: 250px;
|
||||
max-width: calc(100vw - 20px);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user