in translate/src/modules/comments/components/MentionList.tsx [17:111]
export function MentionList({
editor,
index,
onSelect,
suggestedUsers,
target,
}: Props): React.ReactPortal | null {
const ref = useRef<HTMLDivElement>(null);
const [scrollPosition, setScrollPosition] = useState(0);
// Set position of mentions suggestions
useLayoutEffect(() => {
try {
if (ref.current) {
const range = ReactEditor.toDOMRange(editor, target);
setMentionListStyle(ref.current, range);
}
} catch (error) {
// https://github.com/mozilla/pontoon/issues/2298
// toDOMRange may fail on e.g. paste events, as the onChange may be
// triggered before the DOM is updated. In that case, ignore the error
// and let the next render fix things if necessary.
}
}, [editor, suggestedUsers.length, target, scrollPosition]);
// Set scroll position values for Translation and Team Comment containers ~
// This allows for the mention suggestions to stay properly positioned
// when the container scrolls.
useEffect(() => {
const handleScroll = (e: Event) => {
const element = e.currentTarget as HTMLElement;
setScrollPosition(element.scrollTop);
};
const historyScroll = document.querySelector('#history-list');
const teamsScroll = document.querySelector('#react-tabs-3');
if (historyScroll || teamsScroll) {
historyScroll?.addEventListener('scroll', handleScroll);
teamsScroll?.addEventListener('scroll', handleScroll);
return () => {
historyScroll?.removeEventListener('scroll', handleScroll);
teamsScroll?.removeEventListener('scroll', handleScroll);
};
}
}, []);
const setStyleForHover = (ev: React.MouseEvent<HTMLDivElement>) => {
ev.preventDefault();
ev.currentTarget.children[index].className = 'mention';
};
const removeStyleForHover = (ev: React.MouseEvent<HTMLDivElement>) => {
ev.preventDefault();
ev.currentTarget.children[index].className = 'mention active-mention';
};
return document.body && suggestedUsers.length > 0
? createPortal(
<div
ref={ref}
className='comments-mention-list'
onMouseEnter={setStyleForHover}
onMouseLeave={removeStyleForHover}
>
{suggestedUsers.map((user, i) => (
<div
key={user.name}
className={i === index ? 'mention active-mention' : 'mention'}
onMouseDown={(ev) => {
ev.preventDefault();
onSelect(user);
}}
>
<Localized
id='comments-AddComment--mention-avatar-alt'
attrs={{ alt: true }}
>
<span className='user-avatar'>
<img
src={user.gravatar}
alt='User Avatar'
width={22}
height={22}
/>
</span>
</Localized>
<span className='name'>{user.name}</span>
</div>
))}
</div>,
document.body,
)
: null;
}