/** * Interactive overlay layer for inline @mention badges. * * Positioned above the textarea (z-20), provides hover tooltips * showing the member/team name and role on mention spans. * * Uses the same mirror div technique (calculateMentionPositions) * as ChipInteractionLayer to position elements exactly over * the corresponding @mention tokens in the textarea. */ import * as React from 'react'; import { MemberBadge } from '@renderer/components/team/MemberBadge'; import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip'; import { getTeamColorSet, getThemedText } from '@renderer/constants/teamColors'; import { useTheme } from '@renderer/hooks/useTheme'; import { calculateMentionPositions } from '@renderer/utils/chipUtils'; import { nameColorSet } from '@renderer/utils/projectColor'; import { UsersRound } from 'lucide-react'; import type { MentionSuggestion } from '@renderer/types/mention'; import type { MentionPosition } from '@renderer/utils/chipUtils'; interface MentionInteractionLayerProps { suggestions: MentionSuggestion[]; value: string; textareaRef: React.RefObject; scrollTop: number; } export const MentionInteractionLayer = ({ suggestions, value, textareaRef, scrollTop, }: MentionInteractionLayerProps): React.JSX.Element | null => { const [positions, setPositions] = React.useState([]); const { isLight } = useTheme(); React.useLayoutEffect(() => { const filtered = suggestions.filter( (s) => s.type !== 'task' && s.type !== 'file' && s.type !== 'folder' ); if (filtered.length === 0) { setPositions([]); return; } const textarea = textareaRef.current; if (!textarea) return; setPositions(calculateMentionPositions(textarea, value, filtered)); }, [suggestions, value, textareaRef]); if (positions.length === 0) return null; return (
{positions.map((pos, idx) => { const isTeam = pos.suggestion.type === 'team'; const colorSet = pos.suggestion.color ? getTeamColorSet(pos.suggestion.color) : isTeam ? nameColorSet(pos.suggestion.name, isLight) : null; return (
{isTeam ? ( ) : ( )}
{pos.suggestion.name}
{pos.suggestion.subtitle ? (
{pos.suggestion.subtitle}
) : null}
); })}
); };