@@ -94,48 +94,56 @@ export const SymbolHoverPopup: React.FC<SymbolHoverPopupProps> = ({
9494 }
9595 } , [ symbolInfo , onGotoDefinition ] ) ;
9696
97- return symbolInfo ? (
98- < div
99- ref = { ref }
100- className = "absolute z-10 flex flex-col gap-2 bg-background border border-gray-300 dark:border-gray-700 rounded-md shadow-lg p-2 max-w-3xl"
101- onMouseOver = { ( ) => setIsSticky ( true ) }
102- onMouseOut = { ( ) => setIsSticky ( false ) }
103- >
104- { symbolInfo . isSymbolDefinitionsLoading ? (
105- < div className = "flex flex-row items-center gap-2 text-sm" >
106- < Loader2 className = "w-4 h-4 animate-spin" />
107- Loading...
108- </ div >
109- ) : symbolInfo . symbolDefinitions && symbolInfo . symbolDefinitions . length > 0 ? (
110- < SymbolDefinitionPreview
111- symbolDefinition = { symbolInfo . symbolDefinitions [ 0 ] }
112- />
113- ) : (
114- < p className = "text-sm font-medium text-muted-foreground" > No hover info found</ p >
115- ) }
116- < Separator />
117- < div className = "flex flex-row gap-2 mt-2" >
118- < LoadingButton
119- loading = { symbolInfo . isSymbolDefinitionsLoading }
120- disabled = { ! symbolInfo . symbolDefinitions || symbolInfo . symbolDefinitions . length === 0 }
121- variant = "outline"
122- size = "sm"
123- onClick = { onGotoDefinition }
124- >
125- {
126- ! symbolInfo . isSymbolDefinitionsLoading && ( ! symbolInfo . symbolDefinitions || symbolInfo . symbolDefinitions . length === 0 ) ?
127- "No definition found" :
128- `Go to ${ symbolInfo . symbolDefinitions && symbolInfo . symbolDefinitions . length > 1 ? "definitions" : "definition" } `
129- }
130- </ LoadingButton >
131- < Button
132- variant = "outline"
133- size = "sm"
134- onClick = { ( ) => onFindReferences ( symbolInfo . symbolName ) }
135- >
136- Find references
137- </ Button >
97+ if ( ! symbolInfo ) {
98+ return null ;
99+ }
100+
101+ // We use a portal here to render the popup at the document body level.
102+ // This avoids clipping issues that occur when the popup is rendered inside scrollable or overflow-hidden containers (like the editor or its parent).
103+ // By rendering in a portal, the popup can be absolutely positioned anywhere in the viewport without being cut off by parent containers.
104+ return createPortal (
105+ < div
106+ ref = { ref }
107+ className = "absolute z-10 flex flex-col gap-2 bg-background border border-gray-300 dark:border-gray-700 rounded-md shadow-lg p-2 max-w-3xl"
108+ onMouseOver = { ( ) => setIsSticky ( true ) }
109+ onMouseOut = { ( ) => setIsSticky ( false ) }
110+ >
111+ { symbolInfo . isSymbolDefinitionsLoading ? (
112+ < div className = "flex flex-row items-center gap-2 text-sm" >
113+ < Loader2 className = "w-4 h-4 animate-spin" />
114+ Loading...
138115 </ div >
139- </ div >
140- ) : null ;
116+ ) : symbolInfo . symbolDefinitions && symbolInfo . symbolDefinitions . length > 0 ? (
117+ < SymbolDefinitionPreview
118+ symbolDefinition = { symbolInfo . symbolDefinitions [ 0 ] }
119+ />
120+ ) : (
121+ < p className = "text-sm font-medium text-muted-foreground" > No hover info found</ p >
122+ ) }
123+ < Separator />
124+ < div className = "flex flex-row gap-2 mt-2" >
125+ < LoadingButton
126+ loading = { symbolInfo . isSymbolDefinitionsLoading }
127+ disabled = { ! symbolInfo . symbolDefinitions || symbolInfo . symbolDefinitions . length === 0 }
128+ variant = "outline"
129+ size = "sm"
130+ onClick = { onGotoDefinition }
131+ >
132+ {
133+ ! symbolInfo . isSymbolDefinitionsLoading && ( ! symbolInfo . symbolDefinitions || symbolInfo . symbolDefinitions . length === 0 ) ?
134+ "No definition found" :
135+ `Go to ${ symbolInfo . symbolDefinitions && symbolInfo . symbolDefinitions . length > 1 ? "definitions" : "definition" } `
136+ }
137+ </ LoadingButton >
138+ < Button
139+ variant = "outline"
140+ size = "sm"
141+ onClick = { ( ) => onFindReferences ( symbolInfo . symbolName ) }
142+ >
143+ Find references
144+ </ Button >
145+ </ div >
146+ </ div > ,
147+ document . body
148+ ) ;
141149} ;
0 commit comments