@@ -26,26 +26,14 @@ function formatTimestamp(iso: string): string {
2626 }
2727}
2828
29- /**
30- * Common text styling for loading and empty states
31- */
3229const STATE_TEXT_CLASSES = 'px-[8px] py-[8px] text-[12px] text-[var(--text-muted)]'
3330
34- /**
35- * Loading state component for mention folders
36- */
3731const LoadingState = ( ) => < div className = { STATE_TEXT_CLASSES } > Loading...</ div >
3832
39- /**
40- * Empty state component for mention folders
41- */
4233const EmptyState = ( { message } : { message : string } ) => (
4334 < div className = { STATE_TEXT_CLASSES } > { message } </ div >
4435)
4536
46- /**
47- * Aggregated item type for filtered results
48- */
4937interface AggregatedItem {
5038 id : string
5139 label : string
@@ -78,14 +66,6 @@ interface MentionMenuProps {
7866 }
7967}
8068
81- /**
82- * MentionMenu component for mention menu dropdown.
83- * Handles rendering of mention options, submenus, and aggregated search results.
84- * Manages keyboard navigation and selection of mentions.
85- *
86- * @param props - Component props
87- * @returns Rendered mention menu
88- */
8969export function MentionMenu ( {
9070 mentionMenu,
9171 mentionData,
@@ -100,6 +80,7 @@ export function MentionMenu({
10080 submenuActiveIndex,
10181 mentionActiveIndex,
10282 openSubmenuFor,
83+ setOpenSubmenuFor,
10384 } = mentionMenu
10485
10586 const {
@@ -308,72 +289,55 @@ export function MentionMenu({
308289 'Docs' , // 7
309290 ] as const
310291
311- // Get active folder based on navigation when not in submenu and no query
312292 const isInFolderNavigationMode = ! openSubmenuFor && ! showAggregatedView
313293
314- // Compute caret viewport position via mirror technique for precise anchoring
315294 const textareaEl = mentionMenu . textareaRef . current
316295 if ( ! textareaEl ) return null
317296
318- const getCaretViewport = ( textarea : HTMLTextAreaElement , caretPosition : number , text : string ) => {
319- const textareaRect = textarea . getBoundingClientRect ( )
320- const style = window . getComputedStyle ( textarea )
321-
322- const mirrorDiv = document . createElement ( 'div' )
323- mirrorDiv . style . position = 'absolute'
324- mirrorDiv . style . visibility = 'hidden'
325- mirrorDiv . style . whiteSpace = 'pre-wrap'
326- mirrorDiv . style . wordWrap = 'break-word'
327- mirrorDiv . style . font = style . font
328- mirrorDiv . style . padding = style . padding
329- mirrorDiv . style . border = style . border
330- mirrorDiv . style . width = style . width
331- mirrorDiv . style . lineHeight = style . lineHeight
332- mirrorDiv . style . boxSizing = style . boxSizing
333- mirrorDiv . style . letterSpacing = style . letterSpacing
334- mirrorDiv . style . textTransform = style . textTransform
335- mirrorDiv . style . textIndent = style . textIndent
336- mirrorDiv . style . textAlign = style . textAlign
337-
338- mirrorDiv . textContent = text . substring ( 0 , caretPosition )
339-
340- const caretMarker = document . createElement ( 'span' )
341- caretMarker . style . display = 'inline-block'
342- caretMarker . style . width = '0px'
343- caretMarker . style . padding = '0'
344- caretMarker . style . border = '0'
345- mirrorDiv . appendChild ( caretMarker )
346-
347- document . body . appendChild ( mirrorDiv )
348- const markerRect = caretMarker . getBoundingClientRect ( )
349- const mirrorRect = mirrorDiv . getBoundingClientRect ( )
350- document . body . removeChild ( mirrorDiv )
351-
352- const leftOffset = markerRect . left - mirrorRect . left - textarea . scrollLeft
353- const topOffset = markerRect . top - mirrorRect . top - textarea . scrollTop
354-
355- return {
356- left : textareaRect . left + leftOffset ,
357- top : textareaRect . top + topOffset ,
358- }
359- }
360-
361297 const caretPos = getCaretPos ( )
362- const caretViewport = getCaretViewport ( textareaEl , caretPos , message )
298+ const textareaRect = textareaEl . getBoundingClientRect ( )
299+ const style = window . getComputedStyle ( textareaEl )
300+
301+ const mirrorDiv = document . createElement ( 'div' )
302+ mirrorDiv . style . position = 'absolute'
303+ mirrorDiv . style . visibility = 'hidden'
304+ mirrorDiv . style . whiteSpace = 'pre-wrap'
305+ mirrorDiv . style . wordWrap = 'break-word'
306+ mirrorDiv . style . font = style . font
307+ mirrorDiv . style . padding = style . padding
308+ mirrorDiv . style . border = style . border
309+ mirrorDiv . style . width = style . width
310+ mirrorDiv . style . lineHeight = style . lineHeight
311+ mirrorDiv . style . boxSizing = style . boxSizing
312+ mirrorDiv . style . letterSpacing = style . letterSpacing
313+ mirrorDiv . style . textTransform = style . textTransform
314+ mirrorDiv . style . textIndent = style . textIndent
315+ mirrorDiv . style . textAlign = style . textAlign
316+ mirrorDiv . textContent = message . substring ( 0 , caretPos )
317+
318+ const caretMarker = document . createElement ( 'span' )
319+ caretMarker . style . display = 'inline-block'
320+ caretMarker . style . width = '0px'
321+ caretMarker . style . padding = '0'
322+ caretMarker . style . border = '0'
323+ mirrorDiv . appendChild ( caretMarker )
324+
325+ document . body . appendChild ( mirrorDiv )
326+ const markerRect = caretMarker . getBoundingClientRect ( )
327+ const mirrorRect = mirrorDiv . getBoundingClientRect ( )
328+ document . body . removeChild ( mirrorDiv )
329+
330+ const caretViewport = {
331+ left : textareaRect . left + ( markerRect . left - mirrorRect . left ) - textareaEl . scrollLeft ,
332+ top : textareaRect . top + ( markerRect . top - mirrorRect . top ) - textareaEl . scrollTop ,
333+ }
363334
364- // Decide preferred side based on available space
365335 const margin = 8
366- const spaceAbove = caretViewport . top - margin
367336 const spaceBelow = window . innerHeight - caretViewport . top - margin
368- const side : 'top' | 'bottom' = spaceBelow >= spaceAbove ? 'bottom' : 'top'
337+ const side : 'top' | 'bottom' = spaceBelow >= caretViewport . top - margin ? 'bottom' : 'top'
369338
370339 return (
371- < Popover
372- open = { open }
373- onOpenChange = { ( ) => {
374- /* controlled by mentionMenu */
375- } }
376- >
340+ < Popover open = { open } onOpenChange = { ( ) => { } } >
377341 < PopoverAnchor asChild >
378342 < div
379343 style = { {
@@ -399,7 +363,7 @@ export function MentionMenu({
399363 onOpenAutoFocus = { ( e ) => e . preventDefault ( ) }
400364 onCloseAutoFocus = { ( e ) => e . preventDefault ( ) }
401365 >
402- < PopoverBackButton />
366+ < PopoverBackButton onClick = { ( ) => setOpenSubmenuFor ( null ) } />
403367 < PopoverScrollArea ref = { menuListRef } className = 'space-y-[2px]' >
404368 { openSubmenuFor ? (
405369 // Submenu view - showing contents of a specific folder
0 commit comments