fix: tooltip z-index layering issue

Fixed the '+N more...' tooltip appearing behind other UI elements
by using React Portal to render the tooltip at document.body level.

- Uses createPortal to render tooltip outside stacking context
- Calculates absolute position based on badge location
- Uses z-index 10001 to ensure it's above all other elements
- Maintains purple border styling for consistency

The tooltip now properly appears above all UI elements including
buttons, cards, and other components.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
leex279
2025-09-07 19:43:08 +02:00
parent 95c13cacec
commit c39eac81dd

View File

@@ -1,4 +1,5 @@
import React, { useState, useRef, useEffect } from 'react';
import { createPortal } from 'react-dom';
import { X, Plus } from 'lucide-react';
import { Badge } from '../ui/Badge';
import { Input } from '../../features/ui/primitives/input';
@@ -35,6 +36,8 @@ export const EditableTags: React.FC<EditableTagsProps> = ({
const inputRef = useRef<HTMLInputElement>(null);
const addInputRef = useRef<HTMLInputElement>(null);
const tooltipRef = useRef<HTMLDivElement>(null);
const [tooltipPosition, setTooltipPosition] = useState<{ x: number; y: number } | null>(null);
// Prevent concurrent save operations
const saveInProgress = useRef(false);
@@ -328,9 +331,20 @@ export const EditableTags: React.FC<EditableTagsProps> = ({
{/* More tags tooltip */}
{hasMoreTags && (
<div
ref={tooltipRef}
className="cursor-pointer relative"
onMouseEnter={() => setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
onMouseEnter={(e) => {
const rect = e.currentTarget.getBoundingClientRect();
setTooltipPosition({
x: rect.left + rect.width / 2,
y: rect.bottom + 8
});
setShowTooltip(true);
}}
onMouseLeave={() => {
setShowTooltip(false);
setTooltipPosition(null);
}}
>
<Badge
color="purple"
@@ -339,23 +353,33 @@ export const EditableTags: React.FC<EditableTagsProps> = ({
>
+{remainingTags.length} more...
</Badge>
{showTooltip && (
<div className="absolute top-full mt-2 left-1/2 transform -translate-x-1/2 bg-black dark:bg-zinc-800 text-white text-xs rounded-lg py-2 px-3 shadow-lg z-[100] whitespace-nowrap max-w-xs">
<div className="font-semibold text-purple-300 mb-1">
Additional Tags:
</div>
{remainingTags.map((tag, index) => (
<div key={index} className="text-gray-300">
{tag}
</div>
))}
<div className="absolute bottom-full left-1/2 transform -translate-x-1/2 border-4 border-transparent border-b-black dark:border-b-zinc-800"></div>
</div>
)}
</div>
)}
</div>
{/* Portal tooltip for proper z-index layering */}
{showTooltip && tooltipPosition && createPortal(
<div
className="fixed bg-black dark:bg-zinc-800 text-white text-xs rounded-lg py-2 px-3 shadow-lg z-[10001] whitespace-nowrap max-w-xs border border-purple-500/50 pointer-events-none"
style={{
left: tooltipPosition.x,
top: tooltipPosition.y,
transform: 'translateX(-50%)'
}}
>
<div className="font-semibold text-purple-300 mb-1">
Additional Tags:
</div>
{remainingTags.map((tag, index) => (
<div key={index} className="text-gray-300">
{tag}
</div>
))}
<div className="absolute bottom-full left-1/2 transform -translate-x-1/2 border-4 border-transparent border-b-black dark:border-b-zinc-800"></div>
</div>,
document.body
)}
{/* Error display */}
{validationError && (
<div className="mt-2 text-xs text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded px-2 py-1">