diff --git a/apps/web/src/components/ui/inputs/MentionInput/MentionList/MentionList.tsx b/apps/web/src/components/ui/inputs/MentionInput/MentionList/MentionList.tsx index 1859cbd06..89de3328b 100644 --- a/apps/web/src/components/ui/inputs/MentionInput/MentionList/MentionList.tsx +++ b/apps/web/src/components/ui/inputs/MentionInput/MentionList/MentionList.tsx @@ -1,5 +1,12 @@ import type { SuggestionProps } from '@tiptap/suggestion'; -import React, { useEffect, useImperativeHandle, useState } from 'react'; +import React, { + createContext, + useContext, + useEffect, + useImperativeHandle, + useRef, + useState, +} from 'react'; import { cn } from '@/lib/utils'; import type { MentionInputTriggerItem, @@ -26,6 +33,7 @@ function MentionListInner( { trigger, emptyState, items, command, className }: MentionListProps, ref: React.ForwardedRef ) { + const listRef = useRef(null); const [selectedItem, setSelectedItem] = useState(undefined); const selectItem = (value: T) => { @@ -98,30 +106,55 @@ function MentionListInner( })); return ( -
- {items.length ? ( - items.map((item, index: number) => ( - - key={index} - {...item} - selectedItem={selectedItem} - setSelectedItem={setSelectedItem} - onSelectItem={selectItem} - /> - )) - ) : ( -
{emptyState || 'No results'}
- )} -
+ +
+ {items.length ? ( + items.map((item, index: number) => ( + + key={index} + {...item} + selectedItem={selectedItem} + setSelectedItem={setSelectedItem} + onSelectItem={selectItem} + /> + )) + ) : ( +
{emptyState || 'No results'}
+ )} +
+
); } export const MentionList = React.forwardRef(MentionListInner) as ( props: MentionListProps & { ref?: React.ForwardedRef } ) => ReturnType & { displayName?: string }; + +const MentionListContext = createContext<{ + listRef: React.RefObject | null; +}>({ + listRef: null, +}); + +const MentionListProvider = ({ + children, + listRef, +}: { + children: React.ReactNode; + listRef: React.RefObject; +}) => { + return {children}; +}; + +export const useMentionListRef = () => { + const { listRef } = useContext(MentionListContext); + return listRef; +}; diff --git a/apps/web/src/components/ui/inputs/MentionInput/MentionList/MentionListItem.tsx b/apps/web/src/components/ui/inputs/MentionInput/MentionList/MentionListItem.tsx index 0a10a253b..b012f0876 100644 --- a/apps/web/src/components/ui/inputs/MentionInput/MentionList/MentionListItem.tsx +++ b/apps/web/src/components/ui/inputs/MentionInput/MentionList/MentionListItem.tsx @@ -1,5 +1,8 @@ +import { useEffect, useRef } from 'react'; import { Text } from '@/components/ui/typography/Text'; +import { useInViewport } from '@/hooks/useInViewport'; import { cn } from '@/lib/utils'; +import { useMentionListRef } from './MentionList'; import type { MentionTriggerItemExtended } from './MentionListSelector'; export function MentionListItem({ @@ -13,10 +16,14 @@ export function MentionListItem({ onSelectItem, secondaryContent, }: MentionTriggerItemExtended) { + const containerRef = useRef(null); + return (
onSelectItem(value)} onMouseEnter={() => setSelectedItem(value)} + data-testid={`mention-list-item-${value}`} data-disabled={disabled} data-loading={loading} data-selected={isSelected} diff --git a/apps/web/src/components/ui/inputs/MentionInput/MentionPill.tsx b/apps/web/src/components/ui/inputs/MentionInput/MentionPill.tsx index 46a9d867e..1035f6b8f 100644 --- a/apps/web/src/components/ui/inputs/MentionInput/MentionPill.tsx +++ b/apps/web/src/components/ui/inputs/MentionInput/MentionPill.tsx @@ -13,7 +13,6 @@ export const MentionPill = ({ editor, }: ReactNodeViewProps>) => { const { trigger, label, value, pillLabel } = node.attrs as MentionPillAttributes; - console.log('node', node); const pillStyling = editor.storage.mention.pillStylingByTrigger.get(trigger); const pillClassName = typeof pillStyling?.className === 'function' diff --git a/apps/web/src/hooks/useInViewport.ts b/apps/web/src/hooks/useInViewport.ts index c19a1c7de..ba26536dc 100644 --- a/apps/web/src/hooks/useInViewport.ts +++ b/apps/web/src/hooks/useInViewport.ts @@ -1,11 +1,12 @@ import type React from 'react'; -import { useEffect, useRef, useState } from 'react'; +import { type RefObject, useEffect, useRef, useState } from 'react'; interface UseInViewportOptions { /** The percentage of the element that needs to be visible (0 to 1) */ threshold?: number; /** Margin around the root element (viewport) */ rootMargin?: string; + root?: Element; } /** @@ -36,6 +37,7 @@ export const useInViewport = ( { threshold: options.threshold ?? 0, rootMargin: options.rootMargin ?? '0px', + root: options.root, } ); @@ -49,7 +51,7 @@ export const useInViewport = ( observer.unobserve(currentRef); } }; - }, [ref, options.threshold, options.rootMargin]); + }, [ref, options.threshold, options.rootMargin, options.root]); return [inViewport] as const; };