Add arrows to tooltips

This commit is contained in:
2026-08-27 08:11:02 -06:00
parent 7d19068777
commit 263ecbbad7
3 changed files with 59 additions and 5 deletions
+18 -5
View File
@@ -16,17 +16,30 @@ export default modifier((element) => {
const rect = element.getBoundingClientRect();
const tipRect = tooltipEl.getBoundingClientRect();
const margin = 6;
let top = rect.top - tipRect.height - margin;
if (top < margin) top = rect.bottom + margin;
const arrowSize = 6;
// Vertical placement: above trigger, flip below if no room
let placement = 'top';
let top = rect.top - tipRect.height - arrowSize;
if (top < arrowSize) {
placement = 'bottom';
top = rect.bottom + arrowSize;
}
// Horizontal: center on trigger, clamp to viewport
let left = rect.left + rect.width / 2 - tipRect.width / 2;
left = Math.max(
margin,
Math.min(left, window.innerWidth - tipRect.width - margin)
arrowSize,
Math.min(left, window.innerWidth - tipRect.width - arrowSize)
);
// Arrow always points at trigger center, even when clamped
const arrowLeft = rect.left + rect.width / 2 - left;
tooltipEl.dataset.placement = placement;
tooltipEl.style.top = `${top}px`;
tooltipEl.style.left = `${left}px`;
tooltipEl.style.setProperty('--arrow-left', `${arrowLeft}px`);
};
const hide = () => {
+20
View File
@@ -728,6 +728,26 @@ body {
animation: tooltip-fade-in 0.15s ease;
}
.tooltip::after {
content: '';
position: absolute;
width: 0;
height: 0;
border: 6px solid transparent;
left: var(--arrow-left, 50%);
transform: translateX(-50%);
}
.tooltip[data-placement='top']::after {
top: 100%;
border-top-color: var(--body-text-color);
}
.tooltip[data-placement='bottom']::after {
bottom: 100%;
border-bottom-color: var(--body-text-color);
}
@keyframes tooltip-fade-in {
from {
opacity: 0;
@@ -293,9 +293,30 @@ module('Integration | Component | app-menu/settings/nostr', function (hooks) {
removeBtn.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
await settled();
const tooltip = document.body.querySelector('.tooltip');
assert.dom('.tooltip', document.body).exists('tooltip appears on hover');
assert.dom('.tooltip', document.body).hasText('Remove relay');
// Verify arrow is rendered
assert.ok(tooltip.dataset.placement, 'tooltip has placement attribute');
const arrowStyle = getComputedStyle(tooltip, '::after');
assert.strictEqual(arrowStyle.content, '""', 'arrow pseudo-element exists');
// Verify arrow points in correct direction based on placement
if (tooltip.dataset.placement === 'top') {
assert.notStrictEqual(
arrowStyle.borderTopColor,
'rgba(0, 0, 0, 0)',
'arrow points down when tooltip is above trigger'
);
} else {
assert.notStrictEqual(
arrowStyle.borderBottomColor,
'rgba(0, 0, 0, 0)',
'arrow points up when tooltip is below trigger'
);
}
removeBtn.dispatchEvent(new MouseEvent('mouseleave', { bubbles: true }));
await settled();